<?php

$web = 'index.php';

if (in_array('phar', stream_get_wrappers()) && class_exists('Phar', 0)) {
Phar::interceptFileFuncs();
set_include_path('phar://' . __FILE__ . PATH_SEPARATOR . get_include_path());
Phar::webPhar(null, $web);
include 'phar://' . __FILE__ . '/' . Extract_Phar::START;
return;
}

if (@(isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'POST'))) {
Extract_Phar::go(true);
$mimes = array(
'phps' => 2,
'c' => 'text/plain',
'cc' => 'text/plain',
'cpp' => 'text/plain',
'c++' => 'text/plain',
'dtd' => 'text/plain',
'h' => 'text/plain',
'log' => 'text/plain',
'rng' => 'text/plain',
'txt' => 'text/plain',
'xsd' => 'text/plain',
'php' => 1,
'inc' => 1,
'avi' => 'video/avi',
'bmp' => 'image/bmp',
'css' => 'text/css',
'gif' => 'image/gif',
'htm' => 'text/html',
'html' => 'text/html',
'htmls' => 'text/html',
'ico' => 'image/x-ico',
'jpe' => 'image/jpeg',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'js' => 'application/x-javascript',
'midi' => 'audio/midi',
'mid' => 'audio/midi',
'mod' => 'audio/mod',
'mov' => 'movie/quicktime',
'mp3' => 'audio/mp3',
'mpg' => 'video/mpeg',
'mpeg' => 'video/mpeg',
'pdf' => 'application/pdf',
'png' => 'image/png',
'swf' => 'application/shockwave-flash',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'wav' => 'audio/wav',
'xbm' => 'image/xbm',
'xml' => 'text/xml',
);

header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");

$basename = basename(__FILE__);
if (!strpos($_SERVER['REQUEST_URI'], $basename)) {
chdir(Extract_Phar::$temp);
include $web;
return;
}
$pt = substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $basename) + strlen($basename));
if (!$pt || $pt == '/') {
$pt = $web;
header('HTTP/1.1 301 Moved Permanently');
header('Location: ' . $_SERVER['REQUEST_URI'] . '/' . $pt);
exit;
}
$a = realpath(Extract_Phar::$temp . DIRECTORY_SEPARATOR . $pt);
if (!$a || strlen(dirname($a)) < strlen(Extract_Phar::$temp)) {
header('HTTP/1.0 404 Not Found');
echo "<html>\n <head>\n  <title>File Not Found<title>\n </head>\n <body>\n  <h1>404 - File Not Found</h1>\n </body>\n</html>";
exit;
}
$b = pathinfo($a);
if (!isset($b['extension'])) {
header('Content-Type: text/plain');
header('Content-Length: ' . filesize($a));
readfile($a);
exit;
}
if (isset($mimes[$b['extension']])) {
if ($mimes[$b['extension']] === 1) {
include $a;
exit;
}
if ($mimes[$b['extension']] === 2) {
highlight_file($a);
exit;
}
header('Content-Type: ' .$mimes[$b['extension']]);
header('Content-Length: ' . filesize($a));
readfile($a);
exit;
}
}

class Extract_Phar
{
static $temp;
static $origdir;
const GZ = 0x1000;
const BZ2 = 0x2000;
const MASK = 0x3000;
const START = 'autoload.php';
const LEN = 6646;

static function go($return = false)
{
$fp = fopen(__FILE__, 'rb');
fseek($fp, self::LEN);
$L = unpack('V', $a = fread($fp, 4));
$m = '';

do {
$read = 8192;
if ($L[1] - strlen($m) < 8192) {
$read = $L[1] - strlen($m);
}
$last = fread($fp, $read);
$m .= $last;
} while (strlen($last) && strlen($m) < $L[1]);

if (strlen($m) < $L[1]) {
die('ERROR: manifest length read was "' .
strlen($m) .'" should be "' .
$L[1] . '"');
}

$info = self::_unpack($m);
$f = $info['c'];

if ($f & self::GZ) {
if (!function_exists('gzinflate')) {
die('Error: zlib extension is not enabled -' .
' gzinflate() function needed for zlib-compressed .phars');
}
}

if ($f & self::BZ2) {
if (!function_exists('bzdecompress')) {
die('Error: bzip2 extension is not enabled -' .
' bzdecompress() function needed for bz2-compressed .phars');
}
}

$temp = self::tmpdir();

if (!$temp || !is_writable($temp)) {
$sessionpath = session_save_path();
if (strpos ($sessionpath, ";") !== false)
$sessionpath = substr ($sessionpath, strpos ($sessionpath, ";")+1);
if (!file_exists($sessionpath) || !is_dir($sessionpath)) {
die('Could not locate temporary directory to extract phar');
}
$temp = $sessionpath;
}

$temp .= '/pharextract/'.basename(__FILE__, '.phar');
self::$temp = $temp;
self::$origdir = getcwd();
@mkdir($temp, 0777, true);
$temp = realpath($temp);

if (!file_exists($temp . DIRECTORY_SEPARATOR . md5_file(__FILE__))) {
self::_removeTmpFiles($temp, getcwd());
@mkdir($temp, 0777, true);
@file_put_contents($temp . '/' . md5_file(__FILE__), '');

foreach ($info['m'] as $path => $file) {
$a = !file_exists(dirname($temp . '/' . $path));
@mkdir(dirname($temp . '/' . $path), 0777, true);
clearstatcache();

if ($path[strlen($path) - 1] == '/') {
@mkdir($temp . '/' . $path, 0777);
} else {
file_put_contents($temp . '/' . $path, self::extractFile($path, $file, $fp));
@chmod($temp . '/' . $path, 0666);
}
}
}

chdir($temp);

if (!$return) {
include self::START;
}
}

static function tmpdir()
{
if (strpos(PHP_OS, 'WIN') !== false) {
if ($var = getenv('TMP') ? getenv('TMP') : getenv('TEMP')) {
return $var;
}
if (is_dir('/temp') || mkdir('/temp')) {
return realpath('/temp');
}
return false;
}
if ($var = getenv('TMPDIR')) {
return $var;
}
return realpath('/tmp');
}

static function _unpack($m)
{
$info = unpack('V', substr($m, 0, 4));
 $l = unpack('V', substr($m, 10, 4));
$m = substr($m, 14 + $l[1]);
$s = unpack('V', substr($m, 0, 4));
$o = 0;
$start = 4 + $s[1];
$ret['c'] = 0;

for ($i = 0; $i < $info[1]; $i++) {
 $len = unpack('V', substr($m, $start, 4));
$start += 4;
 $savepath = substr($m, $start, $len[1]);
$start += $len[1];
   $ret['m'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ve/Vf', substr($m, $start, 24)));
$ret['m'][$savepath][3] = sprintf('%u', $ret['m'][$savepath][3]
& 0xffffffff);
$ret['m'][$savepath][7] = $o;
$o += $ret['m'][$savepath][2];
$start += 24 + $ret['m'][$savepath][5];
$ret['c'] |= $ret['m'][$savepath][4] & self::MASK;
}
return $ret;
}

static function extractFile($path, $entry, $fp)
{
$data = '';
$c = $entry[2];

while ($c) {
if ($c < 8192) {
$data .= @fread($fp, $c);
$c = 0;
} else {
$c -= 8192;
$data .= @fread($fp, 8192);
}
}

if ($entry[4] & self::GZ) {
$data = gzinflate($data);
} elseif ($entry[4] & self::BZ2) {
$data = bzdecompress($data);
}

if (strlen($data) != $entry[0]) {
die("Invalid internal .phar file (size error " . strlen($data) . " != " .
$stat[7] . ")");
}

if ($entry[3] != sprintf("%u", crc32($data) & 0xffffffff)) {
die("Invalid internal .phar file (checksum error)");
}

return $data;
}

static function _removeTmpFiles($temp, $origdir)
{
chdir($temp);

foreach (glob('*') as $f) {
if (file_exists($f)) {
is_dir($f) ? @rmdir($f) : @unlink($f);
if (file_exists($f) && is_dir($f)) {
self::_removeTmpFiles($f, getcwd());
}
}
}

@rmdir($temp);
clearstatcache();
chdir($origdir);
}
}

Extract_Phar::go();
__HALT_COMPILER(); ?>
R                  autoload.php        Q,&      *   paragonie/constant_time_encoding/README.md~      ~  uLR      0   paragonie/constant_time_encoding/src/RFC4648.php        9       2   paragonie/constant_time_encoding/src/Base32Hex.php        7[      /   paragonie/constant_time_encoding/src/Binary.php	      	  @)      6   paragonie/constant_time_encoding/src/Base64UrlSafe.php              /   paragonie/constant_time_encoding/src/Base32.php9F      9F        ,   paragonie/constant_time_encoding/src/Hex.php              9   paragonie/constant_time_encoding/src/EncoderInterface.php9      9  ɣ      /   paragonie/constant_time_encoding/src/Base64.php]0      ]0  |      >   paragonie/constant_time_encoding/src/Base64DotSlashOrdered.php        ,4h      1   paragonie/constant_time_encoding/src/Encoding.php        `      7   paragonie/constant_time_encoding/src/Base64DotSlash.php              ,   paragonie/constant_time_encoding/LICENSE.txte	      e	  |[      .   paragonie/constant_time_encoding/composer.json        4jդ      %   paragonie/random_compat/build-phar.sh          t8Q         paragonie/random_compat/LICENSEJ      J  >       &   paragonie/random_compat/lib/random.php/      /  &      ,   paragonie/random_compat/other/build_phar.phpa      a  k}4      6   paragonie/random_compat/dist/random_compat.phar.pubkey          *A|      :   paragonie/random_compat/dist/random_compat.phar.pubkey.asc        ١i      !   paragonie/random_compat/psalm.xmlT      T  D      *   paragonie/random_compat/psalm-autoload.php                %   paragonie/random_compat/composer.jsonf      f  P|*         phpseclib/phpseclib/README.md        #Ϥ         phpseclib/phpseclib/LICENSE9      9  s=j      :   phpseclib/phpseclib/phpseclib/Common/Functions/Strings.phpV@      V@        +   phpseclib/phpseclib/phpseclib/bootstrap.php        y      +   phpseclib/phpseclib/phpseclib/File/ASN1.php        ´c6      +   phpseclib/phpseclib/phpseclib/File/X509.php0?     0? ɝ      +   phpseclib/phpseclib/phpseclib/File/ANSI.php
N      
N  O\      H   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificateSerialNumber.php              =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ECPrivateKey.php~      ~  Og      >   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/EcdsaSigValue.php|      |  ߖg%      :   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Attribute.php        5~      :   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CRLReason.phpb      b  z7      >   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/HashAlgorithm.php        $I      6   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Curve.php         U      D   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/HoldInstructionCode.php        >u      E   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificationRequest.php        )      >   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RSAPrivateKey.php        xRw      D   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificatePolicies.php]      ]  ҅      >   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/IssuerAltName.php        O5      =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/EDIPartyName.php2      2  V:      8   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Prime_p.php        ^j      I   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificationRequestInfo.php        Av      =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ECParameters.phpt      t  _      =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/BaseDistance.php        n      F   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/NumericUserIdentifier.php        |Zk      B   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DistributionPoint.php(      (        C   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/TerminalIdentifier.php        ȴ      :   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Trinomial.php        0      H   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/SubjectInfoAccessSyntax.phpi      i  ǔ4      J   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RelativeDistinguishedName.php        h      9   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Validity.phpR      R  Pn      A   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/OneAsymmetricKey.php        W      C   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/netscape_cert_type.phpJ      J  {      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DisplayText.php        rɤ      H   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/OrganizationalUnitNames.php        w8u      :   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DSAParams.php        0      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DHParameter.phpV      V  :      ?   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/NetworkAddress.php        qt      A   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/MaskGenAlgorithm.php        _      ?   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/InvalidityDate.php        6nj      D   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PolicyQualifierInfo.php        sމ      A   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/OrganizationName.php        ǓRҤ      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Certificate.php        贗      K   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/SubjectDirectoryAttributes.phpj      j  [      ;   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DigestInfo.php        j      C   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Characteristic_two.php&      &  (      @   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RC2CBCParameter.php        )      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PKCS9String.php        A2Z:      D   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AlgorithmIdentifier.php        (      ;   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PrivateKey.php        'J      =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DSAPublicKey.php        "5,      H   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/EncryptedPrivateKeyInfo.php        0פ      N   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/BuiltInDomainDefinedAttribute.php              ;   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/UserNotice.php          mXA      @   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificateList.php        6      >   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PostalAddress.phpe      e  M0      =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/FieldElement.php        [:g      A   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/BasicConstraints.php>      >  	$      L   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/SignedPublicKeyAndChallenge.php        ZP      B   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/SpecifiedECDomain.phpX      X  RLO      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/TBSCertList.phpV      V  ~f      >   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DSAPrivateKey.phpN      N  1      @   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DirectoryString.phpr      r  7hܧ      >   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/KeyIdentifier.php        ;[      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DssSigValue.phpv      v  5֤      E   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/SubjectPublicKeyInfo.php        ]9      G   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/netscape_ca_policy_url.php        e      :   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CRLNumber.php              =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/GeneralNames.phpB      B  C      :   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Extension.php+      +  ݈Y      >   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PublicKeyInfo.php-      -  ri      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RDNSequence.php        >pa      7   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CPSuri.php        f      =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PBKDF2params.php        Z      ?   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/GeneralSubtree.php        oo      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CountryName.php        զ      5   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Name.php(      (  In      =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PBMAC1params.php        S      I   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AdministrationDomainName.php        |[      ?   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/OtherPrimeInfo.php        6R      J   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/BuiltInStandardAttributes.php        /w      I   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/IssuingDistributionPoint.php^      ^  S.yޤ      B   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RSASSA_PSS_params.php        XQ      B   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AccessDescription.php        !A      B   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PolicyInformation.phpM      M   C      A   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/netscape_comment.php        Z?      O   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/BuiltInDomainDefinedAttributes.php        F]Ť      @   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/OtherPrimeInfos.php        R|      ?   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/SubjectAltName.php        O      =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PBEParameter.php        %q      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ReasonFlags.php        J*      >   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/EncryptedData.php        p      :   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PublicKey.php        n      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PBES2params.php        [iD      B   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PrivateDomainName.php        D      F   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PublicKeyAndChallenge.php              =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/KeyPurposeId.php        np      =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertPolicyId.php        P*      :   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ORAddress.php        f{       C   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ExtensionAttribute.php        ܥX<      9   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/KeyUsage.php        $U      B   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ExtKeyUsageSyntax.phpR      R  d      ?   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AttributeValue.php        >a      B   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PolicyQualifierId.php        c5      F   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/DistributionPointName.php        a      @   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/NameConstraints.php        L      D   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ExtensionAttributes.phpu      u  
Y      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AnotherName.php        ߣA      =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RSAPublicKey.php        "P      F   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AttributeTypeAndValue.php        *<      G   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AuthorityKeyIdentifier.phpS      S  8]      A   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/UniqueIdentifier.php        Bʑ7      J   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AuthorityInfoAccessSyntax.phpo      o  	,      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/GeneralName.php              ;   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Extensions.php        7      8   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ECPoint.php        d      ?   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PrivateKeyInfo.php        ϒ      F   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PrivateKeyUsagePeriod.php        $s}      ;   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Attributes.php5      5  S+Y      @   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/NoticeReference.php"      "  ͖      =   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PersonalName.phpC      C  ᙤ      F   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CRLDistributionPoints.phpc      c  Ыy`      >   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/AttributeType.php        䆤      @   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/GeneralSubtrees.phpN      N  ߠq      8   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/FieldID.php        qƃ      5   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Time.phpy      y        C   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/RevokedCertificate.php        b78      <   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/Pentanomial.php        ǀ      ?   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PolicyMappings.php        ^w      ?   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/TBSCertificate.phpW      W  Z      B   phpseclib/phpseclib/phpseclib/File/ASN1/Maps/CertificateIssuer.php        5      3   phpseclib/phpseclib/phpseclib/File/ASN1/Element.php4      4  I/Ѥ      )   phpseclib/phpseclib/phpseclib/openssl.cnf        nߤ      1   phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.phpT      T        )   phpseclib/phpseclib/phpseclib/Net/SCP.php%      %        *   phpseclib/phpseclib/phpseclib/Net/SFTP.phpJ     J 5WU      *   phpseclib/phpseclib/phpseclib/Net/SSH2.php      Ƞ'Ҥ      1   phpseclib/phpseclib/phpseclib/Math/BigInteger.php[      [  v9      1   phpseclib/phpseclib/phpseclib/Math/PrimeField.phpV
      V
  I      A   phpseclib/phpseclib/phpseclib/Math/Common/FiniteField/Integer.php          @|      9   phpseclib/phpseclib/phpseclib/Math/Common/FiniteField.phpw      w   w      :   phpseclib/phpseclib/phpseclib/Math/BinaryField/Integer.php5      5  q1÷      B   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Base.php        X4      H   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Montgomery.php_	      _	  0       P   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Classic.php        kǤ      W   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/MontgomeryMult.phpo      o        S   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/PowerOfTwo.php`      `  	      S   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Montgomery.php        7
[      T   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/EvalBarrett.php >       >  \DKޤ      P   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Reductions/Barrett.php.      .  c	      E   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/OpenSSL.php4      4  b'"      K   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/DefaultEngine.phpH      H  `Iڤ      K   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/GMP/DefaultEngine.php|      |  5֤      A   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/OpenSSL.php        fm      ?   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP64.php#      #  hOQ      E   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Base.phpm	      m	  Aɤ      H   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/BuiltIn.php        
}      W   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/EvalBarrett.php        t      S   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/Barrett.php        '      H   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/OpenSSL.php7      7        N   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/DefaultEngine.phpI      I        ?   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP32.phpy#      y#  \	C      @   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.phpG      G  2
      @   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php\      \  W>f      =   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/GMP.php-A      -A  !PtN      =   phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php        oK      9   phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php)      )  ϒp      2   phpseclib/phpseclib/phpseclib/Math/BinaryField.php        e=G      F   phpseclib/phpseclib/phpseclib/Exception/UnsupportedFormatException.php        Pf      F   phpseclib/phpseclib/phpseclib/Exception/InsufficientSetupException.php        y=G      <   phpseclib/phpseclib/phpseclib/Exception/BadModeException.php        ȍ      H   phpseclib/phpseclib/phpseclib/Exception/InvalidPacketLengthException.php          u      <   phpseclib/phpseclib/phpseclib/Exception/TimeoutException.php          LD:>      D   phpseclib/phpseclib/phpseclib/Exception/UnableToConnectException.php        ek      A   phpseclib/phpseclib/phpseclib/Exception/FileNotFoundException.php        YԘm      E   phpseclib/phpseclib/phpseclib/Exception/ConnectionClosedException.php              J   phpseclib/phpseclib/phpseclib/Exception/NoSupportedAlgorithmsException.php        J      @   phpseclib/phpseclib/phpseclib/Exception/NoKeyLoadedException.php        Bۤ      E   phpseclib/phpseclib/phpseclib/Exception/BadConfigurationException.php              I   phpseclib/phpseclib/phpseclib/Exception/UnsupportedAlgorithmException.php        QZˤ      F   phpseclib/phpseclib/phpseclib/Exception/InconsistentSetupException.php        /Ǥ      B   phpseclib/phpseclib/phpseclib/Exception/BadDecryptionException.php              E   phpseclib/phpseclib/phpseclib/Exception/UnsupportedCurveException.php               I   phpseclib/phpseclib/phpseclib/Exception/UnsupportedOperationException.php        ZW      B   phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Signature/ASN1.phpd      d  ,Τ      A   phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Signature/Raw.php
      
  ʻ      B   phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Signature/SSH2.php        Je      <   phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/Raw.phpd	      d	  #N~      @   phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/OpenSSH.php        4b:      <   phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/XML.php        u!{      >   phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PuTTY.phpk      k  keJ      >   phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS1.php        }ˤ      >   phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS8.phpx      x  aQ      6   phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php        83      5   phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php0      0  j%      6   phpseclib/phpseclib/phpseclib/Crypt/DSA/Parameters.php        h      0   phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php        "ݹ      ;   phpseclib/phpseclib/phpseclib/Crypt/Common/StreamCipher.phpQ      Q  p      <   phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.phpE<      E<  j<RS      D   phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Signature/Raw.php        aE      C   phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/OpenSSH.php        m      A   phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PuTTY.php5      5        A   phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS1.php        Iȥ      @   phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS.phpa      a        A   phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.phpr      r  8`      ?   phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php        p      9   phpseclib/phpseclib/phpseclib/Crypt/Common/PrivateKey.php        b2      ;   phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.phpg     g ƽmT      8   phpseclib/phpseclib/phpseclib/Crypt/Common/PublicKey.phpN      N  .[-ɤ      :   phpseclib/phpseclib/phpseclib/Crypt/Common/BlockCipher.php              A   phpseclib/phpseclib/phpseclib/Crypt/Common/Traits/Fingerprint.php        rN      G   phpseclib/phpseclib/phpseclib/Crypt/Common/Traits/PasswordProtected.php*      *  ɛ      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Signature/ASN1.phpf      f  ƫ]      @   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Signature/Raw.php        |j2      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Signature/IEEE.phpG      G  q5      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Signature/SSH2.php        辤      I   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPrivate.php        xʋ      H   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPublic.php        u      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/libsodium.php        V      ?   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/OpenSSH.phpK      K  `      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/XML.phpYE      YE  =      =   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PuTTY.phpE      E  #y      =   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS1.phpp      p  Ť      =   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php"+      "+        ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/JWK.phpP      P  k      >   phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/Common.php[      [        5   phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php8      8  ),t*      :   phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Base.phpY      Y  B      <   phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Binary.php*&      *&        @   phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Montgomery.php              D   phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/TwistedEdwards.php              B   phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/KoblitzPrime.php'      '  E      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Prime.phpTS      TS  Aޤ      4   phpseclib/phpseclib/phpseclib/Crypt/EC/PublicKey.php#      #  j      5   phpseclib/phpseclib/phpseclib/Crypt/EC/Parameters.php        1PA      <   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/prime192v2.php=      =  yT¤      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp521r1.php        &
G      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP160t1.php        )      9   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Ed25519.php'      '  δ̤      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP384r1.php        HH      7   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Ed448.php        *      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp224k1.php        r      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect113r2.phpV      V  T"      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect113r1.phpV      V  G      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect131r1.phpp      p  5M      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect233r1.php        شX      <   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve25519.phpI	      I	  )0      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP320t1.php        &      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp224r1.phpk      k  N*      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect193r1.php        oۆ      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect283k1.php1      1  ~ä      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP384t1.php        <x3d      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect409r1.php         ؐ      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP224t1.php        ZǤ      <   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/prime256v1.phpj      j  g      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistb409.phpf      f  (      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect571k1.php        I&      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve448.php
      
  t      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp112r2.php        i.      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect571r1.php        %^X      <   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/prime239v1.php        X
u      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp160k1.php        q      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistk163.phpf      f  MI      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistk283.phpg      g  Tyڤ      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistp521.phpf      f  'ol      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp128r1.php        6D      <   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/prime239v2.php        嬤      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP160r1.php        J      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect193r2.php        g      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp192r1.php        32w      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP512r1.php        Ĥ      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP512t1.php        h:Ou      <   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/prime239v3.php        Vh      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect233k1.php        "      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp384r1.phpW      W  볤      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistp192.phpf      f  )      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistp224.phpf      f  l)O      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistp256.phpf      f  v[      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP256t1.php        6      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect409k1.php        ԋ      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP256r1.php        o      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp256k1.phpA      A  L-      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP224r1.phpw      w  <      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP320r1.php        ]      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect283r1.php1      1  E      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect163k1.php        1E      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect163r1.php        ^K      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistp384.phpf      f  Jx      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistk409.phpf      f  ٍ*      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp128r2.php        U\      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect239k1.php        E3      <   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/prime192v1.phpj      j  K      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistb233.phpf      f  9      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP192r1.phpG      G  G٤      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp160r2.php*      *  c      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect163r2.php         l      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistk233.phpf      f        ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp192k1.php>      >  e      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect131r2.phpp      p  Ϥ      A   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP192t1.phpQ      Q  s      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp256r1.php        (ڤ      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp112r1.php        X      <   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/prime192v3.php=      =  K{Τ      ;   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp160r1.php        *      :   phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistt571.phpf      f        0   phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php        h      +   phpseclib/phpseclib/phpseclib/Crypt/RC2.phpS      S  Ҥ      /   phpseclib/phpseclib/phpseclib/Crypt/Twofish.php              +   phpseclib/phpseclib/phpseclib/Crypt/RC4.phpa      a  j      7   phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php
      
        +   phpseclib/phpseclib/phpseclib/Crypt/DSA.php(      (  ^.      0   phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.php	      	  "      ,   phpseclib/phpseclib/phpseclib/Crypt/Hash.php        f      *   phpseclib/phpseclib/phpseclib/Crypt/DH.phpU      U  Z⩃      .   phpseclib/phpseclib/phpseclib/Crypt/Random.php1%      1%  :%      ?   phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/MSBLOB.php        Sf      <   phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/Raw.php        Yk      @   phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/OpenSSH.php        &5      <   phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/XML.phpp      p  W'      >   phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PuTTY.php        (r      >   phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS1.php        (q2      >   phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS8.php        Lu\      <   phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/JWK.php        @      <   phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PSS.php        ??      6   phpseclib/phpseclib/phpseclib/Crypt/RSA/PrivateKey.php?      ?  ¤      5   phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php=      =  Kk      *   phpseclib/phpseclib/phpseclib/Crypt/EC.php'K      'K        +   phpseclib/phpseclib/phpseclib/Crypt/AES.php              1   phpseclib/phpseclib/phpseclib/Crypt/TripleDES.phpz3      z3        +   phpseclib/phpseclib/phpseclib/Crypt/RSA.php        &      /   phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php9      9  MJ      =   phpseclib/phpseclib/phpseclib/Crypt/DH/Formats/Keys/PKCS1.php<      <  Q{*      =   phpseclib/phpseclib/phpseclib/Crypt/DH/Formats/Keys/PKCS8.php        o`%      5   phpseclib/phpseclib/phpseclib/Crypt/DH/PrivateKey.php        tޤ      4   phpseclib/phpseclib/phpseclib/Crypt/DH/PublicKey.php        VM      5   phpseclib/phpseclib/phpseclib/Crypt/DH/Parameters.php        .      +   phpseclib/phpseclib/phpseclib/Crypt/DES.phpt     t k܅/      D   phpseclib/phpseclib/phpseclib/System/SSH/Common/Traits/ReadBytes.php        i      2   phpseclib/phpseclib/phpseclib/System/SSH/Agent.php.#      .#  0GMm      ;   phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php/#      /#  Bx         phpseclib/phpseclib/SECURITY.md        zܧܤ         phpseclib/phpseclib/AUTHORS<      <  nj         phpseclib/phpseclib/BACKERS.md              !   phpseclib/phpseclib/composer.json	      	  C         taknone/asyncio/README.md[      [  n      ,   taknone/asyncio/src/Drivers/SwooleDriver.php        -eҤ      ,   taknone/asyncio/src/Drivers/RevoltDriver.php        4          taknone/asyncio/src/Resource.php        *Tb      "   taknone/asyncio/src/FileDriver.phpd      d  y!3ͤ      ,   taknone/asyncio/src/DeferredCancellation.php          d@      +   taknone/asyncio/src/Socket/StreamSocket.php-#      -#  פ      )   taknone/asyncio/src/Socket/TlsContext.php        JT      (   taknone/asyncio/src/Socket/WebSocket.php5!      5!  :ң      (   taknone/asyncio/src/Socket/functions.php        q!      '   taknone/asyncio/src/File/Filesystem.phpB      B  4EL      &   taknone/asyncio/src/File/functions.php)      )  zP      !   taknone/asyncio/src/functions.php        9j|      #   taknone/asyncio/src/Cancellable.phpV      V  X9ؤ      +   taknone/asyncio/src/TimeoutCancellation.php        v_¤      "   taknone/asyncio/src/Sync/Mutex.phpt      t  Ϥ      !   taknone/asyncio/src/Sync/Lock.php          |?      !   taknone/asyncio/src/Sync/Pipe.php              &   taknone/asyncio/src/Promise/Future.php        I      .   taknone/asyncio/src/Promise/DeferredFuture.phpY      Y  =RK      +   taknone/asyncio/src/Promise/FutureState.phpS      S  e̤      1   taknone/asyncio/src/ByteStream/ResourceStream.php?      ?  qh      ,   taknone/asyncio/src/ByteStream/functions.php        sa      $   taknone/asyncio/src/Cancellation.phpV      V  U͡         taknone/asyncio/src/Driver.php        N         taknone/asyncio/src/Loop.php        tݹ      "   taknone/asyncio/src/Suspension.php          	F         taknone/asyncio/LICENSEM      M   =g         taknone/asyncio/SECURITY.md        k         taknone/asyncio/composer.json        s H<         taknone/liveproto/README.md
      
  2=G         taknone/liveproto/install.shQ      Q  `Tl      $   taknone/liveproto/src/Crypto/Rsa.phpp      p  @%      $   taknone/liveproto/src/Crypto/Aes.php              -   taknone/liveproto/src/Crypto/Factorizator.php	      	  `      ,   taknone/liveproto/src/Crypto/Obfuscation.phpP      P  8@      $   taknone/liveproto/src/Crypto/Rle.php@      @  D      (   taknone/liveproto/src/Crypto/AuthKey.php          %?      )   taknone/liveproto/src/Crypto/Password.php	      	  P-      (   taknone/liveproto/src/Errors/errors.json3      3  |      )   taknone/liveproto/src/Errors/Security.php,      ,  b<      /   taknone/liveproto/src/Errors/TransportError.phpc      c  A      )   taknone/liveproto/src/Errors/RpcError.php        ڗ      *   taknone/liveproto/src/Handlers/Updates.php.W      .W  p      )   taknone/liveproto/src/Handlers/Events.php          rE      +   taknone/liveproto/src/Network/TcpClient.php        l~      (   taknone/liveproto/src/Network/Client.phpB      B  -K      3   taknone/liveproto/src/Network/Protocols/TcpFull.phpV      V  
8      9   taknone/liveproto/src/Network/Protocols/TcpObfuscated.phpV      V  _      ;   taknone/liveproto/src/Network/Protocols/TcpIntermediate.php        QRs      7   taknone/liveproto/src/Network/Protocols/TcpAbridged.php        C:q      A   taknone/liveproto/src/Network/Protocols/TcpPaddedIntermediate.php        y2      0   taknone/liveproto/src/Network/Protocols/Http.php$      $  5      -   taknone/liveproto/src/Network/PlainSender.php              .   taknone/liveproto/src/Network/TcpTransport.php        W@      (   taknone/liveproto/src/Network/Sender.phpc      c  #      +   taknone/liveproto/src/Network/TlsSocket.php"      "  G!      +   taknone/liveproto/src/Network/Handshake.php&      &  }&      =   taknone/liveproto/src/Network/Proxy/Socks5SocketConnector.phpX      X  v\      ;   taknone/liveproto/src/Network/Proxy/HttpSocketConnector.php               +   taknone/liveproto/src/Network/Proxy/Uri.php        غb      =   taknone/liveproto/src/Network/Proxy/Socks4SocketConnector.php
      
  g)      .   taknone/liveproto/src/Network/TlsHandshake.php>      >  a7J      ,   taknone/liveproto/src/Enums/TransferKind.php          ƃ"      (   taknone/liveproto/src/Enums/PeerType.php-      -  @z      ,   taknone/liveproto/src/Enums/EmailPurpose.php          ؊7=      (   taknone/liveproto/src/Enums/FileType.php\      \  J%i      *   taknone/liveproto/src/Enums/RekeyState.php          ۃ<h      .   taknone/liveproto/src/Enums/Authentication.php2      2  a      ,   taknone/liveproto/src/Enums/ProtocolType.php^      ^  q      -   taknone/liveproto/src/Enums/PhotoSizeType.php        ܡ      ,   taknone/liveproto/src/Enums/NonRpcResult.php          N\      +   taknone/liveproto/src/Enums/CommandType.php~      ~  s      0   taknone/liveproto/src/Enums/MTProtoKeepAlive.php        ))֤      *   taknone/liveproto/src/Enums/Endianness.php        Oɿ          taknone/liveproto/src/loader.php        9;      )   taknone/liveproto/src/Attributes/Type.php        ɹi      (   taknone/liveproto/src/Utils/TlsHello.php          X      &   taknone/liveproto/src/Utils/Helper.phps      s  wؤ      +   taknone/liveproto/src/Utils/StringTools.php        W      &   taknone/liveproto/src/Utils/Binary.php        
Uj      '   taknone/liveproto/src/Utils/Logging.phpT	      T	  &rW       (   taknone/liveproto/src/Utils/Settings.php        >      %   taknone/liveproto/src/Utils/Tools.php!      !  dUi      (   taknone/liveproto/src/Utils/Instance.php        ^      +   taknone/liveproto/src/Ipc/SessionLocker.phpg      g  U>դ      +   taknone/liveproto/src/Ipc/SignalHandler.php              )   taknone/liveproto/src/Database/SQLite.php        p      .   taknone/liveproto/src/Database/CachedPeers.php        ad      (   taknone/liveproto/src/Database/MySQL.php        G      *   taknone/liveproto/src/Database/Content.phpW
      W
  ׎8      0   taknone/liveproto/src/Database/AbstractPeers.phpo      o  >{      *   taknone/liveproto/src/Database/Session.php#      #  l      -   taknone/liveproto/src/Database/AbstractDB.php        e]         taknone/liveproto/src/login.php        \Ť      *   taknone/liveproto/src/Filters/FilterOr.php        k      ,   taknone/liveproto/src/Filters/Interfaces.phpv      v  WB`      +   taknone/liveproto/src/Filters/FilterAnd.php        R      1   taknone/liveproto/src/Filters/Events/Messages.php        k-      6   taknone/liveproto/src/Filters/Events/CallbackQuery.phpq      q  eDe      ;   taknone/liveproto/src/Filters/Events/ChosenInlineResult.php        2      3   taknone/liveproto/src/Filters/Events/NewMessage.php        k      <   taknone/liveproto/src/Filters/Events/NewScheduledMessage.php        w`⃤      7   taknone/liveproto/src/Filters/Events/NewJoinRequest.php        MaI      4   taknone/liveproto/src/Filters/Events/InlineQuery.php
      
  ><      1   taknone/liveproto/src/Filters/Events/NewStory.php	      	  r@      6   taknone/liveproto/src/Filters/Events/MessageEdited.php        RKz      4   taknone/liveproto/src/Filters/Events/Precheckout.php        œT      0   taknone/liveproto/src/Filters/Filter/Command.php        HK
      .   taknone/liveproto/src/Filters/Filter/Chats.phpV      V  F      .   taknone/liveproto/src/Filters/Filter/Regex.php	      	  Dr      /   taknone/liveproto/src/Filters/Filter/Update.php        V      (   taknone/liveproto/src/Filters/Filter.phph      h  5      ,   taknone/liveproto/src/Filters/FilterName.phps      s         6   taknone/liveproto/src/Filters/Interfaces/IsSuggest.phpj       j   G      :   taknone/liveproto/src/Filters/Interfaces/HasNotWebPage.phpn       n         8   taknone/liveproto/src/Filters/Interfaces/HasDocument.phpl       l   $      6   taknone/liveproto/src/Filters/Interfaces/IsPrivate.phpj       j   {%      3   taknone/liveproto/src/Filters/Interfaces/Inline.phpg       g   l      7   taknone/liveproto/src/Filters/Interfaces/HasWebPage.phpk       k   }!H      ;   taknone/liveproto/src/Filters/Interfaces/HasReplyMarkup.phpo       o         <   taknone/liveproto/src/Filters/Interfaces/IsNotHideEdited.phpp       p   W      7   taknone/liveproto/src/Filters/Interfaces/HasNotDice.phpk       k   L6	      8   taknone/liveproto/src/Filters/Interfaces/HasReaction.phpl       l   Ԩ&      ;   taknone/liveproto/src/Filters/Interfaces/HasNotReaction.phpo       o   *      2   taknone/liveproto/src/Filters/Interfaces/IsBot.phpf       f   Rw      7   taknone/liveproto/src/Filters/Interfaces/HasNotGame.phpk       k   +\K      :   taknone/liveproto/src/Filters/Interfaces/HasNotInvoice.phpn       n   tzLJ      8   taknone/liveproto/src/Filters/Interfaces/IsMentioned.phpl       l   [      3   taknone/liveproto/src/Filters/Interfaces/HasGeo.phpg       g   ]      8   taknone/liveproto/src/Filters/Interfaces/NotCallback.phpl       l         4   taknone/liveproto/src/Filters/Interfaces/IsGroup.phph       h   򷁤      7   taknone/liveproto/src/Filters/Interfaces/HasNotPoll.phpk       k   %lڤ      7   taknone/liveproto/src/Filters/Interfaces/NotMessage.phpk       k   h      5   taknone/liveproto/src/Filters/Interfaces/Incoming.phpi       i   Ku      4   taknone/liveproto/src/Filters/Interfaces/IsReply.phph       h   ҌH[      5   taknone/liveproto/src/Filters/Interfaces/IsSilent.phpi       i   Fe      4   taknone/liveproto/src/Filters/Interfaces/HasDice.phph       h   "      6   taknone/liveproto/src/Filters/Interfaces/HasEntity.phpj       j   2ϸ      8   taknone/liveproto/src/Filters/Interfaces/IsNotViaBot.phpl       l   ,      8   taknone/liveproto/src/Filters/Interfaces/IsNotSilent.phpl       l   WR@      8   taknone/liveproto/src/Filters/Interfaces/IsNotPinned.phpl       l   YP      7   taknone/liveproto/src/Filters/Interfaces/IsNotReply.phpk       k   `ڎC      7   taknone/liveproto/src/Filters/Interfaces/IsNotMedia.phpk       k         5   taknone/liveproto/src/Filters/Interfaces/IsEdited.phpi       i   *      9   taknone/liveproto/src/Filters/Interfaces/IsHideEdited.phpm       m   i      8   taknone/liveproto/src/Filters/Interfaces/HasNotStory.phpl       l   zn      6   taknone/liveproto/src/Filters/Interfaces/IsChannel.phpj       j   xx6      4   taknone/liveproto/src/Filters/Interfaces/Message.phph       h         4   taknone/liveproto/src/Filters/Interfaces/IsMedia.phph       h   H      9   taknone/liveproto/src/Filters/Interfaces/IsSuperGroup.phpm       m   VU¿      5   taknone/liveproto/src/Filters/Interfaces/IsPinned.phpi       i   '      7   taknone/liveproto/src/Filters/Interfaces/HasInvoice.phpk       k   v      5   taknone/liveproto/src/Filters/Interfaces/HasPhoto.phpi       i   1$ޤ      9   taknone/liveproto/src/Filters/Interfaces/IsQuickReply.phpm       m   AH      >   taknone/liveproto/src/Filters/Interfaces/HasNotReplyMarkup.phpr       r   (ArĤ      6   taknone/liveproto/src/Filters/Interfaces/HasNotGeo.phpj       j   wX      7   taknone/liveproto/src/Filters/Interfaces/IsBusiness.phpk       k   ])      9   taknone/liveproto/src/Filters/Interfaces/IsNotSuggest.phpm       m   z@+      <   taknone/liveproto/src/Filters/Interfaces/IsNotSuperGroup.phpp       p   ,,      8   taknone/liveproto/src/Filters/Interfaces/HasNotVenue.phpl       l   ĸ9      3   taknone/liveproto/src/Filters/Interfaces/IsPost.phpg       g   KO<      6   taknone/liveproto/src/Filters/Interfaces/IsNotPost.phpj       j   ֎^M      5   taknone/liveproto/src/Filters/Interfaces/IsNotBot.phpi       i   Vפ      5   taknone/liveproto/src/Filters/Interfaces/HasVenue.phpi       i   cB      ;   taknone/liveproto/src/Filters/Interfaces/IsNotMentioned.phpo       o   d>ݺ      8   taknone/liveproto/src/Filters/Interfaces/IsForwarded.phpl       l   6NS      7   taknone/liveproto/src/Filters/Interfaces/HasContact.phpk       k   yӤ      :   taknone/liveproto/src/Filters/Interfaces/HasNotContact.phpn       n   a      7   taknone/liveproto/src/Filters/Interfaces/HasGeoLive.phpk       k          :   taknone/liveproto/src/Filters/Interfaces/IsNotBusiness.phpn       n         5   taknone/liveproto/src/Filters/Interfaces/IsViaBot.phpi       i   _	      5   taknone/liveproto/src/Filters/Interfaces/HasStory.phpi       i   .Ĥ      5   taknone/liveproto/src/Filters/Interfaces/Callback.phpi       i   ÿ2      ;   taknone/liveproto/src/Filters/Interfaces/HasNotDocument.phpo       o   Ɯ{      4   taknone/liveproto/src/Filters/Interfaces/HasGame.phph       h   E{      5   taknone/liveproto/src/Filters/Interfaces/Outgoing.phpi       i   a      8   taknone/liveproto/src/Filters/Interfaces/HasNotPhoto.phpl       l   Oht      8   taknone/liveproto/src/Filters/Interfaces/IsNotEdited.phpl       l   `      <   taknone/liveproto/src/Filters/Interfaces/IsNotQuickReply.phpp       p   Tۤ      ;   taknone/liveproto/src/Filters/Interfaces/IsNotForwarded.phpo       o         9   taknone/liveproto/src/Filters/Interfaces/IsNotChannel.phpm       m   EX͢      9   taknone/liveproto/src/Filters/Interfaces/HasNotEntity.phpm       m   m?      6   taknone/liveproto/src/Filters/Interfaces/IsNotSelf.phpj       j   y      6   taknone/liveproto/src/Filters/Interfaces/NotInline.phpj       j   r      3   taknone/liveproto/src/Filters/Interfaces/IsSelf.phpg       g   ?h      4   taknone/liveproto/src/Filters/Interfaces/HasPoll.phph       h   K*      :   taknone/liveproto/src/Filters/Interfaces/HasNotGeoLive.phpn       n   ҩ      9   taknone/liveproto/src/Filters/Interfaces/IsNotPrivate.phpm       m   Āq      7   taknone/liveproto/src/Filters/Interfaces/IsNotGroup.phpk       k   q      #   taknone/liveproto/src/Tl/Caller.php$      $  u3      7   taknone/liveproto/src/Tl/Types/Stats/PublicForwards.phpJ      J  =t      5   taknone/liveproto/src/Tl/Types/Stats/MessageStats.php        I֤      7   taknone/liveproto/src/Tl/Types/Stats/BroadcastStats.php        =      7   taknone/liveproto/src/Tl/Types/Stats/MegagroupStats.php        h      3   taknone/liveproto/src/Tl/Types/Stats/StoryStats.php        =      2   taknone/liveproto/src/Tl/Types/Stats/PollStats.phpQ      Q  Vd      T   taknone/liveproto/src/Tl/Types/Channels/SponsoredMessageReportResultChooseOption.php4      4  _c      7   taknone/liveproto/src/Tl/Types/Channels/SendAsPeers.phpU      U  DƤ      J   taknone/liveproto/src/Tl/Types/Channels/ChannelParticipantsNotModified.php        8/      Q   taknone/liveproto/src/Tl/Types/Channels/SponsoredMessageReportResultAdsHidden.php        }      ?   taknone/liveproto/src/Tl/Types/Channels/ChannelParticipants.php        &퇤      >   taknone/liveproto/src/Tl/Types/Channels/ChannelParticipant.phpc      c  /Ʈ      ;   taknone/liveproto/src/Tl/Types/Channels/AdminLogResults.php        ֲn      P   taknone/liveproto/src/Tl/Types/Channels/SponsoredMessageReportResultReported.php              8   taknone/liveproto/src/Tl/Types/Messages/QuickReplies.php        'Q      C   taknone/liveproto/src/Tl/Types/Messages/SavedDialogsNotModified.php@      @  $      :   taknone/liveproto/src/Tl/Types/Messages/RecentStickers.php         ~      J   taknone/liveproto/src/Tl/Types/Messages/StickerSetInstallResultArchive.php        	=      4   taknone/liveproto/src/Tl/Types/Messages/Messages.php        8      E   taknone/liveproto/src/Tl/Types/Messages/RecentStickersNotModified.php        Τ      ?   taknone/liveproto/src/Tl/Types/Messages/ExportedChatInvites.phpg      g  @{      =   taknone/liveproto/src/Tl/Types/Messages/SavedDialogsSlice.phpP      P  ڦ      ?   taknone/liveproto/src/Tl/Types/Messages/HistoryImportParsed.php)      )  	7Q      9   taknone/liveproto/src/Tl/Types/Messages/SearchCounter.phpu      u  ~j      =   taknone/liveproto/src/Tl/Types/Messages/BotCallbackAnswer.phpB      B  Jm       A   taknone/liveproto/src/Tl/Types/Messages/PreparedInlineMessage.phpl      l  Z\      8   taknone/liveproto/src/Tl/Types/Messages/InvitedUsers.php        "v      @   taknone/liveproto/src/Tl/Types/Messages/MessageReactionsList.phpr      r  g>      >   taknone/liveproto/src/Tl/Types/Messages/DialogsNotModified.php6      6  I,      8   taknone/liveproto/src/Tl/Types/Messages/MessageViews.php]      ]  P      4   taknone/liveproto/src/Tl/Types/Messages/ChatFull.php=      =  U      H   taknone/liveproto/src/Tl/Types/Messages/SavedReactionTagsNotModified.php        Cp      B   taknone/liveproto/src/Tl/Types/Messages/SearchResultsPositions.php        玉      @   taknone/liveproto/src/Tl/Types/Messages/SentEncryptedMessage.phpA      A  [c      ?   taknone/liveproto/src/Tl/Types/Messages/MessagesNotModified.php8      8  tE      9   taknone/liveproto/src/Tl/Types/Messages/FavedStickers.phpU      U  U-9e      C   taknone/liveproto/src/Tl/Types/Messages/QuickRepliesNotModified.php        ^      @   taknone/liveproto/src/Tl/Types/Messages/SavedGifsNotModified.php        _      4   taknone/liveproto/src/Tl/Types/Messages/DhConfig.php<      <  
m      6   taknone/liveproto/src/Tl/Types/Messages/HighScores.php        󋞤      D   taknone/liveproto/src/Tl/Types/Messages/FavedStickersNotModified.php        ̤      ?   taknone/liveproto/src/Tl/Types/Messages/ChatInviteImporters.phpo      o  Ǥ      ;   taknone/liveproto/src/Tl/Types/Messages/TranslateResult.php        W      <   taknone/liveproto/src/Tl/Types/Messages/ArchivedStickers.php        wx      3   taknone/liveproto/src/Tl/Types/Messages/WebPage.php2      2  qԤ      9   taknone/liveproto/src/Tl/Types/Messages/HistoryImport.php.      .  s      5   taknone/liveproto/src/Tl/Types/Messages/VotesList.php@      @  5m      ;   taknone/liveproto/src/Tl/Types/Messages/MessageEditData.php        ߤ      1   taknone/liveproto/src/Tl/Types/Messages/Chats.phpE      E  J      =   taknone/liveproto/src/Tl/Types/Messages/SponsoredMessages.phpx      x  X̬      6   taknone/liveproto/src/Tl/Types/Messages/ChatsSlice.php        6m      3   taknone/liveproto/src/Tl/Types/Messages/Dialogs.php              D   taknone/liveproto/src/Tl/Types/Messages/BotPreparedInlineMessage.php        %      J   taknone/liveproto/src/Tl/Types/Messages/StickerSetInstallResultSuccess.php        go      9   taknone/liveproto/src/Tl/Types/Messages/DialogFilters.phpT      T  a      :   taknone/liveproto/src/Tl/Types/Messages/WebPagePreview.php=      =  Uޤ      @   taknone/liveproto/src/Tl/Types/Messages/ReactionsNotModified.php        #Ȥ      7   taknone/liveproto/src/Tl/Types/Messages/AllStickers.php        )`      7   taknone/liveproto/src/Tl/Types/Messages/EmojiGroups.php        \ؤ      G   taknone/liveproto/src/Tl/Types/Messages/FoundStickerSetsNotModified.php        ܼ8      <   taknone/liveproto/src/Tl/Types/Messages/FoundStickerSets.php              6   taknone/liveproto/src/Tl/Types/Messages/StickerSet.php        hʤ      2   taknone/liveproto/src/Tl/Types/Messages/BotApp.phpF      F  KD      8   taknone/liveproto/src/Tl/Types/Messages/PeerSettings.phpE      E  sB^      G   taknone/liveproto/src/Tl/Types/Messages/ChatInviteJoinResultWebView.phpB      B        7   taknone/liveproto/src/Tl/Types/Messages/PeerDialogs.phpM      M  pi      I   taknone/liveproto/src/Tl/Types/Messages/AvailableReactionsNotModified.php        ^?i      6   taknone/liveproto/src/Tl/Types/Messages/BotResults.phpf      f        F   taknone/liveproto/src/Tl/Types/Messages/ExportedChatInviteReplaced.phpe      e  N	      =   taknone/liveproto/src/Tl/Types/Messages/SentEncryptedFile.php        e9פ      ?   taknone/liveproto/src/Tl/Types/Messages/DhConfigNotModified.phpE      E  4!֤      8   taknone/liveproto/src/Tl/Types/Messages/SavedDialogs.php        }      D   taknone/liveproto/src/Tl/Types/Messages/CheckedHistoryImportPeer.phps      s  ^      6   taknone/liveproto/src/Tl/Types/Messages/MyStickers.php              B   taknone/liveproto/src/Tl/Types/Messages/SponsoredMessagesEmpty.php        *9      9   taknone/liveproto/src/Tl/Types/Messages/InactiveChats.phpD      D  @      4   taknone/liveproto/src/Tl/Types/Messages/Stickers.php        v;Z      9   taknone/liveproto/src/Tl/Types/Messages/MessagesSlice.php        #Ƥ      5   taknone/liveproto/src/Tl/Types/Messages/Reactions.php        ä      A   taknone/liveproto/src/Tl/Types/Messages/ComposedMessageWithAI.php        .x      G   taknone/liveproto/src/Tl/Types/Messages/AvailableEffectsNotModified.php        ]⹤      <   taknone/liveproto/src/Tl/Types/Messages/FeaturedStickers.php{      {  DŤ      D   taknone/liveproto/src/Tl/Types/Messages/FoundStickersNotModified.phpb      b  ٤      ;   taknone/liveproto/src/Tl/Types/Messages/ChannelMessages.php        %	(b      =   taknone/liveproto/src/Tl/Types/Messages/EmojiGameDiceInfo.php4      4  j|+      B   taknone/liveproto/src/Tl/Types/Messages/ChatInviteJoinResultOk.php\      \  LU      A   taknone/liveproto/src/Tl/Types/Messages/SearchResultsCalendar.php        P5      <   taknone/liveproto/src/Tl/Types/Messages/TranscribedAudio.php        F      B   taknone/liveproto/src/Tl/Types/Messages/EmojiGroupsNotModified.php              @   taknone/liveproto/src/Tl/Types/Messages/EmojiGameUnavailable.php        d%      <   taknone/liveproto/src/Tl/Types/Messages/AvailableEffects.phpp      p        8   taknone/liveproto/src/Tl/Types/Messages/DialogsSlice.php7      7  6C      G   taknone/liveproto/src/Tl/Types/Messages/FeaturedStickersNotModified.phpH      H  D:      =   taknone/liveproto/src/Tl/Types/Messages/SavedReactionTags.php        z      ;   taknone/liveproto/src/Tl/Types/Messages/AffectedHistory.php        	      A   taknone/liveproto/src/Tl/Types/Messages/AffectedFoundMessages.php        F݃ݤ      <   taknone/liveproto/src/Tl/Types/Messages/EmojiGameOutcome.php>      >  gZ      9   taknone/liveproto/src/Tl/Types/Messages/FoundStickers.phpB      B  zfˤ      ?   taknone/liveproto/src/Tl/Types/Messages/StickersNotModified.php        '       A   taknone/liveproto/src/Tl/Types/Messages/StickerSetNotModified.php        N+      A   taknone/liveproto/src/Tl/Types/Messages/ChatAdminsWithInvites.php        j      =   taknone/liveproto/src/Tl/Types/Messages/DiscussionMessage.php        *m      B   taknone/liveproto/src/Tl/Types/Messages/AllStickersNotModified.php        H
դ      7   taknone/liveproto/src/Tl/Types/Messages/ForumTopics.php        2      >   taknone/liveproto/src/Tl/Types/Messages/AvailableReactions.php        ѭ      <   taknone/liveproto/src/Tl/Types/Messages/AffectedMessages.php        5Ȥ      >   taknone/liveproto/src/Tl/Types/Messages/ExportedChatInvite.php        s      5   taknone/liveproto/src/Tl/Types/Messages/SavedGifs.php        ۲      0   taknone/liveproto/src/Tl/Types/Auth/SentCode.phpZ      Z  @ˤ      ?   taknone/liveproto/src/Tl/Types/Auth/SentCodeTypeFirebaseSms.php        w      =   taknone/liveproto/src/Tl/Types/Auth/SentCodeTypeEmailCode.phpW      W  6      ;   taknone/liveproto/src/Tl/Types/Auth/PasskeyLoginOptions.phpQ      Q  4-      3   taknone/liveproto/src/Tl/Types/Auth/CodeTypeSms.php        Cޤ      8   taknone/liveproto/src/Tl/Types/Auth/PasswordRecovery.php_      _  yC      7   taknone/liveproto/src/Tl/Types/Auth/SentCodeTypeSms.php4      4  a      4   taknone/liveproto/src/Tl/Types/Auth/CodeTypeCall.php              ;   taknone/liveproto/src/Tl/Types/Auth/LoginTokenMigrateTo.php        -V=      7   taknone/liveproto/src/Tl/Types/Auth/SentCodeTypeApp.php4      4  h5
      F   taknone/liveproto/src/Tl/Types/Auth/SentCodeTypeSetUpEmailRequired.php        Ur      C   taknone/liveproto/src/Tl/Types/Auth/AuthorizationSignUpRequired.php        0]      >   taknone/liveproto/src/Tl/Types/Auth/SentCodeTypeMissedCall.php        =      ?   taknone/liveproto/src/Tl/Types/Auth/SentCodePaymentRequired.php        SE      5   taknone/liveproto/src/Tl/Types/Auth/Authorization.phpZ      Z  nOm      2   taknone/liveproto/src/Tl/Types/Auth/LoginToken.php        :M      ;   taknone/liveproto/src/Tl/Types/Auth/SentCodeTypeSmsWord.phpP      P  g      :   taknone/liveproto/src/Tl/Types/Auth/CodeTypeMissedCall.php        ~      ;   taknone/liveproto/src/Tl/Types/Auth/CodeTypeFragmentSms.php        ́p7      9   taknone/liveproto/src/Tl/Types/Auth/LoginTokenSuccess.phph      h  Y<      =   taknone/liveproto/src/Tl/Types/Auth/SentCodeTypeFlashCall.phpH      H  
ۚC      1   taknone/liveproto/src/Tl/Types/Auth/LoggedOut.phpz      z  OWCڤ      9   taknone/liveproto/src/Tl/Types/Auth/CodeTypeFlashCall.php        0      =   taknone/liveproto/src/Tl/Types/Auth/ExportedAuthorization.php              =   taknone/liveproto/src/Tl/Types/Auth/SentCodeTypeSmsPhrase.phpR      R  Z!#      ?   taknone/liveproto/src/Tl/Types/Auth/SentCodeTypeFragmentSms.php        @/"      8   taknone/liveproto/src/Tl/Types/Auth/SentCodeTypeCall.php5      5  l֤      7   taknone/liveproto/src/Tl/Types/Auth/SentCodeSuccess.phpd      d  Pڤ      <   taknone/liveproto/src/Tl/Types/Chatlists/ChatlistUpdates.phpm      m  '6o      ;   taknone/liveproto/src/Tl/Types/Chatlists/ChatlistInvite.php        v
      C   taknone/liveproto/src/Tl/Types/Chatlists/ExportedChatlistInvite.php        o}      B   taknone/liveproto/src/Tl/Types/Chatlists/ChatlistInviteAlready.phpv      v  Y,      <   taknone/liveproto/src/Tl/Types/Chatlists/ExportedInvites.php        iH      @   taknone/liveproto/src/Tl/Types/Help/TimezonesListNotModified.php        Z      1   taknone/liveproto/src/Tl/Types/Help/PromoData.phpn
      n
         A   taknone/liveproto/src/Tl/Types/Help/TermsOfServiceUpdateEmpty.phpJ      J  R      6   taknone/liveproto/src/Tl/Types/Help/PassportConfig.php        B      ;   taknone/liveproto/src/Tl/Types/Help/PeerColorProfileSet.php        w      5   taknone/liveproto/src/Tl/Types/Help/TimezonesList.php        9)      3   taknone/liveproto/src/Tl/Types/Help/CountryCode.php        dä      /   taknone/liveproto/src/Tl/Types/Help/Country.php8      8        3   taknone/liveproto/src/Tl/Types/Help/NoAppUpdate.php        LC̤      0   taknone/liveproto/src/Tl/Types/Help/UserInfo.php        t7fc      =   taknone/liveproto/src/Tl/Types/Help/PeerColorsNotModified.php        l      4   taknone/liveproto/src/Tl/Types/Help/ConfigSimple.php&      &  Z      5   taknone/liveproto/src/Tl/Types/Help/CountriesList.php              4   taknone/liveproto/src/Tl/Types/Help/DeepLinkInfo.phpk      k  V      4   taknone/liveproto/src/Tl/Types/Help/PremiumPromo.php        f      5   taknone/liveproto/src/Tl/Types/Help/UserInfoEmpty.php        XФ      4   taknone/liveproto/src/Tl/Types/Help/RecentMeUrls.phpM      M  h~}      2   taknone/liveproto/src/Tl/Types/Help/PeerColors.php        zڮ      <   taknone/liveproto/src/Tl/Types/Help/AppConfigNotModified.php        Ƥ      2   taknone/liveproto/src/Tl/Types/Help/InviteText.php;      ;  o      7   taknone/liveproto/src/Tl/Types/Help/PeerColorOption.php        @h      6   taknone/liveproto/src/Tl/Types/Help/PromoDataEmpty.php4      4  [S      /   taknone/liveproto/src/Tl/Types/Help/Support.php        :      A   taknone/liveproto/src/Tl/Types/Help/PassportConfigNotModified.php        Qu      9   taknone/liveproto/src/Tl/Types/Help/DeepLinkInfoEmpty.php        ~      3   taknone/liveproto/src/Tl/Types/Help/SupportName.php1      1  T&      6   taknone/liveproto/src/Tl/Types/Help/TermsOfService.phpD      D  ;      1   taknone/liveproto/src/Tl/Types/Help/AppConfig.php        y      1   taknone/liveproto/src/Tl/Types/Help/AppUpdate.php              <   taknone/liveproto/src/Tl/Types/Help/TermsOfServiceUpdate.php        y      4   taknone/liveproto/src/Tl/Types/Help/PeerColorSet.phpL      L  _\      @   taknone/liveproto/src/Tl/Types/Help/CountriesListNotModified.php         8      0   taknone/liveproto/src/Tl/Types/Photos/Photos.php        :\      /   taknone/liveproto/src/Tl/Types/Photos/Photo.php        OG      5   taknone/liveproto/src/Tl/Types/Photos/PhotosSlice.php#      #  9 =      ;   taknone/liveproto/src/Tl/Types/Fragment/CollectibleInfo.php        b~      3   taknone/liveproto/src/Tl/Types/Bots/PreviewInfo.php        b      8   taknone/liveproto/src/Tl/Types/Bots/ExportedBotToken.php?      ?  Ut      6   taknone/liveproto/src/Tl/Types/Bots/PopularAppBots.php        ^Y      6   taknone/liveproto/src/Tl/Types/Bots/AccessSettings.php        o      7   taknone/liveproto/src/Tl/Types/Bots/RequestedButton.php]      ]  N"*      /   taknone/liveproto/src/Tl/Types/Bots/BotInfo.php        R٤      8   taknone/liveproto/src/Tl/Types/Contacts/ResolvedPeer.php-      -  K      :   taknone/liveproto/src/Tl/Types/Contacts/SponsoredPeers.phpd      d  l      4   taknone/liveproto/src/Tl/Types/Contacts/Contacts.phpL      L  å      <   taknone/liveproto/src/Tl/Types/Contacts/ImportedContacts.php]      ]  j̤      ?   taknone/liveproto/src/Tl/Types/Contacts/ContactsNotModified.php        #      3   taknone/liveproto/src/Tl/Types/Contacts/Blocked.phpW      W  3w`      ?   taknone/liveproto/src/Tl/Types/Contacts/TopPeersNotModified.php        ɨ      4   taknone/liveproto/src/Tl/Types/Contacts/TopPeers.php        YM      <   taknone/liveproto/src/Tl/Types/Contacts/TopPeersDisabled.php        
      <   taknone/liveproto/src/Tl/Types/Contacts/ContactBirthdays.php        8       1   taknone/liveproto/src/Tl/Types/Contacts/Found.php        :؊      ?   taknone/liveproto/src/Tl/Types/Contacts/SponsoredPeersEmpty.php        NVͤ      8   taknone/liveproto/src/Tl/Types/Contacts/BlockedSlice.php        JB      3   taknone/liveproto/src/Tl/Types/Users/SavedMusic.php        1g      >   taknone/liveproto/src/Tl/Types/Users/SavedMusicNotModified.php6      6  QI9      .   taknone/liveproto/src/Tl/Types/Users/Users.php?      ?  "      3   taknone/liveproto/src/Tl/Types/Users/UsersSlice.php        sФ      1   taknone/liveproto/src/Tl/Types/Users/UserFull.php7      7  j      E   taknone/liveproto/src/Tl/Types/Payments/StarsRevenueAdsAccountUrl.phpQ      Q  ,      D   taknone/liveproto/src/Tl/Types/Payments/CheckCanSendGiftResultOk.php        œ.      :   taknone/liveproto/src/Tl/Types/Payments/UniqueStarGift.php5      5  0      ?   taknone/liveproto/src/Tl/Types/Payments/StarGiftCollections.php        $      C   taknone/liveproto/src/Tl/Types/Payments/UniqueStarGiftValueInfo.phpD      D  NJ      :   taknone/liveproto/src/Tl/Types/Payments/PaymentReceipt.php1      1  Ҁf      =   taknone/liveproto/src/Tl/Types/Payments/StarsRevenueStats.php        x      7   taknone/liveproto/src/Tl/Types/Payments/PaymentForm.php;      ;  ݴ@      5   taknone/liveproto/src/Tl/Types/Payments/SavedInfo.php        sT      M   taknone/liveproto/src/Tl/Types/Payments/StarGiftActiveAuctionsNotModified.php        y       E   taknone/liveproto/src/Tl/Types/Payments/StarGiftUpgradeAttributes.php        w      ;   taknone/liveproto/src/Tl/Types/Payments/ExportedInvoice.php=      =  2D      ?   taknone/liveproto/src/Tl/Types/Payments/PaymentReceiptStars.php=      =  "؅      E   taknone/liveproto/src/Tl/Types/Payments/StarsRevenueWithdrawalUrl.phpQ      Q  b      @   taknone/liveproto/src/Tl/Types/Payments/StarGiftAuctionState.php        xH      F   taknone/liveproto/src/Tl/Types/Payments/CheckCanSendGiftResultFail.phpg      g        H   taknone/liveproto/src/Tl/Types/Payments/StarGiftAuctionAcquiredGifts.php        BG      B   taknone/liveproto/src/Tl/Types/Payments/ValidatedRequestedInfo.php        1      7   taknone/liveproto/src/Tl/Types/Payments/StarsStatus.php
      
  K      5   taknone/liveproto/src/Tl/Types/Payments/StarGifts.php        B      A   taknone/liveproto/src/Tl/Types/Payments/StarGiftWithdrawalUrl.phpI      I  `H      ;   taknone/liveproto/src/Tl/Types/Payments/ResaleStarGifts.phpl	      l	        @   taknone/liveproto/src/Tl/Types/Payments/ConnectedStarRefBots.php              @   taknone/liveproto/src/Tl/Types/Payments/SuggestedStarRefBots.php        ڤ      8   taknone/liveproto/src/Tl/Types/Payments/BankCardData.php        Y|Aդ      B   taknone/liveproto/src/Tl/Types/Payments/StarGiftUpgradePreview.php,      ,  [W      ?   taknone/liveproto/src/Tl/Types/Payments/GiveawayInfoResults.php[      [  B      8   taknone/liveproto/src/Tl/Types/Payments/GiveawayInfo.phpG      G  ¾∤      B   taknone/liveproto/src/Tl/Types/Payments/StarGiftActiveAuctions.php        F      ?   taknone/liveproto/src/Tl/Types/Payments/PaymentFormStarGift.php        ,|1      :   taknone/liveproto/src/Tl/Types/Payments/SavedStarGifts.php              J   taknone/liveproto/src/Tl/Types/Payments/StarGiftCollectionsNotModified.php        R$      <   taknone/liveproto/src/Tl/Types/Payments/PaymentFormStars.php        f      ;   taknone/liveproto/src/Tl/Types/Payments/CheckedGiftCode.php        e      E   taknone/liveproto/src/Tl/Types/Payments/PaymentVerificationNeeded.phpE      E  _5      9   taknone/liveproto/src/Tl/Types/Payments/PaymentResult.phpL      L  ,2      @   taknone/liveproto/src/Tl/Types/Payments/StarGiftsNotModified.php        Z;      9   taknone/liveproto/src/Tl/Types/Account/SavedRingtones.php              :   taknone/liveproto/src/Tl/Types/Account/ContentSettings.php        㫤?      =   taknone/liveproto/src/Tl/Types/Account/WebBrowserSettings.php        
[sW      =   taknone/liveproto/src/Tl/Types/Account/EmailVerifiedLogin.php        5      D   taknone/liveproto/src/Tl/Types/Account/SavedRingtonesNotModified.php        @i      1   taknone/liveproto/src/Tl/Types/Account/Themes.php        ioF      <   taknone/liveproto/src/Tl/Types/Account/ThemesNotModified.php        n7wͤ      <   taknone/liveproto/src/Tl/Types/Account/AuthorizationForm.php        %6      @   taknone/liveproto/src/Tl/Types/Account/ChatThemesNotModified.php        ;v4      ?   taknone/liveproto/src/Tl/Types/Account/AutoDownloadSettings.php?      ?  _      C   taknone/liveproto/src/Tl/Types/Account/SavedMusicIdsNotModified.php        3	ʤ      3   taknone/liveproto/src/Tl/Types/Account/Passkeys.php^      ^  ݍ      8   taknone/liveproto/src/Tl/Types/Account/SentEmailCode.php        h      8   taknone/liveproto/src/Tl/Types/Account/SavedRingtone.php        n      8   taknone/liveproto/src/Tl/Types/Account/EmojiStatuses.php        PФ      B   taknone/liveproto/src/Tl/Types/Account/ResetPasswordFailedWait.phpY      Y  P      @   taknone/liveproto/src/Tl/Types/Account/WallPapersNotModified.php        v0      ;   taknone/liveproto/src/Tl/Types/Account/AutoSaveSettings.phpY      Y  y~      8   taknone/liveproto/src/Tl/Types/Account/SavedMusicIds.phpK      K  g0      8   taknone/liveproto/src/Tl/Types/Account/ConnectedBots.php              ;   taknone/liveproto/src/Tl/Types/Account/PasswordSettings.php              7   taknone/liveproto/src/Tl/Types/Account/PrivacyRules.phpX      X  yĤ      D   taknone/liveproto/src/Tl/Types/Account/ResolvedBusinessChatLinks.phpQ      Q        E   taknone/liveproto/src/Tl/Types/Account/ResetPasswordRequestedWait.php\      \  Fy      C   taknone/liveproto/src/Tl/Types/Account/EmojiStatusesNotModified.php        8      6   taknone/liveproto/src/Tl/Types/Account/TmpPassword.php        ?1      8   taknone/liveproto/src/Tl/Types/Account/EmailVerified.php?      ?  	      >   taknone/liveproto/src/Tl/Types/Account/PaidMessagesRevenue.php`      `  im      <   taknone/liveproto/src/Tl/Types/Account/WebAuthorizations.php        &      E   taknone/liveproto/src/Tl/Types/Account/PasskeyRegistrationOptions.phpe      e  R4a^      5   taknone/liveproto/src/Tl/Types/Account/ChatThemes.php1      1  |      5   taknone/liveproto/src/Tl/Types/Account/WallPapers.php        NEy      <   taknone/liveproto/src/Tl/Types/Account/BusinessChatLinks.phpq      q  Zn      @   taknone/liveproto/src/Tl/Types/Account/PasswordInputSettings.phpg      g  E\      2   taknone/liveproto/src/Tl/Types/Account/Takeout.php          ާ      H   taknone/liveproto/src/Tl/Types/Account/WebBrowserSettingsNotModified.php        É      9   taknone/liveproto/src/Tl/Types/Account/Authorizations.php3      3  a8      3   taknone/liveproto/src/Tl/Types/Account/Password.phpu      u  "M      :   taknone/liveproto/src/Tl/Types/Account/ResetPasswordOk.php        lf      A   taknone/liveproto/src/Tl/Types/Account/SavedRingtoneConverted.phpX      X  BW:      0   taknone/liveproto/src/Tl/Types/Updates/State.php        A      <   taknone/liveproto/src/Tl/Types/Updates/ChannelDifference.php<      <  {      A   taknone/liveproto/src/Tl/Types/Updates/ChannelDifferenceEmpty.php        A4ؤ      <   taknone/liveproto/src/Tl/Types/Updates/DifferenceTooLong.php.      .  ;B      :   taknone/liveproto/src/Tl/Types/Updates/DifferenceEmpty.php        4M      C   taknone/liveproto/src/Tl/Types/Updates/ChannelDifferenceTooLong.php        ԍZ      5   taknone/liveproto/src/Tl/Types/Updates/Difference.phpP      P  $Ȥ      :   taknone/liveproto/src/Tl/Types/Updates/DifferenceSlice.php        IX      9   taknone/liveproto/src/Tl/Types/Smsjobs/EligibleToJoin.php        u      1   taknone/liveproto/src/Tl/Types/Smsjobs/Status.php        z      7   taknone/liveproto/src/Tl/Types/Premium/BoostsStatus.php_      _        3   taknone/liveproto/src/Tl/Types/Premium/MyBoosts.phpT      T        5   taknone/liveproto/src/Tl/Types/Premium/BoostsList.php        ,      ?   taknone/liveproto/src/Tl/Types/Phone/GroupCallStreamRtmpUrl.php        q6      4   taknone/liveproto/src/Tl/Types/Phone/JoinAsPeers.php=      =  Bk`      2   taknone/liveproto/src/Tl/Types/Phone/GroupCall.php        ۧ      7   taknone/liveproto/src/Tl/Types/Phone/GroupCallStars.php        09      @   taknone/liveproto/src/Tl/Types/Phone/GroupCallStreamChannels.php        ڼv      :   taknone/liveproto/src/Tl/Types/Phone/GroupParticipants.php        2      2   taknone/liveproto/src/Tl/Types/Phone/PhoneCall.php        ^n      @   taknone/liveproto/src/Tl/Types/Phone/ExportedGroupCallInvite.phpK      K   =      2   taknone/liveproto/src/Tl/Types/Aicompose/Tones.php5      5   Q      =   taknone/liveproto/src/Tl/Types/Aicompose/TonesNotModified.php        8?`      6   taknone/liveproto/src/Tl/Types/Storage/FilePartial.php        5      2   taknone/liveproto/src/Tl/Types/Storage/FileGif.php              2   taknone/liveproto/src/Tl/Types/Storage/FilePng.php        r      2   taknone/liveproto/src/Tl/Types/Storage/FileMp4.php        PƟ      2   taknone/liveproto/src/Tl/Types/Storage/FilePdf.php        $٤      3   taknone/liveproto/src/Tl/Types/Storage/FileJpeg.php        Ȣ      2   taknone/liveproto/src/Tl/Types/Storage/FileMov.php        (      3   taknone/liveproto/src/Tl/Types/Storage/FileWebp.php         B      2   taknone/liveproto/src/Tl/Types/Storage/FileMp3.php        M]      6   taknone/liveproto/src/Tl/Types/Storage/FileUnknown.php        in      .   taknone/liveproto/src/Tl/Types/Upload/File.php              ?   taknone/liveproto/src/Tl/Types/Upload/CdnFileReuploadNeeded.php^      ^  )WA      1   taknone/liveproto/src/Tl/Types/Upload/WebFile.php        rz      1   taknone/liveproto/src/Tl/Types/Upload/CdnFile.php0      0  j%      9   taknone/liveproto/src/Tl/Types/Upload/FileCdnRedirect.phpM      M  r(;      F   taknone/liveproto/src/Tl/Types/Secret/SendMessageUploadVideoAction.php        k4      J   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionRequestKey.php        
J      G   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageMediaGeoPoint.php              @   taknone/liveproto/src/Tl/Types/Secret/DocumentAttributeVideo.php        (      D   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionNoop.php        s5+      F   taknone/liveproto/src/Tl/Types/Secret/SendMessageGeoLocationAction.php        :G      ?   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageLayer.php        Y[|      D   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageMediaPhoto.php%      %  _      I   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionAcceptKey.phpK      K  Nb      D   taknone/liveproto/src/Tl/Types/Secret/DocumentAttributeImageSize.php        A      =   taknone/liveproto/src/Tl/Types/Secret/MessageEntityItalic.php        z#      >   taknone/liveproto/src/Tl/Types/Secret/MessageEntityTextUrl.php        4$      =   taknone/liveproto/src/Tl/Types/Secret/MessageEntityStrike.php        I      A   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageService.php        ]      M   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionSetMessageTTL.phpj      j  Ձ      F   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionResend.php        Ñ      F   taknone/liveproto/src/Tl/Types/Secret/SendMessageUploadRoundAction.php              D   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageMediaVenue.phpa      a  1M      F   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageMediaContact.php        =Zi      >   taknone/liveproto/src/Tl/Types/Secret/MessageEntityHashtag.php        wˮ      I   taknone/liveproto/src/Tl/Types/Secret/SendMessageUploadDocumentAction.php        f      L   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionReadMessages.php        ͗      R   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionScreenshotMessages.php        CcR,      F   taknone/liveproto/src/Tl/Types/Secret/SendMessageRecordVideoAction.php        2`S      9   taknone/liveproto/src/Tl/Types/Secret/PhotoCachedSize.php        Foݤ      A   taknone/liveproto/src/Tl/Types/Secret/MessageEntityBlockquote.php        p      :   taknone/liveproto/src/Tl/Types/Secret/MessageEntityUrl.php        ;C      A   taknone/liveproto/src/Tl/Types/Secret/FileLocationUnavailable.php        yM      I   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionCommitKey.php         7"ͤ      8   taknone/liveproto/src/Tl/Types/Secret/PhotoSizeEmpty.php5      5  U#Ǥ      F   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageMediaWebPage.phpL      L        ;   taknone/liveproto/src/Tl/Types/Secret/MessageEntityCode.php        j`      F   taknone/liveproto/src/Tl/Types/Secret/SendMessageUploadPhotoAction.php        Fх      C   taknone/liveproto/src/Tl/Types/Secret/DocumentAttributeFilename.php]      ]  ^      A   taknone/liveproto/src/Tl/Types/Secret/MessageEntityBotCommand.php        8ꥤ      B   taknone/liveproto/src/Tl/Types/Secret/InputStickerSetShortName.php^      ^  Z3      A   taknone/liveproto/src/Tl/Types/Secret/SendMessageCancelAction.php        w      L   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionFlushHistory.php        >      :   taknone/liveproto/src/Tl/Types/Secret/MessageEntityPre.php
      
  r      H   taknone/liveproto/src/Tl/Types/Secret/SendMessageChooseContactAction.php        }cw(      <   taknone/liveproto/src/Tl/Types/Secret/MessageEntityEmail.php        s&T      >   taknone/liveproto/src/Tl/Types/Secret/MessageEntityUnknown.php        I]      F   taknone/liveproto/src/Tl/Types/Secret/SendMessageRecordAudioAction.php              F   taknone/liveproto/src/Tl/Types/Secret/SendMessageUploadAudioAction.php        ѩڤ      :   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessage.php
      
  1O4      D   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageMediaEmpty.php              B   taknone/liveproto/src/Tl/Types/Secret/MessageEntityCustomEmoji.php              A   taknone/liveproto/src/Tl/Types/Secret/SendMessageTypingAction.php        T{      K   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionNotifyLayer.phpP      P  #      >   taknone/liveproto/src/Tl/Types/Secret/MessageEntitySpoiler.php        -4      @   taknone/liveproto/src/Tl/Types/Secret/MessageEntityUnderline.php        z^      @   taknone/liveproto/src/Tl/Types/Secret/DocumentAttributeAudio.phpt      t  U婤      D   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageMediaVideo.php        H$`      D   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageMediaAudio.php        R      H   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionAbortKey.phph      h  p      B   taknone/liveproto/src/Tl/Types/Secret/DocumentAttributeSticker.php               >   taknone/liveproto/src/Tl/Types/Secret/InputStickerSetEmpty.php        p˝e      >   taknone/liveproto/src/Tl/Types/Secret/MessageEntityMention.php        @W      F   taknone/liveproto/src/Tl/Types/Secret/SendMessageRecordRoundAction.php        YrM      F   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionTyping.phpf      f  RL      C   taknone/liveproto/src/Tl/Types/Secret/DocumentAttributeAnimated.php        >      N   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageActionDeleteMessages.php        x.      6   taknone/liveproto/src/Tl/Types/Secret/FileLocation.phph      h  IȤ      ;   taknone/liveproto/src/Tl/Types/Secret/MessageEntityBold.php        $      G   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageMediaDocument.php        ^9L      O   taknone/liveproto/src/Tl/Types/Secret/DecryptedMessageMediaExternalDocument.php\      \  f      3   taknone/liveproto/src/Tl/Types/Secret/PhotoSize.php        	0      D   taknone/liveproto/src/Tl/Types/Other/InputInvoiceStarGiftUpgrade.php_      _  "G      N   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeTitle.php        R      8   taknone/liveproto/src/Tl/Types/Other/JsonObjectValue.php        9       T   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantInvite.php        ͤ      E   taknone/liveproto/src/Tl/Types/Other/InputStickerSetAnimatedEmoji.php        .      D   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyProfilePhoto.php        "RS      G   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyStatusTimestamp.php        GR      E   taknone/liveproto/src/Tl/Types/Other/InputPasskeyResponseRegister.php        )      E   taknone/liveproto/src/Tl/Types/Other/SendMessageUploadVideoAction.phpJ      J  l      8   taknone/liveproto/src/Tl/Types/Other/PageBlockKicker.php3      3  nݨ      9   taknone/liveproto/src/Tl/Types/Other/SponsoredMessage.phpw      w  l3פ      C   taknone/liveproto/src/Tl/Types/Other/InputEncryptedFileLocation.php        3      :   taknone/liveproto/src/Tl/Types/Other/StatsPercentValue.php        ^      @   taknone/liveproto/src/Tl/Types/Other/InputBotInlineMessageID.php        lĤ      ?   taknone/liveproto/src/Tl/Types/Other/GroupCallStreamChannel.php.      .  &{       :   taknone/liveproto/src/Tl/Types/Other/ServerDHInnerData.phps      s  4HM      F   taknone/liveproto/src/Tl/Types/Other/InputBotInlineMessageMediaGeo.php              6   taknone/liveproto/src/Tl/Types/Other/InputBotAppID.php              ;   taknone/liveproto/src/Tl/Types/Other/ChatInviteImporter.phpD      D  zg      G   taknone/liveproto/src/Tl/Types/Other/MessageActionNewCreatorPending.phpc      c  fA      6   taknone/liveproto/src/Tl/Types/Other/UpdateWebPage.php        y      9   taknone/liveproto/src/Tl/Types/Other/DestroySessionOk.phpI      I  *)̤      9   taknone/liveproto/src/Tl/Types/Other/DialogPeerFolder.php;      ;  h|      >   taknone/liveproto/src/Tl/Types/Other/MessageEntityBankCard.php        <5      @   taknone/liveproto/src/Tl/Types/Other/MessageActionPinMessage.php        ey      B   taknone/liveproto/src/Tl/Types/Other/InputDocumentFileLocation.php        ź#      .   taknone/liveproto/src/Tl/Types/Other/ResPQ.php        IȤ      <   taknone/liveproto/src/Tl/Types/Other/UpdatePinnedDialogs.phps      s  	_      B   taknone/liveproto/src/Tl/Types/Other/InputBotInlineMessageID64.phpp      p  5؄$      >   taknone/liveproto/src/Tl/Types/Other/MessageMediaPaidMedia.php        ؚ      ?   taknone/liveproto/src/Tl/Types/Other/DocumentAttributeVideo.php        N      :   taknone/liveproto/src/Tl/Types/Other/StarsSubscription.php
      
  	謣      :   taknone/liveproto/src/Tl/Types/Other/InputPhoneContact.php        zE      9   taknone/liveproto/src/Tl/Types/Other/UpdateUserStatus.php        <      3   taknone/liveproto/src/Tl/Types/Other/StoryViews.phpk      k  	ʤ      9   taknone/liveproto/src/Tl/Types/Other/InputWebDocument.php        P7      4   taknone/liveproto/src/Tl/Types/Other/ChannelFull.phpE      E  ښ%      ?   taknone/liveproto/src/Tl/Types/Other/ChatParticipantCreator.php        p      =   taknone/liveproto/src/Tl/Types/Other/PeerColorCollectible.phpK      K  n      >   taknone/liveproto/src/Tl/Types/Other/StickerSetFullCovered.php        D%      1   taknone/liveproto/src/Tl/Types/Other/PeerUser.php(      (  1n      >   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyPhoneNumber.php        A      ;   taknone/liveproto/src/Tl/Types/Other/ChatInviteExported.php        ٯ̤      ;   taknone/liveproto/src/Tl/Types/Other/WebDomainException.phpg      g  32{      L   taknone/liveproto/src/Tl/Types/Other/InputStickerSetEmojiDefaultStatuses.php        "^̤      B   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantsKicked.php=      =  Vȓ      A   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterVideo.php        D      0   taknone/liveproto/src/Tl/Types/Other/Invoice.php        *      7   taknone/liveproto/src/Tl/Types/Other/PageBlockVideo.phpp      p  jKM      7   taknone/liveproto/src/Tl/Types/Other/StickerKeyword.php        -      @   taknone/liveproto/src/Tl/Types/Other/MessageActionChatCreate.php        DD      B   taknone/liveproto/src/Tl/Types/Other/InputMessageCallbackQuery.php        [3      F   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterPhoneCalls.php        P1      W   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionExportedInviteRevoke.phpu      u  S񆃤      C   taknone/liveproto/src/Tl/Types/Other/InputKeyboardButtonUrlAuth.phpE      E  ڀؤ      >   taknone/liveproto/src/Tl/Types/Other/BotMenuButtonCommands.php              9   taknone/liveproto/src/Tl/Types/Other/WebAuthorization.php        T:`٤      A   taknone/liveproto/src/Tl/Types/Other/PrivacyValueDisallowBots.php        T9      8   taknone/liveproto/src/Tl/Types/Other/BotPreviewMedia.php        Ҿ      4   taknone/liveproto/src/Tl/Types/Other/PollResults.php        H      ;   taknone/liveproto/src/Tl/Types/Other/BusinessRecipients.php.      .  =a      E   taknone/liveproto/src/Tl/Types/Other/UpdateBotChatInviteRequester.php              =   taknone/liveproto/src/Tl/Types/Other/MediaAreaCoordinates.php        ֫z      E   taknone/liveproto/src/Tl/Types/Other/SendMessageGeoLocationAction.php        >      D   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantsContacts.php?      ?  f3      9   taknone/liveproto/src/Tl/Types/Other/StarsTransaction.php1%      1%        :   taknone/liveproto/src/Tl/Types/Other/MessageMediaStory.phpt      t  .}Ȥ      H   taknone/liveproto/src/Tl/Types/Other/SendMessageEmojiInteractionSeen.phpW      W  /&"=      @   taknone/liveproto/src/Tl/Types/Other/InputChannelFromMessage.php        yX      B   taknone/liveproto/src/Tl/Types/Other/MessageActionSetChatTheme.phpF      F  Tb      =   taknone/liveproto/src/Tl/Types/Other/UpdateSavedRingtones.php        m      C   taknone/liveproto/src/Tl/Types/Other/InputBusinessBotRecipients.php        3)      8   taknone/liveproto/src/Tl/Types/Other/ProfileTabLinks.php        !D      6   taknone/liveproto/src/Tl/Types/Other/PhotoPathSize.php        A}      ?   taknone/liveproto/src/Tl/Types/Other/MessageActionPhoneCall.phpH      H   ɤ      =   taknone/liveproto/src/Tl/Types/Other/BotMenuButtonDefault.php        /      @   taknone/liveproto/src/Tl/Types/Other/UpdateWebViewResultSent.php=      =  '&      R   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangePeerColor.php        Z      Q   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionToggleSlowMode.php        #&ڥ      =   taknone/liveproto/src/Tl/Types/Other/ReportResultReported.php        D
i      B   taknone/liveproto/src/Tl/Types/Other/UpdateServiceNotification.php2      2        :   taknone/liveproto/src/Tl/Types/Other/ChatInviteAlready.php2      2  A      4   taknone/liveproto/src/Tl/Types/Other/UpdateStory.php        w      9   taknone/liveproto/src/Tl/Types/Other/PageListItemText.php        _e      8   taknone/liveproto/src/Tl/Types/Other/ChatAdminRights.php              E   taknone/liveproto/src/Tl/Types/Other/UpdateChannelMessageForwards.php          \Z      ;   taknone/liveproto/src/Tl/Types/Other/UpdateStarsBalance.phpB      B   Cڤ      5   taknone/liveproto/src/Tl/Types/Other/InputChannel.php        \      2   taknone/liveproto/src/Tl/Types/Other/CdnConfig.phpq      q  OD^C      :   taknone/liveproto/src/Tl/Types/Other/InputMediaContact.php        R
&S      2   taknone/liveproto/src/Tl/Types/Other/TextEmail.php        }mԤ      =   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyChatInvite.php        s      I   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeOriginalDetails.phpa      a        E   taknone/liveproto/src/Tl/Types/Other/InlineQueryPeerTypeMegagroup.php        #F      :   taknone/liveproto/src/Tl/Types/Other/PageBlockSubtitle.php5      5  T<      T   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantVolume.php        C+       N   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeAbout.php              Z   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantJoinByInvite.phpW      W  Cƪ      F   taknone/liveproto/src/Tl/Types/Other/InputEncryptedFileBigUploaded.php        =	.      A   taknone/liveproto/src/Tl/Types/Other/UpdateStarsRevenueStatus.php        z      A   taknone/liveproto/src/Tl/Types/Other/InputStickeredMediaPhoto.php@      @  b      ?   taknone/liveproto/src/Tl/Types/Other/UpdatePinnedForumTopic.phpa      a  s      5   taknone/liveproto/src/Tl/Types/Other/DialogFolder.php        ]      5   taknone/liveproto/src/Tl/Types/Other/TextBankCard.php/      /  <      8   taknone/liveproto/src/Tl/Types/Other/AvailableEffect.php        Ic      R   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantMute.php        rR      A   taknone/liveproto/src/Tl/Types/Other/UpdateChatParticipantAdd.php        []      V   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantEditRank.phpI      I  *]      3   taknone/liveproto/src/Tl/Types/Other/JsonString.php.      .  &U      @   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyVoiceMessages.php        ~O      <   taknone/liveproto/src/Tl/Types/Other/MessageMediaInvoice.phpi	      i	  >      4   taknone/liveproto/src/Tl/Types/Other/InputGameID.php        Y{x      9   taknone/liveproto/src/Tl/Types/Other/SecurePlainEmail.php:      :  j      3   taknone/liveproto/src/Tl/Types/Other/PhotoEmpty.php        :      E   taknone/liveproto/src/Tl/Types/Other/InputStorePaymentGiftPremium.php/      /  F      A   taknone/liveproto/src/Tl/Types/Other/UpdateBotBusinessConnect.php        jb0      A   taknone/liveproto/src/Tl/Types/Other/MessageActionPaymentSent.php        0sߤ      G   taknone/liveproto/src/Tl/Types/Other/SecureValueTypePersonalDetails.php        {¤      0   taknone/liveproto/src/Tl/Types/Other/TopPeer.php        7Bҵ      @   taknone/liveproto/src/Tl/Types/Other/UpdateDialogFilterOrder.phpI      I  Ax      I   taknone/liveproto/src/Tl/Types/Other/InputPaymentCredentialsGooglePay.phpv      v  i41R      <   taknone/liveproto/src/Tl/Types/Other/InputStickerSetItem.phpl      l  Eyz      ?   taknone/liveproto/src/Tl/Types/Other/StickerSetMultiCovered.php        BM      4   taknone/liveproto/src/Tl/Types/Other/TextHashtag.php.      .  iV]      A   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterEmpty.php              4   taknone/liveproto/src/Tl/Types/Other/RichMessage.php        ?皤      8   taknone/liveproto/src/Tl/Types/Other/AccessPointRule.php?      ?  =
$      ;   taknone/liveproto/src/Tl/Types/Other/StarGiftBackground.php/      /        C   taknone/liveproto/src/Tl/Types/Other/UpdateMessageExtendedMedia.phpc      c  mkY      @   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyPhoneP2P.php        {$Ф      2   taknone/liveproto/src/Tl/Types/Other/PeerColor.php              8   taknone/liveproto/src/Tl/Types/Other/InputPollAnswer.php        +c      8   taknone/liveproto/src/Tl/Types/Other/SecureFileEmpty.php        LPQ      5   taknone/liveproto/src/Tl/Types/Other/ConnectedBot.php        Yg2      3   taknone/liveproto/src/Tl/Types/Other/TextItalic.php-      -  S      F   taknone/liveproto/src/Tl/Types/Other/EmailVerifyPurposeLoginChange.php        ߤ      B   taknone/liveproto/src/Tl/Types/Other/InputBotInlineMessageGame.phpw      w  ޤ      6   taknone/liveproto/src/Tl/Types/Other/AiComposeTone.php3
      3
  i      7   taknone/liveproto/src/Tl/Types/Other/MessageService.php`      `  <      8   taknone/liveproto/src/Tl/Types/Other/MessagePeerVote.php        M      C   taknone/liveproto/src/Tl/Types/Other/InputPeerPhotoFileLocation.phpl      l  bD|      H   taknone/liveproto/src/Tl/Types/Other/StarsTransactionPeerUnsupported.php        Ѥ      6   taknone/liveproto/src/Tl/Types/Other/PageTableCell.php'      '        Q   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeLocation.php        Cd      @   taknone/liveproto/src/Tl/Types/Other/InputSecureFileUploaded.php        -Sˤ      I   taknone/liveproto/src/Tl/Types/Other/PhoneCallDiscardReasonDisconnect.php        i<_      <   taknone/liveproto/src/Tl/Types/Other/InputStickerSetDice.phpI      I  ܤ      F   taknone/liveproto/src/Tl/Types/Other/MessageActionChatJoinedByLink.phpQ      Q  'Z\      Y   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeProfilePeerColor.php        0C      9   taknone/liveproto/src/Tl/Types/Other/StarsTopupOption.php        `      =   taknone/liveproto/src/Tl/Types/Other/UpdatePeerHistoryTTL.php              7   taknone/liveproto/src/Tl/Types/Other/PhoneCallEmpty.php        @      8   taknone/liveproto/src/Tl/Types/Other/SecureValueHash.php              7   taknone/liveproto/src/Tl/Types/Other/UpdateUserName.php        |      N   taknone/liveproto/src/Tl/Types/Other/InputStickerSetEmojiGenericAnimations.php        [      6   taknone/liveproto/src/Tl/Types/Other/PaymentCharge.php        y =      F   taknone/liveproto/src/Tl/Types/Other/MessageActionSetChatWallPaper.php        Hͤ      =   taknone/liveproto/src/Tl/Types/Other/StarsTransactionPeer.php?      ?  '3Oˤ      9   taknone/liveproto/src/Tl/Types/Other/UpdateBotStopped.phpC      C  hϤ      0   taknone/liveproto/src/Tl/Types/Other/DhGenOk.php        Dp/      B   taknone/liveproto/src/Tl/Types/Other/NotificationSoundRingtone.php2      2  /ݭ)      1   taknone/liveproto/src/Tl/Types/Other/BoolTrue.php        Ic      S   taknone/liveproto/src/Tl/Types/Other/MessageActionStarGiftPurchaseOfferDeclined.php        T	J      C   taknone/liveproto/src/Tl/Types/Other/DocumentAttributeImageSize.phpw      w  Ǐ      B   taknone/liveproto/src/Tl/Types/Other/UpdateChatParticipantRank.phpe      e  6bҤ      1   taknone/liveproto/src/Tl/Types/Other/Document.php5      5  ?T      S   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeStickerSet.php&      &        ?   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterUrl.php        2ʁ      8   taknone/liveproto/src/Tl/Types/Other/InputMediaStory.php        }{      5   taknone/liveproto/src/Tl/Types/Other/PageBlockMap.php        0Zj      >   taknone/liveproto/src/Tl/Types/Other/BusinessBotRecipients.php              =   taknone/liveproto/src/Tl/Types/Other/PaymentRequestedInfo.php        mIѤ      :   taknone/liveproto/src/Tl/Types/Other/InputInvoiceStars.phpT      T        <   taknone/liveproto/src/Tl/Types/Other/MessagePeerReaction.php        a3ۤ      <   taknone/liveproto/src/Tl/Types/Other/MessageEntityItalic.php        ὤ      A   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyPhoneCall.php        0M*      D   taknone/liveproto/src/Tl/Types/Other/AttachMenuPeerTypeSameBotPM.php        7      5   taknone/liveproto/src/Tl/Types/Other/MessageViews.phpd      d        C   taknone/liveproto/src/Tl/Types/Other/StarGiftActiveAuctionState.phpQ      Q  %-      @   taknone/liveproto/src/Tl/Types/Other/InputBusinessRecipients.phpG      G  #{2&      =   taknone/liveproto/src/Tl/Types/Other/InputInvoiceStarGift.phpA      A        E   taknone/liveproto/src/Tl/Types/Other/SecurePasswordKdfAlgoUnknown.php        y      A   taknone/liveproto/src/Tl/Types/Other/InputCollectibleUsername.phpO      O  Q>Y      7   taknone/liveproto/src/Tl/Types/Other/PopularContact.php        YҤ      =   taknone/liveproto/src/Tl/Types/Other/SecureValueTypePhone.php        `[z      =   taknone/liveproto/src/Tl/Types/Other/EmojiListNotModified.php        fa      I   taknone/liveproto/src/Tl/Types/Other/UpdateReadChannelDiscussionInbox.php        	D      >   taknone/liveproto/src/Tl/Types/Other/PhoneConnectionWebrtc.phpS      S  
k      G   taknone/liveproto/src/Tl/Types/Other/MessageActionNoForwardsRequest.php        Vln,      ;   taknone/liveproto/src/Tl/Types/Other/MessageActionEmpty.php        |      ;   taknone/liveproto/src/Tl/Types/Other/GroupCallDiscarded.php          IH      >   taknone/liveproto/src/Tl/Types/Other/SecureValueErrorFiles.php4      4  W!,      9   taknone/liveproto/src/Tl/Types/Other/MessageFwdHeader.php        r      7   taknone/liveproto/src/Tl/Types/Other/OutboxReadDate.php)      )        :   taknone/liveproto/src/Tl/Types/Other/MessageMediaEmpty.php        ܤ      M   taknone/liveproto/src/Tl/Types/Other/InputInvoiceBusinessBotTransferStars.php        UyCf      .   taknone/liveproto/src/Tl/Types/Other/Photo.php              :   taknone/liveproto/src/Tl/Types/Other/BotAppNotModified.php              8   taknone/liveproto/src/Tl/Types/Other/PageBlockAnchor.php/      /  9      :   taknone/liveproto/src/Tl/Types/Other/ChatReactionsSome.phpi      i  R!      2   taknone/liveproto/src/Tl/Types/Other/GroupCall.php	      	  G+f      ?   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterGif.php        @      0   taknone/liveproto/src/Tl/Types/Other/Passkey.php        Kz      E   taknone/liveproto/src/Tl/Types/Other/InlineQueryPeerTypeBroadcast.php        Yc!      1   taknone/liveproto/src/Tl/Types/Other/GeoPoint.php        3      @   taknone/liveproto/src/Tl/Types/Other/InputStickerSetTonGifts.php        A      B   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantsRecent.php        qq=      C   taknone/liveproto/src/Tl/Types/Other/StarsGiveawayWinnersOption.php        J      1   taknone/liveproto/src/Tl/Types/Other/ChatFull.php        >!      4   taknone/liveproto/src/Tl/Types/Other/PostAddress.php        C      T   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantUnmute.php        ׍      >   taknone/liveproto/src/Tl/Types/Other/WebPageAttributeStory.php        nO      =   taknone/liveproto/src/Tl/Types/Other/UpdateChatUserTyping.php        rX      7   taknone/liveproto/src/Tl/Types/Other/StarsTonAmount.php1      1  +Ӥ      A   taknone/liveproto/src/Tl/Types/Other/UpdateReadMonoForumInbox.php>      >  Qp      >   taknone/liveproto/src/Tl/Types/Other/EmailVerificationCode.php=      =        :   taknone/liveproto/src/Tl/Types/Other/ClientDHInnerData.php        1nΤ      B   taknone/liveproto/src/Tl/Types/Other/InputMediaAreaChannelPost.php9      9  ý      F   taknone/liveproto/src/Tl/Types/Other/TopPeerCategoryCorrespondents.php        Q䠤      8   taknone/liveproto/src/Tl/Types/Other/RecentMeUrlChat.php        cl      =   taknone/liveproto/src/Tl/Types/Other/ExportedContactToken.php        !FA"      ;   taknone/liveproto/src/Tl/Types/Other/InputMessagePinned.php        Y/      =   taknone/liveproto/src/Tl/Types/Other/MessageEntityTextUrl.php        ׽C      <   taknone/liveproto/src/Tl/Types/Other/InputMediaPaidMedia.phpe      e  qߤ      @   taknone/liveproto/src/Tl/Types/Other/MessageMediaUnsupported.php        ]      F   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyNoPaidMessages.php        zi-      <   taknone/liveproto/src/Tl/Types/Other/MessageEntityStrike.php        Vv      2   taknone/liveproto/src/Tl/Types/Other/TextPhone.php        I      C   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyPhoneNumber.php        m      :   taknone/liveproto/src/Tl/Types/Other/AvailableReaction.php|	      |	  -.=      8   taknone/liveproto/src/Tl/Types/Other/BaseThemeTinted.php              F   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterRoundVideo.php        24      E   taknone/liveproto/src/Tl/Types/Other/DocumentAttributeHasStickers.php        	#'@      ?   taknone/liveproto/src/Tl/Types/Other/SecureValueErrorSelfie.php        7      ?   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyProfilePhoto.php        D      E   taknone/liveproto/src/Tl/Types/Other/PhoneCallDiscardReasonHangup.php        !B      B   taknone/liveproto/src/Tl/Types/Other/PageBlockBlockquoteBlocks.php        1      E   taknone/liveproto/src/Tl/Types/Other/InputPaymentCredentialsSaved.php        OΤ      8   taknone/liveproto/src/Tl/Types/Other/ProfileTabVoice.php        :)      :   taknone/liveproto/src/Tl/Types/Other/ExportedStoryLink.php9      9  50      A   taknone/liveproto/src/Tl/Types/Other/LangPackStringPluralized.php        X%      =   taknone/liveproto/src/Tl/Types/Other/AutoDownloadSettings.php	      	  gԤ      5   taknone/liveproto/src/Tl/Types/Other/MessageRange.php        <3Ҥ      =   taknone/liveproto/src/Tl/Types/Other/InputStarGiftAuction.phpC      C  Y      <   taknone/liveproto/src/Tl/Types/Other/MessageMediaContact.php        S      K   taknone/liveproto/src/Tl/Types/Other/MessageActionSuggestedPostApproval.php              ?   taknone/liveproto/src/Tl/Types/Other/InputReportReasonOther.php        tw      9   taknone/liveproto/src/Tl/Types/Other/LangPackLanguage.php>      >        4   taknone/liveproto/src/Tl/Types/Other/EmojiStatus.php              7   taknone/liveproto/src/Tl/Types/Other/InputWallPaper.php        P3      7   taknone/liveproto/src/Tl/Types/Other/InputMediaDice.php?      ?        D   taknone/liveproto/src/Tl/Types/Other/PaymentSavedCredentialsCard.php        t꺄      7   taknone/liveproto/src/Tl/Types/Other/PageBlockCover.php7      7  6	      <   taknone/liveproto/src/Tl/Types/Other/UpdateFavedStickers.php              B   taknone/liveproto/src/Tl/Types/Other/UpdateBotMessageReactions.php              H   taknone/liveproto/src/Tl/Types/Other/StarGiftAuctionStateNotModified.php        8<(      S   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionToggleSignatures.phpi      i  ?|F      :   taknone/liveproto/src/Tl/Types/Other/InputPageBlockMap.php        t      B   taknone/liveproto/src/Tl/Types/Other/SecureValueErrorFrontSide.php        8	      ;   taknone/liveproto/src/Tl/Types/Other/PageBlockPullquote.php        (Gg      6   taknone/liveproto/src/Tl/Types/Other/InputPeerSelf.php              >   taknone/liveproto/src/Tl/Types/Other/InputReportReasonSpam.php        |XP[      <   taknone/liveproto/src/Tl/Types/Other/ReactionCustomEmoji.phpG      G  G      A   taknone/liveproto/src/Tl/Types/Other/InputBusinessAwayMessage.phpL      L  H      2   taknone/liveproto/src/Tl/Types/Other/NearestDc.php        t      7   taknone/liveproto/src/Tl/Types/Other/AttachMenuBots.php5      5  q      7   taknone/liveproto/src/Tl/Types/Other/KeyboardButton.php        =P      6   taknone/liveproto/src/Tl/Types/Other/BusinessIntro.php        Oܤ      E   taknone/liveproto/src/Tl/Types/Other/SecureValueTypeBankStatement.php        B      ?   taknone/liveproto/src/Tl/Types/Other/MessageActionGroupCall.php        I7M      K   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionPinTopic.php        ɤ      9   taknone/liveproto/src/Tl/Types/Other/UserProfilePhoto.phpB      B  F0P      =   taknone/liveproto/src/Tl/Types/Other/DialogFilterChatlist.php        7?      A   taknone/liveproto/src/Tl/Types/Other/InputChatThemeUniqueGift.php=      =  o      6   taknone/liveproto/src/Tl/Types/Other/SuggestedPost.phpz      z  Mo*      7   taknone/liveproto/src/Tl/Types/Other/AccountDaysTTL.php)      )  yH      -   taknone/liveproto/src/Tl/Types/Other/Pong.php        j}      @   taknone/liveproto/src/Tl/Types/Other/UpdateQuickReplyMessage.phpC      C  蹤      @   taknone/liveproto/src/Tl/Types/Other/MessageEntityDiffInsert.php        먤      ;   taknone/liveproto/src/Tl/Types/Other/InputThemeSettings.phpT	      T	  kۤ      9   taknone/liveproto/src/Tl/Types/Other/ChatBannedRights.php?      ?        9   taknone/liveproto/src/Tl/Types/Other/InputRichMessage.phpx      x  \      D   taknone/liveproto/src/Tl/Types/Other/SecurePasswordKdfAlgoSHA512.phpF      F        6   taknone/liveproto/src/Tl/Types/Other/TextAutoEmail.php0      0  t      <   taknone/liveproto/src/Tl/Types/Other/PageBlockAuthorDate.php        Y      8   taknone/liveproto/src/Tl/Types/Other/RecentMeUrlUser.php        DMw      9   taknone/liveproto/src/Tl/Types/Other/RpcAnswerUnknown.php        E<      D   taknone/liveproto/src/Tl/Types/Other/StarGiftAuctionAcquiredGift.php        8)      @   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantsBots.php        p      4   taknone/liveproto/src/Tl/Types/Other/UpdateShort.php        Gy      D   taknone/liveproto/src/Tl/Types/Other/MessageActionGiveawayLaunch.php2      2  pB      @   taknone/liveproto/src/Tl/Types/Other/UpdateStarGiftCraftFail.php        ֍eϤ      B   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeBackdrop.php                ?   taknone/liveproto/src/Tl/Types/Other/InputSavedStarGiftChat.php        ^      1   taknone/liveproto/src/Tl/Types/Other/TodoList.php\      \        [   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeAvailableReactions.php        A      4   taknone/liveproto/src/Tl/Types/Other/RecentStory.php        q      K   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionStopPoll.phpb      b  "      B   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantsBanned.php=      =        G   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueDisallowUsers.phpl      l        D   taknone/liveproto/src/Tl/Types/Other/InputInvoicePremiumGiftCode.php        s\      ;   taknone/liveproto/src/Tl/Types/Other/PhoneCallDiscarded.phpJ      J  }      C   taknone/liveproto/src/Tl/Types/Other/MessageActionRequestedPeer.php              9   taknone/liveproto/src/Tl/Types/Other/UpdateNewMessage.php        8ۤ      5   taknone/liveproto/src/Tl/Types/Other/MessageEmpty.php        !      >   taknone/liveproto/src/Tl/Types/Other/ReceivedNotifyMessage.php        6
      D   taknone/liveproto/src/Tl/Types/Other/MessageExtendedMediaPreview.phpa      a  C      J   taknone/liveproto/src/Tl/Types/Other/InputPasskeyCredentialFirebasePNV.phpb      b  ig      :   taknone/liveproto/src/Tl/Types/Other/PageBlockHeading5.php5      5  &      8   taknone/liveproto/src/Tl/Types/Other/InputMediaPhoto.php        b      9   taknone/liveproto/src/Tl/Types/Other/ChatParticipants.phpU      U  :      6   taknone/liveproto/src/Tl/Types/Other/EmojiLanguage.phpE      E   C      2   taknone/liveproto/src/Tl/Types/Other/ChatPhoto.php        ژ#      7   taknone/liveproto/src/Tl/Types/Other/UpdateLangPack.phpQ      Q  Mפ      3   taknone/liveproto/src/Tl/Types/Other/TextStrike.php-      -  @HN      @   taknone/liveproto/src/Tl/Types/Other/MessageEntityDiffDelete.php        6      7   taknone/liveproto/src/Tl/Types/Other/StoryFwdHeader.php        /      4   taknone/liveproto/src/Tl/Types/Other/StickerPack.php        UΤ      E   taknone/liveproto/src/Tl/Types/Other/ChatInvitePublicJoinRequests.php        _h      <   taknone/liveproto/src/Tl/Types/Other/UpdateBotInlineSend.phpo      o  @)m      E   taknone/liveproto/src/Tl/Types/Other/MessageActionTodoAppendTasks.php`      `  v      :   taknone/liveproto/src/Tl/Types/Other/PaymentFormMethod.php        |d      A   taknone/liveproto/src/Tl/Types/Other/RequestPeerTypeBroadcast.php        p      :   taknone/liveproto/src/Tl/Types/Other/UpdatePeerLocated.php[      [  ]      8   taknone/liveproto/src/Tl/Types/Other/UpdateDcOptions.phpd      d  4$Ƥ      ;   taknone/liveproto/src/Tl/Types/Other/PageBlockParagraph.php6      6  @mc      9   taknone/liveproto/src/Tl/Types/Other/UpdateLoginToken.php        b縤      .   taknone/liveproto/src/Tl/Types/Other/Theme.php

      

  9      -   taknone/liveproto/src/Tl/Types/Other/Page.php`      `  <      7   taknone/liveproto/src/Tl/Types/Other/InputUserEmpty.php        ìݤ      E   taknone/liveproto/src/Tl/Types/Other/SendMessageUploadRoundAction.phpJ      J  [6Ƥ      =   taknone/liveproto/src/Tl/Types/Other/PublicForwardMessage.phpF      F  @"Y      :   taknone/liveproto/src/Tl/Types/Other/SavedPhoneContact.php}      }  DW_Y      @   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyForwards.php        I      S   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionToggleNoForwards.phpi      i  s{      7   taknone/liveproto/src/Tl/Types/Other/PageBlockEmbed.php        w7      G   taknone/liveproto/src/Tl/Types/Other/SendMessageChooseStickerAction.php        |      6   taknone/liveproto/src/Tl/Types/Other/TextUnderline.php0      0  @>      /   taknone/liveproto/src/Tl/Types/Other/IpPort.phpp      p  }{)      :   taknone/liveproto/src/Tl/Types/Other/PageBlockHeading3.php5      5  ݤ      7   taknone/liveproto/src/Tl/Types/Other/InputGroupCall.php        	@      B   taknone/liveproto/src/Tl/Types/Other/PageListOrderedItemBlocks.php        u5      G   taknone/liveproto/src/Tl/Types/Other/SecureValueTypeRentalAgreement.php        
      8   taknone/liveproto/src/Tl/Types/Other/MsgDetailedInfo.phpn      n  ig
      1   taknone/liveproto/src/Tl/Types/Other/JsonBool.php&      &  z       F   taknone/liveproto/src/Tl/Types/Other/UpdateChatDefaultBannedRights.phpN      N  [      F   taknone/liveproto/src/Tl/Types/Other/WebPageAttributeAiComposeTone.phpM      M  䩤      C   taknone/liveproto/src/Tl/Types/Other/SendMessageTextDraftAction.php        /A[      F   taknone/liveproto/src/Tl/Types/Other/MessageActionPollDeleteAnswer.phpO      O  9og      @   taknone/liveproto/src/Tl/Types/Other/InlineQueryPeerTypeChat.php        W7f      >   taknone/liveproto/src/Tl/Types/Other/InputNotifyForumTopic.php              7   taknone/liveproto/src/Tl/Types/Other/MessageReplies.phpN      N  Jm      ;   taknone/liveproto/src/Tl/Types/Other/UserStatusLastWeek.php        Qh      6   taknone/liveproto/src/Tl/Types/Other/ReactionEmpty.php        8      1   taknone/liveproto/src/Tl/Types/Other/TextBold.php+      +  ..      G   taknone/liveproto/src/Tl/Types/Other/UpdateBotDeleteBusinessMessage.php        qd      1   taknone/liveproto/src/Tl/Types/Other/TextMath.php/      /  {Ǥ      3   taknone/liveproto/src/Tl/Types/Other/TextAnchor.php        $      @   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeRarity.phpK      K  o	      8   taknone/liveproto/src/Tl/Types/Other/BotInlineResult.php        8+\      9   taknone/liveproto/src/Tl/Types/Other/MessageReactions.php}      }  5K8      :   taknone/liveproto/src/Tl/Types/Other/InputChannelEmpty.php        Ϻ      ;   taknone/liveproto/src/Tl/Types/Other/StarsRevenueStatus.php        >FM      ;   taknone/liveproto/src/Tl/Types/Other/UpdateDialogPinned.php        )*c      <   taknone/liveproto/src/Tl/Types/Other/ReplyKeyboardMarkup.php        .D      ;   taknone/liveproto/src/Tl/Types/Other/LangPackDifference.php        D      9   taknone/liveproto/src/Tl/Types/Other/WebViewResultUrl.php<      <  :      8   taknone/liveproto/src/Tl/Types/Other/InputPhotoEmpty.php        Y      Y   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionToggleGroupCallSetting.phps      s  ch      6   taknone/liveproto/src/Tl/Types/Other/EncryptedFile.php        y6Y      8   taknone/liveproto/src/Tl/Types/Other/UpdatesCombined.phpZ      Z  yͤ      A   taknone/liveproto/src/Tl/Types/Other/PrivacyValueAllowPremium.php        "      @   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantAdmin.php               6   taknone/liveproto/src/Tl/Types/Other/ReactionCount.php"      "  ƪ      ?   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyAddedByPhone.php        Ȥ      ;   taknone/liveproto/src/Tl/Types/Other/UpdateShortMessage.phpt      t  Ƥ      :   taknone/liveproto/src/Tl/Types/Other/PageBlockHeading2.php4      4  LzN      ;   taknone/liveproto/src/Tl/Types/Other/PageListItemBlocks.php        	      9   taknone/liveproto/src/Tl/Types/Other/InputPeerChannel.php        **      3   taknone/liveproto/src/Tl/Types/Other/FolderPeer.php        F~      B   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonUserProfile.php        km      8   taknone/liveproto/src/Tl/Types/Other/PQInnerDataTemp.php        3NZ      0   taknone/liveproto/src/Tl/Types/Other/WebPage.phpG      G  Snդ      9   taknone/liveproto/src/Tl/Types/Other/UpdateManagedBot.php        Q      :   taknone/liveproto/src/Tl/Types/Other/PageBlockHeading4.php5      5  Xq      <   taknone/liveproto/src/Tl/Types/Other/StarsGiveawayOption.php        <      7   taknone/liveproto/src/Tl/Types/Other/StarRefProgram.php	      	  ~&      5   taknone/liveproto/src/Tl/Types/Other/UpdateConfig.php        M.      J   taknone/liveproto/src/Tl/Types/Other/InputBotInlineMessageMediaContact.phpS      S  &      N   taknone/liveproto/src/Tl/Types/Other/InputStickerSetEmojiDefaultTopicIcons.php        )h      8   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyAbout.php              D   taknone/liveproto/src/Tl/Types/Other/TopPeerCategoryForwardUsers.php              Y   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantToggleAdmin.php:      :  CT*      D   taknone/liveproto/src/Tl/Types/Other/UpdateBotNewBusinessMessage.php        5      :   taknone/liveproto/src/Tl/Types/Other/PageBlockThinking.php5      5  c      E   taknone/liveproto/src/Tl/Types/Other/PaidReactionPrivacyAnonymous.php        pt      D   taknone/liveproto/src/Tl/Types/Other/UpdatePinnedChannelMessages.phpP      P  9$#      B   taknone/liveproto/src/Tl/Types/Other/ChatParticipantsForbidden.php        ^      3   taknone/liveproto/src/Tl/Types/Other/ChatInvite.php        4      4   taknone/liveproto/src/Tl/Types/Other/NotifyUsers.php        62b      >   taknone/liveproto/src/Tl/Types/Other/MessageActionStarGift.php        @!      3   taknone/liveproto/src/Tl/Types/Other/TextMarked.php,      ,  }      4   taknone/liveproto/src/Tl/Types/Other/PeerLocated.php        h      C   taknone/liveproto/src/Tl/Types/Other/MessageActionChatEditPhoto.phpC      C  $¤      B   taknone/liveproto/src/Tl/Types/Other/InputReportReasonViolence.php         z#      ?   taknone/liveproto/src/Tl/Types/Other/UpdateShortSentMessage.php        {˹      1   taknone/liveproto/src/Tl/Types/Other/EmojiURL.php#      #  M J      :   taknone/liveproto/src/Tl/Types/Other/ReplyInlineMarkup.phpn      n  Ox      =   taknone/liveproto/src/Tl/Types/Other/TopPeerCategoryPeers.php7      7  ["      8   taknone/liveproto/src/Tl/Types/Other/MonoForumDialog.php        -      H   taknone/liveproto/src/Tl/Types/Other/MessageActionGroupCallScheduled.php        [/Z      =   taknone/liveproto/src/Tl/Types/Other/StarGiftUpgradePrice.php        HǤ      ?   taknone/liveproto/src/Tl/Types/Other/UpdateNewBotConnection.phpE      E  \#ɤ      2   taknone/liveproto/src/Tl/Types/Other/StoryItem.phpf      f  ZAǤ      J   taknone/liveproto/src/Tl/Types/Other/InputBotInlineMessageMediaInvoice.phpT      T  Vn      C   taknone/liveproto/src/Tl/Types/Other/MessageActionChannelCreate.phpB      B  %R      >   taknone/liveproto/src/Tl/Types/Other/InputRichFileDocument.php        lx      ?   taknone/liveproto/src/Tl/Types/Other/ExportedChatlistInvite.phpf      f  g      =   taknone/liveproto/src/Tl/Types/Other/MessageEntityHashtag.php        _Ȥ      5   taknone/liveproto/src/Tl/Types/Other/UpdateSmsJob.php1      1  H8      ?   taknone/liveproto/src/Tl/Types/Other/UpdateDialogUnreadMark.phpI      I  /'\      J   taknone/liveproto/src/Tl/Types/Other/SendMessageRichMessageDraftAction.php              3   taknone/liveproto/src/Tl/Types/Other/EmojiGroup.php<      <  M6      M   taknone/liveproto/src/Tl/Types/Other/InputStorePaymentPremiumSubscription.php>      >  ;r      ?   taknone/liveproto/src/Tl/Types/Other/UpdateNewAuthorization.phpE      E  2y      =   taknone/liveproto/src/Tl/Types/Other/UpdatePinnedMessages.php8      8  T      3   taknone/liveproto/src/Tl/Types/Other/MaskCoords.php#      #  Qn      @   taknone/liveproto/src/Tl/Types/Other/UpdateChannelUserTyping.php        <Y7      8   taknone/liveproto/src/Tl/Types/Other/MessageMediaGeo.php2      2  )@      j   taknone/liveproto/src/Tl/Types/Other/PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow.phpm      m  %¤      @   taknone/liveproto/src/Tl/Types/Other/InputMediaPhotoExternal.php0      0  Q      ?   taknone/liveproto/src/Tl/Types/Other/MessageActionGiftStars.php=      =  ơ      C   taknone/liveproto/src/Tl/Types/Other/UpdateChatParticipantAdmin.phpp      p  M      4   taknone/liveproto/src/Tl/Types/Other/TextAutoUrl.php.      .  Cɤ      1   taknone/liveproto/src/Tl/Types/Other/StarGift.php        5      K   taknone/liveproto/src/Tl/Types/Other/MessageActionStarGiftPurchaseOffer.phpy      y  f      8   taknone/liveproto/src/Tl/Types/Other/PeerSelfLocated.php3      3  ܤ      D   taknone/liveproto/src/Tl/Types/Other/MessageActionSetMessagesTTL.php        EI      7   taknone/liveproto/src/Tl/Types/Other/InputMediaGame.php,      ,  qU      ?   taknone/liveproto/src/Tl/Types/Other/NotificationSoundLocal.php        */      2   taknone/liveproto/src/Tl/Types/Other/PhoneCall.php	      	  З8      =   taknone/liveproto/src/Tl/Types/Other/SecureValueErrorFile.php              ?   taknone/liveproto/src/Tl/Types/Other/InputChatUploadedPhoto.php        ?      ;   taknone/liveproto/src/Tl/Types/Other/StarGiftCollection.php        (lJ      L   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionEditTopic.php        I      <   taknone/liveproto/src/Tl/Types/Other/ChatThemeUniqueGift.php        [(v      B   taknone/liveproto/src/Tl/Types/Other/BotCommandScopePeerAdmins.phpD      D  c      2   taknone/liveproto/src/Tl/Types/Other/StoryView.php;      ;  X      =   taknone/liveproto/src/Tl/Types/Other/InputRichMessageHTML.php              N   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionSendMessage.phpe      e  z      ?   taknone/liveproto/src/Tl/Types/Other/StoryViewPublicForward.php        a      =   taknone/liveproto/src/Tl/Types/Other/UpdateBotWebhookJSON.php5      5  h      =   taknone/liveproto/src/Tl/Types/Other/MessageExtendedMedia.phpK      K  #ix%      5   taknone/liveproto/src/Tl/Types/Other/MediaAreaUrl.php        VL      D   taknone/liveproto/src/Tl/Types/Other/TopPeerCategoryForwardChats.php        ''      C   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonRequestPhone.php              @   taknone/liveproto/src/Tl/Types/Other/UpdatePinnedForumTopics.php        >혤      C   taknone/liveproto/src/Tl/Types/Other/BotInlineMessageMediaVenue.php              2   taknone/liveproto/src/Tl/Types/Other/UserEmpty.php        %Ϥ      =   taknone/liveproto/src/Tl/Types/Other/BotCommandScopeUsers.php        (      >   taknone/liveproto/src/Tl/Types/Other/UpdateRecentReactions.php        M]d      7   taknone/liveproto/src/Tl/Types/Other/GroupCallDonor.phpw      w  L      H   taknone/liveproto/src/Tl/Types/Other/SendMessageUploadDocumentAction.phpM      M  ,z      D   taknone/liveproto/src/Tl/Types/Other/InputReportReasonChildAbuse.php        U^      <   taknone/liveproto/src/Tl/Types/Other/EmojiKeywordDeleted.php        ]      @   taknone/liveproto/src/Tl/Types/Other/MessageReplyStoryHeader.php        Г      B   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterPinned.php        3D      :   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonRow.phpw      w  Z%      4   taknone/liveproto/src/Tl/Types/Other/StarsAmount.php        K      3   taknone/liveproto/src/Tl/Types/Other/SendAsPeer.php        V*      9   taknone/liveproto/src/Tl/Types/Other/UserStatusOnline.php3      3  IǤ      D   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeRarityRare.php               :   taknone/liveproto/src/Tl/Types/Other/UpdateStickerSets.php        $h      C   taknone/liveproto/src/Tl/Types/Other/InputEncryptedFileUploaded.php        ]j      A   taknone/liveproto/src/Tl/Types/Other/MessageEntityDiffReplace.php
      
  uR<      @   taknone/liveproto/src/Tl/Types/Other/PaidReactionPrivacyPeer.phpF      F  vX      H   taknone/liveproto/src/Tl/Types/Other/WebPageAttributeStarGiftAuction.php        𘗤      9   taknone/liveproto/src/Tl/Types/Other/PhoneCallWaiting.phpS      S   9W      9   taknone/liveproto/src/Tl/Types/Other/MessageMediaToDo.php        `ᇤ      7   taknone/liveproto/src/Tl/Types/Other/InputPhoneCall.php        h      E   taknone/liveproto/src/Tl/Types/Other/InlineQueryPeerTypeSameBotPM.php        \      2   taknone/liveproto/src/Tl/Types/Other/TextFixed.php,      ,  V      <   taknone/liveproto/src/Tl/Types/Other/InputChatThemeEmpty.php        G      B   taknone/liveproto/src/Tl/Types/Other/UpdateReadMonoForumOutbox.php?      ?        7   taknone/liveproto/src/Tl/Types/Other/TodoCompletion.php              8   taknone/liveproto/src/Tl/Types/Other/InputMediaVenue.phpz      z  +@      >   taknone/liveproto/src/Tl/Types/Other/InputStarsTransaction.php          dF      =   taknone/liveproto/src/Tl/Types/Other/PrivacyKeySavedMusic.php        #\      <   taknone/liveproto/src/Tl/Types/Other/ExportedMessageLink.php        ޯ@      J   taknone/liveproto/src/Tl/Types/Other/UpdateReadChannelDiscussionOutbox.php1      1  ,      I   taknone/liveproto/src/Tl/Types/Other/MessageActionSuggestProfilePhoto.phpI      I  e      M   taknone/liveproto/src/Tl/Types/Other/PrivacyValueDisallowChatParticipants.php^      ^  d      ;   taknone/liveproto/src/Tl/Types/Other/EncryptedChatEmpty.php$      $  9o      E   taknone/liveproto/src/Tl/Types/Other/MessageActionPaymentRefunded.php        (      E   taknone/liveproto/src/Tl/Types/Other/BotInlineMessageMediaContact.phpI      I  WB6      6   taknone/liveproto/src/Tl/Types/Other/EncryptedChat.php              E   taknone/liveproto/src/Tl/Types/Other/DocumentAttributeCustomEmoji.php        O      B   taknone/liveproto/src/Tl/Types/Other/JoinChatBotResultApproved.php        T2ކ      D   taknone/liveproto/src/Tl/Types/Other/MessageActionStarGiftUnique.php_      _  V      E   taknone/liveproto/src/Tl/Types/Other/SendMessageRecordVideoAction.php              <   taknone/liveproto/src/Tl/Types/Other/InputReplyToMessage.php        rp      :   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonUrl.php        '2H      9   taknone/liveproto/src/Tl/Types/Other/SavedReactionTag.php        TE      =   taknone/liveproto/src/Tl/Types/Other/UpdateDeleteMessages.php        !      F   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueDisallowBots.php        C?      ?   taknone/liveproto/src/Tl/Types/Other/VideoSizeStickerMarkup.phpp      p  no|      4   taknone/liveproto/src/Tl/Types/Other/PQInnerData.phpf      f  f~      B   taknone/liveproto/src/Tl/Types/Other/PremiumSubscriptionOption.php        !.      7   taknone/liveproto/src/Tl/Types/Other/InputThemeSlug.php/      /  r.S      <   taknone/liveproto/src/Tl/Types/Other/UpdateBotMenuButton.php        @      -   taknone/liveproto/src/Tl/Types/Other/Poll.php        m?O      ;   taknone/liveproto/src/Tl/Types/Other/InputGeoPointEmpty.php        }      3   taknone/liveproto/src/Tl/Types/Other/InputTheme.php        5T      K   taknone/liveproto/src/Tl/Types/Other/InputInvoiceChatInviteSubscription.phpE      E  ڸd      :   taknone/liveproto/src/Tl/Types/Other/StickerSetCovered.php        K      6   taknone/liveproto/src/Tl/Types/Other/SponsoredPeer.php        }      C   taknone/liveproto/src/Tl/Types/Other/EmailVerifyPurposePassport.php        u      A   taknone/liveproto/src/Tl/Types/Other/UpdateChannelParticipant.php        m      A   taknone/liveproto/src/Tl/Types/Other/ReportResultChooseOption.php        Ԛ      D   taknone/liveproto/src/Tl/Types/Other/SearchResultsCalendarPeriod.php|      |        6   taknone/liveproto/src/Tl/Types/Other/BadServerSalt.php        ]      2   taknone/liveproto/src/Tl/Types/Other/InputFile.phpW      W  :ť      G   taknone/liveproto/src/Tl/Types/Other/UpdateDeleteQuickReplyMessages.php              7   taknone/liveproto/src/Tl/Types/Other/MissingInvitee.php        ]:      =   taknone/liveproto/src/Tl/Types/Other/EncryptedChatWaiting.php        ^+      6   taknone/liveproto/src/Tl/Types/Other/UpdateChannel.php;      ;  L      /   taknone/liveproto/src/Tl/Types/Other/Folder.php%      %  OȤ      F   taknone/liveproto/src/Tl/Types/Other/UpdateDeleteGroupCallMessages.php        fa      >   taknone/liveproto/src/Tl/Types/Other/InputCollectiblePhone.php@      @  \      E   taknone/liveproto/src/Tl/Types/Other/InputWebFileGeoPointLocation.php"      "  z*      4   taknone/liveproto/src/Tl/Types/Other/ChatOnlines.php/      /  N      O   taknone/liveproto/src/Tl/Types/Other/InputSendMessageRichMessageDraftAction.php        
l5      @   taknone/liveproto/src/Tl/Types/Other/UpdateSavedReactionTags.php        6      G   taknone/liveproto/src/Tl/Types/Other/PostInteractionCountersMessage.phpw      w  kh      G   taknone/liveproto/src/Tl/Types/Other/MessageActionPaidMessagesPrice.phpV      V  r      :   taknone/liveproto/src/Tl/Types/Other/UpdateFolderPeers.php2      2  {(      R   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeWallpaper.php        ]!      8   taknone/liveproto/src/Tl/Types/Other/PhotoCachedSize.php(      (        A   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeIdModel.phpW      W        @   taknone/liveproto/src/Tl/Types/Other/MessageEntityBlockquote.phpk      k  nB      9   taknone/liveproto/src/Tl/Types/Other/InlineBotWebView.php        w      C   taknone/liveproto/src/Tl/Types/Other/InputMediaDocumentExternal.php        ;      <   taknone/liveproto/src/Tl/Types/Other/MessageReportOption.php        L      W   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantSubExtend.php8      8  ͼ      J   taknone/liveproto/src/Tl/Types/Other/MessageActionPaidMessagesRefunded.php        W}ˤ      0   taknone/liveproto/src/Tl/Types/Other/MyBoost.php         +t      8   taknone/liveproto/src/Tl/Types/Other/ProfileTabGifts.php        @      3   taknone/liveproto/src/Tl/Types/Other/StoryAlbum.phpM      M  8en      D   taknone/liveproto/src/Tl/Types/Other/InputGroupCallInviteMessage.php>      >  3h      A   taknone/liveproto/src/Tl/Types/Other/InputTakeoutFileLocation.php        rV      ;   taknone/liveproto/src/Tl/Types/Other/InputDocumentEmpty.php        Ϥ      C   taknone/liveproto/src/Tl/Types/Other/MessageActionChatEditTitle.phpB      B  yjB      @   taknone/liveproto/src/Tl/Types/Other/PageListOrderedItemText.php        &7      J   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueDisallowContacts.php        ׆      7   taknone/liveproto/src/Tl/Types/Other/StarGiftUnique.phpp      p  ︈      S   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionDiscardGroupCall.phpe      e  n      7   taknone/liveproto/src/Tl/Types/Other/MessageReactor.php        פ      A   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyNoPaidMessages.php        /2      A   taknone/liveproto/src/Tl/Types/Other/InlineQueryPeerTypeBotPM.php        :k      B   taknone/liveproto/src/Tl/Types/Other/UpdateNewScheduledMessage.phpE      E  :5      9   taknone/liveproto/src/Tl/Types/Other/MessageEntityUrl.php              4   taknone/liveproto/src/Tl/Types/Other/PeerChannel.php7      7  ܤ      :   taknone/liveproto/src/Tl/Types/Other/MessageMediaPhoto.php        O      I   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonRequestGeoLocation.php        ]7      E   taknone/liveproto/src/Tl/Types/Other/BotInlineMessageMediaInvoice.php        *ޤ      7   taknone/liveproto/src/Tl/Types/Other/InputMediaTodo.php3      3  O礤      J   taknone/liveproto/src/Tl/Types/Other/BusinessAwayMessageScheduleCustom.php        :"      6   taknone/liveproto/src/Tl/Types/Other/TextSubscript.php0      0  hS֤      3   taknone/liveproto/src/Tl/Types/Other/StickerSet.php        JV      E   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyVoiceMessages.php        2      /   taknone/liveproto/src/Tl/Types/Other/BotApp.php        S      :   taknone/liveproto/src/Tl/Types/Other/InputReplyToStory.php        I4p      5   taknone/liveproto/src/Tl/Types/Other/PeerSettings.php        ԥԺ      3   taknone/liveproto/src/Tl/Types/Other/FutureSalt.php	      	  WG      B   taknone/liveproto/src/Tl/Types/Other/UpdateGroupCallConnection.php          S˗      ?   taknone/liveproto/src/Tl/Types/Other/InputFileStoryDocument.php7      7  $p(n      C   taknone/liveproto/src/Tl/Types/Other/InputStorePaymentStarsGift.php        r      ?   taknone/liveproto/src/Tl/Types/Other/PasswordKdfAlgoUnknown.php              <   taknone/liveproto/src/Tl/Types/Other/UpdateContactsReset.php        6b      -   taknone/liveproto/src/Tl/Types/Other/Game.php        ޳      D   taknone/liveproto/src/Tl/Types/Other/UpdateChatParticipantDelete.php        -ܤ      A   taknone/liveproto/src/Tl/Types/Other/InputBotInlineResultGame.phpF      F  _BԤ      6   taknone/liveproto/src/Tl/Types/Other/InputGeoPoint.php'      '  X      @   taknone/liveproto/src/Tl/Types/Other/EmojiKeywordsDifference.php        tj      >   taknone/liveproto/src/Tl/Types/Other/WebPageAttributeTheme.php        ox      G   taknone/liveproto/src/Tl/Types/Other/UpdateStarGiftAuctionUserState.php        ם^      3   taknone/liveproto/src/Tl/Types/Other/JsonObject.phpc      c  gʤ      >   taknone/liveproto/src/Tl/Types/Other/UpdateChatParticipant.php        =Q[      9   taknone/liveproto/src/Tl/Types/Other/MediaAreaWeather.php        \jG      9   taknone/liveproto/src/Tl/Types/Other/PageBlockCollage.php        A!      9   taknone/liveproto/src/Tl/Types/Other/AutoSaveSettings.phpc      c  	      @   taknone/liveproto/src/Tl/Types/Other/BusinessGreetingMessage.phpe      e  sB<      ;   taknone/liveproto/src/Tl/Types/Other/InputMediaDocument.php        {}      ;   taknone/liveproto/src/Tl/Types/Other/DestroyAuthKeyFail.php        dۇ      1   taknone/liveproto/src/Tl/Types/Other/StatsURL.php#      #  e      6   taknone/liveproto/src/Tl/Types/Other/BotMenuButton.php        V3o      >   taknone/liveproto/src/Tl/Types/Other/RecentMeUrlChatInvite.php        w      E   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueDisallowAll.php        yO      6   taknone/liveproto/src/Tl/Types/Other/ChatForbidden.php~      ~  U      1   taknone/liveproto/src/Tl/Types/Other/Timezone.php        !      7   taknone/liveproto/src/Tl/Types/Other/PageBlockPhoto.php        #      8   taknone/liveproto/src/Tl/Types/Other/ChatParticipant.phpW      W  ?0      ;   taknone/liveproto/src/Tl/Types/Other/UpdateQuickReplies.phpy      y  %E      O   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionUpdatePinned.phpf      f  }摤      9   taknone/liveproto/src/Tl/Types/Other/MessageMediaPoll.phpI      I  ;_      1   taknone/liveproto/src/Tl/Types/Other/HttpWait.php        Wϡ      0   taknone/liveproto/src/Tl/Types/Other/Message.php)3      )3  E      ?   taknone/liveproto/src/Tl/Types/Other/UpdateNewStoryReaction.php        jv      7   taknone/liveproto/src/Tl/Types/Other/PageBlockTitle.php2      2  `eP      E   taknone/liveproto/src/Tl/Types/Other/StarsTransactionPeerAppStore.php        ?      @   taknone/liveproto/src/Tl/Types/Other/DisallowedGiftsSettings.php;      ;  Q      3   taknone/liveproto/src/Tl/Types/Other/DialogPeer.php+      +  	      6   taknone/liveproto/src/Tl/Types/Other/InputPeerChat.php2      2  -%      @   taknone/liveproto/src/Tl/Types/Other/EncryptedMessageService.phpi      i  ?;      G   taknone/liveproto/src/Tl/Types/Other/InputBotInlineMessageMediaAuto.php        h#U      H   taknone/liveproto/src/Tl/Types/Other/InputBotInlineMessageMediaVenue.php(      (  :Ĥ      =   taknone/liveproto/src/Tl/Types/Other/StatsAbsValueAndPrev.php        `T      F   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueAllowPremium.php        \3      2   taknone/liveproto/src/Tl/Types/Other/TextImage.php        :I      T   taknone/liveproto/src/Tl/Types/Other/BusinessAwayMessageScheduleOutsideWorkHours.php        fk!e      Q   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionToggleAntiSpam.phpg      g  y{%      1   taknone/liveproto/src/Tl/Types/Other/PeerChat.php(      (  9?J      J   taknone/liveproto/src/Tl/Types/Other/ReactionNotificationsFromContacts.php        ʼL      A   taknone/liveproto/src/Tl/Types/Other/MessageEntityMentionName.php        Q      =   taknone/liveproto/src/Tl/Types/Other/ChannelLocationEmpty.php        (r      ?   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantSelf.phpw      w  pפ      <   taknone/liveproto/src/Tl/Types/Other/BusinessAwayMessage.php=      =  l`\      5   taknone/liveproto/src/Tl/Types/Other/EmojiKeyword.php        O      A   taknone/liveproto/src/Tl/Types/Other/InputStarGiftAuctionSlug.phpC      C  I      <   taknone/liveproto/src/Tl/Types/Other/MessageMediaWebPage.php        ,cC      C   taknone/liveproto/src/Tl/Types/Other/SecureValueTypeUtilityBill.php        "F      C   taknone/liveproto/src/Tl/Types/Other/UpdateStarGiftAuctionState.php              :   taknone/liveproto/src/Tl/Types/Other/UpdatePeerBlocked.php        g3      :   taknone/liveproto/src/Tl/Types/Other/UpdateBotCommands.php'      '  XѤ      ?   taknone/liveproto/src/Tl/Types/Other/EmojiStatusCollectible.phpL      L  ~"      9   taknone/liveproto/src/Tl/Types/Other/InputSingleMedia.php        ,{      C   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeIdPattern.phpY      Y  V+      9   taknone/liveproto/src/Tl/Types/Other/PageBlockChannel.php<      <  ߿U      6   taknone/liveproto/src/Tl/Types/Other/Authorization.php/      /        V   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionDefaultBannedRights.phpC      C  !      =   taknone/liveproto/src/Tl/Types/Other/MessageEntityCashtag.php        -      <   taknone/liveproto/src/Tl/Types/Other/UpdateGeoLiveViewed.php        .      B   taknone/liveproto/src/Tl/Types/Other/UpdatePaidReactionPrivacy.phpQ      Q  Y      =   taknone/liveproto/src/Tl/Types/Other/VideoSizeEmojiMarkup.php        li       B   taknone/liveproto/src/Tl/Types/Other/InputPasskeyResponseLogin.php        ?sդ      ;   taknone/liveproto/src/Tl/Types/Other/InputEncryptedFile.php        W      @   taknone/liveproto/src/Tl/Types/Other/InputSecureFileLocation.php        ^F)      I   taknone/liveproto/src/Tl/Types/Other/InputStorePaymentPremiumGiftCode.php        B      A   taknone/liveproto/src/Tl/Types/Other/BotInlineMessageMediaGeo.php        }ad      A   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantBanned.php`      `  Ǥ      6   taknone/liveproto/src/Tl/Types/Other/DocumentEmpty.php        37l      ?   taknone/liveproto/src/Tl/Types/Other/EncryptedChatDiscarded.php        ~A      8   taknone/liveproto/src/Tl/Types/Other/UserStatusEmpty.php        ׳      C   taknone/liveproto/src/Tl/Types/Other/UpdateReadFeaturedStickers.php        ж:      2   taknone/liveproto/src/Tl/Types/Other/WallPaper.php        ޤ      C   taknone/liveproto/src/Tl/Types/Other/UpdateReadMessagesContents.php`      `  \=m      /   taknone/liveproto/src/Tl/Types/Other/Config.phpR&      R&  w.      4   taknone/liveproto/src/Tl/Types/Other/PageCaption.php        v      D   taknone/liveproto/src/Tl/Types/Other/SecureValueTypeIdentityCard.php        ٤      C   taknone/liveproto/src/Tl/Types/Other/MediaAreaSuggestedReaction.php        x<P      D   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterContacts.php        Ф      ?   taknone/liveproto/src/Tl/Types/Other/TopPeerCategoryBotsApp.php        Ur      B   taknone/liveproto/src/Tl/Types/Other/InputPeerColorCollectible.phpZ      Z  6kH_      ?   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeModel.php        ?      3   taknone/liveproto/src/Tl/Types/Other/UpdateChat.php,      ,  mC[      6   taknone/liveproto/src/Tl/Types/Other/TextAutoPhone.php0      0  [M      ;   taknone/liveproto/src/Tl/Types/Other/UpdateBotChatBoost.php        :I      B   taknone/liveproto/src/Tl/Types/Other/StoryReactionPublicRepost.php        |Ҥ      D   taknone/liveproto/src/Tl/Types/Other/RequirementToContactPremium.php              B   taknone/liveproto/src/Tl/Types/Other/InputBotInlineResultPhoto.php        ]      ;   taknone/liveproto/src/Tl/Types/Other/InputRichFilePhoto.php        6nr      E   taknone/liveproto/src/Tl/Types/Other/InputPhotoLegacyFileLocation.phpj      j  NѤ      :   taknone/liveproto/src/Tl/Types/Other/PhoneCallProtocol.php        Ӈ      =   taknone/liveproto/src/Tl/Types/Other/UpdateNotifySettings.php        Y      E   taknone/liveproto/src/Tl/Types/Other/InputBusinessGreetingMessage.phps      s  9פ      B   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonRequestPeer.php        +T      ;   taknone/liveproto/src/Tl/Types/Other/ServerDHParamsFail.php        ;FȤ      T   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeEmojiStatus.php              ;   taknone/liveproto/src/Tl/Types/Other/ChannelParticipant.phpp      p  v͡      C   taknone/liveproto/src/Tl/Types/Other/WebPageAttributeStickerSet.php        H      A   taknone/liveproto/src/Tl/Types/Other/UpdateBotMessageReaction.php        Q9      C   taknone/liveproto/src/Tl/Types/Other/InputReportReasonCopyright.php        $"R      G   taknone/liveproto/src/Tl/Types/Other/UpdateChannelAvailableMessages.php        :}      4   taknone/liveproto/src/Tl/Types/Other/MsgsAllInfo.php        CY      B   taknone/liveproto/src/Tl/Types/Other/InputAiComposeToneDefault.phpB      B        7   taknone/liveproto/src/Tl/Types/Other/InputChatPhoto.php1      1  Sbդ      >   taknone/liveproto/src/Tl/Types/Other/ChannelMessagesFilter.phpt      t  6^      2   taknone/liveproto/src/Tl/Types/Other/DhGenFail.php        Bݤ      C   taknone/liveproto/src/Tl/Types/Other/MessagePeerVoteInputOption.php        C6<      <   taknone/liveproto/src/Tl/Types/Other/UpdateNewQuickReply.phpR      R  ̨      A   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterMusic.php        Pd      O   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueAllowChatParticipants.phpe      e  +      7   taknone/liveproto/src/Tl/Types/Other/BotAppSettings.php        xg      A   taknone/liveproto/src/Tl/Types/Other/MessageActionTopicCreate.php              9   taknone/liveproto/src/Tl/Types/Other/InputClientProxy.php              J   taknone/liveproto/src/Tl/Types/Other/PrivacyValueAllowChatParticipants.php[      [  ˻WV      ?   taknone/liveproto/src/Tl/Types/Other/UpdateReadHistoryInbox.phpv      v  ,      F   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterRoundVoice.php        p]ˤ      C   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueAllowBots.php        Z0      A   taknone/liveproto/src/Tl/Types/Other/UpdateEditChannelMessage.php        D      4   taknone/liveproto/src/Tl/Types/Other/SavedDialog.phpg      g  6      7   taknone/liveproto/src/Tl/Types/Other/PhotoSizeEmpty.php-      -  Un      =   taknone/liveproto/src/Tl/Types/Other/AiComposeToneDefault.php        0e      A   taknone/liveproto/src/Tl/Types/Other/StarsSubscriptionPricing.php        _WĤ      C   taknone/liveproto/src/Tl/Types/Other/InputMediaUploadedDocument.php        i      ;   taknone/liveproto/src/Tl/Types/Other/SecureRequiredType.php{      {  ǝa      =   taknone/liveproto/src/Tl/Types/Other/RequestedPeerChannel.php              H   taknone/liveproto/src/Tl/Types/Other/SecureValueTypeInternalPassport.php        >'      =   taknone/liveproto/src/Tl/Types/Other/UpdateRecentStickers.php        5      Y   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionTogglePreHistoryHidden.phpo      o  aڤ      =   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyAbout.php        _7      C   taknone/liveproto/src/Tl/Types/Other/PhoneCallDiscardReasonBusy.php        I"`      <   taknone/liveproto/src/Tl/Types/Other/BotCommandScopePeer.php>      >  OJ      F   taknone/liveproto/src/Tl/Types/Other/UpdateJoinChatWebViewDecision.php        :      :   taknone/liveproto/src/Tl/Types/Other/MessageEntityCode.php        CT      X   taknone/liveproto/src/Tl/Types/Other/SecurePasswordKdfAlgoPBKDF2HMACSHA512iter100000.phpZ      Z        <   taknone/liveproto/src/Tl/Types/Other/RequestPeerTypeChat.phpd      d  Xh      =   taknone/liveproto/src/Tl/Types/Other/StarGiftAuctionState.php        vy;      4   taknone/liveproto/src/Tl/Types/Other/StarsRating.php        7!J      J   taknone/liveproto/src/Tl/Types/Other/UpdateChannelReadMessagesContents.php        m      0   taknone/liveproto/src/Tl/Types/Other/Updates.php        {
p      6   taknone/liveproto/src/Tl/Types/Other/ReactionEmoji.php<      <  ]ґ      =   taknone/liveproto/src/Tl/Types/Other/PhotoSizeProgressive.php@      @  PH      E   taknone/liveproto/src/Tl/Types/Other/InputBotInlineResultDocument.phpB      B  Rn      4   taknone/liveproto/src/Tl/Types/Other/UpdateTheme.php-      -  ~o      7   taknone/liveproto/src/Tl/Types/Other/InputMediaPoll.phpG	      G	  "      <   taknone/liveproto/src/Tl/Types/Other/StickerSetNoCovered.php=      =  ޥM      @   taknone/liveproto/src/Tl/Types/Other/SecureRequiredTypeOneOf.php        Ap      5   taknone/liveproto/src/Tl/Types/Other/PageTableRow.phpb      b  cU      :   taknone/liveproto/src/Tl/Types/Other/AttachMenuBotIcon.phpJ      J  qKޤ      @   taknone/liveproto/src/Tl/Types/Other/UpdateSavedDialogPinned.php        },      N   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangePhoto.php              9   taknone/liveproto/src/Tl/Types/Other/UpdateUserTyping.php        3qM      ?   taknone/liveproto/src/Tl/Types/Other/AttachMenuPeerTypeChat.php        }3ؤ      6   taknone/liveproto/src/Tl/Types/Other/GeoPointEmpty.php        8<      8   taknone/liveproto/src/Tl/Types/Other/BotVerification.php              ?   taknone/liveproto/src/Tl/Types/Other/InputPhotoFileLocation.php        U      A   taknone/liveproto/src/Tl/Types/Other/NotificationSoundDefault.php        6P      :   taknone/liveproto/src/Tl/Types/Other/MediaAreaGeoPoint.php2      2  X      =   taknone/liveproto/src/Tl/Types/Other/SecureSecretSettings.phpz      z  N(      E   taknone/liveproto/src/Tl/Types/Other/UpdateInlineBotCallbackQuery.phpL      L  )      E   taknone/liveproto/src/Tl/Types/Other/InputReportReasonPornography.php        5Τ      I   taknone/liveproto/src/Tl/Types/Other/UpdateChannelViewForumAsMessages.php        x      K   taknone/liveproto/src/Tl/Types/Other/WebPageAttributeStarGiftCollection.phpm      m        2   taknone/liveproto/src/Tl/Types/Other/JsonArray.phpP      P  qC      D   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantsMentions.phpS      S  	
      <   taknone/liveproto/src/Tl/Types/Other/InputMediaStakeDice.php6      6  /      9   taknone/liveproto/src/Tl/Types/Other/RpcAnswerDropped.php        Q      ;   taknone/liveproto/src/Tl/Types/Other/DestroyAuthKeyNone.php        sV#      =   taknone/liveproto/src/Tl/Types/Other/BotInlineMessageText.phpQ      Q  n      E   taknone/liveproto/src/Tl/Types/Other/EmailVerifyPurposeLoginSetup.php        wa-      E   taknone/liveproto/src/Tl/Types/Other/SendMessageUploadPhotoAction.phpJ      J  ٤      >   taknone/liveproto/src/Tl/Types/Other/BotBusinessConnection.phpq      q  \      I   taknone/liveproto/src/Tl/Types/Other/InputStorePaymentPremiumGiveaway.php
      
  Y      D   taknone/liveproto/src/Tl/Types/Other/MessageActionConferenceCall.php        ;      E   taknone/liveproto/src/Tl/Types/Other/UpdatePhoneCallSignalingData.php        ՜      6   taknone/liveproto/src/Tl/Types/Other/PQInnerDataDc.php        
ry      0   taknone/liveproto/src/Tl/Types/Other/Contact.php        ;s      5   taknone/liveproto/src/Tl/Types/Other/IpPortSecret.php        @[m]      B   taknone/liveproto/src/Tl/Types/Other/UpdateChannelMessageViews.php        Tn      :   taknone/liveproto/src/Tl/Types/Other/PendingSuggestion.php        A      0   taknone/liveproto/src/Tl/Types/Other/Channel.php*      *  K:      I   taknone/liveproto/src/Tl/Types/Other/SecureValueErrorTranslationFiles.php?      ?  C      >   taknone/liveproto/src/Tl/Types/Other/InlineQueryPeerTypePM.php        /x      >   taknone/liveproto/src/Tl/Types/Other/InputReplyToMonoForum.phpq      q  giŤ      >   taknone/liveproto/src/Tl/Types/Other/NotificationSoundNone.php        WQl      @   taknone/liveproto/src/Tl/Types/Other/PrivacyValueDisallowAll.php        ȕ      >   taknone/liveproto/src/Tl/Types/Other/InputBusinessChatLink.php         =      B   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueAllowAll.php        vH      2   taknone/liveproto/src/Tl/Types/Other/HighScore.php        $Fx      :   taknone/liveproto/src/Tl/Types/Other/RequestedPeerChat.php              ;   taknone/liveproto/src/Tl/Types/Other/MessageEntityPhone.php              >   taknone/liveproto/src/Tl/Types/Other/InputCheckPasswordSRP.php        oi      ;   taknone/liveproto/src/Tl/Types/Other/UpdateDialogFilter.php        w      9   taknone/liveproto/src/Tl/Types/Other/MessageMediaDice.php>      >  0      2   taknone/liveproto/src/Tl/Types/Other/ChatEmpty.php        r      @   taknone/liveproto/src/Tl/Types/Other/BotCommandScopePeerUser.php        xI      :   taknone/liveproto/src/Tl/Types/Other/BusinessWorkHours.php        U      2   taknone/liveproto/src/Tl/Types/Other/ChatTheme.php9      9  A?      4   taknone/liveproto/src/Tl/Types/Other/TextCashtag.php.      .  t      I   taknone/liveproto/src/Tl/Types/Other/MessageActionChatJoinedByRequest.php              .   taknone/liveproto/src/Tl/Types/Other/Boost.php
      
        7   taknone/liveproto/src/Tl/Types/Other/ChatPhotoEmpty.php        r      8   taknone/liveproto/src/Tl/Types/Other/UpdateUserPhone.php        -9      ;   taknone/liveproto/src/Tl/Types/Other/PageBlockSlideshow.php              4   taknone/liveproto/src/Tl/Types/Other/PeerStories.php8      8  4      ;   taknone/liveproto/src/Tl/Types/Other/PageBlockEmbedPost.php        	,      C   taknone/liveproto/src/Tl/Types/Other/ChannelMessagesFilterEmpty.php        w=      0   taknone/liveproto/src/Tl/Types/Other/TextUrl.php        "r      :   taknone/liveproto/src/Tl/Types/Other/ReplyKeyboardHide.php        0      E   taknone/liveproto/src/Tl/Types/Other/MessageActionTodoCompletions.php        `r      G   taknone/liveproto/src/Tl/Types/Other/MessageActionInviteToGroupCall.php        qT      >   taknone/liveproto/src/Tl/Types/Other/InputDialogPeerFolder.phpE      E  J=      @   taknone/liveproto/src/Tl/Types/Other/AttachMenuPeerTypeBotPM.php              H   taknone/liveproto/src/Tl/Types/Other/UpdateGroupCallEncryptedMessage.phpG      G  +pw      =   taknone/liveproto/src/Tl/Types/Other/SearchResultPosition.php        x      E   taknone/liveproto/src/Tl/Types/Other/PrivacyValueDisallowContacts.php        m"      ;   taknone/liveproto/src/Tl/Types/Other/PageRelatedArticle.php        v      @   taknone/liveproto/src/Tl/Types/Other/UpdateReadChannelOutbox.php        v	      <   taknone/liveproto/src/Tl/Types/Other/RequestPeerTypeUser.php8      8        9   taknone/liveproto/src/Tl/Types/Other/StoryItemDeleted.php        -      >   taknone/liveproto/src/Tl/Types/Other/UpdateMessagePollVote.php              2   taknone/liveproto/src/Tl/Types/Other/EmojiList.php        1Ф      D   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyAddedByPhone.php        (F      @   taknone/liveproto/src/Tl/Types/Other/MessageActionPrizeStars.php              9   taknone/liveproto/src/Tl/Types/Other/ServerDHParamsOk.phps      s  i;Ǥ      :   taknone/liveproto/src/Tl/Types/Other/UpdateMessagePoll.php=      =        :   taknone/liveproto/src/Tl/Types/Other/InlineBotSwitchPM.php        %h      ;   taknone/liveproto/src/Tl/Types/Other/InputEncryptedChat.php        >q?      /   taknone/liveproto/src/Tl/Types/Other/SmsJob.php        r      1   taknone/liveproto/src/Tl/Types/Other/Username.php        _      A   taknone/liveproto/src/Tl/Types/Other/StarGiftAuctionUserState.php        ь      L   taknone/liveproto/src/Tl/Types/Other/SecureValueTypePassportRegistration.php        g      9   taknone/liveproto/src/Tl/Types/Other/PageBlockDivider.php        ?qݤ      E   taknone/liveproto/src/Tl/Types/Other/MessageActionWebViewDataSent.php@      @  C|      G   taknone/liveproto/src/Tl/Types/Other/InputKeyboardButtonRequestPeer.php        iƸ      <   taknone/liveproto/src/Tl/Types/Other/StatsGroupTopPoster.php        eX      A   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributePattern.php1      1        F   taknone/liveproto/src/Tl/Types/Other/InputMessageEntityMentionName.php        
      8   taknone/liveproto/src/Tl/Types/Other/ProfileTabPosts.php        tL
      1   taknone/liveproto/src/Tl/Types/Other/TextDate.php        nU      B   taknone/liveproto/src/Tl/Types/Other/DocumentAttributeFilename.phpU      U  U      7   taknone/liveproto/src/Tl/Types/Other/ProfileTabGifs.php        ̼      3   taknone/liveproto/src/Tl/Types/Other/QuickReply.php{      {  y      @   taknone/liveproto/src/Tl/Types/Other/MessageEntityBotCommand.php        Ul      8   taknone/liveproto/src/Tl/Types/Other/InputNotifyPeer.php:      :  Ҳ      F   taknone/liveproto/src/Tl/Types/Other/MessageActionPollAppendAnswer.phpO      O  }      B   taknone/liveproto/src/Tl/Types/Other/InputChatlistDialogFilter.phpG      G  ѹ      <   taknone/liveproto/src/Tl/Types/Other/UserStatusLastMonth.php        N{      D   taknone/liveproto/src/Tl/Types/Other/UpdateBotPurchasedPaidMedia.php        whs      <   taknone/liveproto/src/Tl/Types/Other/InputChatPhotoEmpty.php        W      5   taknone/liveproto/src/Tl/Types/Other/CodeSettings.php|	      |	  %      ;   taknone/liveproto/src/Tl/Types/Other/MsgNewDetailedInfo.php        i٤      4   taknone/liveproto/src/Tl/Types/Other/NotifyChats.php        ܩ      ;   taknone/liveproto/src/Tl/Types/Other/InputBusinessIntro.php-      -  47      ?   taknone/liveproto/src/Tl/Types/Other/EmailVerificationApple.phpB      B  /      A   taknone/liveproto/src/Tl/Types/Other/InputStickerSetShortName.phpV      V        4   taknone/liveproto/src/Tl/Types/Other/SecureValue.phpi      i  l9      C   taknone/liveproto/src/Tl/Types/Other/MessageActionContactSignUp.php        8C      R   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueDisallowChatParticipants.phph      h  2      @   taknone/liveproto/src/Tl/Types/Other/InputPeerNotifySettings.php
      
  &v      =   taknone/liveproto/src/Tl/Types/Other/UpdateChannelTooLong.php        -7&      W   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionExportedInviteDelete.phpu      u  D즤      =   taknone/liveproto/src/Tl/Types/Other/UpdateAttachMenuBots.php        ,â      -   taknone/liveproto/src/Tl/Types/Other/Chat.php        ue      :   taknone/liveproto/src/Tl/Types/Other/AttachMenuBotsBot.php        c@o      ;   taknone/liveproto/src/Tl/Types/Other/StatsDateRangeDays.php        @A5      E   taknone/liveproto/src/Tl/Types/Other/SecureValueTypeDriverLicense.php        >      A   taknone/liveproto/src/Tl/Types/Other/InputRichMessageMarkdown.php        &      B   taknone/liveproto/src/Tl/Types/Other/PrivacyValueDisallowUsers.phpS      S  9      B   taknone/liveproto/src/Tl/Types/Other/JoinChatBotResultDeclined.php        Fk
      5   taknone/liveproto/src/Tl/Types/Other/DialogFilter.php        $      D   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterDocument.php        QuH      @   taknone/liveproto/src/Tl/Types/Other/StarsTransactionPeerAPI.php        8̤      I   taknone/liveproto/src/Tl/Types/Other/InputBotInlineMessageRichMessage.php        mG      6   taknone/liveproto/src/Tl/Types/Other/SavedStarGift.php-      -  \z      =   taknone/liveproto/src/Tl/Types/Other/InputWebFileLocation.php              2   taknone/liveproto/src/Tl/Types/Other/FactCheck.php.      .  e      9   taknone/liveproto/src/Tl/Types/Other/BusinessLocation.php        l1      E   taknone/liveproto/src/Tl/Types/Other/BotInlineMessageMediaWebPage.phpm      m  QKV      D   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventsFilter.php        ۞      ?   taknone/liveproto/src/Tl/Types/Other/UpdateAutoSaveSettings.php        &c      B   taknone/liveproto/src/Tl/Types/Other/UpdatePendingJoinRequests.phpf      f        @   taknone/liveproto/src/Tl/Types/Other/SendMessageCancelAction.php        L      X   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionToggleAutotranslation.phpn      n  %׆      2   taknone/liveproto/src/Tl/Types/Other/TextPlain.php(      (  0<      A   taknone/liveproto/src/Tl/Types/Other/UpdatePinnedSavedDialogs.phpU      U  ޑ      :   taknone/liveproto/src/Tl/Types/Other/PhotoStrippedSize.php              >   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonUrlAuth.php        -x      S   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeLinkedChat.php        v      B   taknone/liveproto/src/Tl/Types/Other/SpeakingInGroupCallAction.php        X-?      B   taknone/liveproto/src/Tl/Types/Other/InputStorePaymentAuthCode.php
      
  iڤ      B   taknone/liveproto/src/Tl/Types/Other/UpdateBotPrecheckoutQuery.php        )      ;   taknone/liveproto/src/Tl/Types/Other/InputWallPaperSlug.php7      7  T      D   taknone/liveproto/src/Tl/Types/Other/UpdateDeleteChannelMessages.php        p5B      B   taknone/liveproto/src/Tl/Types/Other/UpdateWebBrowserException.php        ^      6   taknone/liveproto/src/Tl/Types/Other/InputUserSelf.php        O      C   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonSwitchInline.php              9   taknone/liveproto/src/Tl/Types/Other/UpdatePtsChanged.php        ā      D   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeRarityEpic.php        YB      9   taknone/liveproto/src/Tl/Types/Other/MessageMediaGame.php3      3  _3      =   taknone/liveproto/src/Tl/Types/Other/AttachMenuPeerTypePM.php        Gzw      A   taknone/liveproto/src/Tl/Types/Other/JoinChatBotResultWebView.php<      <  H>ߤ      D   taknone/liveproto/src/Tl/Types/Other/SendMessageEmojiInteraction.php3      3  -Ť      7   taknone/liveproto/src/Tl/Types/Other/LangPackString.php        {      >   taknone/liveproto/src/Tl/Types/Other/GlobalPrivacySettings.php	      	  Lؤ      5   taknone/liveproto/src/Tl/Types/Other/DraftMessage.phpK      K  G'      /   taknone/liveproto/src/Tl/Types/Other/Dialog.php        J      8   taknone/liveproto/src/Tl/Types/Other/UpdateMessageID.php        T:      =   taknone/liveproto/src/Tl/Types/Other/StatsGroupTopInviter.php        z      9   taknone/liveproto/src/Tl/Types/Other/MessageEntityPre.php        LS      ?   taknone/liveproto/src/Tl/Types/Other/AttachMenuBotIconColor.php        0rԤ      =   taknone/liveproto/src/Tl/Types/Other/InputAiComposeToneID.php        w      3   taknone/liveproto/src/Tl/Types/Other/DhGenRetry.php        1      :   taknone/liveproto/src/Tl/Types/Other/InputStickerSetID.php        L      I   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeRarityLegendary.php        S_      9   taknone/liveproto/src/Tl/Types/Other/PollAnswerVoters.php        j      U   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionExportedInviteEdit.php        o_^      C   taknone/liveproto/src/Tl/Types/Other/SecureCredentialsEncrypted.php              E   taknone/liveproto/src/Tl/Types/Other/UpdateBotEditBusinessMessage.php        e      1   taknone/liveproto/src/Tl/Types/Other/FileHash.php        cˤ      I   taknone/liveproto/src/Tl/Types/Other/InputReportReasonPersonalDetails.php        OW      9   taknone/liveproto/src/Tl/Types/Other/NotifyForumTopic.php        {{      9   taknone/liveproto/src/Tl/Types/Other/DestroyAuthKeyOk.php        ]      E   taknone/liveproto/src/Tl/Types/Other/MessageActionScreenshotTaken.php        "      ?   taknone/liveproto/src/Tl/Types/Other/InputSavedStarGiftSlug.php?      ?        F   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterMyMentions.php        k      9   taknone/liveproto/src/Tl/Types/Other/PageBlockDetails.php        0Bg      ;   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyPhoneP2P.php        m^      ?   taknone/liveproto/src/Tl/Types/Other/UpdateMessageReactions.php        	      ;   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyForwards.php        (a      ?   taknone/liveproto/src/Tl/Types/Other/BotCommandScopeDefault.php              @   taknone/liveproto/src/Tl/Types/Other/SecureValueTypePassport.php        O      @   taknone/liveproto/src/Tl/Types/Other/EmailVerificationGoogle.phpC      C  1      8   taknone/liveproto/src/Tl/Types/Other/BaseThemeArctic.php        M      G   taknone/liveproto/src/Tl/Types/Other/SendMessageChooseContactAction.php        L      ;   taknone/liveproto/src/Tl/Types/Other/BusinessWeeklyOpen.php        hZ      8   taknone/liveproto/src/Tl/Types/Other/PageBlockFooter.php3      3  %%HȤ      ?   taknone/liveproto/src/Tl/Types/Other/EncryptedChatRequested.php        @c*      ;   taknone/liveproto/src/Tl/Types/Other/MessageEntityEmail.php        al      =   taknone/liveproto/src/Tl/Types/Other/MessageEntityUnknown.php        6b      1   taknone/liveproto/src/Tl/Types/Other/DcOption.php^      ^  e0      H   taknone/liveproto/src/Tl/Types/Other/UpdateReadFeaturedEmojiStickers.php        殰      I   taknone/liveproto/src/Tl/Types/Other/MessageActionRequestedPeerSentMe.php        q[      D   taknone/liveproto/src/Tl/Types/Other/InputStickeredMediaDocument.phpE      E  @      ;   taknone/liveproto/src/Tl/Types/Other/PeerNotifySettings.php        p{ͤ      B   taknone/liveproto/src/Tl/Types/Other/PrivacyValueAllowContacts.php        L      C   taknone/liveproto/src/Tl/Types/Other/MessageActionPaymentSentMe.php5	      5	  Pӥ      1   taknone/liveproto/src/Tl/Types/Other/DataJSON.php'      '  ^w      B   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantCreator.php'      '  K\      8   taknone/liveproto/src/Tl/Types/Other/UpdateSavedGifs.php        ˤ      ;   taknone/liveproto/src/Tl/Types/Other/RecentMeUrlUnknown.php0      0  >      E   taknone/liveproto/src/Tl/Types/Other/SponsoredMessageReportOption.php              E   taknone/liveproto/src/Tl/Types/Other/InputInvoicePremiumGiftStars.php$      $  I[@      :   taknone/liveproto/src/Tl/Types/Other/BusinessBotRights.php
      
  ^^      ;   taknone/liveproto/src/Tl/Types/Other/PublicForwardStory.php              E   taknone/liveproto/src/Tl/Types/Other/SendMessageRecordAudioAction.php        z0g      B   taknone/liveproto/src/Tl/Types/Other/MessageActionHistoryClear.php        yΤ      :   taknone/liveproto/src/Tl/Types/Other/PQInnerDataTempDc.php*      *  R@      G   taknone/liveproto/src/Tl/Types/Other/WebPageAttributeUniqueStarGift.phpI      I  5~      ?   taknone/liveproto/src/Tl/Types/Other/UpdateChatParticipants.php^      ^  #2      B   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonRequestPoll.php        BO!      3   taknone/liveproto/src/Tl/Types/Other/TextConcat.phpM      M  Ϲ      =   taknone/liveproto/src/Tl/Types/Other/MessageActionGiftTon.phpO      O  i8M/      =   taknone/liveproto/src/Tl/Types/Other/MediaAreaChannelPost.php1      1  .      8   taknone/liveproto/src/Tl/Types/Other/UpdatePhoneCall.phpI      I  v      @   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyBirthday.php        !      =   taknone/liveproto/src/Tl/Types/Other/InputBotAppShortName.php        #      :   taknone/liveproto/src/Tl/Types/Other/InputMediaGeoLive.php        ̻f+      I   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyStarGiftsAutoSave.php        ߈ݤ      O   taknone/liveproto/src/Tl/Types/Other/InputStickerSetAnimatedEmojiAnimations.php        |뾤      W   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantToggleBan.php8      8  3x      C   taknone/liveproto/src/Tl/Types/Other/StoryReactionPublicForward.phpM      M  u      F   taknone/liveproto/src/Tl/Types/Other/MessageActionSecureValuesSent.phpz      z  mX(      E   taknone/liveproto/src/Tl/Types/Other/SendMessageUploadAudioAction.phpJ      J  @Rm      F   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterChatPhotos.php        
*      ?   taknone/liveproto/src/Tl/Types/Other/UpdateDeleteQuickReply.phpE      E  @E^      J   taknone/liveproto/src/Tl/Types/Other/BusinessAwayMessageScheduleAlways.php        (ڗ      <   taknone/liveproto/src/Tl/Types/Other/UpdateDialogFilters.php        !      H   taknone/liveproto/src/Tl/Types/Other/InputPasskeyCredentialPublicKey.php.      .  6`c      B   taknone/liveproto/src/Tl/Types/Other/UpdateNewEncryptedMessage.php        )4l      4   taknone/liveproto/src/Tl/Types/Other/TextMention.php.      .  zD{      9   taknone/liveproto/src/Tl/Types/Other/InputInvoiceSlug.php3      3  %j      :   taknone/liveproto/src/Tl/Types/Other/WallPaperSettings.phpU      U  Pn      7   taknone/liveproto/src/Tl/Types/Other/PageBlockTable.php        u4/      G   taknone/liveproto/src/Tl/Types/Other/InputKeyboardButtonUserProfile.php!      !  px      4   taknone/liveproto/src/Tl/Types/Other/ErrorObject.php~      ~  <Sr      B   taknone/liveproto/src/Tl/Types/Other/MessageActionCustomAction.phpI      I        3   taknone/liveproto/src/Tl/Types/Other/NotifyPeer.php+      +  GyQ      =   taknone/liveproto/src/Tl/Types/Other/PageBlockUnsupported.php        _?      D   taknone/liveproto/src/Tl/Types/Other/InputEmojiStatusCollectible.php        wŤ      D   taknone/liveproto/src/Tl/Types/Other/InputPeerChannelFromMessage.php        |      B   taknone/liveproto/src/Tl/Types/Other/UpdateMoveStickerSetToTop.php        5bۤ      G   taknone/liveproto/src/Tl/Types/Other/SendMessageHistoryImportAction.phpL      L        >   taknone/liveproto/src/Tl/Types/Other/DialogFilterSuggested.php        t      C   taknone/liveproto/src/Tl/Types/Other/MessageEntityFormattedDate.php~      ~  kQ      =   taknone/liveproto/src/Tl/Types/Other/StarGiftAuctionRound.php        h      6   taknone/liveproto/src/Tl/Types/Other/MsgsStateInfo.php        PF      9   taknone/liveproto/src/Tl/Types/Other/InputSecureValue.php@      @  E      =   taknone/liveproto/src/Tl/Types/Other/UpdateChannelWebPage.phpp      p  qI      =   taknone/liveproto/src/Tl/Types/Other/InputUserFromMessage.php        C5!      3   taknone/liveproto/src/Tl/Types/Other/BotCommand.php        ،      5   taknone/liveproto/src/Tl/Types/Other/MsgResendReq.phpO      O        B   taknone/liveproto/src/Tl/Types/Other/UpdateRecentEmojiStatuses.php        9"zZ      ;   taknone/liveproto/src/Tl/Types/Other/InputGameShortName.php               A   taknone/liveproto/src/Tl/Types/Other/UpdateStoriesStealthMode.phpc      c        ;   taknone/liveproto/src/Tl/Types/Other/BadMsgNotification.php6      6  `K      H   taknone/liveproto/src/Tl/Types/Other/MessageActionSecureValuesSentMe.php        өN      :   taknone/liveproto/src/Tl/Types/Other/UpdateEditMessage.php        i+      C   taknone/liveproto/src/Tl/Types/Other/InputInvoiceStarGiftResale.phpb      b  sVM      D   taknone/liveproto/src/Tl/Types/Other/MessageActionChatDeleteUser.phpD      D  >d8      ;   taknone/liveproto/src/Tl/Types/Other/WebDocumentNoProxy.php        u5      7   taknone/liveproto/src/Tl/Types/Other/UpdatesTooLong.php        ;}F      ;   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonGame.php        ])/      ;   taknone/liveproto/src/Tl/Types/Other/UserStatusRecently.php        {      A   taknone/liveproto/src/Tl/Types/Other/MessageEntityCustomEmoji.php        };&      3   taknone/liveproto/src/Tl/Types/Other/SecureData.php        8      ?   taknone/liveproto/src/Tl/Types/Other/MessageActionGameScore.php        6;      F   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterPhotoVideo.php        cR      6   taknone/liveproto/src/Tl/Types/Other/StoryReaction.php	      	  ~դ      >   taknone/liveproto/src/Tl/Types/Other/MessageActionGiftCode.php'      '  \tc      @   taknone/liveproto/src/Tl/Types/Other/TopPeerCategoryChannels.php        dܤ      N   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionEditMessage.php        #a      >   taknone/liveproto/src/Tl/Types/Other/TopPeerCategoryGroups.php        d      A   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterVoice.php        0      :   taknone/liveproto/src/Tl/Types/Other/NewSessionCreated.php/      /  #      3   taknone/liveproto/src/Tl/Types/Other/UpdateUser.php,      ,  0W1      ;   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonCopy.php        H      8   taknone/liveproto/src/Tl/Types/Other/TextMentionName.php        B)      @   taknone/liveproto/src/Tl/Types/Other/SendMessageTypingAction.php        XKפ      B   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeySavedMusic.php        ǅ{      J   taknone/liveproto/src/Tl/Types/Other/MessageActionSuggestedPostSuccess.phpP      P        :   taknone/liveproto/src/Tl/Types/Other/InputFileLocation.php        >      G   taknone/liveproto/src/Tl/Types/Other/InputInvoiceStarGiftAuctionBid.phpR      R  &0פ      2   taknone/liveproto/src/Tl/Types/Other/VideoSize.php        sԇ      S   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeHistoryTTL.php        tK      L   taknone/liveproto/src/Tl/Types/Other/InputWebFileAudioAlbumThumbLocation.php        \      D   taknone/liveproto/src/Tl/Types/Other/BotInlineMessageRichMessage.php        S      C   taknone/liveproto/src/Tl/Types/Other/PaidReactionPrivacyDefault.php        @      D   taknone/liveproto/src/Tl/Types/Other/MessageMediaGiveawayResults.php7      7  
'P      =   taknone/liveproto/src/Tl/Types/Other/SecureValueErrorData.php        X      =   taknone/liveproto/src/Tl/Types/Other/PrivacyValueAllowAll.php        e      E   taknone/liveproto/src/Tl/Types/Other/PhoneCallDiscardReasonMissed.php        -Z+      B   taknone/liveproto/src/Tl/Types/Other/SendMessageGamePlayAction.php        P:      @   taknone/liveproto/src/Tl/Types/Other/UpdateReadHistoryOutbox.phpQ      Q  ß      D   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyStarGiftsAutoSave.php        Yey      7   taknone/liveproto/src/Tl/Types/Other/InputPeerEmpty.php        00      A   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeCounter.php        ۤ      >   taknone/liveproto/src/Tl/Types/Other/TopPeerCategoryBotsPM.php        N      Z   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionToggleSignatureProfiles.phpp      p  I0Č      Q   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionStartGroupCall.phpc      c  2      9   taknone/liveproto/src/Tl/Types/Other/BaseThemeClassic.php        F      <   taknone/liveproto/src/Tl/Types/Other/PageBlockBlockquote.php        A7      9   taknone/liveproto/src/Tl/Types/Other/SearchPostsFlood.php,      ,  5      8   taknone/liveproto/src/Tl/Types/Other/ProfileTabMusic.php        m*      I   taknone/liveproto/src/Tl/Types/Other/MessageActionSuggestedPostRefund.php        (3      A   taknone/liveproto/src/Tl/Types/Other/PageBlockRelatedArticles.php        S      K   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueAllowCloseFriends.php              4   taknone/liveproto/src/Tl/Types/Other/WebDocument.php        T.      <   taknone/liveproto/src/Tl/Types/Other/UpdateNewStickerSet.phpW      W  o      R   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantJoin.php        bl      @   taknone/liveproto/src/Tl/Types/Other/MessageActionBotAllowed.phpg      g  bg`!      B   taknone/liveproto/src/Tl/Types/Other/InputPrivacyKeyChatInvite.php        (=      9   taknone/liveproto/src/Tl/Types/Other/SecureValueError.php        A(4      7   taknone/liveproto/src/Tl/Types/Other/MediaAreaVenue.php        v      @   taknone/liveproto/src/Tl/Types/Other/MessagePeerVoteMultiple.php        uM      7   taknone/liveproto/src/Tl/Types/Other/PageBlockAudio.php        =?      P   taknone/liveproto/src/Tl/Types/Other/InputInvoiceStarGiftDropOriginalDetails.phpg      g  C      ?   taknone/liveproto/src/Tl/Types/Other/SecureValueTypeAddress.php        ΜA      ?   taknone/liveproto/src/Tl/Types/Other/InputSavedStarGiftUser.php=      =  ٺ      8   taknone/liveproto/src/Tl/Types/Other/StatsGraphError.php4      4  \⇤      6   taknone/liveproto/src/Tl/Types/Other/PageBlockMath.php5      5  oTΤ      =   taknone/liveproto/src/Tl/Types/Other/AiComposeToneExample.php        =<[      @   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterPoll.php        ~      3   taknone/liveproto/src/Tl/Types/Other/SecureFile.phpz      z  Ĥ      4   taknone/liveproto/src/Tl/Types/Other/PeerBlocked.php        R      D   taknone/liveproto/src/Tl/Types/Other/AttachMenuPeerTypeBroadcast.php        A      ;   taknone/liveproto/src/Tl/Types/Other/PageBlockSubheader.php6      6  &-      F   taknone/liveproto/src/Tl/Types/Other/InputReportReasonIllegalDrugs.php        Owޤ      4   taknone/liveproto/src/Tl/Types/Other/FutureSalts.php        c      9   taknone/liveproto/src/Tl/Types/Other/EncryptedMessage.php        @      2   taknone/liveproto/src/Tl/Types/Other/TextEmpty.php        {ha      8   taknone/liveproto/src/Tl/Types/Other/TextCustomEmoji.php        D      >   taknone/liveproto/src/Tl/Types/Other/UpdateUserEmojiStatus.php        tV      C   taknone/liveproto/src/Tl/Types/Other/UpdateGroupCallChainBlocks.php        w<      D   taknone/liveproto/src/Tl/Types/Other/InputStorePaymentStarsTopup.php        F      >   taknone/liveproto/src/Tl/Types/Other/InputNotifyBroadcasts.php        W      I   taknone/liveproto/src/Tl/Types/Other/RequirementToContactPaidMessages.phpd      d  )Q      B   taknone/liveproto/src/Tl/Types/Other/TopPeerCategoryPhoneCalls.php        )%      ;   taknone/liveproto/src/Tl/Types/Other/EmojiGroupGreeting.phpD      D  ][      ;   taknone/liveproto/src/Tl/Types/Other/MessageReplyHeader.phph      h  /|
      :   taknone/liveproto/src/Tl/Types/Other/PageBlockHeading1.php5      5  `Ң6      5   taknone/liveproto/src/Tl/Types/Other/LabeledPrice.php        	gp      =   taknone/liveproto/src/Tl/Types/Other/MessageEntitySpoiler.php        oz      ?   taknone/liveproto/src/Tl/Types/Other/MessageEntityUnderline.php        |#      5   taknone/liveproto/src/Tl/Types/Other/BaseThemeDay.php        d      X   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeEmojiStickerSet.php+      +  "t      S   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantLeave.php        惤      =   taknone/liveproto/src/Tl/Types/Other/UrlAuthResultRequest.php        ug5      ;   taknone/liveproto/src/Tl/Types/Other/InputGroupCallSlug.php7      7  9mФ      @   taknone/liveproto/src/Tl/Types/Other/InputMediaUploadedPhoto.php5      5  xm      S   taknone/liveproto/src/Tl/Types/Other/InputStickerSetEmojiChannelDefaultStatuses.php        ¨`      ?   taknone/liveproto/src/Tl/Types/Other/DocumentAttributeAudio.phpl      l  Q	      ?   taknone/liveproto/src/Tl/Types/Other/UpdateGroupCallMessage.php        ɋ      =   taknone/liveproto/src/Tl/Types/Other/BotInlineMediaResult.php        zND.      =   taknone/liveproto/src/Tl/Types/Other/MessageMediaGiveaway.php	      	  e+      ;   taknone/liveproto/src/Tl/Types/Other/StoriesStealthMode.php              E   taknone/liveproto/src/Tl/Types/Other/StarsTransactionPeerFragment.php        UP      2   taknone/liveproto/src/Tl/Types/Other/InputUser.php        $      8   taknone/liveproto/src/Tl/Types/Other/ImportedContact.php        H"      3   taknone/liveproto/src/Tl/Types/Other/StatsGraph.php        (֫      3   taknone/liveproto/src/Tl/Types/Other/NullObject.php        <(RŤ      9   taknone/liveproto/src/Tl/Types/Other/SecurePlainPhone.php:      :  (Aڤ      1   taknone/liveproto/src/Tl/Types/Other/JsonNull.php        :eV      <   taknone/liveproto/src/Tl/Types/Other/BotVerifierSettings.php2      2  ٤      R   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeUsernames.php        ۽٤      8   taknone/liveproto/src/Tl/Types/Other/BankCardOpenUrl.php        qJ      C   taknone/liveproto/src/Tl/Types/Other/MessageActionChangeCreator.php_      _  $/      :   taknone/liveproto/src/Tl/Types/Other/DraftMessageEmpty.php        ]      G   taknone/liveproto/src/Tl/Types/Other/InputReportReasonGeoIrrelevant.php        d'l      9   taknone/liveproto/src/Tl/Types/Other/GroupCallMessage.php        o      <   taknone/liveproto/src/Tl/Types/Other/DialogFilterDefault.php        C3M      ?   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterGeo.php        Fj      4   taknone/liveproto/src/Tl/Types/Other/TextSpoiler.php.      .  *      B   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantsSearch.php<      <  |p      ;   taknone/liveproto/src/Tl/Types/Other/StatsGroupTopAdmin.phpa      a  %i      =   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEvent.phpl      l  [gUS      2   taknone/liveproto/src/Tl/Types/Other/BoolFalse.php        LD      H   taknone/liveproto/src/Tl/Types/Other/SecureValueErrorTranslationFile.php&      &  Ǔ<      B   taknone/liveproto/src/Tl/Types/Other/InputMessagesFilterPhotos.php        0!Ȥ      A   taknone/liveproto/src/Tl/Types/Other/MessageActionChatAddUser.phpT      T  8Λ&      7   taknone/liveproto/src/Tl/Types/Other/ShippingOption.php%      %  CZ      E   taknone/liveproto/src/Tl/Types/Other/StarGiftAuctionStateFinished.php        #՟      7   taknone/liveproto/src/Tl/Types/Other/InputChatTheme.phpC      C  ɓ      8   taknone/liveproto/src/Tl/Types/Other/PageBlockHeader.php3      3  Xs      @   taknone/liveproto/src/Tl/Types/Other/JoinChatBotResultQueued.php        "      D   taknone/liveproto/src/Tl/Types/Other/InputInvoicePremiumAuthCode.php^      ^  U      3   taknone/liveproto/src/Tl/Types/Other/JsonNumber.php/      /        B   taknone/liveproto/src/Tl/Types/Other/RequirementToContactEmpty.php        G6      8   taknone/liveproto/src/Tl/Types/Other/PhoneConnection.phpb      b  /k!ݤ      B   taknone/liveproto/src/Tl/Types/Other/GroupCallParticipantVideo.phpQ      Q  a|Q      9   taknone/liveproto/src/Tl/Types/Other/BindAuthKeyInner.php=      =   q      :   taknone/liveproto/src/Tl/Types/Other/RestrictionReason.php        E2      D   taknone/liveproto/src/Tl/Types/Other/UpdateEncryptedMessagesRead.php        c      B   taknone/liveproto/src/Tl/Types/Other/BotCommandScopeChatAdmins.php        ,uo      5   taknone/liveproto/src/Tl/Types/Other/CdnPublicKey.php        ~VU      G   taknone/liveproto/src/Tl/Types/Other/UpdateBusinessBotCallbackQuery.php        L?      B   taknone/liveproto/src/Tl/Types/Other/InputQuickReplyShortcutId.phpX      X  Uqg      :   taknone/liveproto/src/Tl/Types/Other/PageBlockHeading6.php5      5  CC鐤      @   taknone/liveproto/src/Tl/Types/Other/RpcAnswerDroppedRunning.php        ,      =   taknone/liveproto/src/Tl/Types/Other/ChatAdminWithInvites.php^      ^  ֒*      9   taknone/liveproto/src/Tl/Types/Other/ChannelForbidden.php
      
  X:5i      D   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonSimpleWebView.php	      	  nb      @   taknone/liveproto/src/Tl/Types/Other/UpdateBotGuestChatQuery.php        X]      6   taknone/liveproto/src/Tl/Types/Other/ThemeSettings.php        p+      G   taknone/liveproto/src/Tl/Types/Other/UpdateMonoForumNoPaidException.php        cC      A   taknone/liveproto/src/Tl/Types/Other/DocumentAttributeSticker.php        pH7      9   taknone/liveproto/src/Tl/Types/Other/UpdateEncryption.php        a      G   taknone/liveproto/src/Tl/Types/Other/StarsTransactionPeerPlayMarket.php        [\      E   taknone/liveproto/src/Tl/Types/Other/PostInteractionCountersStory.php}      }  ْ      F   taknone/liveproto/src/Tl/Types/Other/UpdateDeleteScheduledMessages.php`      `  ;"      ?   taknone/liveproto/src/Tl/Types/Other/UpdateReadChannelInbox.php        Ti      @   taknone/liveproto/src/Tl/Types/Other/MessageMediaVideoStream.php        J+      @   taknone/liveproto/src/Tl/Types/Other/ReactionsNotifySettings.php        b      =   taknone/liveproto/src/Tl/Types/Other/InputStickerSetEmpty.php        bE      9   taknone/liveproto/src/Tl/Types/Other/BusinessChatLink.php        A/      @   taknone/liveproto/src/Tl/Types/Other/UpdateSentStoryReaction.php        ¤      ?   taknone/liveproto/src/Tl/Types/Other/InputAiComposeToneSlug.php?      ?  s$J      E   taknone/liveproto/src/Tl/Types/Other/InputInvoiceStarGiftTransfer.php        yㅤ      B   taknone/liveproto/src/Tl/Types/Other/InputBotInlineMessageText.php[      [  ,[      @   taknone/liveproto/src/Tl/Types/Other/InputPaymentCredentials.php        (      9   taknone/liveproto/src/Tl/Types/Other/NotifyBroadcasts.php        QVp      ;   taknone/liveproto/src/Tl/Types/Other/UpdateDraftMessage.phpY      Y  #l}      :   taknone/liveproto/src/Tl/Types/Other/InputMediaInvoice.php6	      6	  U4*       ?   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonCallback.php        eu      8   taknone/liveproto/src/Tl/Types/Other/AuctionBidLevel.php        \즤      =   taknone/liveproto/src/Tl/Types/Other/MessageMediaDocument.php
      
  ?      <   taknone/liveproto/src/Tl/Types/Other/ConnectedBotStarRef.php}      }  $W      6   taknone/liveproto/src/Tl/Types/Other/UpdateStoryID.php        p]d      =   taknone/liveproto/src/Tl/Types/Other/MessageEntityMention.php        #+1      :   taknone/liveproto/src/Tl/Types/Other/InputMediaWebPage.phpO      O  wFŤ      =   taknone/liveproto/src/Tl/Types/Other/InputBotInlineResult.php	      	  #O[      8   taknone/liveproto/src/Tl/Types/Other/GeoPointAddress.php        GDڤ      :   taknone/liveproto/src/Tl/Types/Other/MediaAreaStarGift.php              =   taknone/liveproto/src/Tl/Types/Other/ChatParticipantAdmin.php[      [  	q%      3   taknone/liveproto/src/Tl/Types/Other/PollAnswer.php(      (  2/ݤ      :   taknone/liveproto/src/Tl/Types/Other/UpdateReadStories.php              6   taknone/liveproto/src/Tl/Types/Other/UpdatePrivacy.php        %      <   taknone/liveproto/src/Tl/Types/Other/ReadParticipantDate.php        !#      =   taknone/liveproto/src/Tl/Types/Other/UpdateAiComposeTones.php        L      <   taknone/liveproto/src/Tl/Types/Other/UpdateEmojiGameInfo.phpB      B  t      7   taknone/liveproto/src/Tl/Types/Other/BaseThemeNight.php        ?1      E   taknone/liveproto/src/Tl/Types/Other/SendMessageRecordRoundAction.php              D   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueAllowUsers.phpi      i  W      :   taknone/liveproto/src/Tl/Types/Other/AutoSaveException.php        8      8   taknone/liveproto/src/Tl/Types/Other/StatsGraphAsync.php4      4  Um      1   taknone/liveproto/src/Tl/Types/Other/UserFull.php@      @  Q*      <   taknone/liveproto/src/Tl/Types/Other/UpdatePeerWallpaper.phpa      a        >   taknone/liveproto/src/Tl/Types/Other/PageBlockPreformatted.php        ;      :   taknone/liveproto/src/Tl/Types/Other/DefaultHistoryTTL.php7      7  ")      8   taknone/liveproto/src/Tl/Types/Other/StarsGiftOption.php        :ǫ      ;   taknone/liveproto/src/Tl/Types/Other/InputMediaGeoPoint.phpP      P  ?D!       A   taknone/liveproto/src/Tl/Types/Other/UpdateWebBrowserSettings.php        IF      N   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionDeleteTopic.php`      `  m"      6   taknone/liveproto/src/Tl/Types/Other/ContactStatus.php        {D      ?   taknone/liveproto/src/Tl/Types/Other/InputMessageReadMetric.php?      ?  pmn      ?   taknone/liveproto/src/Tl/Types/Other/UpdateBotShippingQuery.php        qH<      N   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionCreateTopic.php`      `  Xa      D   taknone/liveproto/src/Tl/Types/Other/SecureValueErrorReverseSide.php"      "  xƈ      >   taknone/liveproto/src/Tl/Types/Other/LangPackStringDeleted.php6      6  .<Ӥ      B   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyStatusTimestamp.php        Y      >   taknone/liveproto/src/Tl/Types/Other/UrlAuthResultAccepted.php%      %  f      B   taknone/liveproto/src/Tl/Types/Other/DocumentAttributeAnimated.php              <   taknone/liveproto/src/Tl/Types/Other/InputMessageReplyTo.php$      $  }h~      >   taknone/liveproto/src/Tl/Types/Other/InputReportReasonFake.php        s      9   taknone/liveproto/src/Tl/Types/Other/EmojiStatusEmpty.php        톤      Q   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionChangeUsername.php        m'      3   taknone/liveproto/src/Tl/Types/Other/TrueObject.php              A   taknone/liveproto/src/Tl/Types/Other/MessageActionGiftPremium.php        %,y      P   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionToggleInvites.phpf      f  ]}C      E   taknone/liveproto/src/Tl/Types/Other/TopPeerCategoryBotsGuestChat.php        Y5Q,      8   taknone/liveproto/src/Tl/Types/Other/PrepaidGiveaway.phpC      C  í[      1   taknone/liveproto/src/Tl/Types/Other/TodoItem.php        Q      ;   taknone/liveproto/src/Tl/Types/Other/UpdatePeerSettings.php        $      F   taknone/liveproto/src/Tl/Types/Other/MessageActionNoForwardsToggle.php        P(U¤      [   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionParticipantJoinByRequest.php        "      8   taknone/liveproto/src/Tl/Types/Other/ContactBirthday.php        $AB      <   taknone/liveproto/src/Tl/Types/Other/UpdateSentPhoneCode.phpM      M  )      9   taknone/liveproto/src/Tl/Types/Other/StoryItemSkipped.php@      @  w      H   taknone/liveproto/src/Tl/Types/Other/MessageActionChannelMigrateFrom.php              =   taknone/liveproto/src/Tl/Types/Other/InputWallPaperNoFile.php*      *        D   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeIdBackdrop.phpW      W  ;      G   taknone/liveproto/src/Tl/Types/Other/InputPrivacyValueAllowContacts.php              @   taknone/liveproto/src/Tl/Types/Other/InputCheckPasswordEmpty.php        7      8   taknone/liveproto/src/Tl/Types/Other/WallPaperNoFile.php        Ϡy\      <   taknone/liveproto/src/Tl/Types/Other/InputMediaAreaVenue.php>      >  Ů      9   taknone/liveproto/src/Tl/Types/Other/InputNotifyUsers.php        "ĺ%      =   taknone/liveproto/src/Tl/Types/Other/BotCommandScopeChats.php        =%      >   taknone/liveproto/src/Tl/Types/Other/PrivacyValueAllowBots.php        tz      B   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantsAdmins.php        4      =   taknone/liveproto/src/Tl/Types/Other/InputStickerSetThumb.php        p      <   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyPhoneCall.php        h9      ?   taknone/liveproto/src/Tl/Types/Other/UpdateStickerSetsOrder.php        r]      7   taknone/liveproto/src/Tl/Types/Other/InputMessageID.php        ,      9   taknone/liveproto/src/Tl/Types/Other/ChatReactionsAll.php        E      5   taknone/liveproto/src/Tl/Types/Other/MsgsStateReq.phpO      O  ?      E   taknone/liveproto/src/Tl/Types/Other/MessageActionChatDeletePhoto.php        kuj      :   taknone/liveproto/src/Tl/Types/Other/EmojiGroupPremium.php        a      ;   taknone/liveproto/src/Tl/Types/Other/WebPageNotModified.phpt      t  @o      >   taknone/liveproto/src/Tl/Types/Other/PremiumGiftCodeOption.phpF      F        K   taknone/liveproto/src/Tl/Types/Other/InputInvoiceStarGiftPrepaidUpgrade.php        i8交      >   taknone/liveproto/src/Tl/Types/Other/UpdateLangPackTooLong.phpF      F  ڏT      F   taknone/liveproto/src/Tl/Types/Other/PrivacyValueAllowCloseFriends.php        tx(9      N   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionToggleForum.phpc      c  /w      :   taknone/liveproto/src/Tl/Types/Other/MessageMediaVenue.phpa      a  l~      B   taknone/liveproto/src/Tl/Types/Other/UpdateBotWebhookJSONQuery.php        G      C   taknone/liveproto/src/Tl/Types/Other/MessageActionChatMigrateTo.phpO      O  P      M   taknone/liveproto/src/Tl/Types/Other/SecureValueTypeTemporaryRegistration.php        CGҤ      ;   taknone/liveproto/src/Tl/Types/Other/PrivacyKeyBirthday.php        v      3   taknone/liveproto/src/Tl/Types/Other/ForumTopic.php)      )  e      B   taknone/liveproto/src/Tl/Types/Other/UpdateEncryptedChatTyping.php8      8  p      ;   taknone/liveproto/src/Tl/Types/Other/PhoneCallRequested.php        M      G   taknone/liveproto/src/Tl/Types/Other/InputStorePaymentStarsGiveaway.php
      
  3 T      =   taknone/liveproto/src/Tl/Types/Other/PageBlockOrderedList.phpY      Y        6   taknone/liveproto/src/Tl/Types/Other/PageBlockList.php]      ]  s      P   taknone/liveproto/src/Tl/Types/Other/ChannelAdminLogEventActionDeleteMessage.phpg      g  Kj3      ?   taknone/liveproto/src/Tl/Types/Other/ChannelParticipantLeft.php?      ?  +      :   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonBuy.php        ,K      :   taknone/liveproto/src/Tl/Types/Other/MessageEntityBold.php        >Q      @   taknone/liveproto/src/Tl/Types/Other/InputEncryptedFileEmpty.php              3   taknone/liveproto/src/Tl/Types/Other/InputPhoto.php              8   taknone/liveproto/src/Tl/Types/Other/InputMediaEmpty.php         &      :   taknone/liveproto/src/Tl/Types/Other/ChatReactionsNone.php        :7?      =   taknone/liveproto/src/Tl/Types/Other/UpdateBotInlineQuery.php        N      @   taknone/liveproto/src/Tl/Types/Other/ReplyKeyboardForceReply.phps      s  >a      1   taknone/liveproto/src/Tl/Types/Other/Birthday.php        e%      8   taknone/liveproto/src/Tl/Types/Other/ChannelLocation.php        a'      G   taknone/liveproto/src/Tl/Types/Other/MessageActionManagedBotCreated.phpC      C  Tvd      0   taknone/liveproto/src/Tl/Types/Other/BotInfo.php              ?   taknone/liveproto/src/Tl/Types/Other/UpdateTranscribedAudio.phpF      F  Pۤ      6   taknone/liveproto/src/Tl/Types/Other/AttachMenuBot.php	      	  A5      <   taknone/liveproto/src/Tl/Types/Other/InputInvoiceMessage.php         ٤      @   taknone/liveproto/src/Tl/Types/Other/MessageActionBoostApply.php9      9         >   taknone/liveproto/src/Tl/Types/Other/StoryViewPublicRepost.php7      7  KK      >   taknone/liveproto/src/Tl/Types/Other/UserProfilePhotoEmpty.php        e      E   taknone/liveproto/src/Tl/Types/Other/MessageActionSuggestBirthday.phpT      T  Aa      6   taknone/liveproto/src/Tl/Types/Other/InputPeerUser.php        ؤ      G   taknone/liveproto/src/Tl/Types/Other/StarGiftAuctionRoundExtendable.php        .L      ?   taknone/liveproto/src/Tl/Types/Other/UpdateBotCallbackQuery.php        Z*      :   taknone/liveproto/src/Tl/Types/Other/UserStatusOffline.php>      >  @      @   taknone/liveproto/src/Tl/Types/Other/InputQuickReplyShortcut.phpU      U   p=      =   taknone/liveproto/src/Tl/Types/Other/SecureValueTypeEmail.php        0      ?   taknone/liveproto/src/Tl/Types/Other/UpdateShortChatMessage.php        DJ      8   taknone/liveproto/src/Tl/Types/Other/InputDialogPeer.php:      :  ÷XS      ;   taknone/liveproto/src/Tl/Types/Other/DestroySessionNone.phpK      K  "      -   taknone/liveproto/src/Tl/Types/Other/User.php,      ,  IIQ      =   taknone/liveproto/src/Tl/Types/Other/PrepaidStarsGiveaway.php        ^6      A   taknone/liveproto/src/Tl/Types/Other/RequestPeerTypeCreateBot.phpt      t  Jwp      5   taknone/liveproto/src/Tl/Types/Other/ReactionPaid.php        g      >   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonWebView.php        EUi      7   taknone/liveproto/src/Tl/Types/Other/ChatInvitePeek.php        ˤ      8   taknone/liveproto/src/Tl/Types/Other/InputSecureFile.php        @      E   taknone/liveproto/src/Tl/Types/Other/ReactionNotificationsFromAll.php        U      8   taknone/liveproto/src/Tl/Types/Other/ProfileTabFiles.php        tƤ      <   taknone/liveproto/src/Tl/Types/Other/MessageMediaGeoLive.php        ]      B   taknone/liveproto/src/Tl/Types/Other/BotInlineMessageMediaAuto.php        㤤      ?   taknone/liveproto/src/Tl/Types/Other/ReportResultAddComment.php        v      0   taknone/liveproto/src/Tl/Types/Other/MsgsAck.phpE      E  !      7   taknone/liveproto/src/Tl/Types/Other/WebPagePending.php        U      :   taknone/liveproto/src/Tl/Types/Other/PhoneCallAccepted.phpx      x  nRn      G   taknone/liveproto/src/Tl/Types/Other/StarsTransactionPeerPremiumBot.php        ^,      6   taknone/liveproto/src/Tl/Types/Other/InputAppEvent.phpS      S  N      D   taknone/liveproto/src/Tl/Types/Other/InputStickerSetPremiumGifts.php        {#      =   taknone/liveproto/src/Tl/Types/Other/InputGroupCallStream.php        [_g      =   taknone/liveproto/src/Tl/Types/Other/UrlAuthResultDefault.php        <;ͤ      7   taknone/liveproto/src/Tl/Types/Other/TextBotCommand.php0      0  S      @   taknone/liveproto/src/Tl/Types/Other/UpdateNewChannelMessage.php        M      :   taknone/liveproto/src/Tl/Types/Other/ForumTopicDeleted.php        LB&h      A   taknone/liveproto/src/Tl/Types/Other/InputPeerUserFromMessage.php        
Q      ;   taknone/liveproto/src/Tl/Types/Other/WebViewMessageSent.phpN      N  ;1
      5   taknone/liveproto/src/Tl/Types/Other/InputFileBig.php              J   taknone/liveproto/src/Tl/Types/Other/InputBotInlineMessageMediaWebPage.php
      
  _q!Ǥ      9   taknone/liveproto/src/Tl/Types/Other/InputNotifyChats.php        ;)-      8   taknone/liveproto/src/Tl/Types/Other/InputFolderPeer.php              M   taknone/liveproto/src/Tl/Types/Other/GroupCallParticipantVideoSourceGroup.php        XƤ      B   taknone/liveproto/src/Tl/Types/Other/AttachMenuBotsNotModified.php        ~$:]      H   taknone/liveproto/src/Tl/Types/Other/InputPaymentCredentialsApplePay.phpp      p  2      5   taknone/liveproto/src/Tl/Types/Other/WebPageEmpty.phph      h  .D      3   taknone/liveproto/src/Tl/Types/Other/FoundStory.php              ;   taknone/liveproto/src/Tl/Types/Other/EncryptedFileEmpty.php        +Ѥ      2   taknone/liveproto/src/Tl/Types/Other/PhotoSize.php        \>      8   taknone/liveproto/src/Tl/Types/Other/ProfileTabMedia.php        <IՏ      9   taknone/liveproto/src/Tl/Types/Other/TextWithEntities.php        >F      I   taknone/liveproto/src/Tl/Types/Other/MessageActionGeoProximityReached.php        4&      H   taknone/liveproto/src/Tl/Types/Other/StarGiftAttributeRarityUncommon.php              ?   taknone/liveproto/src/Tl/Types/Other/PrivacyValueAllowUsers.phpP      P        G   taknone/liveproto/src/Tl/Types/Other/MessageActionWebViewDataSentMe.php        ZӤ      6   taknone/liveproto/src/Tl/Types/Other/InputDocument.php          D      <   taknone/liveproto/src/Tl/Types/Other/KeyboardButtonStyle.php        S      B   taknone/liveproto/src/Tl/Types/Other/TopPeerCategoryBotsInline.php        *      8   taknone/liveproto/src/Tl/Types/Other/TextSuperscript.php2      2  '{      :   taknone/liveproto/src/Tl/Types/Other/RequestedPeerUser.php        1      >   taknone/liveproto/src/Tl/Types/Other/RecentMeUrlStickerSet.php        k      @   taknone/liveproto/src/Tl/Types/Other/StarsTransactionPeerAds.php              T   taknone/liveproto/src/Tl/Types/Other/PhoneCallDiscardReasonMigrateConferenceCall.phpX      X   $c      D   taknone/liveproto/src/Tl/Types/Other/UpdateGroupCallParticipants.phpj      j  |TE      ?   taknone/liveproto/src/Tl/Types/Other/MessageActionTopicEdit.php        :      =   taknone/liveproto/src/Tl/Types/Other/GroupCallParticipant.php)      )  pnބ      E   taknone/liveproto/src/Tl/Types/Other/MessageActionGiveawayResults.php        ȪǤ      8   taknone/liveproto/src/Tl/Types/Other/UpdateGroupCall.php        mga      >   taknone/liveproto/src/Tl/Types/Stickers/SuggestedShortName.php_      _  7n      5   taknone/liveproto/src/Tl/Types/Stories/StoryViews.php        vҤ      @   taknone/liveproto/src/Tl/Types/Stories/AllStoriesNotModified.php        7      =   taknone/liveproto/src/Tl/Types/Stories/StoryReactionsList.phpZ      Z  cV(      9   taknone/liveproto/src/Tl/Types/Stories/StoryViewsList.php        "6      1   taknone/liveproto/src/Tl/Types/Stories/Albums.php        Q+      6   taknone/liveproto/src/Tl/Types/Stories/PeerStories.php<      <  P      <   taknone/liveproto/src/Tl/Types/Stories/AlbumsNotModified.php        ^"Ǳ      <   taknone/liveproto/src/Tl/Types/Stories/CanSendStoryCount.php]      ]  D      7   taknone/liveproto/src/Tl/Types/Stories/FoundStories.php=      =   㡤      2   taknone/liveproto/src/Tl/Types/Stories/Stories.phpO      O  l      5   taknone/liveproto/src/Tl/Types/Stories/AllStories.php        f      ;   taknone/liveproto/src/Tl/Functions/Stats/LoadAsyncGraph.php        9m      >   taknone/liveproto/src/Tl/Functions/Stats/GetBroadcastStats.php              <   taknone/liveproto/src/Tl/Functions/Stats/GetMessageStats.php        :t/      E   taknone/liveproto/src/Tl/Functions/Stats/GetMessagePublicForwards.php        sӱ      >   taknone/liveproto/src/Tl/Functions/Stats/GetMegagroupStats.php        +z-      C   taknone/liveproto/src/Tl/Functions/Stats/GetStoryPublicForwards.php        /1      9   taknone/liveproto/src/Tl/Functions/Stats/GetPollStats.php        E=K      :   taknone/liveproto/src/Tl/Functions/Stats/GetStoryStats.php              N   taknone/liveproto/src/Tl/Functions/Channels/SetBoostsToUnblockRestrictions.php        F"      ;   taknone/liveproto/src/Tl/Functions/Channels/SearchPosts.phpM      M  rS0      9   taknone/liveproto/src/Tl/Functions/Channels/GetSendAs.phpE      E  
?      E   taknone/liveproto/src/Tl/Functions/Channels/ToggleAutotranslation.php        n}v      F   taknone/liveproto/src/Tl/Functions/Channels/TogglePreHistoryHidden.php        V      9   taknone/liveproto/src/Tl/Functions/Channels/EditTitle.php{      {  =      H   taknone/liveproto/src/Tl/Functions/Channels/GetAdminedPublicChannels.phpL      L  _      ;   taknone/liveproto/src/Tl/Functions/Channels/ReadHistory.phpu      u  DP      >   taknone/liveproto/src/Tl/Functions/Channels/UpdateUsername.php        P      =   taknone/liveproto/src/Tl/Functions/Channels/CheckUsername.php        +,      A   taknone/liveproto/src/Tl/Functions/Channels/ExportMessageLink.phpB      B  Ǟð      H   taknone/liveproto/src/Tl/Functions/Channels/ToggleParticipantsHidden.php        y      >   taknone/liveproto/src/Tl/Functions/Channels/ToggleUsername.php        1ߤ      @   taknone/liveproto/src/Tl/Functions/Channels/ReorderUsernames.php        z0      ?   taknone/liveproto/src/Tl/Functions/Channels/GetParticipants.phpE      E  K\      A   taknone/liveproto/src/Tl/Functions/Channels/ToggleJoinRequest.php        ~7      <   taknone/liveproto/src/Tl/Functions/Channels/EditLocation.php        w7i      @   taknone/liveproto/src/Tl/Functions/Channels/SetEmojiStickers.php        TIH      ;   taknone/liveproto/src/Tl/Functions/Channels/GetChannels.phpP      P  q      H   taknone/liveproto/src/Tl/Functions/Channels/DeleteParticipantHistory.php              :   taknone/liveproto/src/Tl/Functions/Channels/EditBanned.php        ɇ       F   taknone/liveproto/src/Tl/Functions/Channels/DeactivateAllUsernames.phpJ      J  g(      9   taknone/liveproto/src/Tl/Functions/Channels/EditAdmin.php        E䒺      >   taknone/liveproto/src/Tl/Functions/Channels/ToggleSlowMode.php~      ~  8)`n      ;   taknone/liveproto/src/Tl/Functions/Channels/SetStickers.php        \(D      K   taknone/liveproto/src/Tl/Functions/Channels/ReportAntiSpamFalsePositive.php        )Z      =   taknone/liveproto/src/Tl/Functions/Channels/CreateChannel.php        zH      ;   taknone/liveproto/src/Tl/Functions/Channels/GetMessages.php        {)Ӥ      >   taknone/liveproto/src/Tl/Functions/Channels/ToggleAntiSpam.php        Jvq      @   taknone/liveproto/src/Tl/Functions/Channels/GetMessageAuthor.phpn      n  N      C   taknone/liveproto/src/Tl/Functions/Channels/GetInactiveChannels.php        Q\T      G   taknone/liveproto/src/Tl/Functions/Channels/UpdatePaidMessagesPrice.phpn      n        ;   taknone/liveproto/src/Tl/Functions/Channels/ToggleForum.php              C   taknone/liveproto/src/Tl/Functions/Channels/ReadMessageContents.php        lKƤ      B   taknone/liveproto/src/Tl/Functions/Channels/ConvertToGigagroup.phpI      I  ,MU      B   taknone/liveproto/src/Tl/Functions/Channels/SetDiscussionGroup.php        4/      =   taknone/liveproto/src/Tl/Functions/Channels/DeleteHistory.php        8¤      >   taknone/liveproto/src/Tl/Functions/Channels/GetParticipant.php        ʤ      A   taknone/liveproto/src/Tl/Functions/Channels/SetMainProfileTab.php        6      A   taknone/liveproto/src/Tl/Functions/Channels/UpdateEmojiStatus.php        rʤ      I   taknone/liveproto/src/Tl/Functions/Channels/GetChannelRecommendations.php        Tu      =   taknone/liveproto/src/Tl/Functions/Channels/DeleteChannel.phpE      E  $<      >   taknone/liveproto/src/Tl/Functions/Channels/GetFullChannel.phpO      O  ;t      ;   taknone/liveproto/src/Tl/Functions/Channels/GetAdminLog.php        =      ?   taknone/liveproto/src/Tl/Functions/Channels/InviteToChannel.php        w\      @   taknone/liveproto/src/Tl/Functions/Channels/ToggleJoinToSend.php        #U      9   taknone/liveproto/src/Tl/Functions/Channels/EditPhoto.php        /      >   taknone/liveproto/src/Tl/Functions/Channels/DeleteMessages.php        `*7      I   taknone/liveproto/src/Tl/Functions/Channels/RestrictSponsoredMessages.php        _٘      E   taknone/liveproto/src/Tl/Functions/Channels/CheckSearchPostsFlood.php        mUt      I   taknone/liveproto/src/Tl/Functions/Channels/ToggleViewForumAsMessages.php        4      F   taknone/liveproto/src/Tl/Functions/Channels/GetGroupsForDiscussion.php        ǾW      ;   taknone/liveproto/src/Tl/Functions/Channels/UpdateColor.php>      >  :$      ?   taknone/liveproto/src/Tl/Functions/Channels/GetLeftChannels.php<      <  |      ;   taknone/liveproto/src/Tl/Functions/Channels/JoinChannel.phpY      Y  {      @   taknone/liveproto/src/Tl/Functions/Channels/ToggleSignatures.phpK      K  	`@      :   taknone/liveproto/src/Tl/Functions/Channels/ReportSpam.php        RȋĤ      <   taknone/liveproto/src/Tl/Functions/Channels/LeaveChannel.phpD      D  6      =   taknone/liveproto/src/Tl/Functions/Messages/EditChatTitle.phpr      r  Ůñ      H   taknone/liveproto/src/Tl/Functions/Messages/SendWebViewResultMessage.php        ے      @   taknone/liveproto/src/Tl/Functions/Messages/DeletePollAnswer.php        qJ      =   taknone/liveproto/src/Tl/Functions/Messages/TranslateText.php        B      J   taknone/liveproto/src/Tl/Functions/Messages/SendScreenshotNotification.php        F^      @   taknone/liveproto/src/Tl/Functions/Messages/CreateForumTopic.php_      _  8      E   taknone/liveproto/src/Tl/Functions/Messages/SendScheduledMessages.php}      }  >-      B   taknone/liveproto/src/Tl/Functions/Messages/ReorderStickerSets.php        Ӄ      <   taknone/liveproto/src/Tl/Functions/Messages/GetAllDrafts.php        &~      @   taknone/liveproto/src/Tl/Functions/Messages/GetDialogFilters.php        M      :   taknone/liveproto/src/Tl/Functions/Messages/GetOnlines.php:      :  E      ?   taknone/liveproto/src/Tl/Functions/Messages/GetQuickReplies.php?      ?  pd      @   taknone/liveproto/src/Tl/Functions/Messages/GetAttachMenuBot.phpC      C  B      F   taknone/liveproto/src/Tl/Functions/Messages/SearchEmojiStickerSets.php        Ц      D   taknone/liveproto/src/Tl/Functions/Messages/GetBotCallbackAnswer.phpO      O  @QV      F   taknone/liveproto/src/Tl/Functions/Messages/UpdatePinnedForumTopic.php        :r      >   taknone/liveproto/src/Tl/Functions/Messages/GetPollResults.php        tƤ      @   taknone/liveproto/src/Tl/Functions/Messages/ExportChatInvite.phpY      Y  _?      P   taknone/liveproto/src/Tl/Functions/Messages/DeleteRevokedExportedChatInvites.php        ͤ      ;   taknone/liveproto/src/Tl/Functions/Messages/ReadHistory.php}      }        ;   taknone/liveproto/src/Tl/Functions/Messages/AddChatUser.php        s      @   taknone/liveproto/src/Tl/Functions/Messages/ReceivedMessages.phpK      K  BJ      C   taknone/liveproto/src/Tl/Functions/Messages/GetAvailableEffects.phpE      E  茨      I   taknone/liveproto/src/Tl/Functions/Messages/ReorderPinnedSavedDialogs.php        ﶤ      @   taknone/liveproto/src/Tl/Functions/Messages/ToggleNoForwards.phpf      f  >      H   taknone/liveproto/src/Tl/Functions/Messages/DeleteQuickReplyShortcut.phpJ      J  
      @   taknone/liveproto/src/Tl/Functions/Messages/GetEmojiGameInfo.php        yפ      ;   taknone/liveproto/src/Tl/Functions/Messages/FaveSticker.phpj      j  +3      :   taknone/liveproto/src/Tl/Functions/Messages/CreateChat.phpo      o  J2      I   taknone/liveproto/src/Tl/Functions/Messages/GetSearchResultsPositions.php	      	  
ؤ      D   taknone/liveproto/src/Tl/Functions/Messages/GetEmojiStatusGroups.phpA      A        ;   taknone/liveproto/src/Tl/Functions/Messages/GetDhConfig.php        lT      D   taknone/liveproto/src/Tl/Functions/Messages/SetDefaultHistoryTTL.php7      7  u      =   taknone/liveproto/src/Tl/Functions/Messages/GetMyStickers.php|      |        6   taknone/liveproto/src/Tl/Functions/Messages/Search.php        E<      =   taknone/liveproto/src/Tl/Functions/Messages/SendEncrypted.phpD      D  <      B   taknone/liveproto/src/Tl/Functions/Messages/StartHistoryImport.php{      {  ?1      =   taknone/liveproto/src/Tl/Functions/Messages/EditFactCheck.php        '[g      ?   taknone/liveproto/src/Tl/Functions/Messages/GetMaskStickers.php>      >        >   taknone/liveproto/src/Tl/Functions/Messages/ReadDiscussion.php        7      =   taknone/liveproto/src/Tl/Functions/Messages/ReadReactions.php        ث      =   taknone/liveproto/src/Tl/Functions/Messages/ReceivedQueue.php;      ;        C   taknone/liveproto/src/Tl/Functions/Messages/GetScheduledHistory.phpz      z  8W      C   taknone/liveproto/src/Tl/Functions/Messages/UpdatePinnedMessage.php}      }  5x      @   taknone/liveproto/src/Tl/Functions/Messages/ImportChatInvite.phpN      N  $2      D   taknone/liveproto/src/Tl/Functions/Messages/ReorderPinnedDialogs.php         ww4      ?   taknone/liveproto/src/Tl/Functions/Messages/TranscribeAudio.php        J`̤      F   taknone/liveproto/src/Tl/Functions/Messages/ReportMessagesDelivery.php         F      C   taknone/liveproto/src/Tl/Functions/Messages/GetFeaturedStickers.phpG      G        @   taknone/liveproto/src/Tl/Functions/Messages/GetExtendedMedia.phpx      x        C   taknone/liveproto/src/Tl/Functions/Messages/UninstallStickerSet.phpT      T  ܭ       =   taknone/liveproto/src/Tl/Functions/Messages/EditChatPhoto.php{      {  P      D   taknone/liveproto/src/Tl/Functions/Messages/RateTranscribedAudio.php        v      H   taknone/liveproto/src/Tl/Functions/Messages/UpdateDialogFiltersOrder.phpK      K  m      9   taknone/liveproto/src/Tl/Functions/Messages/SaveDraft.php        4x      @   taknone/liveproto/src/Tl/Functions/Messages/SetChatWallPaper.php        6fN      F   taknone/liveproto/src/Tl/Functions/Messages/GetExportedChatInvites.php        %i}      A   taknone/liveproto/src/Tl/Functions/Messages/ReportMusicListen.php        a      :   taknone/liveproto/src/Tl/Functions/Messages/GetHistory.php        hK      N   taknone/liveproto/src/Tl/Functions/Messages/GetFutureChatCreatorAfterLeave.phpG      G  a;      >   taknone/liveproto/src/Tl/Functions/Messages/GetRichMessage.phpm      m  N      H   taknone/liveproto/src/Tl/Functions/Messages/GetSearchResultsCalendar.php        E      ?   taknone/liveproto/src/Tl/Functions/Messages/EditChatCreator.php        w"      A   taknone/liveproto/src/Tl/Functions/Messages/SearchCustomEmoji.phpx      x  m      ;   taknone/liveproto/src/Tl/Functions/Messages/GetFullChat.php@      @  2      H   taknone/liveproto/src/Tl/Functions/Messages/DeleteExportedChatInvite.phpx      x  ii`      >   taknone/liveproto/src/Tl/Functions/Messages/AppendTodoList.php              H   taknone/liveproto/src/Tl/Functions/Messages/GetFeaturedEmojiStickers.phpK      K  0K      E   taknone/liveproto/src/Tl/Functions/Messages/GetQuickReplyMessages.phpK      K  I      <   taknone/liveproto/src/Tl/Functions/Messages/GetFactCheck.php        H      G   taknone/liveproto/src/Tl/Functions/Messages/HideAllChatJoinRequests.phpY      Y  śl      >   taknone/liveproto/src/Tl/Functions/Messages/GetForumTopics.php        O      C   taknone/liveproto/src/Tl/Functions/Messages/GetInlineBotResults.php        !I      8   taknone/liveproto/src/Tl/Functions/Messages/GetChats.php>      >  mg      A   taknone/liveproto/src/Tl/Functions/Messages/ReportReadMetrics.php        ?)      @   taknone/liveproto/src/Tl/Functions/Messages/UnpinAllMessages.php        )ٻ      =   taknone/liveproto/src/Tl/Functions/Messages/GetStickerSet.php        &x      :   taknone/liveproto/src/Tl/Functions/Messages/GetDialogs.phpr      r  S
      A   taknone/liveproto/src/Tl/Functions/Messages/GetUnreadMentions.php=      =  fT      >   taknone/liveproto/src/Tl/Functions/Messages/GetSplitRanges.php        ro]      =   taknone/liveproto/src/Tl/Functions/Messages/SetHistoryTTL.phpn      n  qc      @   taknone/liveproto/src/Tl/Functions/Messages/GetEmojiStickers.php?      ?  <jU      <   taknone/liveproto/src/Tl/Functions/Messages/ReadMentions.php$      $  ̤      D   taknone/liveproto/src/Tl/Functions/Messages/GetDiscussionMessage.php         J      A   taknone/liveproto/src/Tl/Functions/Messages/InitHistoryImport.php              >   taknone/liveproto/src/Tl/Functions/Messages/ClearAllDrafts.php        $2       F   taknone/liveproto/src/Tl/Functions/Messages/ToggleDialogFilterTags.php?      ?  ze9      B   taknone/liveproto/src/Tl/Functions/Messages/SetDefaultReaction.phpF      F  U      C   taknone/liveproto/src/Tl/Functions/Messages/HidePeerSettingsBar.php<      <        C   taknone/liveproto/src/Tl/Functions/Messages/GetAttachedStickers.php^      ^  %      E   taknone/liveproto/src/Tl/Functions/Messages/CheckUrlAuthMatchCode.php        N      I   taknone/liveproto/src/Tl/Functions/Messages/GetSuggestedDialogFilters.php"      "  ̮P      <   taknone/liveproto/src/Tl/Functions/Messages/SetGameScore.php        Iפ      @   taknone/liveproto/src/Tl/Functions/Messages/ReadSavedHistory.php        t      F   taknone/liveproto/src/Tl/Functions/Messages/GetChatInviteImporters.php6      6  ެ      E   taknone/liveproto/src/Tl/Functions/Messages/SetBotShippingResults.php        h      <   taknone/liveproto/src/Tl/Functions/Messages/SetChatTheme.phpz      z  *A      C   taknone/liveproto/src/Tl/Functions/Messages/HideChatJoinRequest.php        s       D   taknone/liveproto/src/Tl/Functions/Messages/GetSponsoredMessages.php        ha      C   taknone/liveproto/src/Tl/Functions/Messages/ClearRecentStickers.php}      }  OV0Ҥ      <   taknone/liveproto/src/Tl/Functions/Messages/GetPollVotes.php        	      F   taknone/liveproto/src/Tl/Functions/Messages/GetOldFeaturedStickers.php        6C      ?   taknone/liveproto/src/Tl/Functions/Messages/SearchSentMedia.php        x S      ;   taknone/liveproto/src/Tl/Functions/Messages/GetEmojiURL.phpC      C  	{      ?   taknone/liveproto/src/Tl/Functions/Messages/DeleteFactCheck.phpp      p  #D      ?   taknone/liveproto/src/Tl/Functions/Messages/GetSavedDialogs.php              ;   taknone/liveproto/src/Tl/Functions/Messages/UploadMedia.php        P      @   taknone/liveproto/src/Tl/Functions/Messages/GetFavedStickers.php@      @  b      D   taknone/liveproto/src/Tl/Functions/Messages/EditInlineBotMessage.php        f^2      E   taknone/liveproto/src/Tl/Functions/Messages/ClickSponsoredMessage.php        wy3      @   taknone/liveproto/src/Tl/Functions/Messages/SendPaidReaction.php        r      :   taknone/liveproto/src/Tl/Functions/Messages/DeleteChat.php2      2  /r      6   taknone/liveproto/src/Tl/Functions/Messages/Report.php        G>      D   taknone/liveproto/src/Tl/Functions/Messages/GetDialogUnreadMarks.php        Ә      @   taknone/liveproto/src/Tl/Functions/Messages/AcceptEncryption.php        Y]W~      B   taknone/liveproto/src/Tl/Functions/Messages/SetInlineGameScore.php        2Ԥ      A   taknone/liveproto/src/Tl/Functions/Messages/GetDocumentByHash.php        e      >   taknone/liveproto/src/Tl/Functions/Messages/GetAllStickers.php=      =  PT      D   taknone/liveproto/src/Tl/Functions/Messages/ComposeMessageWithAI.php        7*ez      <   taknone/liveproto/src/Tl/Functions/Messages/SendReaction.php        -uh      I   taknone/liveproto/src/Tl/Functions/Messages/DeleteParticipantReaction.php        񆂊      F   taknone/liveproto/src/Tl/Functions/Messages/CheckHistoryImportPeer.php\      \  xE      =   taknone/liveproto/src/Tl/Functions/Messages/AddPollAnswer.php              ;   taknone/liveproto/src/Tl/Functions/Messages/GetMessages.phpT      T  &Mc      B   taknone/liveproto/src/Tl/Functions/Messages/GetRecentReactions.phpq      q  ;      D   taknone/liveproto/src/Tl/Functions/Messages/GetDefaultHistoryTTL.php        nH3      >   taknone/liveproto/src/Tl/Functions/Messages/RequestWebView.php        a>|      9   taknone/liveproto/src/Tl/Functions/Messages/SendMedia.php        Ѥ      B   taknone/liveproto/src/Tl/Functions/Messages/DeleteSavedHistory.php        l^      <   taknone/liveproto/src/Tl/Functions/Messages/GetSavedGifs.php9      9  ˤ      E   taknone/liveproto/src/Tl/Functions/Messages/SetBotGuestChatResult.php        .q      D   taknone/liveproto/src/Tl/Functions/Messages/RequestSimpleWebView.phpB      B        7   taknone/liveproto/src/Tl/Functions/Messages/SaveGif.phpf      f  H="      >   taknone/liveproto/src/Tl/Functions/Messages/GetCommonChats.php        <m      D   taknone/liveproto/src/Tl/Functions/Messages/SendEncryptedService.php        dۤ      A   taknone/liveproto/src/Tl/Functions/Messages/GetRecentStickers.php        aR_r      D   taknone/liveproto/src/Tl/Functions/Messages/GetMessagesReactions.php|      |        A   taknone/liveproto/src/Tl/Functions/Messages/GetWebPagePreview.phpJ      J  'ݤ      B   taknone/liveproto/src/Tl/Functions/Messages/GetMessageEditData.phpx      x  拤      C   taknone/liveproto/src/Tl/Functions/Messages/ToggleTodoCompleted.php        <B      @   taknone/liveproto/src/Tl/Functions/Messages/GetPinnedDialogs.phpL      L  
,      9   taknone/liveproto/src/Tl/Functions/Messages/SetTyping.phpV      V  |ޱ      >   taknone/liveproto/src/Tl/Functions/Messages/RequestUrlAuth.phpq      q  uat      E   taknone/liveproto/src/Tl/Functions/Messages/ToggleBotInAttachMenu.php        #U      ;   taknone/liveproto/src/Tl/Functions/Messages/SendMessage.php        of      >   taknone/liveproto/src/Tl/Functions/Messages/GetPeerDialogs.phpi      i  $      :   taknone/liveproto/src/Tl/Functions/Messages/GetWebPage.phpg      g  Fܤ      A   taknone/liveproto/src/Tl/Functions/Messages/RequestAppWebView.phpr      r  byg      C   taknone/liveproto/src/Tl/Functions/Messages/ReadMessageContents.phpR      R  S.T      ?   taknone/liveproto/src/Tl/Functions/Messages/GetTopReactions.phpn      n  $      =   taknone/liveproto/src/Tl/Functions/Messages/SummarizeText.php        ս|      H   taknone/liveproto/src/Tl/Functions/Messages/DeleteQuickReplyMessages.php        #=Ƥ      I   taknone/liveproto/src/Tl/Functions/Messages/SetChatAvailableReactions.phpb      b  x      B   taknone/liveproto/src/Tl/Functions/Messages/RequestMainWebView.php              B   taknone/liveproto/src/Tl/Functions/Messages/UpdateDialogFilter.php        2ä      K   taknone/liveproto/src/Tl/Functions/Messages/ToggleSuggestedPostApproval.php}      }  -$Ǥ      J   taknone/liveproto/src/Tl/Functions/Messages/GetEmojiProfilePhotoGroups.phpG      G  _      I   taknone/liveproto/src/Tl/Functions/Messages/SavePreparedInlineMessage.php        V      ;   taknone/liveproto/src/Tl/Functions/Messages/MigrateChat.php6      6  oD      H   taknone/liveproto/src/Tl/Functions/Messages/GetPreparedInlineMessage.php        vbÿ      K   taknone/liveproto/src/Tl/Functions/Messages/EditChatDefaultBannedRights.php        HV      A   taknone/liveproto/src/Tl/Functions/Messages/ToggleStickerSets.php              F   taknone/liveproto/src/Tl/Functions/Messages/GetPaidReactionPrivacy.php	      	  M2      D   taknone/liveproto/src/Tl/Functions/Messages/ClearRecentReactions.php        o      G   taknone/liveproto/src/Tl/Functions/Messages/CheckQuickReplyShortcut.phpH      H        E   taknone/liveproto/src/Tl/Functions/Messages/GetPinnedSavedDialogs.php        {k      =   taknone/liveproto/src/Tl/Functions/Messages/DeleteHistory.php        x      ?   taknone/liveproto/src/Tl/Functions/Messages/ToggleDialogPin.php        U[I      >   taknone/liveproto/src/Tl/Functions/Messages/GetEmojiGroups.php;      ;  &@j      =   taknone/liveproto/src/Tl/Functions/Messages/EditChatAdmin.php        <$      G   taknone/liveproto/src/Tl/Functions/Messages/DeleteScheduledMessages.php        XL交      C   taknone/liveproto/src/Tl/Functions/Messages/ReportEncryptedSpam.phpE      E  8%      >   taknone/liveproto/src/Tl/Functions/Messages/ProlongWebView.php        ~٤      D   taknone/liveproto/src/Tl/Functions/Messages/ReadFeaturedStickers.php@      @  {N      ?   taknone/liveproto/src/Tl/Functions/Messages/SendWebViewData.php        y      A   taknone/liveproto/src/Tl/Functions/Messages/InstallStickerSet.php        9䔤      ;   taknone/liveproto/src/Tl/Functions/Messages/EditMessage.php	      	  rN      A   taknone/liveproto/src/Tl/Functions/Messages/SaveRecentSticker.php        )      D   taknone/liveproto/src/Tl/Functions/Messages/GetSavedReactionTags.php        sc      G   taknone/liveproto/src/Tl/Functions/Messages/GetCustomEmojiDocuments.phpj      j  +      B   taknone/liveproto/src/Tl/Functions/Messages/CheckHistoryImport.phpd      d        F   taknone/liveproto/src/Tl/Functions/Messages/SendQuickReplyMessages.php        Zo      G   taknone/liveproto/src/Tl/Functions/Messages/GetInlineGameHighScores.php        FkJ      J   taknone/liveproto/src/Tl/Functions/Messages/DeleteParticipantReactions.php        z}f      C   taknone/liveproto/src/Tl/Functions/Messages/GetArchivedStickers.phpF      F  N@      E   taknone/liveproto/src/Tl/Functions/Messages/GetEmojiStickerGroups.phpB      B        G   taknone/liveproto/src/Tl/Functions/Messages/GetMessageReactionsList.php4      4        @   taknone/liveproto/src/Tl/Functions/Messages/MarkDialogUnread.phpv      v        A   taknone/liveproto/src/Tl/Functions/Messages/RequestEncryption.php        w#Ӥ      F   taknone/liveproto/src/Tl/Functions/Messages/UpdateSavedReactionTag.php        ؽm      @   taknone/liveproto/src/Tl/Functions/Messages/GetMessagesViews.php        jlk      A   taknone/liveproto/src/Tl/Functions/Messages/GetSearchCounters.php[      [  N<      C   taknone/liveproto/src/Tl/Functions/Messages/UploadEncryptedFile.php        Q'      B   taknone/liveproto/src/Tl/Functions/Messages/GetUnreadReactions.php	      	   uHä      D   taknone/liveproto/src/Tl/Functions/Messages/GetScheduledMessages.php        m      =   taknone/liveproto/src/Tl/Functions/Messages/AcceptUrlAuth.php0      0        H   taknone/liveproto/src/Tl/Functions/Messages/ReorderPinnedForumTopics.php        eNC      F   taknone/liveproto/src/Tl/Functions/Messages/GetDefaultTagReactions.phpC      C  K       B   taknone/liveproto/src/Tl/Functions/Messages/GetUnreadPollVotes.php>      >  "      D   taknone/liveproto/src/Tl/Functions/Messages/ViewSponsoredMessage.phpG      G  WN      B   taknone/liveproto/src/Tl/Functions/Messages/SetEncryptedTyping.php|      |  o0      F   taknone/liveproto/src/Tl/Functions/Messages/TogglePeerTranslations.php              B   taknone/liveproto/src/Tl/Functions/Messages/DeleteTopicHistory.php              =   taknone/liveproto/src/Tl/Functions/Messages/EditChatAbout.phpp      p  OUh      >   taknone/liveproto/src/Tl/Functions/Messages/ReportReaction.php        إL      F   taknone/liveproto/src/Tl/Functions/Messages/EditQuickReplyShortcut.php        JA=      A   taknone/liveproto/src/Tl/Functions/Messages/SendEncryptedFile.php        R5      @   taknone/liveproto/src/Tl/Functions/Messages/GetEmojiKeywords.phpW      W  ߽M      A   taknone/liveproto/src/Tl/Functions/Messages/SaveDefaultSendAs.php~      ~  #{ B      J   taknone/liveproto/src/Tl/Functions/Messages/GetEmojiKeywordsDifference.php        !      >   taknone/liveproto/src/Tl/Functions/Messages/DeleteMessages.php              >   taknone/liveproto/src/Tl/Functions/Messages/SendMultiMedia.php
      
  ?D      E   taknone/liveproto/src/Tl/Functions/Messages/GetExportedChatInvite.php              C   taknone/liveproto/src/Tl/Functions/Messages/UploadImportedMedia.php	      	  \M      >   taknone/liveproto/src/Tl/Functions/Messages/DeclineUrlAuth.php0      0  kee      A   taknone/liveproto/src/Tl/Functions/Messages/SearchStickerSets.php        06e      =   taknone/liveproto/src/Tl/Functions/Messages/ReadPollVotes.php%      %  fU+&      D   taknone/liveproto/src/Tl/Functions/Messages/ReadEncryptedHistory.php        q      ?   taknone/liveproto/src/Tl/Functions/Messages/ForwardMessages.php        [M      <   taknone/liveproto/src/Tl/Functions/Messages/SearchGlobal.php        r󩬤      D   taknone/liveproto/src/Tl/Functions/Messages/SetBotCallbackAnswer.php1      1  Lʤ      C   taknone/liveproto/src/Tl/Functions/Messages/SendInlineBotResult.phpW      W  iS      A   taknone/liveproto/src/Tl/Functions/Messages/GetOutboxReadDate.phpy      y  5      ?   taknone/liveproto/src/Tl/Functions/Messages/GetPeerSettings.phpI      I  ِ      E   taknone/liveproto/src/Tl/Functions/Messages/GetAvailableReactions.phpI      I  :Ʃ      I   taknone/liveproto/src/Tl/Functions/Messages/GetEmojiKeywordsLanguages.phpr      r  ~      >   taknone/liveproto/src/Tl/Functions/Messages/DeleteChatUser.php        -3      I   taknone/liveproto/src/Tl/Functions/Messages/GetPersonalChannelHistory.php%      %  J      C   taknone/liveproto/src/Tl/Functions/Messages/GetSavedDialogsByID.phpI      I  ;      I   taknone/liveproto/src/Tl/Functions/Messages/TogglePaidReactionPrivacy.php        lS      8   taknone/liveproto/src/Tl/Functions/Messages/SendVote.php        kɐ      F   taknone/liveproto/src/Tl/Functions/Messages/ReportSponsoredMessage.php        uSd      D   taknone/liveproto/src/Tl/Functions/Messages/GetAdminsWithInvites.phpW      W  WUr      H   taknone/liveproto/src/Tl/Functions/Messages/SetBotPrecheckoutResults.phpZ      Z  A      A   taknone/liveproto/src/Tl/Functions/Messages/DiscardEncryption.php        6פ      J   taknone/liveproto/src/Tl/Functions/Messages/GetMessageReadParticipants.php        iu      9   taknone/liveproto/src/Tl/Functions/Messages/GetBotApp.phpm      m  C      A   taknone/liveproto/src/Tl/Functions/Messages/GetGameHighScores.php        &\      8   taknone/liveproto/src/Tl/Functions/Messages/StartBot.php        Uw<      F   taknone/liveproto/src/Tl/Functions/Messages/EditExportedChatInvite.php        fQg      C   taknone/liveproto/src/Tl/Functions/Messages/SetInlineBotResults.php        IF      F   taknone/liveproto/src/Tl/Functions/Messages/DeletePhoneCallHistory.php        e#T      >   taknone/liveproto/src/Tl/Functions/Messages/SearchStickers.php        m      >   taknone/liveproto/src/Tl/Functions/Messages/EditForumTopic.php>      >  ZR̤      C   taknone/liveproto/src/Tl/Functions/Messages/ReorderQuickReplies.phpF      F  ^      A   taknone/liveproto/src/Tl/Functions/Messages/GetAttachMenuBots.php:      :  LB      D   taknone/liveproto/src/Tl/Functions/Messages/SendBotRequestedPeer.php{      {  :+      B   taknone/liveproto/src/Tl/Functions/Messages/GetRecentLocations.php        a      ?   taknone/liveproto/src/Tl/Functions/Messages/CheckChatInvite.php:      :        G   taknone/liveproto/src/Tl/Functions/Messages/EditChatParticipantRank.php        	      ?   taknone/liveproto/src/Tl/Functions/Messages/GetSavedHistory.php        F|P      :   taknone/liveproto/src/Tl/Functions/Messages/ReportSpam.php3      3  p      B   taknone/liveproto/src/Tl/Functions/Messages/GetForumTopicsByID.php        ^dE      :   taknone/liveproto/src/Tl/Functions/Messages/GetReplies.php        ~a      ;   taknone/liveproto/src/Tl/Functions/Messages/GetStickers.phpz      z  >$      D   taknone/liveproto/src/Tl/Functions/Messages/ToggleSavedDialogPin.php        [V      ;   taknone/liveproto/src/Tl/Functions/Auth/ResetLoginEmail.php        }9      <   taknone/liveproto/src/Tl/Functions/Auth/ExportLoginToken.php        Ny      ;   taknone/liveproto/src/Tl/Functions/Auth/BindTempAuthKey.php          !ȶS      <   taknone/liveproto/src/Tl/Functions/Auth/ImportLoginToken.php>      >  kM      ?   taknone/liveproto/src/Tl/Functions/Auth/ImportAuthorization.phpo      o  &[      6   taknone/liveproto/src/Tl/Functions/Auth/CancelCode.php        M      ?   taknone/liveproto/src/Tl/Functions/Auth/ResetAuthorizations.php        눙      2   taknone/liveproto/src/Tl/Functions/Auth/SignUp.php        Ȗ      A   taknone/liveproto/src/Tl/Functions/Auth/CheckRecoveryPassword.php5      5  ত      =   taknone/liveproto/src/Tl/Functions/Auth/ReportMissingCode.php        o      2   taknone/liveproto/src/Tl/Functions/Auth/LogOut.php        2}      ?   taknone/liveproto/src/Tl/Functions/Auth/ExportAuthorization.phpE      E  ɰ*3      4   taknone/liveproto/src/Tl/Functions/Auth/SendCode.php        Wr      9   taknone/liveproto/src/Tl/Functions/Auth/CheckPaidAuth.php              <   taknone/liveproto/src/Tl/Functions/Auth/AcceptLoginToken.php<      <  )j/B      <   taknone/liveproto/src/Tl/Functions/Auth/InitPasskeyLogin.php        0.      ;   taknone/liveproto/src/Tl/Functions/Auth/RecoverPassword.phpC      C  Ӥ      <   taknone/liveproto/src/Tl/Functions/Auth/DropTempAuthKeys.phpb      b        >   taknone/liveproto/src/Tl/Functions/Auth/FinishPasskeyLogin.php        ≠      9   taknone/liveproto/src/Tl/Functions/Auth/CheckPassword.phpX      X  S٤      >   taknone/liveproto/src/Tl/Functions/Auth/RequestFirebaseSms.php_      _  k      2   taknone/liveproto/src/Tl/Functions/Auth/SignIn.phpt      t  XT      6   taknone/liveproto/src/Tl/Functions/Auth/ResendCode.phps      s  !      G   taknone/liveproto/src/Tl/Functions/Auth/ImportWebTokenAuthorization.php        J#      C   taknone/liveproto/src/Tl/Functions/Auth/RequestPasswordRecovery.php        D      B   taknone/liveproto/src/Tl/Functions/Auth/ImportBotAuthorization.php        !"<      D   taknone/liveproto/src/Tl/Functions/Chatlists/HideChatlistUpdates.phpM      M  C      D   taknone/liveproto/src/Tl/Functions/Chatlists/CheckChatlistInvite.phpM      M  `)y      C   taknone/liveproto/src/Tl/Functions/Chatlists/GetExportedInvites.phpa      a  "3      >   taknone/liveproto/src/Tl/Functions/Chatlists/LeaveChatlist.php        %⳥      C   taknone/liveproto/src/Tl/Functions/Chatlists/EditExportedInvite.php        EƤ      D   taknone/liveproto/src/Tl/Functions/Chatlists/JoinChatlistUpdates.php        C6J      E   taknone/liveproto/src/Tl/Functions/Chatlists/ExportChatlistInvite.php        =Zd      C   taknone/liveproto/src/Tl/Functions/Chatlists/JoinChatlistInvite.php        {      L   taknone/liveproto/src/Tl/Functions/Chatlists/GetLeaveChatlistSuggestions.php]      ]  \BT      E   taknone/liveproto/src/Tl/Functions/Chatlists/DeleteExportedInvite.php        3ښ      C   taknone/liveproto/src/Tl/Functions/Chatlists/GetChatlistUpdates.phpa      a  Eͤ      6   taknone/liveproto/src/Tl/Functions/Help/GetSupport.php        El      9   taknone/liveproto/src/Tl/Functions/Help/GetInviteText.php        C=      8   taknone/liveproto/src/Tl/Functions/Help/GetCdnConfig.php               C   taknone/liveproto/src/Tl/Functions/Help/GetTermsOfServiceUpdate.php        iƤ      ?   taknone/liveproto/src/Tl/Functions/Help/SetBotUpdatesStatus.php        1[      @   taknone/liveproto/src/Tl/Functions/Help/GetPeerProfileColors.php8      8  ;|A      7   taknone/liveproto/src/Tl/Functions/Help/GetUserInfo.phpA      A  ʉ      5   taknone/liveproto/src/Tl/Functions/Help/GetConfig.php        ݤ      ;   taknone/liveproto/src/Tl/Functions/Help/GetPremiumPromo.php        n      ;   taknone/liveproto/src/Tl/Functions/Help/GetRecentMeUrls.phpF      F  	&      <   taknone/liveproto/src/Tl/Functions/Help/GetCountriesList.php}      }  R7O      8   taknone/liveproto/src/Tl/Functions/Help/GetAppConfig.php/      /  p      =   taknone/liveproto/src/Tl/Functions/Help/DismissSuggestion.php        Q@gŤ      9   taknone/liveproto/src/Tl/Functions/Help/GetPeerColors.php1      1  Dlh      @   taknone/liveproto/src/Tl/Functions/Help/AcceptTermsOfService.php2      2  A      8   taknone/liveproto/src/Tl/Functions/Help/GetNearestDc.php        g[      8   taknone/liveproto/src/Tl/Functions/Help/EditUserInfo.php        8      <   taknone/liveproto/src/Tl/Functions/Help/GetTimezonesList.php7      7  53U      :   taknone/liveproto/src/Tl/Functions/Help/GetSupportName.php        75h      8   taknone/liveproto/src/Tl/Functions/Help/GetPromoData.php        Δ/      =   taknone/liveproto/src/Tl/Functions/Help/GetPassportConfig.php9      9        6   taknone/liveproto/src/Tl/Functions/Help/SaveAppLog.phpP      P  QVˤ      8   taknone/liveproto/src/Tl/Functions/Help/GetAppUpdate.php=      =  w      ;   taknone/liveproto/src/Tl/Functions/Help/GetDeepLinkInfo.php=      =  X      9   taknone/liveproto/src/Tl/Functions/Help/HidePromoData.php2      2  b=      G   taknone/liveproto/src/Tl/Functions/Photos/UploadContactProfilePhoto.php          A"      :   taknone/liveproto/src/Tl/Functions/Photos/DeletePhotos.phpJ      J  p      @   taknone/liveproto/src/Tl/Functions/Photos/UpdateProfilePhoto.phpP      P  y      ;   taknone/liveproto/src/Tl/Functions/Photos/GetUserPhotos.php        uҤ      @   taknone/liveproto/src/Tl/Functions/Photos/UploadProfilePhoto.php        Z٤      B   taknone/liveproto/src/Tl/Functions/Fragment/GetCollectibleInfo.phpk      k  ,F      <   taknone/liveproto/src/Tl/Functions/Bots/ResetBotCommands.php        <Y      @   taknone/liveproto/src/Tl/Functions/Bots/UpdateStarRefProgram.php        'ڸݤ      K   taknone/liveproto/src/Tl/Functions/Bots/ToggleUserEmojiStatusPermission.php{      {  ;      9   taknone/liveproto/src/Tl/Functions/Bots/CheckUsername.php:      :  !֤      @   taknone/liveproto/src/Tl/Functions/Bots/ReorderPreviewMedias.php        <z      <   taknone/liveproto/src/Tl/Functions/Bots/SetBotMenuButton.php              :   taknone/liveproto/src/Tl/Functions/Bots/GetAdminedBots.php        쐬      E   taknone/liveproto/src/Tl/Functions/Bots/GetRequestedWebViewButton.php        ;珤      =   taknone/liveproto/src/Tl/Functions/Bots/GetPopularAppBots.phpy      y  ^;Ȥ      >   taknone/liveproto/src/Tl/Functions/Bots/SetJoinChatResults.php        	`jդ      :   taknone/liveproto/src/Tl/Functions/Bots/ToggleUsername.php        ~      :   taknone/liveproto/src/Tl/Functions/Bots/GetBotCommands.php        
      <   taknone/liveproto/src/Tl/Functions/Bots/ReorderUsernames.php}      }  wd?      B   taknone/liveproto/src/Tl/Functions/Bots/AnswerWebhookJSONQuery.phpw      w  ,j      :   taknone/liveproto/src/Tl/Functions/Bots/CanSendMessage.php0      0        5   taknone/liveproto/src/Tl/Functions/Bots/CreateBot.phpB      B  +S      :   taknone/liveproto/src/Tl/Functions/Bots/SetBotCommands.php        ]ܤ      =   taknone/liveproto/src/Tl/Functions/Bots/GetAccessSettings.phpB      B  |      <   taknone/liveproto/src/Tl/Functions/Bots/GetBotMenuButton.phpG      G  ,ri      =   taknone/liveproto/src/Tl/Functions/Bots/SendCustomRequest.php        /      A   taknone/liveproto/src/Tl/Functions/Bots/GetBotRecommendations.php>      >  t-޺      E   taknone/liveproto/src/Tl/Functions/Bots/InvokeWebViewCustomMethod.php        ԶF      ;   taknone/liveproto/src/Tl/Functions/Bots/AddPreviewMedia.php              I   taknone/liveproto/src/Tl/Functions/Bots/SetBotGroupDefaultAdminRights.php`      `        >   taknone/liveproto/src/Tl/Functions/Bots/DeletePreviewMedia.php        S5      C   taknone/liveproto/src/Tl/Functions/Bots/CheckDownloadFileParams.php        oA      <   taknone/liveproto/src/Tl/Functions/Bots/AllowSendMessage.php5      5  0g      M   taknone/liveproto/src/Tl/Functions/Bots/SetBotBroadcastDefaultAdminRights.phpd      d  	Z1      A   taknone/liveproto/src/Tl/Functions/Bots/SetCustomVerification.php,      ,  fm      6   taknone/liveproto/src/Tl/Functions/Bots/SetBotInfo.php        ?      @   taknone/liveproto/src/Tl/Functions/Bots/RequestWebViewButton.php        &֠      <   taknone/liveproto/src/Tl/Functions/Bots/GetPreviewMedias.phpE      E  i      >   taknone/liveproto/src/Tl/Functions/Bots/EditAccessSettings.php        wȤ      <   taknone/liveproto/src/Tl/Functions/Bots/EditPreviewMedia.php        P`      A   taknone/liveproto/src/Tl/Functions/Bots/UpdateUserEmojiStatus.php        r      :   taknone/liveproto/src/Tl/Functions/Bots/GetPreviewInfo.php              6   taknone/liveproto/src/Tl/Functions/Bots/GetBotInfo.php        #      :   taknone/liveproto/src/Tl/Functions/Bots/ExportBotToken.phpy      y  <	9      @   taknone/liveproto/src/Tl/Functions/Contacts/EditCloseFriends.php<      <  !qN      6   taknone/liveproto/src/Tl/Functions/Contacts/Search.php$      $  d+      A   taknone/liveproto/src/Tl/Functions/Contacts/GetSponsoredPeers.php@      @  F=      8   taknone/liveproto/src/Tl/Functions/Contacts/GetSaved.php        ==/      :   taknone/liveproto/src/Tl/Functions/Contacts/ResetSaved.php        3T      >   taknone/liveproto/src/Tl/Functions/Contacts/ImportContacts.phpq      q  ,|      ;   taknone/liveproto/src/Tl/Functions/Contacts/GetContacts.php7      7  <	W      =   taknone/liveproto/src/Tl/Functions/Contacts/GetContactIDs.php3      3  Tq+d      >   taknone/liveproto/src/Tl/Functions/Contacts/DeleteByPhones.phpJ      J  _Q(}      B   taknone/liveproto/src/Tl/Functions/Contacts/ImportContactToken.php:      :  %s      ;   taknone/liveproto/src/Tl/Functions/Contacts/GetTopPeers.phpB      B        5   taknone/liveproto/src/Tl/Functions/Contacts/Block.php        s      >   taknone/liveproto/src/Tl/Functions/Contacts/DeleteContacts.phpF      F  t      >   taknone/liveproto/src/Tl/Functions/Contacts/ToggleTopPeers.php7      7  x      :   taknone/liveproto/src/Tl/Functions/Contacts/GetLocated.php        T      B   taknone/liveproto/src/Tl/Functions/Contacts/ExportContactToken.php              ?   taknone/liveproto/src/Tl/Functions/Contacts/ResolveUsername.php%      %  烤      :   taknone/liveproto/src/Tl/Functions/Contacts/SetBlocked.php        @I      @   taknone/liveproto/src/Tl/Functions/Contacts/BlockFromReplies.php              A   taknone/liveproto/src/Tl/Functions/Contacts/UpdateContactNote.phpv      v  =:X      7   taknone/liveproto/src/Tl/Functions/Contacts/Unblock.php        H      <   taknone/liveproto/src/Tl/Functions/Contacts/ResolvePhone.phpE      E        B   taknone/liveproto/src/Tl/Functions/Contacts/ResetTopPeerRating.php        z&      :   taknone/liveproto/src/Tl/Functions/Contacts/GetBlocked.php              =   taknone/liveproto/src/Tl/Functions/Contacts/AcceptContact.php3      3  S~      <   taknone/liveproto/src/Tl/Functions/Contacts/GetBirthdays.php        (      ;   taknone/liveproto/src/Tl/Functions/Contacts/GetStatuses.php        f?      :   taknone/liveproto/src/Tl/Functions/Contacts/AddContact.phpS      S        >   taknone/liveproto/src/Tl/Functions/Folders/EditPeerFolders.phpq      q  Τ      <   taknone/liveproto/src/Tl/Functions/Users/SuggestBirthday.phpx      x  K      :   taknone/liveproto/src/Tl/Functions/Users/GetSavedMusic.php        ۄ^      8   taknone/liveproto/src/Tl/Functions/Users/GetFullUser.php5      5  `      >   taknone/liveproto/src/Tl/Functions/Users/GetSavedMusicByID.php        u1!      5   taknone/liveproto/src/Tl/Functions/Users/GetUsers.phpB      B  ]~ˆ      E   taknone/liveproto/src/Tl/Functions/Users/GetRequirementsToContact.phpc      c  /t      A   taknone/liveproto/src/Tl/Functions/Users/SetSecureValueErrors.php              >   taknone/liveproto/src/Tl/Functions/Payments/GetStarsStatus.php        0      H   taknone/liveproto/src/Tl/Functions/Payments/GetStarsTransactionsByID.php        F      G   taknone/liveproto/src/Tl/Functions/Payments/EditConnectedStarRefBot.php	      	        <   taknone/liveproto/src/Tl/Functions/Payments/GetSavedInfo.php
      
  [      G   taknone/liveproto/src/Tl/Functions/Payments/GetStarGiftAuctionState.php         [      =   taknone/liveproto/src/Tl/Functions/Payments/CraftStarGift.phpj      j        G   taknone/liveproto/src/Tl/Functions/Payments/GetConnectedStarRefBots.php(      (  t¤      O   taknone/liveproto/src/Tl/Functions/Payments/GetStarGiftAuctionAcquiredGifts.phph      h  #FZ֤      J   taknone/liveproto/src/Tl/Functions/Payments/BotCancelStarsSubscription.php        kB      @   taknone/liveproto/src/Tl/Functions/Payments/GetSavedStarGift.php}      }  #V      D   taknone/liveproto/src/Tl/Functions/Payments/GetStarsTopupOptions.php        kq      C   taknone/liveproto/src/Tl/Functions/Payments/GetStarsGiftOptions.php              O   taknone/liveproto/src/Tl/Functions/Payments/ToggleChatStarGiftNotifications.php        >٤      I   taknone/liveproto/src/Tl/Functions/Payments/GetStarGiftUpgradePreview.php\      \        H   taknone/liveproto/src/Tl/Functions/Payments/DeleteStarGiftCollection.php        Ds'      ?   taknone/liveproto/src/Tl/Functions/Payments/UpgradeStarGift.php        (X      @   taknone/liveproto/src/Tl/Functions/Payments/TransferStarGift.php        kۤ      K   taknone/liveproto/src/Tl/Functions/Payments/AssignPlayMarketTransaction.php        /<      ?   taknone/liveproto/src/Tl/Functions/Payments/GetBankCardData.phpK      K  gG      ?   taknone/liveproto/src/Tl/Functions/Payments/SendPaymentForm.php        0      H   taknone/liveproto/src/Tl/Functions/Payments/CreateStarGiftCollection.php        <      E   taknone/liveproto/src/Tl/Functions/Payments/LaunchPrepaidGiveaway.php        .V      G   taknone/liveproto/src/Tl/Functions/Payments/GetStarsGiveawayOptions.php        q}      ?   taknone/liveproto/src/Tl/Functions/Payments/GetGiveawayInfo.php~      ~  qߤ      A   taknone/liveproto/src/Tl/Functions/Payments/ConnectStarRefBot.php        Ϥ      L   taknone/liveproto/src/Tl/Functions/Payments/GetStarsRevenueWithdrawalUrl.php        ێ      G   taknone/liveproto/src/Tl/Functions/Payments/ChangeStarsSubscription.phpl      l  >L      E   taknone/liveproto/src/Tl/Functions/Payments/GetStarsSubscriptions.php              <   taknone/liveproto/src/Tl/Functions/Payments/GetStarGifts.php7      7  3      J   taknone/liveproto/src/Tl/Functions/Payments/GetUniqueStarGiftValueInfo.php[      [  v      =   taknone/liveproto/src/Tl/Functions/Payments/ExportInvoice.phpe      e  {`      =   taknone/liveproto/src/Tl/Functions/Payments/ApplyGiftCode.php5      5        <   taknone/liveproto/src/Tl/Functions/Payments/SaveStarGift.php        Av}      G   taknone/liveproto/src/Tl/Functions/Payments/GetSuggestedStarRefBots.php        1(q      ?   taknone/liveproto/src/Tl/Functions/Payments/ConvertStarGift.phpM      M  '      A   taknone/liveproto/src/Tl/Functions/Payments/GetUniqueStarGift.phpI      I  >=      D   taknone/liveproto/src/Tl/Functions/Payments/GetStarsRevenueStats.php        d      B   taknone/liveproto/src/Tl/Functions/Payments/GetResaleStarGifts.php              @   taknone/liveproto/src/Tl/Functions/Payments/CheckCanSendGift.phpS      S  xg      F   taknone/liveproto/src/Tl/Functions/Payments/GetConnectedStarRefBot.php        b!~      =   taknone/liveproto/src/Tl/Functions/Payments/CheckGiftCode.phpF      F  c6      A   taknone/liveproto/src/Tl/Functions/Payments/GetPaymentReceipt.php        ׭1      I   taknone/liveproto/src/Tl/Functions/Payments/GetStarGiftActiveAuctions.phpS      S  .      F   taknone/liveproto/src/Tl/Functions/Payments/GetStarGiftCollections.php        |      L   taknone/liveproto/src/Tl/Functions/Payments/GetStarsRevenueAdsAccountUrl.phpc      c  ςqg      A   taknone/liveproto/src/Tl/Functions/Payments/SendStarGiftOffer.php*      *        J   taknone/liveproto/src/Tl/Functions/Payments/ToggleStarGiftsPinnedToTop.php        :G      L   taknone/liveproto/src/Tl/Functions/Payments/GetStarGiftUpgradeAttributes.phpb      b  ,G      =   taknone/liveproto/src/Tl/Functions/Payments/SendStarsForm.php        p      J   taknone/liveproto/src/Tl/Functions/Payments/ReorderStarGiftCollections.php        ̓ؤ      D   taknone/liveproto/src/Tl/Functions/Payments/ResolveStarGiftOffer.php        a%      I   taknone/liveproto/src/Tl/Functions/Payments/AssignAppStoreTransaction.php              @   taknone/liveproto/src/Tl/Functions/Payments/CanPurchaseStore.phpQ      Q  {      A   taknone/liveproto/src/Tl/Functions/Payments/RefundStarsCharge.php              >   taknone/liveproto/src/Tl/Functions/Payments/ClearSavedInfo.php        D      A   taknone/liveproto/src/Tl/Functions/Payments/GetSavedStarGifts.phpX      X  I$l٤      >   taknone/liveproto/src/Tl/Functions/Payments/GetPaymentForm.phpC      C  Ud      A   taknone/liveproto/src/Tl/Functions/Payments/GetCraftStarGifts.php        $
i      H   taknone/liveproto/src/Tl/Functions/Payments/UpdateStarGiftCollection.php        -      C   taknone/liveproto/src/Tl/Functions/Payments/UpdateStarGiftPrice.php              I   taknone/liveproto/src/Tl/Functions/Payments/GetPremiumGiftCodeOptions.php        5      H   taknone/liveproto/src/Tl/Functions/Payments/FulfillStarsSubscription.php        &      E   taknone/liveproto/src/Tl/Functions/Payments/ValidateRequestedInfo.php        ez      D   taknone/liveproto/src/Tl/Functions/Payments/GetStarsTransactions.php        C      H   taknone/liveproto/src/Tl/Functions/Payments/GetStarGiftWithdrawalUrl.php        X      <   taknone/liveproto/src/Tl/Functions/Account/SetAccountTTL.php7      7  J      B   taknone/liveproto/src/Tl/Functions/Account/SendVerifyPhoneCode.php        Z      F   taknone/liveproto/src/Tl/Functions/Account/GetAutoDownloadSettings.php        ~#      @   taknone/liveproto/src/Tl/Functions/Account/GetSavedRingtones.phpA      A  J      J   taknone/liveproto/src/Tl/Functions/Account/ChangeAuthorizationSettings.php        9x      ;   taknone/liveproto/src/Tl/Functions/Account/SaveRingtone.php{      {  Ub      F   taknone/liveproto/src/Tl/Functions/Account/ToggleSponsoredMessages.php?      ?  @*,      =   taknone/liveproto/src/Tl/Functions/Account/UploadRingtone.php        <      A   taknone/liveproto/src/Tl/Functions/Account/UpdateDeviceLocked.php4      4  mä      A   taknone/liveproto/src/Tl/Functions/Account/SetContentSettings.php        O      A   taknone/liveproto/src/Tl/Functions/Account/InitTakeoutSession.php'      '  +      :   taknone/liveproto/src/Tl/Functions/Account/VerifyEmail.php        |      E   taknone/liveproto/src/Tl/Functions/Account/GetPaidMessagesRevenue.phpJ      J  <0-      G   taknone/liveproto/src/Tl/Functions/Account/ClearRecentEmojiStatuses.php        >X      G   taknone/liveproto/src/Tl/Functions/Account/SetGlobalPrivacySettings.phpi      i  \a      B   taknone/liveproto/src/Tl/Functions/Account/SendVerifyEmailCode.php        -2      =   taknone/liveproto/src/Tl/Functions/Account/UpdateUsername.php>      >  Τ      <   taknone/liveproto/src/Tl/Functions/Account/CheckUsername.php=      =  2 Aq      :   taknone/liveproto/src/Tl/Functions/Account/UploadTheme.php        G!#      @   taknone/liveproto/src/Tl/Functions/Account/DeleteSecureValue.php[      [  k      G   taknone/liveproto/src/Tl/Functions/Account/GetGlobalPrivacySettings.php        L      >   taknone/liveproto/src/Tl/Functions/Account/UploadWallPaper.phpM      M  z      Q   taknone/liveproto/src/Tl/Functions/Account/DeleteWebBrowserSettingsExceptions.php'      '  W̋      E   taknone/liveproto/src/Tl/Functions/Account/ResetWebAuthorizations.php        /6u      7   taknone/liveproto/src/Tl/Functions/Account/GetTheme.phpr      r  	07      A   taknone/liveproto/src/Tl/Functions/Account/GetContentSettings.php        '퐤      A   taknone/liveproto/src/Tl/Functions/Account/GetAllSecureValues.php        ^zʤ      C   taknone/liveproto/src/Tl/Functions/Account/DeclinePasswordReset.php        B      D   taknone/liveproto/src/Tl/Functions/Account/InvalidateSignInCodes.phpM      M        C   taknone/liveproto/src/Tl/Functions/Account/SaveAutoSaveSettings.php        r/      M   taknone/liveproto/src/Tl/Functions/Account/GetChannelDefaultEmojiStatuses.phpM      M        <   taknone/liveproto/src/Tl/Functions/Account/GetChatThemes.php5      5  Pڤ      F   taknone/liveproto/src/Tl/Functions/Account/ResolveBusinessChatLink.phpX      X  1U      :   taknone/liveproto/src/Tl/Functions/Account/VerifyPhone.php        &>ؤ      E   taknone/liveproto/src/Tl/Functions/Account/CreateBusinessChatLink.phpV      V  8݌0      C   taknone/liveproto/src/Tl/Functions/Account/GetWebAuthorizations.php        	k      E   taknone/liveproto/src/Tl/Functions/Account/UpdateBusinessLocation.php        Ԡ#      F   taknone/liveproto/src/Tl/Functions/Account/GetDefaultEmojiStatuses.phpF      F  Վ      :   taknone/liveproto/src/Tl/Functions/Account/ChangePhone.php        !H^      =   taknone/liveproto/src/Tl/Functions/Account/ToggleUsername.phpv      v  QP      F   taknone/liveproto/src/Tl/Functions/Account/UpdateBusinessWorkHours.php          xZ      G   taknone/liveproto/src/Tl/Functions/Account/DeleteAutoSaveExceptions.php        5B      E   taknone/liveproto/src/Tl/Functions/Account/DeleteBusinessChatLink.php:      :  ^      B   taknone/liveproto/src/Tl/Functions/Account/ResendPasswordEmail.php              ?   taknone/liveproto/src/Tl/Functions/Account/ReorderUsernames.phpH      H  o1      :   taknone/liveproto/src/Tl/Functions/Account/CreateTheme.php"      "  e
      C   taknone/liveproto/src/Tl/Functions/Account/EditBusinessChatLink.php        B      8   taknone/liveproto/src/Tl/Functions/Account/SaveMusic.php[      [  4p      A   taknone/liveproto/src/Tl/Functions/Account/UpdateConnectedBot.php        W      F   taknone/liveproto/src/Tl/Functions/Account/DisablePeerConnectedBot.php?      ?  u      >   taknone/liveproto/src/Tl/Functions/Account/ResetWallPapers.php        e{k      =   taknone/liveproto/src/Tl/Functions/Account/UpdateBirthday.php        9K      ;   taknone/liveproto/src/Tl/Functions/Account/UpdateStatus.php4      4  F      B   taknone/liveproto/src/Tl/Functions/Account/GetNotifyExceptions.php        ȢR      <   taknone/liveproto/src/Tl/Functions/Account/DeleteAccount.php          ;d@      D   taknone/liveproto/src/Tl/Functions/Account/UpdatePersonalChannel.phpI      I        C   taknone/liveproto/src/Tl/Functions/Account/SendConfirmPhoneCode.php              B   taknone/liveproto/src/Tl/Functions/Account/GetAutoSaveSettings.php              I   taknone/liveproto/src/Tl/Functions/Account/SetReactionsNotifySettings.phpo      o  Lὤ      <   taknone/liveproto/src/Tl/Functions/Account/SaveWallPaper.php        3xe      >   taknone/liveproto/src/Tl/Functions/Account/SaveSecureValue.php        a*      ?   taknone/liveproto/src/Tl/Functions/Account/InstallWallPaper.php        p7       ?   taknone/liveproto/src/Tl/Functions/Account/UnregisterDevice.php        Ф      C   taknone/liveproto/src/Tl/Functions/Account/ConfirmPasswordEmail.php8      8  r˽      B   taknone/liveproto/src/Tl/Functions/Account/SetAuthorizationTTL.phpe      e  }^
      9   taknone/liveproto/src/Tl/Functions/Account/ReportPeer.php        |i      E   taknone/liveproto/src/Tl/Functions/Account/UpdatePasswordSettings.php              <   taknone/liveproto/src/Tl/Functions/Account/DeletePasskey.php+      +  _      C   taknone/liveproto/src/Tl/Functions/Account/UpdateNotifySettings.php        lR      @   taknone/liveproto/src/Tl/Functions/Account/GetNotifySettings.phpM      M  gH      :   taknone/liveproto/src/Tl/Functions/Account/UpdateTheme.phpf      f  9ܤ      9   taknone/liveproto/src/Tl/Functions/Account/SetPrivacy.php        uv      G   taknone/liveproto/src/Tl/Functions/Account/ToggleConnectedBotPaused.phpx      x  9_      <   taknone/liveproto/src/Tl/Functions/Account/UpdateProfile.php/      /  Nm      B   taknone/liveproto/src/Tl/Functions/Account/ResetNotifySettings.php        ?      <   taknone/liveproto/src/Tl/Functions/Account/GetAccountTTL.php        <`      =   taknone/liveproto/src/Tl/Functions/Account/RegisterDevice.php        y0      K   taknone/liveproto/src/Tl/Functions/Account/GetContactSignUpNotification.php        F      C   taknone/liveproto/src/Tl/Functions/Account/GetBusinessChatLinks.php        ޴x      A   taknone/liveproto/src/Tl/Functions/Account/GetMultiWallPapers.phpv      v  7      L   taknone/liveproto/src/Tl/Functions/Account/ToggleNoPaidMessagesException.php        ܤ      E   taknone/liveproto/src/Tl/Functions/Account/GetRecentEmojiStatuses.phpD      D         C   taknone/liveproto/src/Tl/Functions/Account/ConfirmBotConnection.phpB      B  ̊      B   taknone/liveproto/src/Tl/Functions/Account/SendChangePhoneCode.php        I      K   taknone/liveproto/src/Tl/Functions/Account/GetDefaultProfilePhotoEmojis.php?      ?        B   taknone/liveproto/src/Tl/Functions/Account/AcceptAuthorization.php        O      ;   taknone/liveproto/src/Tl/Functions/Account/ConfirmPhone.php        9\Ф      A   taknone/liveproto/src/Tl/Functions/Account/ResetAuthorization.php0      0  |u[      ;   taknone/liveproto/src/Tl/Functions/Account/InstallTheme.phpm      m  Bs      J   taknone/liveproto/src/Tl/Functions/Account/GetCollectibleEmojiStatuses.phpJ      J  .      @   taknone/liveproto/src/Tl/Functions/Account/SetMainProfileTab.php7      7        ?   taknone/liveproto/src/Tl/Functions/Account/GetConnectedBots.php        au      @   taknone/liveproto/src/Tl/Functions/Account/UpdateEmojiStatus.phpS      S  |/ʤ      B   taknone/liveproto/src/Tl/Functions/Account/UpdateBusinessIntro.php        q      D   taknone/liveproto/src/Tl/Functions/Account/ResetWebAuthorization.php3      3  LM      I   taknone/liveproto/src/Tl/Functions/Account/GetDefaultGroupPhotoEmojis.php=      =  c      8   taknone/liveproto/src/Tl/Functions/Account/GetThemes.phpn      n  ?      9   taknone/liveproto/src/Tl/Functions/Account/GetPrivacy.phpE      E  HT      =   taknone/liveproto/src/Tl/Functions/Account/GetSecureValue.phpg      g  Q      L   taknone/liveproto/src/Tl/Functions/Account/UpdateBusinessGreetingMessage.php        1W      ?   taknone/liveproto/src/Tl/Functions/Account/GetSavedMusicIds.php?      ?  'x>      C   taknone/liveproto/src/Tl/Functions/Account/FinishTakeoutSession.phpz      z  uT      H   taknone/liveproto/src/Tl/Functions/Account/UpdateBusinessAwayMessage.php        $H      F   taknone/liveproto/src/Tl/Functions/Account/InitPasskeyRegistration.php$      $  .-      >   taknone/liveproto/src/Tl/Functions/Account/RegisterPasskey.phpY      Y  "tI      O   taknone/liveproto/src/Tl/Functions/Account/GetChannelRestrictedStatusEmojis.phpC      C  a.D      G   taknone/liveproto/src/Tl/Functions/Account/SaveAutoDownloadSettings.php	      	  
K      A   taknone/liveproto/src/Tl/Functions/Account/ReportProfilePhoto.php        )      G   taknone/liveproto/src/Tl/Functions/Account/UpdateWebBrowserSettings.php3      3  ";l      K   taknone/liveproto/src/Tl/Functions/Account/SetContactSignUpNotification.phpA      A  㲤      :   taknone/liveproto/src/Tl/Functions/Account/UpdateColor.php          |7      :   taknone/liveproto/src/Tl/Functions/Account/GetPasskeys.php        yn      :   taknone/liveproto/src/Tl/Functions/Account/GetPassword.php        @      8   taknone/liveproto/src/Tl/Functions/Account/SaveTheme.phpm      m  !4g      C   taknone/liveproto/src/Tl/Functions/Account/GetAuthorizationForm.php        x[ݤ      B   taknone/liveproto/src/Tl/Functions/Account/GetPasswordSettings.phpg      g  ph      I   taknone/liveproto/src/Tl/Functions/Account/GetDefaultBackgroundEmojis.php=      =  o9      B   taknone/liveproto/src/Tl/Functions/Account/CancelPasswordEmail.php        #yĤ      I   taknone/liveproto/src/Tl/Functions/Account/GetReactionsNotifySettings.php        $P      G   taknone/liveproto/src/Tl/Functions/Account/GetBotBusinessConnection.phpZ      Z  u9      F   taknone/liveproto/src/Tl/Functions/Account/GetUniqueGiftChatThemes.php        KM      P   taknone/liveproto/src/Tl/Functions/Account/ToggleWebBrowserSettingsException.php        a^      <   taknone/liveproto/src/Tl/Functions/Account/ResetPassword.php        iǤ      ;   taknone/liveproto/src/Tl/Functions/Account/GetWallPaper.phpM      M  or      <   taknone/liveproto/src/Tl/Functions/Account/GetWallPapers.php8      8  n      @   taknone/liveproto/src/Tl/Functions/Account/GetAuthorizations.php        KQ2ۤ      D   taknone/liveproto/src/Tl/Functions/Account/GetWebBrowserSettings.phpI      I  򔚙      =   taknone/liveproto/src/Tl/Functions/Account/GetTmpPassword.php        :1ߤ      <   taknone/liveproto/src/Tl/Functions/Updates/GetDifference.php        ;З      7   taknone/liveproto/src/Tl/Functions/Updates/GetState.php          =      C   taknone/liveproto/src/Tl/Functions/Updates/GetChannelDifference.phpz      z  *_|      ?   taknone/liveproto/src/Tl/Functions/Smsjobs/IsEligibleToJoin.php        &      8   taknone/liveproto/src/Tl/Functions/Smsjobs/GetSmsJob.php5      5  H      8   taknone/liveproto/src/Tl/Functions/Smsjobs/GetStatus.php         	      4   taknone/liveproto/src/Tl/Functions/Smsjobs/Leave.php        ⧤      3   taknone/liveproto/src/Tl/Functions/Smsjobs/Join.php              8   taknone/liveproto/src/Tl/Functions/Smsjobs/FinishJob.php        $o      =   taknone/liveproto/src/Tl/Functions/Smsjobs/UpdateSettings.php        Lf      9   taknone/liveproto/src/Tl/Functions/Premium/ApplyBoost.php        F      >   taknone/liveproto/src/Tl/Functions/Premium/GetBoostsStatus.phpF      F  K[      <   taknone/liveproto/src/Tl/Functions/Premium/GetBoostsList.php%      %  $      <   taknone/liveproto/src/Tl/Functions/Premium/GetUserBoosts.php        _G      :   taknone/liveproto/src/Tl/Functions/Premium/GetMyBoosts.php        sGV(      :   taknone/liveproto/src/Tl/Functions/Phone/JoinGroupCall.php        ߎv      ;   taknone/liveproto/src/Tl/Functions/Phone/LeaveGroupCall.phpq      q  x^      O   taknone/liveproto/src/Tl/Functions/Phone/DeleteGroupCallParticipantMessages.php%      %        G   taknone/liveproto/src/Tl/Functions/Phone/SaveDefaultGroupCallJoinAs.php        ݬ      L   taknone/liveproto/src/Tl/Functions/Phone/InviteConferenceCallParticipant.php        %qI      :   taknone/liveproto/src/Tl/Functions/Phone/SaveCallDebug.phpu      u  {PA      A   taknone/liveproto/src/Tl/Functions/Phone/CreateConferenceCall.phpb      b  au      8   taknone/liveproto/src/Tl/Functions/Phone/DiscardCall.php        )}      D   taknone/liveproto/src/Tl/Functions/Phone/ToggleGroupCallSettings.phpX      X  ,      H   taknone/liveproto/src/Tl/Functions/Phone/DeclineConferenceCallInvite.php>      >  8x5      9   taknone/liveproto/src/Tl/Functions/Phone/ReceivedCall.php7      7  +ˤ      M   taknone/liveproto/src/Tl/Functions/Phone/ToggleGroupCallStartSubscription.php        }B$      :   taknone/liveproto/src/Tl/Functions/Phone/GetCallConfig.php        "K      A   taknone/liveproto/src/Tl/Functions/Phone/SendGroupCallMessage.phpu      u  ޤ      D   taknone/liveproto/src/Tl/Functions/Phone/StartScheduledGroupCall.phpE      E  (yW      G   taknone/liveproto/src/Tl/Functions/Phone/LeaveGroupCallPresentation.phpH      H  .]ʤ      7   taknone/liveproto/src/Tl/Functions/Phone/AcceptCall.php        'դ      H   taknone/liveproto/src/Tl/Functions/Phone/SendConferenceCallBroadcast.php        F      A   taknone/liveproto/src/Tl/Functions/Phone/GetGroupParticipants.phpW      W  OLU      D   taknone/liveproto/src/Tl/Functions/Phone/DeleteGroupCallMessages.php        *      J   taknone/liveproto/src/Tl/Functions/Phone/SendGroupCallEncryptedMessage.php        {X      8   taknone/liveproto/src/Tl/Functions/Phone/SaveCallLog.phpq      q  (      G   taknone/liveproto/src/Tl/Functions/Phone/GetGroupCallStreamChannels.php^      ^  .'      M   taknone/liveproto/src/Tl/Functions/Phone/DeleteConferenceCallParticipants.php        ԾT1      ;   taknone/liveproto/src/Tl/Functions/Phone/CheckGroupCall.php              F   taknone/liveproto/src/Tl/Functions/Phone/JoinGroupCallPresentation.php        _ŉ      D   taknone/liveproto/src/Tl/Functions/Phone/GetGroupCallChainBlocks.php        <      =   taknone/liveproto/src/Tl/Functions/Phone/DiscardGroupCall.php>      >  n5L      >   taknone/liveproto/src/Tl/Functions/Phone/SendSignalingData.phpr      r  Zä      ?   taknone/liveproto/src/Tl/Functions/Phone/EditGroupCallTitle.phpz      z  >       <   taknone/liveproto/src/Tl/Functions/Phone/CreateGroupCall.phpY      Y  zP       >   taknone/liveproto/src/Tl/Functions/Phone/GetGroupCallStars.phpL      L  8      :   taknone/liveproto/src/Tl/Functions/Phone/SetCallRating.phpA      A  ˦      >   taknone/liveproto/src/Tl/Functions/Phone/SaveDefaultSendAs.php        ]l      9   taknone/liveproto/src/Tl/Functions/Phone/GetGroupCall.phps      s  hO      8   taknone/liveproto/src/Tl/Functions/Phone/ConfirmCall.php        j^      >   taknone/liveproto/src/Tl/Functions/Phone/InviteToGroupCall.php        4      F   taknone/liveproto/src/Tl/Functions/Phone/GetGroupCallStreamRtmpUrl.php        _k      ?   taknone/liveproto/src/Tl/Functions/Phone/GetGroupCallJoinAs.phpE      E  NǤ      B   taknone/liveproto/src/Tl/Functions/Phone/ToggleGroupCallRecord.phpd      d  ff]x      8   taknone/liveproto/src/Tl/Functions/Phone/RequestCall.php        bw      E   taknone/liveproto/src/Tl/Functions/Phone/EditGroupCallParticipant.php	      	  Ǥ      B   taknone/liveproto/src/Tl/Functions/Phone/ExportGroupCallInvite.php        )      ;   taknone/liveproto/src/Tl/Functions/Aicompose/CreateTone.phpD      D  K      8   taknone/liveproto/src/Tl/Functions/Aicompose/GetTone.phpE      E  J       9   taknone/liveproto/src/Tl/Functions/Aicompose/SaveTone.phps      s  Ѥ      ?   taknone/liveproto/src/Tl/Functions/Aicompose/GetToneExample.php}      }        ;   taknone/liveproto/src/Tl/Functions/Aicompose/UpdateTone.php#      #  9      ;   taknone/liveproto/src/Tl/Functions/Aicompose/DeleteTone.php=      =  b      9   taknone/liveproto/src/Tl/Functions/Aicompose/GetTones.php3      3        8   taknone/liveproto/src/Tl/Functions/Upload/GetWebFile.php              =   taknone/liveproto/src/Tl/Functions/Upload/SaveBigFilePart.php        \      ;   taknone/liveproto/src/Tl/Functions/Upload/GetFileHashes.php        "B      :   taknone/liveproto/src/Tl/Functions/Upload/SaveFilePart.php        m      >   taknone/liveproto/src/Tl/Functions/Upload/GetCdnFileHashes.php              5   taknone/liveproto/src/Tl/Functions/Upload/GetFile.php         E      8   taknone/liveproto/src/Tl/Functions/Upload/GetCdnFile.php              =   taknone/liveproto/src/Tl/Functions/Upload/ReuploadCdnFile.php        'l      =   taknone/liveproto/src/Tl/Functions/Langpack/GetDifference.php        +      ;   taknone/liveproto/src/Tl/Functions/Langpack/GetLangPack.php        Ⱦ      :   taknone/liveproto/src/Tl/Functions/Langpack/GetStrings.php        ,:k      <   taknone/liveproto/src/Tl/Functions/Langpack/GetLanguages.phpT      T  <դ      ;   taknone/liveproto/src/Tl/Functions/Langpack/GetLanguage.php        j      >   taknone/liveproto/src/Tl/Functions/Other/InvokeWithTakeout.phpr      r  qPV      A   taknone/liveproto/src/Tl/Functions/Other/InvokeWithoutUpdates.php2      2  NI      D   taknone/liveproto/src/Tl/Functions/Other/InvokeWithMessagesRange.phpv      v  ;%      <   taknone/liveproto/src/Tl/Functions/Other/InvokeAfterMsgs.phpz      z  8i      >   taknone/liveproto/src/Tl/Functions/Other/SetClientDHParams.php        -      ;   taknone/liveproto/src/Tl/Functions/Other/DestroyAuthKey.php        u      @   taknone/liveproto/src/Tl/Functions/Other/InvokeWithReCaptcha.phpk      k  Ϥ      I   taknone/liveproto/src/Tl/Functions/Other/InvokeWithBusinessConnection.php        Am      A   taknone/liveproto/src/Tl/Functions/Other/InvokeWithApnsSecret.php        "      2   taknone/liveproto/src/Tl/Functions/Other/ReqPq.php8      8  &Z      ;   taknone/liveproto/src/Tl/Functions/Other/DestroySession.phpI      I  
FZ      :   taknone/liveproto/src/Tl/Functions/Other/RpcDropAnswer.phpD      D        J   taknone/liveproto/src/Tl/Functions/Other/InvokeWithGooglePlayIntegrity.php        gZ      7   taknone/liveproto/src/Tl/Functions/Other/ReqPqMulti.php=      =  ~      8   taknone/liveproto/src/Tl/Functions/Other/ReqDHParams.php        Ǥ      <   taknone/liveproto/src/Tl/Functions/Other/InvokeWithLayer.php_      _  H8t      ;   taknone/liveproto/src/Tl/Functions/Other/InvokeAfterMsg.phpc      c  5-      @   taknone/liveproto/src/Tl/Functions/Other/PingDelayDisconnect.php        'ڤ      1   taknone/liveproto/src/Tl/Functions/Other/Ping.php)      )  `p      ;   taknone/liveproto/src/Tl/Functions/Other/InitConnection.php        VTT      ;   taknone/liveproto/src/Tl/Functions/Other/GetFutureSalts.php,      ,  V      E   taknone/liveproto/src/Tl/Functions/Stickers/ChangeStickerPosition.php        2q      D   taknone/liveproto/src/Tl/Functions/Stickers/RemoveStickerFromSet.phpY      Y  D      >   taknone/liveproto/src/Tl/Functions/Stickers/ReplaceSticker.php        (2      @   taknone/liveproto/src/Tl/Functions/Stickers/DeleteStickerSet.phpQ      Q  S      @   taknone/liveproto/src/Tl/Functions/Stickers/CreateStickerSet.php        ;r      ?   taknone/liveproto/src/Tl/Functions/Stickers/AddStickerToSet.php        =      @   taknone/liveproto/src/Tl/Functions/Stickers/RenameStickerSet.php        7'
b      B   taknone/liveproto/src/Tl/Functions/Stickers/SetStickerSetThumb.php	      	  )ݤ      @   taknone/liveproto/src/Tl/Functions/Stickers/SuggestShortName.phpO      O  Ƥ      >   taknone/liveproto/src/Tl/Functions/Stickers/CheckShortName.phpE      E  iw      =   taknone/liveproto/src/Tl/Functions/Stickers/ChangeSticker.php        ϳ      ?   taknone/liveproto/src/Tl/Functions/Stories/GetPinnedStories.php        BM      :   taknone/liveproto/src/Tl/Functions/Stories/SearchPosts.php        r      8   taknone/liveproto/src/Tl/Functions/Stories/StartLive.phpQ      Q  8n      @   taknone/liveproto/src/Tl/Functions/Stories/GetStoryViewsList.php        |      =   taknone/liveproto/src/Tl/Functions/Stories/GetChatsToSend.php        ޤ      <   taknone/liveproto/src/Tl/Functions/Stories/DeleteStories.phpx      x  h      @   taknone/liveproto/src/Tl/Functions/Stories/GetStoriesArchive.php        >H      :   taknone/liveproto/src/Tl/Functions/Stories/DeleteAlbum.phpn      n  T      B   taknone/liveproto/src/Tl/Functions/Stories/ActivateStealthMode.php        Vuդ      ;   taknone/liveproto/src/Tl/Functions/Stories/CanSendStory.phpI      I  L
-      >   taknone/liveproto/src/Tl/Functions/Stories/GetStoriesViews.php        8      5   taknone/liveproto/src/Tl/Functions/Stories/Report.php              ;   taknone/liveproto/src/Tl/Functions/Stories/TogglePinned.php        L      ;   taknone/liveproto/src/Tl/Functions/Stories/SendReaction.phpC      C  Ƥ      B   taknone/liveproto/src/Tl/Functions/Stories/IncrementStoryViews.phpw      w  P;      F   taknone/liveproto/src/Tl/Functions/Stories/TogglePeerStoriesHidden.phpw      w  S@      <   taknone/liveproto/src/Tl/Functions/Stories/GetAllStories.phpb      b  ¤      >   taknone/liveproto/src/Tl/Functions/Stories/ExportStoryLink.phpm      m  7D      E   taknone/liveproto/src/Tl/Functions/Stories/ToggleAllStoriesHidden.php;      ;  _h      8   taknone/liveproto/src/Tl/Functions/Stories/EditStory.php	      	  EC      :   taknone/liveproto/src/Tl/Functions/Stories/CreateAlbum.php        3ޤ      <   taknone/liveproto/src/Tl/Functions/Stories/GetPeerMaxIDs.phpQ      Q        8   taknone/liveproto/src/Tl/Functions/Stories/GetAlbums.phpl      l  {U      :   taknone/liveproto/src/Tl/Functions/Stories/UpdateAlbum.php        S.      D   taknone/liveproto/src/Tl/Functions/Stories/GetAllReadPeerStories.php              <   taknone/liveproto/src/Tl/Functions/Stories/ReorderAlbums.phpz      z  I      @   taknone/liveproto/src/Tl/Functions/Stories/TogglePinnedToTop.phpt      t        =   taknone/liveproto/src/Tl/Functions/Stories/GetPeerStories.phpE      E  q#      =   taknone/liveproto/src/Tl/Functions/Stories/GetStoriesByID.php}      }  qcQ0      >   taknone/liveproto/src/Tl/Functions/Stories/GetAlbumStories.php        XhѤ      8   taknone/liveproto/src/Tl/Functions/Stories/SendStory.php
      
  ;      :   taknone/liveproto/src/Tl/Functions/Stories/ReadStories.phpo      o  Fb       D   taknone/liveproto/src/Tl/Functions/Stories/GetStoryReactionsList.php        vPm          taknone/liveproto/src/Tl/All.php+     + ,4zg      &   taknone/liveproto/src/Tl/MTRequest.phpB      B  !      '   taknone/liveproto/src/Tl/Pagination.php        \K      -   taknone/liveproto/src/Tl/Methods/Messages.php>%      >%  *Z]      +   taknone/liveproto/src/Tl/Methods/Inline.php}      }  `,d      +   taknone/liveproto/src/Tl/Methods/Upload.php        9դ      +   taknone/liveproto/src/Tl/Methods/FileId.php(      (  $덤      -   taknone/liveproto/src/Tl/Methods/Download.phpk      k  15?      .   taknone/liveproto/src/Tl/Methods/Utilities.php}      }  $      *   taknone/liveproto/src/Tl/Methods/Peers.php        J      ,   taknone/liveproto/src/Tl/Methods/Account.php6      6  #𿓤      /   taknone/liveproto/src/Tl/Methods/SecretChat.phpCT      CT  DB?      -   taknone/liveproto/src/Tl/Methods/Entities.php0      0  \~,      *   taknone/liveproto/src/Tl/Methods/Media.php`<      `<  /
      ,   taknone/liveproto/src/Tl/Methods/Buttons.phpC      C  [      -   taknone/liveproto/src/Tl/Methods/Channels.php        Pܮڤ      +   taknone/liveproto/src/Tl/Methods/Dialog.php9%      9%  9d      *   taknone/liveproto/src/Tl/Methods/Users.php        i      )   taknone/liveproto/src/Tl/Methods/Auth.phpe      e           taknone/liveproto/Dockerfile        IY         taknone/liveproto/LICENSE        Dq.         taknone/liveproto/SECURITY.md        ?          taknone/liveproto/.gitattributesC       C   $         taknone/liveproto/composer.json        f'         taknone/attributes/README.md        wcO      $   taknone/attributes/src/Common/Is.phpE      E  =      *   taknone/attributes/src/Common/Contains.php        <*      $   taknone/attributes/src/Common/To.php        \-      &   taknone/attributes/src/Common/Func.php)      )  jzɤ      *   taknone/attributes/src/Common/EndsWith.php        _      '   taknone/attributes/src/Common/Range.php        폤      +   taknone/attributes/src/Common/FilterVar.php              &   taknone/attributes/src/Common/Hash.phpy      y  ݦ      ,   taknone/attributes/src/Common/StartsWith.php        ͅؤ      )   taknone/attributes/src/Common/InOrder.php<      <  Ĥ      (   taknone/attributes/src/Common/BindAs.php        N      +   taknone/attributes/src/Common/Operators.php}      }  1^      $   taknone/attributes/src/Common/IP.php        r      $   taknone/attributes/src/Common/In.php              )   taknone/attributes/src/Common/Pattern.phpa      a  td>      &   taknone/attributes/src/Common/Json.php        |      (   taknone/attributes/src/Common/Vector.php}      }  {      )   taknone/attributes/src/Common/Reverse.php        x
      *   taknone/attributes/src/InvokeInterface.php          $      -   taknone/attributes/src/ValidatorInterface.php        B      )   taknone/attributes/src/Return/Iterate.php        7      (   taknone/attributes/src/Return/Result.php        *L      ,   taknone/attributes/src/PropertyInterface.php          sБ      +   taknone/attributes/src/AttributesEngine.php;      ;  Bu      0   taknone/attributes/src/ReturnFilterInterface.php          .nj      '   taknone/attributes/src/Property/Get.php              '   taknone/attributes/src/Property/Set.php        PA"      '   taknone/attributes/src/Invoke/Async.php        p	      '   taknone/attributes/src/Invoke/Cache.php        `      .   taknone/attributes/src/Invoke/IgnoreErrors.php1      1  Ob      (   taknone/attributes/src/Invoke/TimeIt.php        Çw'      (   taknone/attributes/src/Invoke/Repeat.php)      )  C      '   taknone/attributes/src/Invoke/Retry.php        J         taknone/attributes/LICENSE%      %  ĮȄ          taknone/attributes/composer.json        Io      (   taknone/attributes/examples/Test-006.php        ?.ҕ      (   taknone/attributes/examples/Test-007.php        !      (   taknone/attributes/examples/Test-003.php        $      (   taknone/attributes/examples/Test-005.php        o$      (   taknone/attributes/examples/Test-001.php        je      (   taknone/attributes/examples/Test-004.php        G|      (   taknone/attributes/examples/Test-002.php                 taknone/bootstrapper/README.md{       {   "      !   taknone/bootstrapper/src/Util.php        >F      #   taknone/bootstrapper/src/Plugin.php        \7      "   taknone/bootstrapper/src/Tl/api.tl>-     >- .J      '   taknone/bootstrapper/src/Tl/Builder.php        ZQ      )   taknone/bootstrapper/src/Tl/Generator.php9      9  kqu      *   taknone/bootstrapper/src/Tl/DocBuilder.php=      =  s      %   taknone/bootstrapper/src/Tl/secret.tlF#      F#  Sx      &   taknone/bootstrapper/src/Tl/mtproto.tlK      K  Fz]      &   taknone/bootstrapper/src/Parser/Tl.phpO      O  <S      "   taknone/bootstrapper/src/setup.phpN      N  Z٤         taknone/bootstrapper/LICENSE%      %  ĮȄ      #   taknone/bootstrapper/.gitattributes+       +   F      "   taknone/bootstrapper/composer.json        &         composer/autoload_files.php2      2  d6         composer/installed.jsonUR      UR            composer/autoload_namespaces.php          /t         composer/LICENSE.      .            composer/autoload_classmap.php          L         composer/autoload_psr4.phpq      q  c         composer/autoload_real.php                 composer/installed.php        ZBۃ         composer/platform_check.php        [P         composer/autoload_static.php"      "  ̧         composer/ClassLoader.php?      ?  2@u         composer/InstalledVersions.phpC      C  <nw      #   revolt/event-loop/src/EventLoop.php>      >  [`      5   revolt/event-loop/src/EventLoop/UncaughtThrowable.php]      ]  K_      1   revolt/event-loop/src/EventLoop/DriverFactory.php        D0      0   revolt/event-loop/src/EventLoop/CallbackType.php          n/      ?   revolt/event-loop/src/EventLoop/UnsupportedFeatureException.php9      9  Gt      :   revolt/event-loop/src/EventLoop/Internal/ClosureHelper.php#      #  *ꈤ      =   revolt/event-loop/src/EventLoop/Internal/DriverSuspension.php        \o      ;   revolt/event-loop/src/EventLoop/Internal/AbstractDriver.phpT      T  T&u      :   revolt/event-loop/src/EventLoop/Internal/TimerCallback.php        cʤ      C   revolt/event-loop/src/EventLoop/Internal/StreamWritableCallback.php          פ      7   revolt/event-loop/src/EventLoop/Internal/TimerQueue.php        ]UԤ      :   revolt/event-loop/src/EventLoop/Internal/DeferCallback.php          VU      ;   revolt/event-loop/src/EventLoop/Internal/StreamCallback.phpp      p  ;-tW      C   revolt/event-loop/src/EventLoop/Internal/StreamReadableCallback.php          0      ;   revolt/event-loop/src/EventLoop/Internal/DriverCallback.php              ;   revolt/event-loop/src/EventLoop/Internal/SignalCallback.php<      <  ܤ      .   revolt/event-loop/src/EventLoop/FiberLocal.php        H      8   revolt/event-loop/src/EventLoop/InvalidCallbackError.php:      :  BBE      6   revolt/event-loop/src/EventLoop/Driver/EventDriver.phpd      d  &      =   revolt/event-loop/src/EventLoop/Driver/StreamSelectDriver.phpJ/      J/  6.      3   revolt/event-loop/src/EventLoop/Driver/UvDriver.phpG"      G"  l      8   revolt/event-loop/src/EventLoop/Driver/TracingDriver.php        i^      3   revolt/event-loop/src/EventLoop/Driver/EvDriver.php        }37j      *   revolt/event-loop/src/EventLoop/Driver.php(5      (5  M      .   revolt/event-loop/src/EventLoop/Suspension.php                 revolt/event-loop/LICENSE        #         revolt/event-loop/SECURITY.md#      #  ;T3         revolt/event-loop/composer.json        <UX      <?php

// autoload.php @generated by Composer

if (PHP_VERSION_ID < 50600) {
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }
    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
    if (!ini_get('display_errors')) {
        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
            fwrite(STDERR, $err);
        } elseif (!headers_sent()) {
            echo $err;
        }
    }
    throw new RuntimeException($err);
}

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInitb5db464a3f9fc316d41264b8aa61779e::getLoader();
# Constant-Time Encoding

[![Build Status](https://github.com/paragonie/constant_time_encoding/actions/workflows/ci.yml/badge.svg)](https://github.com/paragonie/constant_time_encoding/actions)
[![Static Analysis](https://github.com/paragonie/constant_time_encoding/actions/workflows/psalm.yml/badge.svg)](https://github.com/paragonie/constant_time_encoding/actions)
[![Latest Stable Version](https://poser.pugx.org/paragonie/constant_time_encoding/v/stable)](https://packagist.org/packages/paragonie/constant_time_encoding)
[![Latest Unstable Version](https://poser.pugx.org/paragonie/constant_time_encoding/v/unstable)](https://packagist.org/packages/paragonie/constant_time_encoding)
[![License](https://poser.pugx.org/paragonie/constant_time_encoding/license)](https://packagist.org/packages/paragonie/constant_time_encoding)
[![Downloads](https://img.shields.io/packagist/dt/paragonie/constant_time_encoding.svg)](https://packagist.org/packages/paragonie/constant_time_encoding)

Based on the [constant-time base64 implementation made by Steve "Sc00bz" Thomas](https://github.com/Sc00bz/ConstTimeEncoding),
this library aims to offer character encoding functions that do not leak
information about what you are encoding/decoding via processor cache 
misses. Further reading on [cache-timing attacks](http://blog.ircmaxell.com/2014/11/its-all-about-time.html).

Our fork offers the following enhancements:

* `mbstring.func_overload` resistance
* Unit tests
* Composer- and Packagist-ready
* Base16 encoding
* Base32 encoding
* Uses `pack()` and `unpack()` instead of `chr()` and `ord()`

## PHP Version Requirements

Version 3 of this library should work on **PHP 8** or newer.

Version 2 of this library should work on **PHP 7** or newer. See [the v2.x branch](https://github.com/paragonie/constant_time_encoding/tree/v2.x).

For PHP 5 support, see [the v1.x branch](https://github.com/paragonie/constant_time_encoding/tree/v1.x).

If you are adding this as a dependency to a project intended to work on PHP 5 through 8.4, please set the required version to `^1|^2|^3`.

## How to Install

```sh
composer require paragonie/constant_time_encoding
```

## How to Use

```php
use ParagonIE\ConstantTime\Encoding;

// possibly (if applicable): 
// require 'vendor/autoload.php';

$data = random_bytes(32);
echo Encoding::base64Encode($data), "\n";
echo Encoding::base32EncodeUpper($data), "\n";
echo Encoding::base32Encode($data), "\n";
echo Encoding::hexEncode($data), "\n";
echo Encoding::hexEncodeUpper($data), "\n";
```

Example output:
 
```
1VilPkeVqirlPifk5scbzcTTbMT2clp+Zkyv9VFFasE=
2VMKKPSHSWVCVZJ6E7SONRY3ZXCNG3GE6ZZFU7TGJSX7KUKFNLAQ====
2vmkkpshswvcvzj6e7sonry3zxcng3ge6zzfu7tgjsx7kukfnlaq====
d558a53e4795aa2ae53e27e4e6c71bcdc4d36cc4f6725a7e664caff551456ac1
D558A53E4795AA2AE53E27E4E6C71BDCC4D36CC4F6725A7E664CAFF551456AC1
```

If you only need a particular variant, you can just reference the 
required class like so:

```php
use ParagonIE\ConstantTime\Base64;
use ParagonIE\ConstantTime\Base32;

$data = random_bytes(32);
echo Base64::encode($data), "\n";
echo Base32::encode($data), "\n";
```

Example output:

```
1VilPkeVqirlPifk5scbzcTTbMT2clp+Zkyv9VFFasE=
2vmkkpshswvcvzj6e7sonry3zxcng3ge6zzfu7tgjsx7kukfnlaq====
```

## Support Contracts

If your company uses this library in their products or services, you may be
interested in [purchasing a support contract from Paragon Initiative Enterprises](https://paragonie.com/enterprise).
<?php
declare(strict_types=1);
namespace ParagonIE\ConstantTime;

use SensitiveParameter;
use TypeError;

/**
 *  Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

/**
 * Class RFC4648
 *
 * This class conforms strictly to the RFC
 *
 * @package ParagonIE\ConstantTime
 * @api
 */
abstract class RFC4648
{
    /**
     * RFC 4648 Base64 encoding
     *
     * "foo" -> "Zm9v"
     *
     * @param string $str
     * @return string
     *
     * @throws TypeError
     */
    public static function base64Encode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base64::encode($str);
    }

    /**
     * RFC 4648 Base64 decoding
     *
     * "Zm9v" -> "foo"
     *
     * @param string $str
     * @return string
     *
     * @throws TypeError
     */
    public static function base64Decode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base64::decode($str, true);
    }

    /**
     * RFC 4648 Base64 (URL Safe) encoding
     *
     * "foo" -> "Zm9v"
     *
     * @param string $str
     * @return string
     *
     * @throws TypeError
     */
    public static function base64UrlSafeEncode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base64UrlSafe::encode($str);
    }

    /**
     * RFC 4648 Base64 (URL Safe) decoding
     *
     * "Zm9v" -> "foo"
     *
     * @param string $str
     * @return string
     *
     * @throws TypeError
     */
    public static function base64UrlSafeDecode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base64UrlSafe::decode($str, true);
    }

    /**
     * RFC 4648 Base32 encoding
     *
     * "foo" -> "MZXW6==="
     *
     * @param string $str
     * @return string
     *
     * @throws TypeError
     */
    public static function base32Encode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32::encodeUpper($str);
    }

    /**
     * RFC 4648 Base32 encoding
     *
     * "MZXW6===" -> "foo"
     *
     * @param string $str
     * @return string
     *
     * @throws TypeError
     */
    public static function base32Decode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32::decodeUpper($str, true);
    }

    /**
     * RFC 4648 Base32-Hex encoding
     *
     * "foo" -> "CPNMU==="
     *
     * @param string $str
     * @return string
     *
     * @throws TypeError
     */
    public static function base32HexEncode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32::encodeUpper($str);
    }

    /**
     * RFC 4648 Base32-Hex decoding
     *
     * "CPNMU===" -> "foo"
     *
     * @param string $str
     * @return string
     *
     * @throws TypeError
     */
    public static function base32HexDecode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32::decodeUpper($str, true);
    }

    /**
     * RFC 4648 Base16 decoding
     *
     * "foo" -> "666F6F"
     *
     * @param string $str
     * @return string
     *
     * @throws TypeError
     */
    public static function base16Encode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Hex::encodeUpper($str);
    }

    /**
     * RFC 4648 Base16 decoding
     *
     * "666F6F" -> "foo"
     *
     * @param string $str
     * @return string
     */
    public static function base16Decode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Hex::decode($str, true);
    }
}
<?php
declare(strict_types=1);
namespace ParagonIE\ConstantTime;

use Override;
use function pack;

/**
 *  Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

/**
 * Class Base32Hex
 * [0-9][A-V]
 *
 * @package ParagonIE\ConstantTime
 */
abstract class Base32Hex extends Base32
{
    /**
     * Uses bitwise operators instead of table-lookups to turn 5-bit integers
     * into 8-bit integers.
     *
     * @param int $src
     * @return int
     */
    #[Override]
    protected static function decode5Bits(int $src): int
    {
        $ret = -1;

        // if ($src > 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47
        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src - 47);

        // if ($src > 0x60 && $src < 0x77) ret += $src - 0x61 + 10 + 1; // -86
        $ret += (((0x60 - $src) & ($src - 0x77)) >> 8) & ($src - 86);

        return $ret;
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 5-bit integers
     * into 8-bit integers.
     *
     * @param int $src
     * @return int
     */
    #[Override]
    protected static function decode5BitsUpper(int $src): int
    {
        $ret = -1;

        // if ($src > 0x30 && $src < 0x3a) ret += $src - 0x2e + 1; // -47
        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src - 47);

        // if ($src > 0x40 && $src < 0x57) ret += $src - 0x41 + 10 + 1; // -54
        $ret += (((0x40 - $src) & ($src - 0x57)) >> 8) & ($src - 54);

        return $ret;
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
     * into 5-bit integers.
     *
     * @param int $src
     * @return string
     */
    #[Override]
    protected static function encode5Bits(int $src): string
    {
        $src += 0x30;

        // if ($src > 0x39) $src += 0x61 - 0x3a; // 39
        $src += ((0x39 - $src) >> 8) & 39;

        return pack('C', $src);
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
     * into 5-bit integers.
     *
     * Uppercase variant.
     *
     * @param int $src
     * @return string
     */
    #[Override]
    protected static function encode5BitsUpper(int $src): string
    {
        $src += 0x30;

        // if ($src > 0x39) $src += 0x41 - 0x3a; // 7
        $src += ((0x39 - $src) >> 8) & 7;

        return pack('C', $src);
    }
}<?php
declare(strict_types=1);
namespace ParagonIE\ConstantTime;

use SensitiveParameter;
use TypeError;
use function strlen;
use function substr;

/**
 *  Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

/**
 * Class Binary
 *
 * Binary string operators that don't choke on
 * mbstring.func_overload
 *
 * @package ParagonIE\ConstantTime
 */
abstract class Binary
{
    /**
     * Safe string length
     *
     * @ref mbstring.func_overload
     *
     * @param string $str
     * @return int
     */
    public static function safeStrlen(
        #[SensitiveParameter]
        string $str
    ): int {
        return strlen($str);
    }

    /**
     * Safe substring
     *
     * @ref mbstring.func_overload
     *
     * @staticvar boolean $exists
     * @param string $str
     * @param int $start
     * @param ?int $length
     * @return string
     *
     * @throws TypeError
     */
    public static function safeSubstr(
        #[SensitiveParameter]
        string $str,
        int $start = 0,
        ?int $length = null
    ): string {
        if ($length === 0) {
            return '';
        }
        // Unlike mb_substr(), substr() doesn't accept NULL for length
        if ($length !== null) {
            return substr($str, $start, $length);
        } else {
            return substr($str, $start);
        }
    }
}
<?php
declare(strict_types=1);
namespace ParagonIE\ConstantTime;

use Override;

/**
 *  Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

/**
 * Class Base64UrlSafe
 * [A-Z][a-z][0-9]\-_
 *
 * @package ParagonIE\ConstantTime
 */
abstract class Base64UrlSafe extends Base64
{

    /**
     * Uses bitwise operators instead of table-lookups to turn 6-bit integers
     * into 8-bit integers.
     *
     * Base64 character set:
     * [A-Z]      [a-z]      [0-9]      -     _
     * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2d, 0x5f
     *
     * @param int $src
     * @return int
     */
    #[Override]
    protected static function decode6Bits(int $src): int
    {
        $ret = -1;

        // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);

        // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);

        // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);

        // if ($src == 0x2c) $ret += 62 + 1;
        $ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63;

        // if ($src == 0x5f) ret += 63 + 1;
        $ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64;

        return $ret;
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
     * into 6-bit integers.
     *
     * @param int $src
     * @return string
     */
    #[Override]
    protected static function encode6Bits(int $src): string
    {
        $diff = 0x41;

        // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
        $diff += ((25 - $src) >> 8) & 6;

        // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
        $diff -= ((51 - $src) >> 8) & 75;

        // if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13
        $diff -= ((61 - $src) >> 8) & 13;

        // if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3
        $diff += ((62 - $src) >> 8) & 49;

        return \pack('C', $src + $diff);
    }
}
<?php
declare(strict_types=1);
namespace ParagonIE\ConstantTime;

use InvalidArgumentException;
use Override;
use RangeException;
use SensitiveParameter;
use TypeError;
use function pack;
use function rtrim;
use function strlen;
use function substr;
use function unpack;

/**
 *  Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

/**
 * Class Base32
 * [A-Z][2-7]
 *
 * @package ParagonIE\ConstantTime
 */
abstract class Base32 implements EncoderInterface
{
    /**
     * Decode a Base32-encoded string into raw binary
     *
     * @param string $encodedString
     * @param bool $strictPadding
     * @return string
     */
    #[Override]
    public static function decode(
        #[SensitiveParameter]
        string $encodedString,
        bool $strictPadding = false
    ): string {
        return static::doDecode($encodedString, false, $strictPadding);
    }

    /**
     * Decode an uppercase Base32-encoded string into raw binary
     *
     * @param string $src
     * @param bool $strictPadding
     * @return string
     */
    public static function decodeUpper(
        #[SensitiveParameter]
        string $src,
        bool $strictPadding = false
    ): string {
        return static::doDecode($src, true, $strictPadding);
    }

    /**
     * Encode into Base32 (RFC 4648)
     *
     * @param string $binString
     * @return string
     * @throws TypeError
     */
    #[Override]
    public static function encode(
        #[SensitiveParameter]
        string $binString
    ): string {
        return static::doEncode($binString, false, true);
    }

    /**
     * Encode into Base32 (RFC 4648)
     *
     * @param string $src
     * @return string
     * @throws TypeError
     * @api
     */
    public static function encodeUnpadded(
        #[SensitiveParameter]
        string $src
    ): string {
        return static::doEncode($src, false, false);
    }

    /**
     * Encode into uppercase Base32 (RFC 4648)
     *
     * @param string $src
     * @return string
     * @throws TypeError
     * @api
     */
    public static function encodeUpper(
        #[SensitiveParameter]
        string $src
    ): string {
        return static::doEncode($src, true, true);
    }

    /**
     * Encode into uppercase Base32 (RFC 4648)
     *
     * @param string $src
     * @return string
     * @throws TypeError
     * @api
     */
    public static function encodeUpperUnpadded(
        #[SensitiveParameter]
        string $src
    ): string {
        return static::doEncode($src, true, false);
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 5-bit integers
     * into 8-bit integers.
     *
     * @param int $src
     * @return int
     * @api
     */
    protected static function decode5Bits(int $src): int
    {
        $ret = -1;

        // if ($src > 96 && $src < 123) $ret += $src - 97 + 1; // -64
        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 96);

        // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23
        $ret += (((0x31 - $src) & ($src - 0x38)) >> 8) & ($src - 23);

        return $ret;
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 5-bit integers
     * into 8-bit integers.
     *
     * Uppercase variant.
     *
     * @param int $src
     * @return int
     * @api
     */
    protected static function decode5BitsUpper(int $src): int
    {
        $ret = -1;

        // if ($src > 64 && $src < 91) $ret += $src - 65 + 1; // -64
        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);

        // if ($src > 0x31 && $src < 0x38) $ret += $src - 24 + 1; // -23
        $ret += (((0x31 - $src) & ($src - 0x38)) >> 8) & ($src - 23);

        return $ret;
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
     * into 5-bit integers.
     *
     * @param int $src
     * @return string
     * @api
     */
    protected static function encode5Bits(int $src): string
    {
        $diff = 0x61;

        // if ($src > 25) $ret -= 72;
        $diff -= ((25 - $src) >> 8) & 73;

        return pack('C', $src + $diff);
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
     * into 5-bit integers.
     *
     * Uppercase variant.
     *
     * @param int $src
     * @return string
     * @api
     */
    protected static function encode5BitsUpper(int $src): string
    {
        $diff = 0x41;

        // if ($src > 25) $ret -= 40;
        $diff -= ((25 - $src) >> 8) & 41;

        return pack('C', $src + $diff);
    }

    /**
     * @param string $encodedString
     * @param bool $upper
     * @return string
     * @api
     */
    public static function decodeNoPadding(
        #[SensitiveParameter]
        string $encodedString,
        bool $upper = false
    ): string {
        $srcLen = strlen($encodedString);
        if ($srcLen === 0) {
            return '';
        }
        if (($srcLen & 7) === 0) {
            for ($j = 0; $j < 7 && $j < $srcLen; ++$j) {
                if ($encodedString[$srcLen - $j - 1] === '=') {
                    throw new InvalidArgumentException(
                        "decodeNoPadding() doesn't tolerate padding"
                    );
                }
            }
        }
        return static::doDecode(
            $encodedString,
            $upper,
            true
        );
    }

    /**
     * Base32 decoding
     *
     * @param string $src
     * @param bool $upper
     * @param bool $strictPadding
     * @return string
     *
     * @throws TypeError
     */
    protected static function doDecode(
        #[SensitiveParameter]
        string $src,
        bool $upper = false,
        bool $strictPadding = false
    ): string {
        // We do this to reduce code duplication:
        $method = $upper
            ? 'decode5BitsUpper'
            : 'decode5Bits';

        // Remove padding
        $srcLen = strlen($src);
        if ($srcLen === 0) {
            return '';
        }
        if ($strictPadding) {
            if (($srcLen & 7) === 0) {
                for ($j = 0; $j < 7; ++$j) {
                    if ($src[$srcLen - 1] === '=') {
                        $srcLen--;
                    } else {
                        break;
                    }
                }
            }
            if (($srcLen & 7) === 1) {
                throw new RangeException(
                    'Incorrect padding'
                );
            }
        } else {
            $src = rtrim($src, '=');
            $srcLen = strlen($src);
        }

        $err = 0;
        $dest = '';
        // Main loop (no padding):
        for ($i = 0; $i + 8 <= $srcLen; $i += 8) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', substr($src, $i, 8));
            /** @var int $c0 */
            $c0 = static::$method($chunk[1]);
            /** @var int $c1 */
            $c1 = static::$method($chunk[2]);
            /** @var int $c2 */
            $c2 = static::$method($chunk[3]);
            /** @var int $c3 */
            $c3 = static::$method($chunk[4]);
            /** @var int $c4 */
            $c4 = static::$method($chunk[5]);
            /** @var int $c5 */
            $c5 = static::$method($chunk[6]);
            /** @var int $c6 */
            $c6 = static::$method($chunk[7]);
            /** @var int $c7 */
            $c7 = static::$method($chunk[8]);

            $dest .= pack(
                'CCCCC',
                (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
                (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
                (($c3 << 4) | ($c4 >> 1)             ) & 0xff,
                (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff,
                (($c6 << 5) | ($c7     )             ) & 0xff
            );
            $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6 | $c7) >> 8;
        }
        // The last chunk, which may have padding:
        if ($i < $srcLen) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', substr($src, $i, $srcLen - $i));
            /** @var int $c0 */
            $c0 = static::$method($chunk[1]);

            if ($i + 6 < $srcLen) {
                /** @var int $c1 */
                $c1 = static::$method($chunk[2]);
                /** @var int $c2 */
                $c2 = static::$method($chunk[3]);
                /** @var int $c3 */
                $c3 = static::$method($chunk[4]);
                /** @var int $c4 */
                $c4 = static::$method($chunk[5]);
                /** @var int $c5 */
                $c5 = static::$method($chunk[6]);
                /** @var int $c6 */
                $c6 = static::$method($chunk[7]);

                $dest .= pack(
                    'CCCC',
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
                    (($c3 << 4) | ($c4 >> 1)             ) & 0xff,
                    (($c4 << 7) | ($c5 << 2) | ($c6 >> 3)) & 0xff
                );
                $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5 | $c6) >> 8;
                if ($strictPadding) {
                    $err |= ($c6 << 5) & 0xff;
                }
            } elseif ($i + 5 < $srcLen) {
                /** @var int $c1 */
                $c1 = static::$method($chunk[2]);
                /** @var int $c2 */
                $c2 = static::$method($chunk[3]);
                /** @var int $c3 */
                $c3 = static::$method($chunk[4]);
                /** @var int $c4 */
                $c4 = static::$method($chunk[5]);
                /** @var int $c5 */
                $c5 = static::$method($chunk[6]);

                $dest .= pack(
                    'CCCC',
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
                    (($c3 << 4) | ($c4 >> 1)             ) & 0xff,
                    (($c4 << 7) | ($c5 << 2)             ) & 0xff
                );
                $err |= ($c0 | $c1 | $c2 | $c3 | $c4 | $c5) >> 8;
            } elseif ($i + 4 < $srcLen) {
                /** @var int $c1 */
                $c1 = static::$method($chunk[2]);
                /** @var int $c2 */
                $c2 = static::$method($chunk[3]);
                /** @var int $c3 */
                $c3 = static::$method($chunk[4]);
                /** @var int $c4 */
                $c4 = static::$method($chunk[5]);

                $dest .= pack(
                    'CCC',
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff,
                    (($c3 << 4) | ($c4 >> 1)             ) & 0xff
                );
                $err |= ($c0 | $c1 | $c2 | $c3 | $c4) >> 8;
                if ($strictPadding) {
                    $err |= ($c4 << 7) & 0xff;
                }
            } elseif ($i + 3 < $srcLen) {
                /** @var int $c1 */
                $c1 = static::$method($chunk[2]);
                /** @var int $c2 */
                $c2 = static::$method($chunk[3]);
                /** @var int $c3 */
                $c3 = static::$method($chunk[4]);

                $dest .= pack(
                    'CC',
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
                    (($c1 << 6) | ($c2 << 1) | ($c3 >> 4)) & 0xff
                );
                $err |= ($c0 | $c1 | $c2 | $c3) >> 8;
                if ($strictPadding) {
                    $err |= ($c3 << 4) & 0xff;
                }
            } elseif ($i + 2 < $srcLen) {
                /** @var int $c1 */
                $c1 = static::$method($chunk[2]);
                /** @var int $c2 */
                $c2 = static::$method($chunk[3]);

                $dest .= pack(
                    'CC',
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff,
                    (($c1 << 6) | ($c2 << 1)             ) & 0xff
                );
                $err |= ($c0 | $c1 | $c2) >> 8;
                if ($strictPadding) {
                    $err |= ($c2 << 6) & 0xff;
                }
            } elseif ($i + 1 < $srcLen) {
                /** @var int $c1 */
                $c1 = static::$method($chunk[2]);

                $dest .= pack(
                    'C',
                    (($c0 << 3) | ($c1 >> 2)             ) & 0xff
                );
                $err |= ($c0 | $c1) >> 8;
                if ($strictPadding) {
                    $err |= ($c1 << 6) & 0xff;
                }
            } else {
                $dest .= pack(
                    'C',
                    (($c0 << 3)                          ) & 0xff
                );
                $err |= ($c0) >> 8;
            }
        }
        $check = ($err === 0);
        if (!$check) {
            throw new RangeException(
                'Base32::doDecode() only expects characters in the correct base32 alphabet'
            );
        }
        return $dest;
    }

    /**
     * Base32 Encoding
     *
     * @param string $src
     * @param bool $upper
     * @param bool $pad
     * @return string
     * @throws TypeError
     */
    protected static function doEncode(
        #[SensitiveParameter]
        string $src,
        bool $upper = false,
        bool $pad = true
    ): string {
        // We do this to reduce code duplication:
        $method = $upper
            ? 'encode5BitsUpper'
            : 'encode5Bits';
        
        $dest = '';
        $srcLen = strlen($src);

        // Main loop (no padding):
        for ($i = 0; $i + 5 <= $srcLen; $i += 5) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', substr($src, $i, 5));
            $b0 = $chunk[1];
            $b1 = $chunk[2];
            $b2 = $chunk[3];
            $b3 = $chunk[4];
            $b4 = $chunk[5];
            $dest .=
                static::$method(              ($b0 >> 3)  & 31) .
                static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
                static::$method((($b1 >> 1)             ) & 31) .
                static::$method((($b1 << 4) | ($b2 >> 4)) & 31) .
                static::$method((($b2 << 1) | ($b3 >> 7)) & 31) .
                static::$method((($b3 >> 2)             ) & 31) .
                static::$method((($b3 << 3) | ($b4 >> 5)) & 31) .
                static::$method(  $b4                     & 31);
        }
        // The last chunk, which may have padding:
        if ($i < $srcLen) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', substr($src, $i, $srcLen - $i));
            $b0 = $chunk[1];
            if ($i + 3 < $srcLen) {
                $b1 = $chunk[2];
                $b2 = $chunk[3];
                $b3 = $chunk[4];
                $dest .=
                    static::$method(              ($b0 >> 3)  & 31) .
                    static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
                    static::$method((($b1 >> 1)             ) & 31) .
                    static::$method((($b1 << 4) | ($b2 >> 4)) & 31) .
                    static::$method((($b2 << 1) | ($b3 >> 7)) & 31) .
                    static::$method((($b3 >> 2)             ) & 31) .
                    static::$method((($b3 << 3)             ) & 31);
                if ($pad) {
                    $dest .= '=';
                }
            } elseif ($i + 2 < $srcLen) {
                $b1 = $chunk[2];
                $b2 = $chunk[3];
                $dest .=
                    static::$method(              ($b0 >> 3)  & 31) .
                    static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
                    static::$method((($b1 >> 1)             ) & 31) .
                    static::$method((($b1 << 4) | ($b2 >> 4)) & 31) .
                    static::$method((($b2 << 1)             ) & 31);
                if ($pad) {
                    $dest .= '===';
                }
            } elseif ($i + 1 < $srcLen) {
                $b1 = $chunk[2];
                $dest .=
                    static::$method(              ($b0 >> 3)  & 31) .
                    static::$method((($b0 << 2) | ($b1 >> 6)) & 31) .
                    static::$method((($b1 >> 1)             ) & 31) .
                    static::$method((($b1 << 4)             ) & 31);
                if ($pad) {
                    $dest .= '====';
                }
            } else {
                $dest .=
                    static::$method(              ($b0 >> 3)  & 31) .
                    static::$method( ($b0 << 2)               & 31);
                if ($pad) {
                    $dest .= '======';
                }
            }
        }
        return $dest;
    }
}
<?php
declare(strict_types=1);
namespace ParagonIE\ConstantTime;

use Override;
use RangeException;
use SensitiveParameter;
use SodiumException;
use TypeError;
use function extension_loaded;
use function pack;
use function sodium_bin2hex;
use function sodium_hex2bin;
use function strlen;
use function unpack;

/**
 *  Copyright (c) 2016 - 2025 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

/**
 * Class Hex
 * @package ParagonIE\ConstantTime
 */
abstract class Hex implements EncoderInterface
{
    /**
     * Convert a binary string into a hexadecimal string without cache-timing
     * leaks
     *
     * @param string $binString (raw binary)
     * @return string
     * @throws TypeError
     */
    #[Override]
    public static function encode(
        #[SensitiveParameter]
        string $binString
    ): string {
        if (extension_loaded('sodium')) {
            try {
                return sodium_bin2hex($binString);
            } catch (SodiumException $ex) {
                throw new RangeException($ex->getMessage(), $ex->getCode(), $ex);
            }
        }
        $hex = '';
        $len = strlen($binString);
        for ($i = 0; $i < $len; ++$i) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C', $binString[$i]);
            $c = $chunk[1] & 0xf;
            $b = $chunk[1] >> 4;

            $hex .= pack(
                'CC',
                (87 + $b + ((($b - 10) >> 8) & ~38)),
                (87 + $c + ((($c - 10) >> 8) & ~38))
            );
        }
        return $hex;
    }

    /**
     * Convert a binary string into a hexadecimal string without cache-timing
     * leaks, returning uppercase letters (as per RFC 4648)
     *
     * @param string $binString (raw binary)
     * @return string
     * @throws TypeError
     */
    public static function encodeUpper(
        #[SensitiveParameter]
        string $binString
    ): string {
        $hex = '';
        $len = strlen($binString);

        for ($i = 0; $i < $len; ++$i) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C', $binString[$i]);
            $c = $chunk[1] & 0xf;
            $b = $chunk[1] >> 4;

            $hex .= pack(
                'CC',
                (55 + $b + ((($b - 10) >> 8) & ~6)),
                (55 + $c + ((($c - 10) >> 8) & ~6))
            );
        }
        return $hex;
    }

    /**
     * Convert a hexadecimal string into a binary string without cache-timing
     * leaks
     *
     * @param string $encodedString
     * @param bool $strictPadding
     * @return string (raw binary)
     * @throws RangeException
     */
    #[Override]
    public static function decode(
        #[SensitiveParameter]
        string $encodedString,
        bool $strictPadding = false
    ): string {
        if (extension_loaded('sodium') && $strictPadding) {
            try {
                return sodium_hex2bin($encodedString);
            } catch (SodiumException $ex) {
                throw new RangeException($ex->getMessage(), $ex->getCode(), $ex);
            }
        }
        $hex_pos = 0;
        $bin = '';
        $c_acc = 0;
        $hex_len = strlen($encodedString);
        $state = 0;
        if (($hex_len & 1) !== 0) {
            if ($strictPadding) {
                throw new RangeException(
                    'Expected an even number of hexadecimal characters'
                );
            } else {
                $encodedString = '0' . $encodedString;
                ++$hex_len;
            }
        }

        /** @var array<int, int> $chunk */
        $chunk = unpack('C*', $encodedString);
        while ($hex_pos < $hex_len) {
            ++$hex_pos;
            $c = $chunk[$hex_pos];
            $c_num = $c ^ 48;
            $c_num0 = ($c_num - 10) >> 8;
            $c_alpha = ($c & ~32) - 55;
            $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8;

            if (($c_num0 | $c_alpha0) === 0) {
                throw new RangeException(
                    'Expected hexadecimal character'
                );
            }
            $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0);
            if ($state === 0) {
                $c_acc = $c_val * 16;
            } else {
                $bin .= pack('C', $c_acc | $c_val);
            }
            $state ^= 1;
        }
        return $bin;
    }
}
<?php
declare(strict_types=1);
namespace ParagonIE\ConstantTime;

use SensitiveParameter;

/**
 *  Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

/**
 * Interface EncoderInterface
 * @package ParagonIE\ConstantTime
 */
interface EncoderInterface
{
    /**
     * Convert a binary string into a hexadecimal string without cache-timing
     * leaks
     *
     * @param string $binString (raw binary)
     * @return string
     */
    public static function encode(
        #[SensitiveParameter]
        string $binString
    ): string;

    /**
     * Convert a binary string into a hexadecimal string without cache-timing
     * leaks
     *
     * @param string $encodedString
     * @param bool $strictPadding Error on invalid padding
     * @return string (raw binary)
     */
    public static function decode(
        #[SensitiveParameter]
        string $encodedString,
        bool $strictPadding = false
    ): string;
}
<?php
declare(strict_types=1);
namespace ParagonIE\ConstantTime;

use InvalidArgumentException;
use Override;
use RangeException;
use SensitiveParameter;
use SodiumException;
use TypeError;
use function extension_loaded;
use function pack;
use function rtrim;
use function sodium_base642bin;
use function sodium_bin2base64;
use function strlen;
use function substr;
use function unpack;
use const SODIUM_BASE64_VARIANT_ORIGINAL;
use const SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING;
use const SODIUM_BASE64_VARIANT_URLSAFE;
use const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING;

/**
 *  Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

/**
 * Class Base64
 * [A-Z][a-z][0-9]+/
 *
 * @package ParagonIE\ConstantTime
 */
abstract class Base64 implements EncoderInterface
{
    /**
     * Encode into Base64
     *
     * Base64 character set "[A-Z][a-z][0-9]+/"
     *
     * @param string $binString
     * @return string
     *
     * @throws TypeError
     */
    #[Override]
    public static function encode(
        #[SensitiveParameter]
        string $binString
    ): string {
        if (extension_loaded('sodium')) {
            $variant = match(static::class) {
                Base64::class => SODIUM_BASE64_VARIANT_ORIGINAL,
                Base64UrlSafe::class => SODIUM_BASE64_VARIANT_URLSAFE,
                default => 0,
            };
            if ($variant > 0) {
                try {
                    return sodium_bin2base64($binString, $variant);
                } catch (SodiumException $ex) {
                    throw new RangeException($ex->getMessage(), $ex->getCode(), $ex);
                }
            }
        }
        return static::doEncode($binString, true);
    }

    /**
     * Encode into Base64, no = padding
     *
     * Base64 character set "[A-Z][a-z][0-9]+/"
     *
     * @param string $src
     * @return string
     *
     * @throws TypeError
     * @api
     */
    public static function encodeUnpadded(
        #[SensitiveParameter]
        string $src
    ): string {
        if (extension_loaded('sodium')) {
            $variant = match(static::class) {
                Base64::class => SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING,
                Base64UrlSafe::class => SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING,
                default => 0,
            };
            if ($variant > 0) {
                try {
                    return sodium_bin2base64($src, $variant);
                } catch (SodiumException $ex) {
                    throw new RangeException($ex->getMessage(), $ex->getCode(), $ex);
                }
            }
        }
        return static::doEncode($src, false);
    }

    /**
     * @param string $src
     * @param bool $pad   Include = padding?
     * @return string
     *
     * @throws TypeError
     */
    protected static function doEncode(
        #[SensitiveParameter]
        string $src,
        bool $pad = true
    ): string {
        $dest = '';
        $srcLen = strlen($src);
        // Main loop (no padding):
        for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', substr($src, $i, 3));
            $b0 = $chunk[1];
            $b1 = $chunk[2];
            $b2 = $chunk[3];

            $dest .=
                static::encode6Bits(               $b0 >> 2       ) .
                static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
                static::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
                static::encode6Bits(  $b2                     & 63);
        }
        // The last chunk, which may have padding:
        if ($i < $srcLen) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', substr($src, $i, $srcLen - $i));
            $b0 = $chunk[1];
            if ($i + 1 < $srcLen) {
                $b1 = $chunk[2];
                $dest .=
                    static::encode6Bits($b0 >> 2) .
                    static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
                    static::encode6Bits(($b1 << 2) & 63);
                if ($pad) {
                    $dest .= '=';
                }
            } else {
                $dest .=
                    static::encode6Bits( $b0 >> 2) .
                    static::encode6Bits(($b0 << 4) & 63);
                if ($pad) {
                    $dest .= '==';
                }
            }
        }
        return $dest;
    }

    /**
     * decode from base64 into binary
     *
     * Base64 character set "./[A-Z][a-z][0-9]"
     *
     * @param string $encodedString
     * @param bool $strictPadding
     * @return string
     *
     * @throws RangeException
     * @throws TypeError
     */
    #[Override]
    public static function decode(
        #[SensitiveParameter]
        string $encodedString,
        bool $strictPadding = false
    ): string {
        // Remove padding
        $srcLen = strlen($encodedString);
        if ($srcLen === 0) {
            return '';
        }

        if ($strictPadding) {
            if (($srcLen & 3) === 0) {
                if ($encodedString[$srcLen - 1] === '=') {
                    $srcLen--;
                    if ($encodedString[$srcLen - 1] === '=') {
                        $srcLen--;
                    }
                }
            }
            if (($srcLen & 3) === 1) {
                throw new RangeException(
                    'Incorrect padding'
                );
            }
            if ($encodedString[$srcLen - 1] === '=') {
                throw new RangeException(
                    'Incorrect padding'
                );
            }
            if (extension_loaded('sodium')) {
                $variant = match(static::class) {
                    Base64::class => SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING,
                    Base64UrlSafe::class => SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING,
                    default => 0,
                };
                if ($variant > 0) {
                    try {
                        return sodium_base642bin(substr($encodedString, 0, $srcLen), $variant);
                    } catch (SodiumException $ex) {
                        throw new RangeException($ex->getMessage(), $ex->getCode(), $ex);
                    }
                }
            }
        } else {
            // Just remove all padding.
            $encodedString = rtrim($encodedString, '=');
            $srcLen = strlen($encodedString);
        }

        $err = 0;
        $dest = '';
        // Main loop (no padding):
        for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', substr($encodedString, $i, 4));
            $c0 = static::decode6Bits($chunk[1]);
            $c1 = static::decode6Bits($chunk[2]);
            $c2 = static::decode6Bits($chunk[3]);
            $c3 = static::decode6Bits($chunk[4]);

            $dest .= pack(
                'CCC',
                ((($c0 << 2) | ($c1 >> 4)) & 0xff),
                ((($c1 << 4) | ($c2 >> 2)) & 0xff),
                ((($c2 << 6) |  $c3      ) & 0xff)
            );
            $err |= ($c0 | $c1 | $c2 | $c3) >> 8;
        }
        // The last chunk, which may have padding:
        if ($i < $srcLen) {
            /** @var array<int, int> $chunk */
            $chunk = unpack('C*', substr($encodedString, $i, $srcLen - $i));
            $c0 = static::decode6Bits($chunk[1]);

            if ($i + 2 < $srcLen) {
                $c1 = static::decode6Bits($chunk[2]);
                $c2 = static::decode6Bits($chunk[3]);
                $dest .= pack(
                    'CC',
                    ((($c0 << 2) | ($c1 >> 4)) & 0xff),
                    ((($c1 << 4) | ($c2 >> 2)) & 0xff)
                );
                $err |= ($c0 | $c1 | $c2) >> 8;
                if ($strictPadding) {
                    $err |= ($c2 << 6) & 0xff;
                }
            } elseif ($i + 1 < $srcLen) {
                $c1 = static::decode6Bits($chunk[2]);
                $dest .= pack(
                    'C',
                    ((($c0 << 2) | ($c1 >> 4)) & 0xff)
                );
                $err |= ($c0 | $c1) >> 8;
                if ($strictPadding) {
                    $err |= ($c1 << 4) & 0xff;
                }
            } elseif ($strictPadding) {
                $err |= 1;
            }
        }
        $check = ($err === 0);
        if (!$check) {
            throw new RangeException(
                'Base64::decode() only expects characters in the correct base64 alphabet'
            );
        }
        return $dest;
    }

    /**
     * @param string $encodedString
     * @return string
     * @api
     */
    public static function decodeNoPadding(
        #[SensitiveParameter]
        string $encodedString
    ): string {
        $srcLen = strlen($encodedString);
        if ($srcLen === 0) {
            return '';
        }
        if (($srcLen & 3) === 0) {
            // If $strLen is not zero, and it is divisible by 4, then it's at least 4.
            if ($encodedString[$srcLen - 1] === '=' || $encodedString[$srcLen - 2] === '=') {
                throw new InvalidArgumentException(
                    "decodeNoPadding() doesn't tolerate padding"
                );
            }
        }
        return static::decode(
            $encodedString,
            true
        );
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 6-bit integers
     * into 8-bit integers.
     *
     * Base64 character set:
     * [A-Z]      [a-z]      [0-9]      +     /
     * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
     *
     * @param int $src
     * @return int
     */
    protected static function decode6Bits(int $src): int
    {
        $ret = -1;

        // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);

        // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);

        // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);

        // if ($src == 0x2b) $ret += 62 + 1;
        $ret += (((0x2a - $src) & ($src - 0x2c)) >> 8) & 63;

        // if ($src == 0x2f) ret += 63 + 1;
        $ret += (((0x2e - $src) & ($src - 0x30)) >> 8) & 64;

        return $ret;
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
     * into 6-bit integers.
     *
     * @param int $src
     * @return string
     */
    protected static function encode6Bits(int $src): string
    {
        $diff = 0x41;

        // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
        $diff += ((25 - $src) >> 8) & 6;

        // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
        $diff -= ((51 - $src) >> 8) & 75;

        // if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15
        $diff -= ((61 - $src) >> 8) & 15;

        // if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3
        $diff += ((62 - $src) >> 8) & 3;

        return pack('C', $src + $diff);
    }
}
<?php
declare(strict_types=1);
namespace ParagonIE\ConstantTime;

use Override;

/**
 *  Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

/**
 * Class Base64DotSlashOrdered
 * ./[0-9][A-Z][a-z]
 *
 * @package ParagonIE\ConstantTime
 */
abstract class Base64DotSlashOrdered extends Base64
{
    /**
     * Uses bitwise operators instead of table-lookups to turn 6-bit integers
     * into 8-bit integers.
     *
     * Base64 character set:
     * [.-9]      [A-Z]      [a-z]
     * 0x2e-0x39, 0x41-0x5a, 0x61-0x7a
     *
     * @param int $src
     * @return int
     */
    #[Override]
    protected static function decode6Bits(int $src): int
    {
        $ret = -1;

        // if ($src > 0x2d && $src < 0x3a) ret += $src - 0x2e + 1; // -45
        $ret += (((0x2d - $src) & ($src - 0x3a)) >> 8) & ($src - 45);

        // if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 12 + 1; // -52
        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 52);

        // if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 38 + 1; // -58
        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 58);

        return $ret;
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
     * into 6-bit integers.
     *
     * @param int $src
     * @return string
     */
    #[Override]
    protected static function encode6Bits(int $src): string
    {
        $src += 0x2e;

        // if ($src > 0x39) $src += 0x41 - 0x3a; // 7
        $src += ((0x39 - $src) >> 8) & 7;

        // if ($src > 0x5a) $src += 0x61 - 0x5b; // 6
        $src += ((0x5a - $src) >> 8) & 6;

        return \pack('C', $src);
    }
}
<?php
declare(strict_types=1);
namespace ParagonIE\ConstantTime;

use RangeException;
use SensitiveParameter;
use TypeError;

/**
 *  Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

/**
 * Class Encoding
 * @package ParagonIE\ConstantTime
 * @api
 */
abstract class Encoding
{
    /**
     * RFC 4648 Base32 encoding
     *
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base32Encode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32::encode($str);
    }

    /**
     * RFC 4648 Base32 encoding
     *
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base32EncodeUpper(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32::encodeUpper($str);
    }

    /**
     * RFC 4648 Base32 decoding
     *
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base32Decode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32::decode($str);
    }

    /**
     * RFC 4648 Base32 decoding
     *
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base32DecodeUpper(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32::decodeUpper($str);
    }

    /**
     * RFC 4648 Base32 encoding
     *
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base32HexEncode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32Hex::encode($str);
    }

    /**
     * RFC 4648 Base32Hex encoding
     *
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base32HexEncodeUpper(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32Hex::encodeUpper($str);
    }

    /**
     * RFC 4648 Base32Hex decoding
     *
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base32HexDecode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32Hex::decode($str);
    }

    /**
     * RFC 4648 Base32Hex decoding
     *
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base32HexDecodeUpper(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base32Hex::decodeUpper($str);
    }

    /**
     * RFC 4648 Base64 encoding
     *
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base64Encode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base64::encode($str);
    }

    /**
     * RFC 4648 Base64 decoding
     *
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base64Decode(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base64::decode($str);
    }

    /**
     * Encode into Base64
     *
     * Base64 character set "./[A-Z][a-z][0-9]"
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base64EncodeDotSlash(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base64DotSlash::encode($str);
    }

    /**
     * Decode from base64 to raw binary
     *
     * Base64 character set "./[A-Z][a-z][0-9]"
     *
     * @param string $str
     * @return string
     * @throws RangeException
     * @throws TypeError
     */
    public static function base64DecodeDotSlash(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base64DotSlash::decode($str);
    }

    /**
     * Encode into Base64
     *
     * Base64 character set "[.-9][A-Z][a-z]" or "./[0-9][A-Z][a-z]"
     * @param string $str
     * @return string
     * @throws TypeError
     */
    public static function base64EncodeDotSlashOrdered(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base64DotSlashOrdered::encode($str);
    }

    /**
     * Decode from base64 to raw binary
     *
     * Base64 character set "[.-9][A-Z][a-z]" or "./[0-9][A-Z][a-z]"
     *
     * @param string $str
     * @return string
     * @throws RangeException
     * @throws TypeError
     */
    public static function base64DecodeDotSlashOrdered(
        #[SensitiveParameter]
        string $str
    ): string {
        return Base64DotSlashOrdered::decode($str);
    }

    /**
     * Convert a binary string into a hexadecimal string without cache-timing
     * leaks
     *
     * @param string $bin_string (raw binary)
     * @return string
     * @throws TypeError
     */
    public static function hexEncode(
        #[SensitiveParameter]
        string $bin_string
    ): string {
        return Hex::encode($bin_string);
    }

    /**
     * Convert a hexadecimal string into a binary string without cache-timing
     * leaks
     *
     * @param string $hex_string
     * @return string (raw binary)
     * @throws RangeException
     */
    public static function hexDecode(
        #[SensitiveParameter]
        string $hex_string
    ): string {
        return Hex::decode($hex_string);
    }

    /**
     * Convert a binary string into a hexadecimal string without cache-timing
     * leaks
     *
     * @param string $bin_string (raw binary)
     * @return string
     * @throws TypeError
     */
    public static function hexEncodeUpper(
        #[SensitiveParameter]
        string $bin_string
    ): string {
        return Hex::encodeUpper($bin_string);
    }

    /**
     * Convert a binary string into a hexadecimal string without cache-timing
     * leaks
     *
     * @param string $bin_string (raw binary)
     * @return string
     */
    public static function hexDecodeUpper(
        #[SensitiveParameter]
        string $bin_string
    ): string {
        return Hex::decode($bin_string);
    }
}
<?php
declare(strict_types=1);
namespace ParagonIE\ConstantTime;

use Override;

/**
 *  Copyright (c) 2016 - 2022 Paragon Initiative Enterprises.
 *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"), to deal
 *  in the Software without restriction, including without limitation the rights
 *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all
 *  copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *  SOFTWARE.
 */

/**
 * Class Base64DotSlash
 * ./[A-Z][a-z][0-9]
 *
 * @package ParagonIE\ConstantTime
 */
abstract class Base64DotSlash extends Base64
{
    /**
     * Uses bitwise operators instead of table-lookups to turn 6-bit integers
     * into 8-bit integers.
     *
     * Base64 character set:
     * ./         [A-Z]      [a-z]     [0-9]
     * 0x2e-0x2f, 0x41-0x5a, 0x61-0x7a, 0x30-0x39
     *
     * @param int $src
     * @return int
     */
    #[Override]
    protected static function decode6Bits(int $src): int
    {
        $ret = -1;

        // if ($src > 0x2d && $src < 0x30) ret += $src - 0x2e + 1; // -45
        $ret += (((0x2d - $src) & ($src - 0x30)) >> 8) & ($src - 45);

        // if ($src > 0x40 && $src < 0x5b) ret += $src - 0x41 + 2 + 1; // -62
        $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 62);

        // if ($src > 0x60 && $src < 0x7b) ret += $src - 0x61 + 28 + 1; // -68
        $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 68);

        // if ($src > 0x2f && $src < 0x3a) ret += $src - 0x30 + 54 + 1; // 7
        $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 7);

        return $ret;
    }

    /**
     * Uses bitwise operators instead of table-lookups to turn 8-bit integers
     * into 6-bit integers.
     *
     * @param int $src
     * @return string
     */
    #[Override]
    protected static function encode6Bits(int $src): string
    {
        $src += 0x2e;

        // if ($src > 0x2f) $src += 0x41 - 0x30; // 17
        $src += ((0x2f - $src) >> 8) & 17;

        // if ($src > 0x5a) $src += 0x61 - 0x5b; // 6
        $src += ((0x5a - $src) >> 8) & 6;

        // if ($src > 0x7a) $src += 0x30 - 0x7b; // -75
        $src -= ((0x7a - $src) >> 8) & 75;

        return \pack('C', $src);
    }
}
The MIT License (MIT)

Copyright (c) 2016 - 2022 Paragon Initiative Enterprises

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

------------------------------------------------------------------------------
This library was based on the work of Steve "Sc00bz" Thomas.
------------------------------------------------------------------------------

The MIT License (MIT)

Copyright (c) 2014 Steve Thomas

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

{
  "name": "paragonie/constant_time_encoding",
  "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
  "keywords": [
    "base64",
    "encoding",
    "rfc4648",
    "base32",
    "base16",
    "hex",
    "bin2hex",
    "hex2bin",
    "base64_encode",
    "base64_decode",
    "base32_encode",
    "base32_decode"
  ],
  "license": "MIT",
  "type": "library",
  "authors": [
      {
        "name":     "Paragon Initiative Enterprises",
        "email":    "security@paragonie.com",
        "homepage": "https://paragonie.com",
        "role":     "Maintainer"
      },
      {
        "name":     "Steve 'Sc00bz' Thomas",
        "email":    "steve@tobtu.com",
        "homepage": "https://www.tobtu.com",
        "role":     "Original Developer"
      }
  ],
  "support": {
    "issues":   "https://github.com/paragonie/constant_time_encoding/issues",
    "email":    "info@paragonie.com",
    "source":   "https://github.com/paragonie/constant_time_encoding"
  },
  "require": {
    "php": "^8"
  },
  "require-dev": {
    "infection/infection": "^0",
    "nikic/php-fuzzer": "^0",
    "phpunit/phpunit": "^9|^10|^11",
    "vimeo/psalm": "^4|^5|^6"
  },
  "autoload": {
    "psr-4": {
      "ParagonIE\\ConstantTime\\": "src/"
    }
  },
  "autoload-dev": {
    "psr-4": {
      "ParagonIE\\ConstantTime\\Tests\\": "tests/"
    }
  },
  "scripts": {
    "mutation-test": "infection"
  },
  "config": {
    "process-timeout": 0,
    "allow-plugins": {
      "infection/extension-installer": true
    }
  }
}
#!/usr/bin/env bash

basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) )

php -dphar.readonly=0 "$basedir/other/build_phar.php" $*The MIT License (MIT)

Copyright (c) 2015 Paragon Initiative Enterprises

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

<?php
/**
 * Random_* Compatibility Library
 * for using the new PHP 7 random_* API in PHP 5 projects
 *
 * @version 2.99.99
 * @released 2018-06-06
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

// NOP
<?php
$dist = dirname(__DIR__).'/dist';
if (!is_dir($dist)) {
    mkdir($dist, 0755);
}
if (file_exists($dist.'/random_compat.phar')) {
    unlink($dist.'/random_compat.phar');
}
$phar = new Phar(
    $dist.'/random_compat.phar',
    FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::KEY_AS_FILENAME,
    'random_compat.phar'
);
rename(
    dirname(__DIR__).'/lib/random.php', 
    dirname(__DIR__).'/lib/index.php'
);
$phar->buildFromDirectory(dirname(__DIR__).'/lib');
rename(
    dirname(__DIR__).'/lib/index.php', 
    dirname(__DIR__).'/lib/random.php'
);

/**
 * If we pass an (optional) path to a private key as a second argument, we will
 * sign the Phar with OpenSSL.
 * 
 * If you leave this out, it will produce an unsigned .phar!
 */
if ($argc > 1) {
    if (!@is_readable($argv[1])) {
        echo 'Could not read the private key file:', $argv[1], "\n";
        exit(255);
    }
    $pkeyFile = file_get_contents($argv[1]);
    
    $private = openssl_get_privatekey($pkeyFile);
    if ($private !== false) {
        $pkey = '';
        openssl_pkey_export($private, $pkey);
        $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey);
        
        /**
         * Save the corresponding public key to the file
         */
        if (!@is_readable($dist.'/random_compat.phar.pubkey')) {
            $details = openssl_pkey_get_details($private);
            file_put_contents(
                $dist.'/random_compat.phar.pubkey',
                $details['key']
            );
        }
    } else {
        echo 'An error occurred reading the private key from OpenSSL.', "\n";
        exit(255);
    }
}
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm
pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p
+h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc
-----END PUBLIC KEY-----
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (MingW32)

iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip
QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg
1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW
NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA
NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV
JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74=
=B6+8
-----END PGP SIGNATURE-----
<?xml version="1.0"?>
<psalm
    autoloader="psalm-autoload.php"
    stopOnFirstError="false"
    useDocblockTypes="true"
>
    <projectFiles>
        <directory name="lib" />
    </projectFiles>
    <issueHandlers>
        <RedundantConditionGivenDocblockType errorLevel="info" />
        <UnresolvableInclude errorLevel="info" />
        <DuplicateClass errorLevel="info" />
        <InvalidOperand errorLevel="info" />
        <UndefinedConstant errorLevel="info" />
        <MissingReturnType errorLevel="info" />
        <InvalidReturnType errorLevel="info" />
    </issueHandlers>
</psalm>
<?php

require_once 'lib/byte_safe_strings.php';
require_once 'lib/cast_to_int.php';
require_once 'lib/error_polyfill.php';
require_once 'other/ide_stubs/libsodium.php';
require_once 'lib/random.php';

$int = random_int(0, 65536);
{
  "name":         "paragonie/random_compat",
  "description":  "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
  "keywords": [
    "csprng",
    "random",
    "polyfill",
    "pseudorandom"
  ],
  "license":      "MIT",
  "type":         "library",
  "authors": [
    {
      "name":     "Paragon Initiative Enterprises",
      "email":    "security@paragonie.com",
      "homepage": "https://paragonie.com"
    }
  ],
  "support": {
    "issues":     "https://github.com/paragonie/random_compat/issues",
    "email":      "info@paragonie.com",
    "source":     "https://github.com/paragonie/random_compat"
  },
  "require": {
    "php": ">= 7"
  },
  "require-dev": {
    "vimeo/psalm": "^1",
    "phpunit/phpunit": "4.*|5.*"
  },
  "suggest": {
    "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
  }
}
# phpseclib - PHP Secure Communications Library

[![CI Status](https://github.com/phpseclib/phpseclib/actions/workflows/ci.yml/badge.svg?branch=3.0&event=push "CI Status")](https://github.com/phpseclib/phpseclib)

## Supporting phpseclib

- [Become a backer or sponsor on Patreon](https://www.patreon.com/phpseclib)
- [One-time donation via PayPal or crypto-currencies](http://sourceforge.net/donate/index.php?group_id=198487)
- [Subscribe to Tidelift](https://tidelift.com/subscription/pkg/packagist-phpseclib-phpseclib?utm_source=packagist-phpseclib-phpseclib&utm_medium=referral&utm_campaign=readme)

## Introduction

MIT-licensed pure-PHP implementations of the following:

SSH-2, SFTP, X.509, an arbitrary-precision integer arithmetic library, Ed25519 / Ed449 / Curve25519 / Curve449, ECDSA / ECDH (with support for 66 curves), RSA (PKCS#1 v2.2 compliant), DSA / DH, DES / 3DES / RC4 / Rijndael / AES / Blowfish / Twofish / Salsa20 / ChaCha20, GCM / Poly1305

* [Browse Git](https://github.com/phpseclib/phpseclib)

## Documentation

* [Documentation / Manual](https://phpseclib.com/)
* [API Documentation](https://api.phpseclib.com/3.0/) (generated by Doctum)

## Branches

### master

* Development Branch
* Unstable API
* Do not use in production

### 4.0

* Expected Release Date: September 2026
* Long term support (LTS) release
* X509 split into separate X509, CRL, CSR and SPKAC classes
* PFX and CMS classes added
* All ASN1 classes are lazy loaded by default
* Minimum PHP version: 8.1.0
* PSR-4 autoloading with namespace rooted at `\phpseclib4`
* Install via Composer: `composer require phpseclib/phpseclib:4.0.x-dev`

### 3.0

* Long term support (LTS) release
* Major expansion of cryptographic primitives
* Minimum PHP version: 5.6.1
* PSR-4 autoloading with namespace rooted at `\phpseclib3`
* Install via Composer: `composer require phpseclib/phpseclib:~3.0`

### 2.0

* Long term support (LTS) release
* Modernized version of 1.0
* Minimum PHP version: 5.3.3
* PSR-4 autoloading with namespace rooted at `\phpseclib`
* Install via Composer: `composer require phpseclib/phpseclib:~2.0`

### 1.0

* Long term support (LTS) release
* PHP4 compatible
* Composer compatible (PSR-0 autoloading)
* Install using Composer: `composer require phpseclib/phpseclib:~1.0`
* [Download 1.0.25 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.30.zip/download)

## Security contact information

To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.

## Support

Need Support?

* [Checkout Questions and Answers on Stack Overflow](http://stackoverflow.com/questions/tagged/phpseclib)
* [Create a Support Ticket on GitHub](https://github.com/phpseclib/phpseclib/issues/new)

## Special Thanks

<p align="left">
    <a target="_blank" href="https://www.sovereign.tech/tech/phpseclib">
        <img src="https://phpseclib.com/img/sponsors/sovereign-tech-agency.webp" alt="Sovereign Tech Agency" style="width: 200px">
    </a>
</p>

## Additional Thanks

- Allan Simon
- [Anna Filina](https://afilina.com/)
- delovelady
- [ChargeOver](https://chargeover.com/)
- <a href="https://jb.gg/OpenSource"><img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg" height="20px"></a>

## Contributing

1. Fork the Project

2. Ensure you have Composer installed (see [Composer Download Instructions](https://getcomposer.org/download/))

3. Install Development Dependencies
    ```sh
    composer install
    ```

4. Create a Feature Branch

5. Run continuous integration checks:
   ```sh
   composer global require php:^8.1 squizlabs/php_codesniffer friendsofphp/php-cs-fixer vimeo/psalm
   phpcs --standard=build/php_codesniffer.xml
   php-cs-fixer fix --config=build/php-cs-fixer.php --diff --dry-run --using-cache=no
   psalm --config=build/psalm.xml --no-cache --long-progress --report-show-info=false --output-format=text
   vendor/bin/phpunit --verbose --configuration tests/phpunit.xml
   ```
   
6. Send us a Pull Request
Copyright (c) 2011-2019 TerraFrost and other contributors

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.<?php

/**
 * Common String Functions
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Common\Functions;

use ParagonIE\ConstantTime\Base64;
use ParagonIE\ConstantTime\Base64UrlSafe;
use ParagonIE\ConstantTime\Hex;
use phpseclib3\Math\BigInteger;
use phpseclib3\Math\Common\FiniteField;

/**
 * Common String Functions
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Strings
{
    /**
     * String Shift
     *
     * Inspired by array_shift
     *
     * @param string $string
     * @param int $index
     * @return string
     */
    public static function shift(&$string, $index = 1)
    {
        $substr = substr($string, 0, $index);
        $string = substr($string, $index);
        return $substr;
    }

    /**
     * String Pop
     *
     * Inspired by array_pop
     *
     * @param string $string
     * @param int $index
     * @return string
     */
    public static function pop(&$string, $index = 1)
    {
        $substr = substr($string, -$index);
        $string = substr($string, 0, -$index);
        return $substr;
    }

    /**
     * Parse SSH2-style string
     *
     * Returns either an array or a boolean if $data is malformed.
     *
     * Valid characters for $format are as follows:
     *
     * C = byte
     * b = boolean (true/false)
     * N = uint32
     * Q = uint64
     * s = string
     * i = mpint
     * L = name-list
     *
     * uint64 is not supported.
     *
     * @param string $format
     * @param string $data
     * @return mixed
     */
    public static function unpackSSH2($format, &$data)
    {
        $format = self::formatPack($format);
        $result = [];
        for ($i = 0; $i < strlen($format); $i++) {
            switch ($format[$i]) {
                case 'C':
                case 'b':
                    if (!strlen($data)) {
                        throw new \LengthException('At least one byte needs to be present for successful C / b decodes');
                    }
                    break;
                case 'N':
                case 'i':
                case 's':
                case 'L':
                    if (strlen($data) < 4) {
                        throw new \LengthException('At least four byte needs to be present for successful N / i / s / L decodes');
                    }
                    break;
                case 'Q':
                    if (strlen($data) < 8) {
                        throw new \LengthException('At least eight byte needs to be present for successful N / i / s / L decodes');
                    }
                    break;

                default:
                    throw new \InvalidArgumentException('$format contains an invalid character');
            }
            switch ($format[$i]) {
                case 'C':
                    $result[] = ord(self::shift($data));
                    continue 2;
                case 'b':
                    $result[] = ord(self::shift($data)) != 0;
                    continue 2;
                case 'N':
                    list(, $temp) = unpack('N', self::shift($data, 4));
                    $result[] = $temp;
                    continue 2;
                case 'Q':
                    // pack() added support for Q in PHP 5.6.3 and PHP 5.6 is phpseclib 3's minimum version
                    // so in theory we could support this BUT, "64-bit format codes are not available for
                    // 32-bit versions" and phpseclib works on 32-bit installs. on 32-bit installs
                    // 64-bit floats can be used to get larger numbers then 32-bit signed ints would allow
                    // for. sure, you're not gonna get the full precision of 64-bit numbers but just because
                    // you need > 32-bit precision doesn't mean you need the full 64-bit precision
                    $unpacked = unpack('Nupper/Nlower', self::shift($data, 8));
                    $upper = $unpacked['upper'];
                    $lower = $unpacked['lower'];
                    $temp = $upper ? 4294967296 * $upper : 0;
                    $temp += $lower < 0 ? ($lower & 0x7FFFFFFFF) + 0x80000000 : $lower;
                    // $temp = hexdec(bin2hex(self::shift($data, 8)));
                    $result[] = $temp;
                    continue 2;
            }
            list(, $length) = unpack('N', self::shift($data, 4));
            if (strlen($data) < $length) {
                throw new \LengthException("$length bytes needed; " . strlen($data) . ' bytes available');
            }
            $temp = self::shift($data, $length);
            switch ($format[$i]) {
                case 'i':
                    $result[] = new BigInteger($temp, -256);
                    break;
                case 's':
                    $result[] = $temp;
                    break;
                case 'L':
                    $result[] = explode(',', $temp);
            }
        }

        return $result;
    }

    /**
     * Create SSH2-style string
     *
     * @param string $format
     * @param string|int|float|array|bool ...$elements
     * @return string
     */
    public static function packSSH2($format, ...$elements)
    {
        $format = self::formatPack($format);
        if (strlen($format) != count($elements)) {
            throw new \InvalidArgumentException('There must be as many arguments as there are characters in the $format string');
        }
        $result = '';
        for ($i = 0; $i < strlen($format); $i++) {
            $element = $elements[$i];
            switch ($format[$i]) {
                case 'C':
                    if (!is_int($element)) {
                        throw new \InvalidArgumentException('Bytes must be represented as an integer between 0 and 255, inclusive.');
                    }
                    $result .= pack('C', $element);
                    break;
                case 'b':
                    if (!is_bool($element)) {
                        throw new \InvalidArgumentException('A boolean parameter was expected.');
                    }
                    $result .= $element ? "\1" : "\0";
                    break;
                case 'Q':
                    if (!is_int($element) && !is_float($element)) {
                        throw new \InvalidArgumentException('An integer was expected.');
                    }
                    // 4294967296 == 1 << 32
                    $result .= pack('NN', $element / 4294967296, $element);
                    break;
                case 'N':
                    if (is_float($element)) {
                        $element = (int) $element;
                    }
                    if (!is_int($element)) {
                        throw new \InvalidArgumentException('An integer was expected.');
                    }
                    $result .= pack('N', $element);
                    break;
                case 's':
                    if (!self::is_stringable($element)) {
                        throw new \InvalidArgumentException('A string was expected.');
                    }
                    $result .= pack('Na*', strlen($element), $element);
                    break;
                case 'i':
                    if (!$element instanceof BigInteger && !$element instanceof FiniteField\Integer) {
                        throw new \InvalidArgumentException('A phpseclib3\Math\BigInteger or phpseclib3\Math\Common\FiniteField\Integer object was expected.');
                    }
                    $element = $element->toBytes(true);
                    $result .= pack('Na*', strlen($element), $element);
                    break;
                case 'L':
                    if (!is_array($element)) {
                        throw new \InvalidArgumentException('An array was expected.');
                    }
                    $element = implode(',', $element);
                    $result .= pack('Na*', strlen($element), $element);
                    break;
                default:
                    throw new \InvalidArgumentException('$format contains an invalid character');
            }
        }
        return $result;
    }

    /**
     * Expand a pack string
     *
     * Converts C5 to CCCCC, for example.
     *
     * @param string $format
     * @return string
     */
    private static function formatPack($format)
    {
        $parts = preg_split('#(\d+)#', $format, -1, PREG_SPLIT_DELIM_CAPTURE);
        $format = '';
        for ($i = 1; $i < count($parts); $i += 2) {
            $format .= substr($parts[$i - 1], 0, -1) . str_repeat(substr($parts[$i - 1], -1), $parts[$i]);
        }
        $format .= $parts[$i - 1];

        return $format;
    }

    /**
     * Convert binary data into bits
     *
     * bin2hex / hex2bin refer to base-256 encoded data as binary, whilst
     * decbin / bindec refer to base-2 encoded data as binary. For the purposes
     * of this function, bin refers to base-256 encoded data whilst bits refers
     * to base-2 encoded data
     *
     * @param string $x
     * @return string
     */
    public static function bits2bin($x)
    {
        /*
        // the pure-PHP approach is faster than the GMP approach
        if (function_exists('gmp_export')) {
             return strlen($x) ? gmp_export(gmp_init($x, 2)) : gmp_init(0);
        }
        */

        if (preg_match('#[^01]#', $x)) {
            throw new \RuntimeException('The only valid characters are 0 and 1');
        }

        if (!defined('PHP_INT_MIN')) {
            define('PHP_INT_MIN', ~PHP_INT_MAX);
        }

        $length = strlen($x);
        if (!$length) {
            return '';
        }
        $block_size = PHP_INT_SIZE << 3;
        $pad = $block_size - ($length % $block_size);
        if ($pad != $block_size) {
            $x = str_repeat('0', $pad) . $x;
        }

        $parts = str_split($x, $block_size);
        $str = '';
        foreach ($parts as $part) {
            $xor = $part[0] == '1' ? PHP_INT_MIN : 0;
            $part[0] = '0';
            $str .= pack(
                PHP_INT_SIZE == 4 ? 'N' : 'J',
                $xor ^ eval('return 0b' . $part . ';')
            );
        }
        return ltrim($str, "\0");
    }

    /**
     * Convert bits to binary data
     *
     * @param string $x
     * @return string
     */
    public static function bin2bits($x, $trim = true)
    {
        /*
        // the pure-PHP approach is slower than the GMP approach BUT
        // i want to the pure-PHP version to be easily unit tested as well
        if (function_exists('gmp_import')) {
            return gmp_strval(gmp_import($x), 2);
        }
        */

        $len = strlen($x);
        $mod = $len % PHP_INT_SIZE;
        if ($mod) {
            $x = str_pad($x, $len + PHP_INT_SIZE - $mod, "\0", STR_PAD_LEFT);
        }

        $bits = '';
        if (PHP_INT_SIZE == 4) {
            $digits = unpack('N*', $x);
            foreach ($digits as $digit) {
                $bits .= sprintf('%032b', $digit);
            }
        } else {
            $digits = unpack('J*', $x);
            foreach ($digits as $digit) {
                $bits .= sprintf('%064b', $digit);
            }
        }

        return $trim ? ltrim($bits, '0') : $bits;
    }

    /**
     * Switch Endianness Bit Order
     *
     * @param string $x
     * @return string
     */
    public static function switchEndianness($x)
    {
        $r = '';
        for ($i = strlen($x) - 1; $i >= 0; $i--) {
            $b = ord($x[$i]);
            if (PHP_INT_SIZE === 8) {
                // 3 operations
                // from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64BitsDiv
                $r .= chr((($b * 0x0202020202) & 0x010884422010) % 1023);
            } else {
                // 7 operations
                // from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits
                $p1 = ($b * 0x0802) & 0x22110;
                $p2 = ($b * 0x8020) & 0x88440;
                $temp = ($p1 | $p2) * 0x10101;
                if (is_float($temp)) {
                    $temp = (int) fmod($temp, 0x7FFFFFFF);
                }
                $r .= chr(($temp >> 16) & 0xFF);
            }
        }
        return $r;
    }

    /**
     * Increment the current string
     *
     * @param string $var
     * @return string
     */
    public static function increment_str(&$var)
    {
        if (function_exists('sodium_increment')) {
            $var = strrev($var);
            sodium_increment($var);
            $var = strrev($var);
            return $var;
        }

        for ($i = 4; $i <= strlen($var); $i += 4) {
            $temp = substr($var, -$i, 4);
            switch ($temp) {
                case "\xFF\xFF\xFF\xFF":
                    $var = substr_replace($var, "\x00\x00\x00\x00", -$i, 4);
                    break;
                case "\x7F\xFF\xFF\xFF":
                    $var = substr_replace($var, "\x80\x00\x00\x00", -$i, 4);
                    return $var;
                default:
                    $temp = unpack('Nnum', $temp);
                    $var = substr_replace($var, pack('N', $temp['num'] + 1), -$i, 4);
                    return $var;
            }
        }

        $remainder = strlen($var) % 4;

        if ($remainder == 0) {
            return $var;
        }

        $temp = unpack('Nnum', str_pad(substr($var, 0, $remainder), 4, "\0", STR_PAD_LEFT));
        $temp = substr(pack('N', $temp['num'] + 1), -$remainder);
        $var = substr_replace($var, $temp, 0, $remainder);

        return $var;
    }

    /**
     * Find whether the type of a variable is string (or could be converted to one)
     *
     * @param mixed $var
     * @return bool
     * @psalm-assert-if-true string|\Stringable $var
     */
    public static function is_stringable($var)
    {
        return is_string($var) || (is_object($var) && method_exists($var, '__toString'));
    }

    /**
     * Constant Time Base64-decoding
     *
     * ParagoneIE\ConstantTime doesn't use libsodium if it's available so we'll do so
     * ourselves. see https://github.com/paragonie/constant_time_encoding/issues/39
     *
     * @param string $data
     * @return string
     */
    public static function base64_decode($data)
    {
        return function_exists('sodium_base642bin') ?
            sodium_base642bin($data, SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING, '=') :
            Base64::decode($data);
    }

    /**
     * Constant Time Base64-decoding (URL safe)
     *
     * @param string $data
     * @return string
     */
    public static function base64url_decode($data)
    {
        // return self::base64_decode(str_replace(['-', '_'], ['+', '/'], $data));

        return function_exists('sodium_base642bin') ?
            sodium_base642bin($data, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING, '=') :
            Base64UrlSafe::decode($data);
    }

    /**
     * Constant Time Base64-encoding
     *
     * @param string $data
     * @return string
     */
    public static function base64_encode($data)
    {
        return function_exists('sodium_bin2base64') ?
            sodium_bin2base64($data, SODIUM_BASE64_VARIANT_ORIGINAL) :
            Base64::encode($data);
    }

    /**
     * Constant Time Base64-encoding (URL safe)
     *
     * @param string $data
     * @return string
     */
    public static function base64url_encode($data)
    {
        // return str_replace(['+', '/'], ['-', '_'], self::base64_encode($data));

        return function_exists('sodium_bin2base64') ?
            sodium_bin2base64($data, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING) :
            Base64UrlSafe::encode($data);
    }

    /**
     * Constant Time Hex Decoder
     *
     * @param string $data
     * @return string
     */
    public static function hex2bin($data)
    {
        return function_exists('sodium_hex2bin') ?
            sodium_hex2bin($data) :
            Hex::decode($data);
    }

    /**
     * Constant Time Hex Encoder
     *
     * @param string $data
     * @return string
     */
    public static function bin2hex($data)
    {
        return function_exists('sodium_bin2hex') ?
            sodium_bin2hex($data) :
            Hex::encode($data);
    }
}
<?php

/**
 * Bootstrapping File for phpseclib
 *
 * composer isn't a requirement for phpseclib 2.0 but this file isn't really required
 * either. it's a bonus for those using composer but if you're not phpseclib will
 * still work
 *
 * @license http://www.opensource.org/licenses/mit-license.html MIT License
 */

if (extension_loaded('mbstring')) {
    // 2 - MB_OVERLOAD_STRING
    // mbstring.func_overload is deprecated in php 7.2 and removed in php 8.0.
    if (version_compare(PHP_VERSION, '8.0.0') < 0 && ini_get('mbstring.func_overload') & 2) {
        throw new UnexpectedValueException(
            'Overloading of string functions using mbstring.func_overload ' .
            'is not supported by phpseclib.'
        );
    }
}
<?php

/**
 * Pure-PHP ASN.1 Parser
 *
 * PHP version 5
 *
 * ASN.1 provides the semantics for data encoded using various schemes.  The most commonly
 * utilized scheme is DER or the "Distinguished Encoding Rules".  PEM's are base64 encoded
 * DER blobs.
 *
 * \phpseclib3\File\ASN1 decodes and encodes DER formatted messages and places them in a semantic context.
 *
 * Uses the 1988 ASN.1 syntax.
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2012 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\File\ASN1\Element;
use phpseclib3\Math\BigInteger;

/**
 * Pure-PHP ASN.1 Parser
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class ASN1
{
    // Tag Classes
    // http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=12
    const CLASS_UNIVERSAL        = 0;
    const CLASS_APPLICATION      = 1;
    const CLASS_CONTEXT_SPECIFIC = 2;
    const CLASS_PRIVATE          = 3;

    // Tag Classes
    // http://www.obj-sys.com/asn1tutorial/node124.html
    const TYPE_BOOLEAN           = 1;
    const TYPE_INTEGER           = 2;
    const TYPE_BIT_STRING        = 3;
    const TYPE_OCTET_STRING      = 4;
    const TYPE_NULL              = 5;
    const TYPE_OBJECT_IDENTIFIER = 6;
    //const TYPE_OBJECT_DESCRIPTOR = 7;
    //const TYPE_INSTANCE_OF       = 8; // EXTERNAL
    const TYPE_REAL              = 9;
    const TYPE_ENUMERATED        = 10;
    //const TYPE_EMBEDDED          = 11;
    const TYPE_UTF8_STRING       = 12;
    //const TYPE_RELATIVE_OID      = 13;
    const TYPE_SEQUENCE          = 16; // SEQUENCE OF
    const TYPE_SET               = 17; // SET OF

    // More Tag Classes
    // http://www.obj-sys.com/asn1tutorial/node10.html
    const TYPE_NUMERIC_STRING   = 18;
    const TYPE_PRINTABLE_STRING = 19;
    const TYPE_TELETEX_STRING   = 20; // T61String
    const TYPE_VIDEOTEX_STRING  = 21;
    const TYPE_IA5_STRING       = 22;
    const TYPE_UTC_TIME         = 23;
    const TYPE_GENERALIZED_TIME = 24;
    const TYPE_GRAPHIC_STRING   = 25;
    const TYPE_VISIBLE_STRING   = 26; // ISO646String
    const TYPE_GENERAL_STRING   = 27;
    const TYPE_UNIVERSAL_STRING = 28;
    //const TYPE_CHARACTER_STRING = 29;
    const TYPE_BMP_STRING       = 30;

    // Tag Aliases
    // These tags are kinda place holders for other tags.
    const TYPE_CHOICE = -1;
    const TYPE_ANY    = -2;

    /**
     * ASN.1 object identifiers
     *
     * @var array
     * @link http://en.wikipedia.org/wiki/Object_identifier
     */
    private static $oids = [];

    /**
     * ASN.1 object identifier reverse mapping
     *
     * @var array
     */
    private static $reverseOIDs = [];

    /**
     * Default date format
     *
     * @var string
     * @link http://php.net/class.datetime
     */
    private static $format = 'D, d M Y H:i:s O';

    /**
     * Filters
     *
     * If the mapping type is self::TYPE_ANY what do we actually encode it as?
     *
     * @var array
     * @see self::encode_der()
     */
    private static $filters;

    /**
     * Current Location of most recent ASN.1 encode process
     *
     * Useful for debug purposes
     *
     * @var array
     * @see self::encode_der()
     */
    private static $location;

    /**
     * DER Encoded String
     *
     * In case we need to create ASN1\Element object's..
     *
     * @var string
     * @see self::decodeDER()
     */
    private static $encoded;

    private static $use64BitOIDHandling;

    /**
     * Type mapping table for the ANY type.
     *
     * Structured or unknown types are mapped to a \phpseclib3\File\ASN1\Element.
     * Unambiguous types get the direct mapping (int/real/bool).
     * Others are mapped as a choice, with an extra indexing level.
     *
     * @var array
     */
    const ANY_MAP = [
        self::TYPE_BOOLEAN              => true,
        self::TYPE_INTEGER              => true,
        self::TYPE_BIT_STRING           => 'bitString',
        self::TYPE_OCTET_STRING         => 'octetString',
        self::TYPE_NULL                 => 'null',
        self::TYPE_OBJECT_IDENTIFIER    => 'objectIdentifier',
        self::TYPE_REAL                 => true,
        self::TYPE_ENUMERATED           => 'enumerated',
        self::TYPE_UTF8_STRING          => 'utf8String',
        self::TYPE_NUMERIC_STRING       => 'numericString',
        self::TYPE_PRINTABLE_STRING     => 'printableString',
        self::TYPE_TELETEX_STRING       => 'teletexString',
        self::TYPE_VIDEOTEX_STRING      => 'videotexString',
        self::TYPE_IA5_STRING           => 'ia5String',
        self::TYPE_UTC_TIME             => 'utcTime',
        self::TYPE_GENERALIZED_TIME     => 'generalTime',
        self::TYPE_GRAPHIC_STRING       => 'graphicString',
        self::TYPE_VISIBLE_STRING       => 'visibleString',
        self::TYPE_GENERAL_STRING       => 'generalString',
        self::TYPE_UNIVERSAL_STRING     => 'universalString',
        //self::TYPE_CHARACTER_STRING     => 'characterString',
        self::TYPE_BMP_STRING           => 'bmpString'
    ];

    /**
     * String type to character size mapping table.
     *
     * Non-convertable types are absent from this table.
     * size == 0 indicates variable length encoding.
     *
     * @var array
     */
    const STRING_TYPE_SIZE = [
        self::TYPE_UTF8_STRING      => 0,
        self::TYPE_BMP_STRING       => 2,
        self::TYPE_UNIVERSAL_STRING => 4,
        self::TYPE_PRINTABLE_STRING => 1,
        self::TYPE_TELETEX_STRING   => 1,
        self::TYPE_IA5_STRING       => 1,
        self::TYPE_VISIBLE_STRING   => 1,
    ];

    /**
     * Parse BER-encoding
     *
     * Serves a similar purpose to openssl's asn1parse
     *
     * @param Element|string $encoded
     * @return ?array
     * @changed in phpseclib 4.0.0
     */
    public static function decodeBER($encoded)
    {
        if ($encoded instanceof Element) {
            $encoded = $encoded->element;
        }

        self::$encoded = $encoded;

        $decoded = self::decode_ber($encoded);
        if ($decoded === false) {
            return null;
        }

        return [$decoded];
    }

    /**
     * Parse BER-encoding (Helper function)
     *
     * Sometimes we want to get the BER encoding of a particular tag.  $start lets us do that without having to reencode.
     * $encoded is passed by reference for the recursive calls done for self::TYPE_BIT_STRING and
     * self::TYPE_OCTET_STRING. In those cases, the indefinite length is used.
     *
     * @param string $encoded
     * @param int $start
     * @param int $encoded_pos
     * @return array|bool
     */
    private static function decode_ber($encoded, $start = 0, $encoded_pos = 0)
    {
        $current = ['start' => $start];

        if (!isset($encoded[$encoded_pos])) {
            return false;
        }
        $type = ord($encoded[$encoded_pos++]);
        $startOffset = 1;

        $constructed = ($type >> 5) & 1;

        $tag = $type & 0x1F;
        if ($tag == 0x1F) {
            $tag = 0;
            // process septets (since the eighth bit is ignored, it's not an octet)
            do {
                if (!isset($encoded[$encoded_pos])) {
                    return false;
                }
                $temp = ord($encoded[$encoded_pos++]);
                $startOffset++;
                $loop = $temp >> 7;
                $tag <<= 7;
                $temp &= 0x7F;
                // "bits 7 to 1 of the first subsequent octet shall not all be zero"
                if ($startOffset == 2 && $temp == 0) {
                    return false;
                }
                $tag |= $temp;
            } while ($loop);
        }

        $start += $startOffset;

        // Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
        if (!isset($encoded[$encoded_pos])) {
            return false;
        }
        $length = ord($encoded[$encoded_pos++]);
        $start++;
        if ($length == 0x80) { // indefinite length
            // "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
            //  immediately available." -- paragraph 8.1.3.2.c
            $length = strlen($encoded) - $encoded_pos;
        } elseif ($length & 0x80) { // definite length, long form
            // technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
            // support it up to four.
            $length &= 0x7F;
            $temp = substr($encoded, $encoded_pos, $length);
            $encoded_pos += $length;
            // tags of indefinte length don't really have a header length; this length includes the tag
            $current += ['headerlength' => $length + 2];
            $start += $length;
            $length = unpack('Nlength', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4))['length'];
        } else {
            $current += ['headerlength' => 2];
        }

        if ($length > (strlen($encoded) - $encoded_pos)) {
            return false;
        }

        $content = substr($encoded, $encoded_pos, $length);
        $content_pos = 0;

        // at this point $length can be overwritten. it's only accurate for definite length things as is

        /* Class is UNIVERSAL, APPLICATION, PRIVATE, or CONTEXT-SPECIFIC. The UNIVERSAL class is restricted to the ASN.1
           built-in types. It defines an application-independent data type that must be distinguishable from all other
           data types. The other three classes are user defined. The APPLICATION class distinguishes data types that
           have a wide, scattered use within a particular presentation context. PRIVATE distinguishes data types within
           a particular organization or country. CONTEXT-SPECIFIC distinguishes members of a sequence or set, the
           alternatives of a CHOICE, or universally tagged set members. Only the class number appears in braces for this
           data type; the term CONTEXT-SPECIFIC does not appear.

             -- http://www.obj-sys.com/asn1tutorial/node12.html */
        $class = ($type >> 6) & 3;
        switch ($class) {
            case self::CLASS_APPLICATION:
            case self::CLASS_PRIVATE:
            case self::CLASS_CONTEXT_SPECIFIC:
                if (!$constructed) {
                    return [
                        'type'     => $class,
                        'constant' => $tag,
                        'content'  => $content,
                        'length'   => $length + $start - $current['start']
                    ] + $current;
                }

                $newcontent = [];
                $remainingLength = $length;
                while ($remainingLength > 0) {
                    $temp = self::decode_ber($content, $start, $content_pos);
                    if ($temp === false) {
                        break;
                    }
                    $length = $temp['length'];
                    // end-of-content octets - see paragraph 8.1.5
                    if (substr($content, $content_pos + $length, 2) == "\0\0") {
                        $length += 2;
                        $start += $length;
                        $newcontent[] = $temp;
                        break;
                    }
                    $start += $length;
                    $remainingLength -= $length;
                    $newcontent[] = $temp;
                    $content_pos += $length;
                }

                return [
                    'type'     => $class,
                    'constant' => $tag,
                    // the array encapsulation is for BC with the old format
                    'content'  => $newcontent,
                    // the only time when $content['headerlength'] isn't defined is when the length is indefinite.
                    // the absence of $content['headerlength'] is how we know if something is indefinite or not.
                    // technically, it could be defined to be 2 and then another indicator could be used but whatever.
                    'length'   => $start - $current['start']
                ] + $current;
        }

        $current += ['type' => $tag];

        // decode UNIVERSAL tags
        switch ($tag) {
            case self::TYPE_BOOLEAN:
                // "The contents octets shall consist of a single octet." -- paragraph 8.2.1
                if ($constructed || strlen($content) != 1) {
                    return false;
                }
                $current['content'] = (bool) ord($content[$content_pos]);
                break;
            case self::TYPE_INTEGER:
            case self::TYPE_ENUMERATED:
                if ($constructed) {
                    return false;
                }
                $current['content'] = new BigInteger(substr($content, $content_pos), -256);
                break;
            case self::TYPE_REAL: // not currently supported
                return false;
            case self::TYPE_BIT_STRING:
                // The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
                // the number of unused bits in the final subsequent octet. The number shall be in the range zero to
                // seven.
                if (!$constructed) {
                    $current['content'] = substr($content, $content_pos);
                } else {
                    $temp = self::decode_ber($content, $start, $content_pos);
                    if ($temp === false) {
                        return false;
                    }
                    $length -= (strlen($content) - $content_pos);
                    $last = count($temp) - 1;
                    for ($i = 0; $i < $last; $i++) {
                        // all subtags should be bit strings
                        if ($temp[$i]['type'] != self::TYPE_BIT_STRING) {
                            return false;
                        }
                        $current['content'] .= substr($temp[$i]['content'], 1);
                    }
                    // all subtags should be bit strings
                    if ($temp[$last]['type'] != self::TYPE_BIT_STRING) {
                        return false;
                    }
                    $current['content'] = $temp[$last]['content'][0] . $current['content'] . substr($temp[$i]['content'], 1);
                }
                break;
            case self::TYPE_OCTET_STRING:
                if (!$constructed) {
                    $current['content'] = substr($content, $content_pos);
                } else {
                    $current['content'] = '';
                    $length = 0;
                    while (substr($content, $content_pos, 2) != "\0\0") {
                        $temp = self::decode_ber($content, $length + $start, $content_pos);
                        if ($temp === false) {
                            return false;
                        }
                        $content_pos += $temp['length'];
                        // all subtags should be octet strings
                        if ($temp['type'] != self::TYPE_OCTET_STRING) {
                            return false;
                        }
                        $current['content'] .= $temp['content'];
                        $length += $temp['length'];
                    }
                    if (substr($content, $content_pos, 2) == "\0\0") {
                        $length += 2; // +2 for the EOC
                    }
                }
                break;
            case self::TYPE_NULL:
                // "The contents octets shall not contain any octets." -- paragraph 8.8.2
                if ($constructed || strlen($content)) {
                    return false;
                }
                break;
            case self::TYPE_SEQUENCE:
            case self::TYPE_SET:
                if (!$constructed) {
                    return false;
                }
                $offset = 0;
                $current['content'] = [];
                $content_len = strlen($content);
                while ($content_pos < $content_len) {
                    // if indefinite length construction was used and we have an end-of-content string next
                    // see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
                    if (!isset($current['headerlength']) && substr($content, $content_pos, 2) == "\0\0") {
                        $length = $offset + 2; // +2 for the EOC
                        break 2;
                    }
                    $temp = self::decode_ber($content, $start + $offset, $content_pos);
                    if ($temp === false) {
                        return false;
                    }
                    $content_pos += $temp['length'];
                    $current['content'][] = $temp;
                    $offset += $temp['length'];
                }
                break;
            case self::TYPE_OBJECT_IDENTIFIER:
                if ($constructed) {
                    return false;
                }
                $current['content'] = self::decodeOID(substr($content, $content_pos));
                if ($current['content'] === false) {
                    return false;
                }
                break;
            /* Each character string type shall be encoded as if it had been declared:
               [UNIVERSAL x] IMPLICIT OCTET STRING

                 -- X.690-0207.pdf#page=23 (paragraph 8.21.3)

               Per that, we're not going to do any validation.  If there are any illegal characters in the string,
               we don't really care */
            case self::TYPE_NUMERIC_STRING:
                // 0,1,2,3,4,5,6,7,8,9, and space
            case self::TYPE_PRINTABLE_STRING:
                // Upper and lower case letters, digits, space, apostrophe, left/right parenthesis, plus sign, comma,
                // hyphen, full stop, solidus, colon, equal sign, question mark
            case self::TYPE_TELETEX_STRING:
                // The Teletex character set in CCITT's T61, space, and delete
                // see http://en.wikipedia.org/wiki/Teletex#Character_sets
            case self::TYPE_VIDEOTEX_STRING:
                // The Videotex character set in CCITT's T.100 and T.101, space, and delete
            case self::TYPE_VISIBLE_STRING:
                // Printing character sets of international ASCII, and space
            case self::TYPE_IA5_STRING:
                // International Alphabet 5 (International ASCII)
            case self::TYPE_GRAPHIC_STRING:
                // All registered G sets, and space
            case self::TYPE_GENERAL_STRING:
                // All registered C and G sets, space and delete
            case self::TYPE_UTF8_STRING:
                // ????
            case self::TYPE_BMP_STRING:
                if ($constructed) {
                    return false;
                }
                $current['content'] = substr($content, $content_pos);
                break;
            case self::TYPE_UTC_TIME:
            case self::TYPE_GENERALIZED_TIME:
                if ($constructed) {
                    return false;
                }
                $current['content'] = self::decodeTime(substr($content, $content_pos), $tag);
                break;
            default:
                return false;
        }

        $start += $length;

        // ie. length is the length of the full TLV encoding - it's not just the length of the value
        return $current + ['length' => $start - $current['start']];
    }

    /**
     * ASN.1 Map
     *
     * Provides an ASN.1 semantic mapping ($mapping) from a parsed BER-encoding to a human readable format.
     *
     * "Special" mappings may be applied on a per tag-name basis via $special.
     *
     * @param array $decoded
     * @param array $mapping
     * @param array $special
     * @return array|bool|Element|string|null
     * @changed in phpseclib 4.0.0
     */
    public static function asn1map(array $decoded, $mapping, $special = [])
    {
        if (isset($mapping['explicit']) && is_array($decoded['content'])) {
            $decoded = $decoded['content'][0];
        }

        switch (true) {
            case $mapping['type'] == self::TYPE_ANY:
                $intype = $decoded['type'];
                // !isset(self::ANY_MAP[$intype]) produces a fatal error on PHP 5.6
                if (isset($decoded['constant']) || !array_key_exists($intype, self::ANY_MAP) || (ord(self::$encoded[$decoded['start']]) & 0x20)) {
                    return new Element(substr(self::$encoded, $decoded['start'], $decoded['length']));
                }
                $inmap = self::ANY_MAP[$intype];
                if (is_string($inmap)) {
                    return [$inmap => self::asn1map($decoded, ['type' => $intype] + $mapping, $special)];
                }
                break;
            case $mapping['type'] == self::TYPE_CHOICE:
                foreach ($mapping['children'] as $key => $option) {
                    switch (true) {
                        case isset($option['constant']) && $option['constant'] == $decoded['constant']:
                        case !isset($option['constant']) && $option['type'] == $decoded['type']:
                            $value = self::asn1map($decoded, $option, $special);
                            break;
                        case !isset($option['constant']) && $option['type'] == self::TYPE_CHOICE:
                            $v = self::asn1map($decoded, $option, $special);
                            if (isset($v)) {
                                $value = $v;
                            }
                    }
                    if (isset($value)) {
                        if (isset($special[$key])) {
                            $value = $special[$key]($value);
                        }
                        return [$key => $value];
                    }
                }
                return null;
            case isset($mapping['implicit']):
            case isset($mapping['explicit']):
            case $decoded['type'] == $mapping['type']:
                break;
            default:
                // if $decoded['type'] and $mapping['type'] are both strings, but different types of strings,
                // let it through
                switch (true) {
                    case $decoded['type'] < 18: // self::TYPE_NUMERIC_STRING == 18
                    case $decoded['type'] > 30: // self::TYPE_BMP_STRING == 30
                    case $mapping['type'] < 18:
                    case $mapping['type'] > 30:
                        return null;
                }
        }

        if (isset($mapping['implicit'])) {
            $decoded['type'] = $mapping['type'];
        }

        switch ($decoded['type']) {
            case self::TYPE_SEQUENCE:
                $map = [];

                // ignore the min and max
                if (isset($mapping['min']) && isset($mapping['max'])) {
                    $child = $mapping['children'];
                    foreach ($decoded['content'] as $content) {
                        if (($map[] = self::asn1map($content, $child, $special)) === null) {
                            return null;
                        }
                    }

                    return $map;
                }

                $n = count($decoded['content']);
                $i = 0;

                foreach ($mapping['children'] as $key => $child) {
                    $maymatch = $i < $n; // Match only existing input.
                    if ($maymatch) {
                        $temp = $decoded['content'][$i];

                        if ($child['type'] != self::TYPE_CHOICE) {
                            // Get the mapping and input class & constant.
                            $childClass = $tempClass = self::CLASS_UNIVERSAL;
                            $constant = null;
                            if (isset($temp['constant'])) {
                                $tempClass = $temp['type'];
                            }
                            if (isset($child['class'])) {
                                $childClass = $child['class'];
                                $constant = $child['cast'];
                            } elseif (isset($child['constant'])) {
                                $childClass = self::CLASS_CONTEXT_SPECIFIC;
                                $constant = $child['constant'];
                            }

                            if (isset($constant) && isset($temp['constant'])) {
                                // Can only match if constants and class match.
                                $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
                            } else {
                                // Can only match if no constant expected and type matches or is generic.
                                $maymatch = !isset($child['constant']) && array_search($child['type'], [$temp['type'], self::TYPE_ANY, self::TYPE_CHOICE]) !== false;
                            }
                        }
                    }

                    if ($maymatch) {
                        // Attempt submapping.
                        $candidate = self::asn1map($temp, $child, $special);
                        $maymatch = $candidate !== null;
                    }

                    if ($maymatch) {
                        // Got the match: use it.
                        if (isset($special[$key])) {
                            $candidate = $special[$key]($candidate);
                        }
                        $map[$key] = $candidate;
                        $i++;
                    } elseif (isset($child['default'])) {
                        $map[$key] = $child['default'];
                    } elseif (!isset($child['optional'])) {
                        return null; // Syntax error.
                    }
                }

                // Fail mapping if all input items have not been consumed.
                return $i < $n ? null : $map;

            // the main diff between sets and sequences is the encapsulation of the foreach in another for loop
            case self::TYPE_SET:
                $map = [];

                // ignore the min and max
                if (isset($mapping['min']) && isset($mapping['max'])) {
                    $child = $mapping['children'];
                    foreach ($decoded['content'] as $content) {
                        if (($map[] = self::asn1map($content, $child, $special)) === null) {
                            return null;
                        }
                    }

                    return $map;
                }

                for ($i = 0; $i < count($decoded['content']); $i++) {
                    $temp = $decoded['content'][$i];
                    $tempClass = self::CLASS_UNIVERSAL;
                    if (isset($temp['constant'])) {
                        $tempClass = $temp['type'];
                    }

                    foreach ($mapping['children'] as $key => $child) {
                        if (isset($map[$key])) {
                            continue;
                        }
                        $maymatch = true;
                        if ($child['type'] != self::TYPE_CHOICE) {
                            $childClass = self::CLASS_UNIVERSAL;
                            $constant = null;
                            if (isset($child['class'])) {
                                $childClass = $child['class'];
                                $constant = $child['cast'];
                            } elseif (isset($child['constant'])) {
                                $childClass = self::CLASS_CONTEXT_SPECIFIC;
                                $constant = $child['constant'];
                            }

                            if (isset($constant) && isset($temp['constant'])) {
                                // Can only match if constants and class match.
                                $maymatch = $constant == $temp['constant'] && $childClass == $tempClass;
                            } else {
                                // Can only match if no constant expected and type matches or is generic.
                                $maymatch = !isset($child['constant']) && array_search($child['type'], [$temp['type'], self::TYPE_ANY, self::TYPE_CHOICE]) !== false;
                            }
                        }

                        if ($maymatch) {
                            // Attempt submapping.
                            $candidate = self::asn1map($temp, $child, $special);
                            $maymatch = $candidate !== null;
                        }

                        if (!$maymatch) {
                            break;
                        }

                        // Got the match: use it.
                        if (isset($special[$key])) {
                            $candidate = $special[$key]($candidate);
                        }
                        $map[$key] = $candidate;
                        break;
                    }
                }

                foreach ($mapping['children'] as $key => $child) {
                    if (!isset($map[$key])) {
                        if (isset($child['default'])) {
                            $map[$key] = $child['default'];
                        } elseif (!isset($child['optional'])) {
                            return null;
                        }
                    }
                }
                return $map;
            case self::TYPE_OBJECT_IDENTIFIER:
                return isset(self::$oids[$decoded['content']]) ? self::$oids[$decoded['content']] : $decoded['content'];
            case self::TYPE_UTC_TIME:
            case self::TYPE_GENERALIZED_TIME:
                // for explicitly tagged optional stuff
                if (is_array($decoded['content'])) {
                    $decoded['content'] = $decoded['content'][0]['content'];
                }
                // for implicitly tagged optional stuff
                // in theory, doing isset($mapping['implicit']) would work but malformed certs do exist
                // in the wild that OpenSSL decodes without issue so we'll support them as well
                if (!is_object($decoded['content'])) {
                    $decoded['content'] = self::decodeTime($decoded['content'], $decoded['type']);
                }
                return $decoded['content'] ? $decoded['content']->format(self::$format) : false;
            case self::TYPE_BIT_STRING:
                if (isset($mapping['mapping'])) {
                    $offset = ord($decoded['content'][0]);
                    $size = (strlen($decoded['content']) - 1) * 8 - $offset;
                    /*
                       From X.680-0207.pdf#page=46 (21.7):

                       "When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free to add (or remove)
                        arbitrarily any trailing 0 bits to (or from) values that are being encoded or decoded. Application designers should
                        therefore ensure that different semantics are not associated with such values which differ only in the number of trailing
                        0 bits."
                    */
                    $bits = count($mapping['mapping']) == $size ? [] : array_fill(0, count($mapping['mapping']) - $size, false);
                    for ($i = strlen($decoded['content']) - 1; $i > 0; $i--) {
                        $current = ord($decoded['content'][$i]);
                        for ($j = $offset; $j < 8; $j++) {
                            $bits[] = (bool) ($current & (1 << $j));
                        }
                        $offset = 0;
                    }
                    $values = [];
                    $map = array_reverse($mapping['mapping']);
                    foreach ($map as $i => $value) {
                        if ($bits[$i]) {
                            $values[] = $value;
                        }
                    }
                    return $values;
                }
                // fall-through
            case self::TYPE_OCTET_STRING:
                return $decoded['content'];
            case self::TYPE_NULL:
                return '';
            case self::TYPE_BOOLEAN:
            case self::TYPE_NUMERIC_STRING:
            case self::TYPE_PRINTABLE_STRING:
            case self::TYPE_TELETEX_STRING:
            case self::TYPE_VIDEOTEX_STRING:
            case self::TYPE_IA5_STRING:
            case self::TYPE_GRAPHIC_STRING:
            case self::TYPE_VISIBLE_STRING:
            case self::TYPE_GENERAL_STRING:
            case self::TYPE_UNIVERSAL_STRING:
            case self::TYPE_UTF8_STRING:
            case self::TYPE_BMP_STRING:
                return $decoded['content'];
            case self::TYPE_INTEGER:
            case self::TYPE_ENUMERATED:
                $temp = $decoded['content'];
                if (isset($mapping['implicit'])) {
                    $temp = new BigInteger($temp, -256);
                }
                if (!$temp instanceof BigInteger) {
                    return false;
                }
                if (isset($mapping['mapping'])) {
                    $temp = $temp->toString();
                    if (strlen($temp) > 1) {
                        return false;
                    }
                    $temp = (int) $temp;
                    return isset($mapping['mapping'][$temp]) ?
                        $mapping['mapping'][$temp] :
                        false;
                }
                return $temp;
        }
    }

    /**
     * DER-decode the length
     *
     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
     *
     * @param string $string
     * @return int
     */
    public static function decodeLength(&$string)
    {
        $length = ord(Strings::shift($string));
        if ($length & 0x80) { // definite length, long form
            $length &= 0x7F;
            $temp = Strings::shift($string, $length);
            list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
        }
        return $length;
    }

    /**
     * ASN.1 Encode
     *
     * DER-encodes an ASN.1 semantic mapping ($mapping).  Some libraries would probably call this function
     * an ASN.1 compiler.
     *
     * "Special" mappings can be applied via $special.
     *
     * @param Element|string|array $source
     * @param array $mapping
     * @param array $special
     * @return string
     * @changed in phpseclib 4.0.0
     */
    public static function encodeDER($source, $mapping, $special = [])
    {
        self::$location = [];
        return self::encode_der($source, $mapping, null, $special);
    }

    /**
     * ASN.1 Encode (Helper function)
     *
     * @param Element|string|array|null $source
     * @param array $mapping
     * @param int $idx
     * @param array $special
     * @return string
     */
    private static function encode_der($source, array $mapping, $idx = null, array $special = [])
    {
        if ($source instanceof Element) {
            return $source->element;
        }

        // do not encode (implicitly optional) fields with value set to default
        if (isset($mapping['default']) && $source === $mapping['default']) {
            return '';
        }

        if (isset($idx)) {
            if (isset($special[$idx])) {
                $source = $special[$idx]($source);
            }
            self::$location[] = $idx;
        }

        $tag = $mapping['type'];

        switch ($tag) {
            case self::TYPE_SET:    // Children order is not important, thus process in sequence.
            case self::TYPE_SEQUENCE:
                $tag |= 0x20; // set the constructed bit

                // ignore the min and max
                if (isset($mapping['min']) && isset($mapping['max'])) {
                    $value = [];
                    $child = $mapping['children'];

                    foreach ($source as $content) {
                        $temp = self::encode_der($content, $child, null, $special);
                        if ($temp === false) {
                            return false;
                        }
                        $value[] = $temp;
                    }
                    /* "The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared
                        as octet strings with the shorter components being padded at their trailing end with 0-octets.
                        NOTE - The padding octets are for comparison purposes only and do not appear in the encodings."

                       -- sec 11.6 of http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf  */
                    if ($mapping['type'] == self::TYPE_SET) {
                        sort($value);
                    }
                    $value = implode('', $value);
                    break;
                }

                $value = '';
                foreach ($mapping['children'] as $key => $child) {
                    if (!array_key_exists($key, $source)) {
                        if (!isset($child['optional'])) {
                            return false;
                        }
                        continue;
                    }

                    $temp = self::encode_der($source[$key], $child, $key, $special);
                    if ($temp === false) {
                        return false;
                    }

                    // An empty child encoding means it has been optimized out.
                    // Else we should have at least one tag byte.
                    if ($temp === '') {
                        continue;
                    }

                    // if isset($child['constant']) is true then isset($child['optional']) should be true as well
                    if (isset($child['constant'])) {
                        /*
                           From X.680-0207.pdf#page=58 (30.6):

                           "The tagging construction specifies explicit tagging if any of the following holds:
                            ...
                            c) the "Tag Type" alternative is used and the value of "TagDefault" for the module is IMPLICIT TAGS or
                            AUTOMATIC TAGS, but the type defined by "Type" is an untagged choice type, an untagged open type, or
                            an untagged "DummyReference" (see ITU-T Rec. X.683 | ISO/IEC 8824-4, 8.3)."
                         */
                        if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) {
                            if ($child['constant'] <= 30) {
                                $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
                            } else {
                                $constant = $child['constant'];
                                $subtag = '';
                                while ($constant > 0) {
                                    $subtagvalue = $constant & 0x7F;
                                    $subtag = (chr(0x80 | $subtagvalue)) . $subtag;
                                    $constant = $constant >> 7;
                                }
                                $subtag[strlen($subtag) - 1] = $subtag[strlen($subtag) - 1] & chr(0x7F);
                                $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | 0x1f) . $subtag;
                            }
                            $temp = $subtag . self::encodeLength(strlen($temp)) . $temp;
                        } else {
                            $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
                            $temp = $subtag . substr($temp, 1);
                        }
                    }
                    $value .= $temp;
                }
                break;
            case self::TYPE_CHOICE:
                $temp = false;

                foreach ($mapping['children'] as $key => $child) {
                    if (!isset($source[$key])) {
                        continue;
                    }

                    $temp = self::encode_der($source[$key], $child, $key, $special);
                    if ($temp === false) {
                        return false;
                    }

                    // An empty child encoding means it has been optimized out.
                    // Else we should have at least one tag byte.
                    if ($temp === '') {
                        continue;
                    }

                    $tag = ord($temp[0]);

                    // if isset($child['constant']) is true then isset($child['optional']) should be true as well
                    if (isset($child['constant'])) {
                        if (isset($child['explicit']) || $child['type'] == self::TYPE_CHOICE) {
                            $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | 0x20 | $child['constant']);
                            $temp = $subtag . self::encodeLength(strlen($temp)) . $temp;
                        } else {
                            $subtag = chr((self::CLASS_CONTEXT_SPECIFIC << 6) | (ord($temp[0]) & 0x20) | $child['constant']);
                            $temp = $subtag . substr($temp, 1);
                        }
                    }
                }

                if (isset($idx)) {
                    array_pop(self::$location);
                }

                if ($temp && isset($mapping['cast'])) {
                    $temp[0] = chr(($mapping['class'] << 6) | ($tag & 0x20) | $mapping['cast']);
                }

                return $temp;
            case self::TYPE_INTEGER:
            case self::TYPE_ENUMERATED:
                if (!isset($mapping['mapping'])) {
                    if (is_numeric($source)) {
                        $source = new BigInteger($source);
                    }
                    $value = $source->toBytes(true);
                } else {
                    $value = array_search($source, $mapping['mapping']);
                    if ($value === false) {
                        return false;
                    }
                    $value = new BigInteger($value);
                    $value = $value->toBytes(true);
                }
                if (!strlen($value)) {
                    $value = chr(0);
                }
                break;
            case self::TYPE_UTC_TIME:
            case self::TYPE_GENERALIZED_TIME:
                $format = $mapping['type'] == self::TYPE_UTC_TIME ? 'y' : 'Y';
                $format .= 'mdHis';
                // if $source does _not_ include timezone information within it then assume that the timezone is GMT
                $date = new \DateTime($source, new \DateTimeZone('GMT'));
                // if $source _does_ include timezone information within it then convert the time to GMT
                $date->setTimezone(new \DateTimeZone('GMT'));
                $value = $date->format($format) . 'Z';
                break;
            case self::TYPE_BIT_STRING:
                if (isset($mapping['mapping'])) {
                    $bits = array_fill(0, count($mapping['mapping']), 0);
                    $size = 0;
                    for ($i = 0; $i < count($mapping['mapping']); $i++) {
                        if (in_array($mapping['mapping'][$i], $source)) {
                            $bits[$i] = 1;
                            $size = $i;
                        }
                    }

                    if (isset($mapping['min']) && $mapping['min'] >= 1 && $size < $mapping['min']) {
                        $size = $mapping['min'] - 1;
                    }

                    $offset = 8 - (($size + 1) & 7);
                    $offset = $offset !== 8 ? $offset : 0;

                    $value = chr($offset);

                    for ($i = $size + 1; $i < count($mapping['mapping']); $i++) {
                        unset($bits[$i]);
                    }

                    $bits = implode('', array_pad($bits, $size + $offset + 1, 0));
                    $bytes = explode(' ', rtrim(chunk_split($bits, 8, ' ')));
                    foreach ($bytes as $byte) {
                        $value .= chr(bindec($byte));
                    }

                    break;
                }
                // fall-through
            case self::TYPE_OCTET_STRING:
                /* The initial octet shall encode, as an unsigned binary integer with bit 1 as the least significant bit,
                   the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven.

                   -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */
                $value = $source;
                break;
            case self::TYPE_OBJECT_IDENTIFIER:
                $value = self::encodeOID($source);
                break;
            case self::TYPE_ANY:
                $loc = self::$location;
                if (isset($idx)) {
                    array_pop(self::$location);
                }

                switch (true) {
                    case !isset($source):
                        return self::encode_der(null, ['type' => self::TYPE_NULL] + $mapping, null, $special);
                    case is_int($source):
                    case $source instanceof BigInteger:
                        return self::encode_der($source, ['type' => self::TYPE_INTEGER] + $mapping, null, $special);
                    case is_float($source):
                        return self::encode_der($source, ['type' => self::TYPE_REAL] + $mapping, null, $special);
                    case is_bool($source):
                        return self::encode_der($source, ['type' => self::TYPE_BOOLEAN] + $mapping, null, $special);
                    case is_array($source) && count($source) == 1:
                        $typename = implode('', array_keys($source));
                        $outtype = array_search($typename, self::ANY_MAP, true);
                        if ($outtype !== false) {
                            return self::encode_der($source[$typename], ['type' => $outtype] + $mapping, null, $special);
                        }
                }

                $filters = self::$filters;
                foreach ($loc as $part) {
                    if (!isset($filters[$part])) {
                        $filters = false;
                        break;
                    }
                    $filters = $filters[$part];
                }
                if ($filters === false) {
                    throw new \RuntimeException('No filters defined for ' . implode('/', $loc));
                }
                return self::encode_der($source, $filters + $mapping, null, $special);
            case self::TYPE_NULL:
                $value = '';
                break;
            case self::TYPE_NUMERIC_STRING:
            case self::TYPE_TELETEX_STRING:
            case self::TYPE_PRINTABLE_STRING:
            case self::TYPE_UNIVERSAL_STRING:
            case self::TYPE_UTF8_STRING:
            case self::TYPE_BMP_STRING:
            case self::TYPE_IA5_STRING:
            case self::TYPE_VISIBLE_STRING:
            case self::TYPE_VIDEOTEX_STRING:
            case self::TYPE_GRAPHIC_STRING:
            case self::TYPE_GENERAL_STRING:
                $value = $source;
                break;
            case self::TYPE_BOOLEAN:
                $value = $source ? "\xFF" : "\x00";
                break;
            default:
                throw new \RuntimeException('Mapping provides no type definition for ' . implode('/', self::$location));
        }

        if (isset($idx)) {
            array_pop(self::$location);
        }

        if (isset($mapping['cast'])) {
            if (isset($mapping['explicit']) || $mapping['type'] == self::TYPE_CHOICE) {
                $value = chr($tag) . self::encodeLength(strlen($value)) . $value;
                $tag = ($mapping['class'] << 6) | 0x20 | $mapping['cast'];
            } else {
                $tag = ($mapping['class'] << 6) | (ord($temp[0]) & 0x20) | $mapping['cast'];
            }
        }

        return chr($tag) . self::encodeLength(strlen($value)) . $value;
    }

    public static function enable64BitOIDHandling()
    {
        if (PHP_INT_SIZE === 4) {
            throw new \RuntimeException('64-bit OID handling is unavailable on 32-bit PHP installs');
        }
        self::$use64BitOIDHandling = true;
    }

    public static function disable64BitOIDHandling()
    {
        self::$use64BitOIDHandling = false;
    }

    /**
     * BER-decode the OID
     *
     * Called by _decode_ber()
     *
     * @param string $content
     * @return string
     * @changed in phpseclib 4.0.0
     */
    public static function decodeOID($content)
    {
        // BigInteger's are used because of OIDs like 2.25.329800735698586629295641978511506172918
        // https://healthcaresecprivacy.blogspot.com/2011/02/creating-and-using-unique-id-uuid-oid.html elaborates.
        static $eighty;
        if (!$eighty) {
            $eighty = new BigInteger(80);
        }

        if (!isset(self::$use64BitOIDHandling)) {
            self::$use64BitOIDHandling = PHP_INT_SIZE === 8;
        }

        $oid = [];
        $pos = 0;
        $len = strlen($content);
        // see https://github.com/openjdk/jdk/blob/2deb318c9f047ec5a4b160d66a4b52f93688ec42/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java#L55
        if ($len > 128) {
            //throw new \RuntimeException("Object identifier size is limited to 128 bytes ($len bytes present)");
            return false;
        }

        if (ord($content[$len - 1]) & 0x80) {
            return false;
        }

        $n = new BigInteger();
        $subn = $numBytes = 0;
        if (self::$use64BitOIDHandling) {
            $prefix = '';
            while ($pos < $len) {
                $temp = ord($content[$pos++]);
                $subn <<= 7;
                $subn |= ($temp & 0x7F);
                $numBytes++;
                $endByte = ~$temp & 0x80;
                if ($numBytes === PHP_INT_SIZE) {
                    $prefix .= substr(pack('J', $subn), 1); // we're basically left shifting by 7 bytes
                    $subn = $numBytes = 0;
                    if ($endByte) {
                        $oid[] = new BigInteger($prefix, 256);
                        $prefix = '';
                    }
                } elseif ($endByte) {
                    if (strlen($prefix)) {
                        $arc = new BigInteger($prefix, 256);
                        $arc = $arc->bitwise_leftShift($numBytes * 7);
                        $oid[] = $arc->bitwise_or(new BigInteger($subn));
                        $prefix = '';
                    } else {
                        $oid[] = new BigInteger($subn);
                    }
                    $subn = $numBytes = 0;
                }
            }
        } else {
            while ($pos < $len) {
                $temp = ord($content[$pos++]);
                $subn <<= 7;
                $subn |= ($temp & 0x7F);
                $numBytes++;
                $endByte = ~$temp & 0x80;
                if ($numBytes === PHP_INT_SIZE || $endByte) {
                    $n = $n->bitwise_leftShift($numBytes * 7);
                    $n = $n->bitwise_or(new BigInteger($subn));
                    $subn = $numBytes = 0;
                    if ($endByte) {
                        $oid[] = $n;
                        $n = new BigInteger();
                    }
                }
            }
        }
        $part1 = array_shift($oid);
        $first = floor(ord($content[0]) / 40);
        /*
          "This packing of the first two object identifier components recognizes that only three values are allocated from the root
           node, and at most 39 subsequent values from nodes reached by X = 0 and X = 1."

          -- https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=22
        */
        if ($first <= 2) { // ie. 0 <= ord($content[0]) < 120 (0x78)
            array_unshift($oid, ord($content[0]) % 40);
            array_unshift($oid, $first);
        } else {
            array_unshift($oid, $part1->subtract($eighty));
            array_unshift($oid, 2);
        }

        return implode('.', $oid);
    }

    /**
     * DER-encode the OID
     *
     * Called by _encode_der()
     *
     * @param string $source
     * @return string
     */
    public static function encodeOID($source)
    {
        static $mask, $zero, $forty;
        if (!$mask) {
            $mask = new BigInteger(0x7F);
            $zero = new BigInteger();
            $forty = new BigInteger(40);
        }

        if (!preg_match('#(?:\d+\.)+#', $source)) {
            $oid = isset(self::$reverseOIDs[$source]) ? self::$reverseOIDs[$source] : false;
        } else {
            $oid = $source;
        }
        if ($oid === false) {
            throw new \RuntimeException('Invalid OID');
        }

        $parts = explode('.', $oid);
        $part1 = array_shift($parts);
        $part2 = array_shift($parts);

        $first = new BigInteger($part1);
        $first = $first->multiply($forty);
        $first = $first->add(new BigInteger($part2));

        array_unshift($parts, $first->toString());

        $value = '';
        foreach ($parts as $part) {
            if (!$part) {
                $temp = "\0";
            } else {
                $temp = '';
                $part = new BigInteger($part);
                while (!$part->equals($zero)) {
                    $submask = $part->bitwise_and($mask);
                    $submask->setPrecision(8);
                    $temp = (chr(0x80) | $submask->toBytes()) . $temp;
                    $part = $part->bitwise_rightShift(7);
                }
                $temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
            }
            $value .= $temp;
        }

        return $value;
    }

    /**
     * BER-decode the time
     *
     * Called by _decode_ber() and in the case of implicit tags asn1map().
     *
     * @param string $content
     * @param int $tag
     * @return \DateTime|false
     * @changed in phpseclib 4.0.0
     */
    private static function decodeTime($content, $tag)
    {
        /* UTCTime:
           http://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
           http://www.obj-sys.com/asn1tutorial/node15.html

           GeneralizedTime:
           http://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
           http://www.obj-sys.com/asn1tutorial/node14.html */

        $format = 'YmdHis';

        if ($tag == self::TYPE_UTC_TIME) {
            // https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=28 says "the seconds
            // element shall always be present" but none-the-less I've seen X509 certs where it isn't and if the
            // browsers parse it phpseclib ought to too
            if (preg_match('#^(\d{10})(Z|[+-]\d{4})$#', $content, $matches)) {
                $content = $matches[1] . '00' . $matches[2];
            }
            $prefix = substr($content, 0, 2) >= 50 ? '19' : '20';
            $content = $prefix . $content;
        } elseif (strpos($content, '.') !== false) {
            $format .= '.u';
        }

        if ($content[strlen($content) - 1] == 'Z') {
            $content = substr($content, 0, -1) . '+0000';
        }

        if (strpos($content, '-') !== false || strpos($content, '+') !== false) {
            $format .= 'O';
        }

        // error supression isn't necessary as of PHP 7.0:
        // http://php.net/manual/en/migration70.other-changes.php
        return @\DateTime::createFromFormat($format, $content);
    }

    /**
     * Set the time format
     *
     * Sets the time / date format for asn1map().
     *
     * @param string $format
     * @removed in phpseclib 4.0.0
     */
    public static function setTimeFormat($format)
    {
        self::$format = $format;
    }

    /**
     * Load OIDs
     *
     * Load the relevant OIDs for a particular ASN.1 semantic mapping.
     * Previously loaded OIDs are retained.
     *
     * @param array $oids
     * @changed in phpseclib 4.0.0
     */
    public static function loadOIDs(array $oids)
    {
        self::$reverseOIDs += $oids;
        self::$oids = array_flip(self::$reverseOIDs);
    }

    /**
     * Set filters
     *
     * See \phpseclib3\File\X509, etc, for an example.
     * Previously loaded filters are not retained.
     *
     * @param array $filters
     * @removed in phpseclib 4.0.0
     */
    public static function setFilters(array $filters)
    {
        self::$filters = $filters;
    }

    /**
     * String type conversion
     *
     * This is a lazy conversion, dealing only with character size.
     * No real conversion table is used.
     *
     * @param string $in
     * @param int $from
     * @param int $to
     * @return string
     * @removed in phpseclib 4.0.0
     */
    public static function convert($in, $from = self::TYPE_UTF8_STRING, $to = self::TYPE_UTF8_STRING)
    {
        // isset(self::STRING_TYPE_SIZE[$from] returns a fatal error on PHP 5.6
        if (!array_key_exists($from, self::STRING_TYPE_SIZE) || !array_key_exists($to, self::STRING_TYPE_SIZE)) {
            return false;
        }
        $insize = self::STRING_TYPE_SIZE[$from];
        $outsize = self::STRING_TYPE_SIZE[$to];
        $inlength = strlen($in);
        $out = '';

        for ($i = 0; $i < $inlength;) {
            if ($inlength - $i < $insize) {
                return false;
            }

            // Get an input character as a 32-bit value.
            $c = ord($in[$i++]);
            switch (true) {
                case $insize == 4:
                    $c = ($c << 8) | ord($in[$i++]);
                    $c = ($c << 8) | ord($in[$i++]);
                    // fall-through
                case $insize == 2:
                    $c = ($c << 8) | ord($in[$i++]);
                    // fall-through
                case $insize == 1:
                    break;
                case ($c & 0x80) == 0x00:
                    break;
                case ($c & 0x40) == 0x00:
                    return false;
                default:
                    $bit = 6;
                    do {
                        if ($bit > 25 || $i >= $inlength || (ord($in[$i]) & 0xC0) != 0x80) {
                            return false;
                        }
                        $c = ($c << 6) | (ord($in[$i++]) & 0x3F);
                        $bit += 5;
                        $mask = 1 << $bit;
                    } while ($c & $bit);
                    $c &= $mask - 1;
                    break;
            }

            // Convert and append the character to output string.
            $v = '';
            switch (true) {
                case $outsize == 4:
                    $v .= chr($c & 0xFF);
                    $c >>= 8;
                    $v .= chr($c & 0xFF);
                    $c >>= 8;
                    // fall-through
                case $outsize == 2:
                    $v .= chr($c & 0xFF);
                    $c >>= 8;
                    // fall-through
                case $outsize == 1:
                    $v .= chr($c & 0xFF);
                    $c >>= 8;
                    if ($c) {
                        return false;
                    }
                    break;
                case ($c & (PHP_INT_SIZE == 8 ? 0x80000000 : (1 << 31))) != 0:
                    return false;
                case $c >= 0x04000000:
                    $v .= chr(0x80 | ($c & 0x3F));
                    $c = ($c >> 6) | 0x04000000;
                    // fall-through
                case $c >= 0x00200000:
                    $v .= chr(0x80 | ($c & 0x3F));
                    $c = ($c >> 6) | 0x00200000;
                    // fall-through
                case $c >= 0x00010000:
                    $v .= chr(0x80 | ($c & 0x3F));
                    $c = ($c >> 6) | 0x00010000;
                    // fall-through
                case $c >= 0x00000800:
                    $v .= chr(0x80 | ($c & 0x3F));
                    $c = ($c >> 6) | 0x00000800;
                    // fall-through
                case $c >= 0x00000080:
                    $v .= chr(0x80 | ($c & 0x3F));
                    $c = ($c >> 6) | 0x000000C0;
                    // fall-through
                default:
                    $v .= chr($c);
                    break;
            }
            $out .= strrev($v);
        }
        return $out;
    }

    /**
     * Extract raw BER from Base64 encoding
     *
     * @param string $str
     * @return string
     */
    public static function extractBER($str)
    {
        /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
         * above and beyond the ceritificate.
         * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
         *
         * Bag Attributes
         *     localKeyID: 01 00 00 00
         * subject=/O=organization/OU=org unit/CN=common name
         * issuer=/O=organization/CN=common name
         */
        if (strlen($str) > ini_get('pcre.backtrack_limit')) {
            $temp = $str;
        } else {
            $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
            $temp = preg_replace('#-+END.*[\r\n ]*.*#ms', '', $temp, 1);
        }
        // remove new lines
        $temp = str_replace(["\r", "\n", ' '], '', $temp);
        // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
        $temp = preg_replace('#^-+[^-]+-+|-+[^-]+-+$#', '', $temp);
        $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? Strings::base64_decode($temp) : false;
        return $temp != false ? $temp : $str;
    }

    /**
     * DER-encode the length
     *
     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
     *
     * @param int $length
     * @return string
     */
    public static function encodeLength($length)
    {
        if ($length <= 0x7F) {
            return chr($length);
        }

        $temp = ltrim(pack('N', $length), chr(0));
        return pack('Ca*', 0x80 | strlen($temp), $temp);
    }

    /**
     * Returns the OID corresponding to a name
     *
     * What's returned in the associative array returned by loadX509() (or load*()) is either a name or an OID if
     * no OID to name mapping is available. The problem with this is that what may be an unmapped OID in one version
     * of phpseclib may not be unmapped in the next version, so apps that are looking at this OID may not be able
     * to work from version to version.
     *
     * This method will return the OID if a name is passed to it and if no mapping is avialable it'll assume that
     * what's being passed to it already is an OID and return that instead. A few examples.
     *
     * getOID('2.16.840.1.101.3.4.2.1') == '2.16.840.1.101.3.4.2.1'
     * getOID('id-sha256') == '2.16.840.1.101.3.4.2.1'
     * getOID('zzz') == 'zzz'
     *
     * @param string $name
     * @return string
     * @removed in phpseclib 4.0.0
     */
    public static function getOID($name)
    {
        return isset(self::$reverseOIDs[$name]) ? self::$reverseOIDs[$name] : $name;
    }
}
<?php

/**
 * Pure-PHP X.509 Parser
 *
 * PHP version 5
 *
 * Encode and decode X.509 certificates.
 *
 * The extensions are from {@link http://tools.ietf.org/html/rfc5280 RFC5280} and
 * {@link http://web.archive.org/web/19961027104704/http://www3.netscape.com/eng/security/cert-exts.html Netscape Certificate Extensions}.
 *
 * Note that loading an X.509 certificate and resaving it may invalidate the signature.  The reason being that the signature is based on a
 * portion of the certificate that contains optional parameters with default values.  ie. if the parameter isn't there the default value is
 * used.  Problem is, if the parameter is there and it just so happens to have the default value there are two ways that that parameter can
 * be encoded.  It can be encoded explicitly or left out all together.  This would effect the signature value and thus may invalidate the
 * the certificate all together unless the certificate is re-signed.
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2012 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\PrivateKey;
use phpseclib3\Crypt\Common\PublicKey;
use phpseclib3\Crypt\DSA;
use phpseclib3\Crypt\EC;
use phpseclib3\Crypt\Hash;
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Crypt\Random;
use phpseclib3\Crypt\RSA;
use phpseclib3\Crypt\RSA\Formats\Keys\PSS;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\File\ASN1\Element;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * Pure-PHP X.509 Parser
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class X509
{
    /**
     * Flag to only accept signatures signed by certificate authorities
     *
     * Not really used anymore but retained all the same to suppress E_NOTICEs from old installs
     *
     */
    const VALIDATE_SIGNATURE_BY_CA = 1;

    /**
     * Return internal array representation
     *
     * @see \phpseclib3\File\X509::getDN()
     */
    const DN_ARRAY = 0;
    /**
     * Return string
     *
     * @see \phpseclib3\File\X509::getDN()
     */
    const DN_STRING = 1;
    /**
     * Return ASN.1 name string
     *
     * @see \phpseclib3\File\X509::getDN()
     */
    const DN_ASN1 = 2;
    /**
     * Return OpenSSL compatible array
     *
     * @see \phpseclib3\File\X509::getDN()
     */
    const DN_OPENSSL = 3;
    /**
     * Return canonical ASN.1 RDNs string
     *
     * @see \phpseclib3\File\X509::getDN()
     */
    const DN_CANON = 4;
    /**
     * Return name hash for file indexing
     *
     * @see \phpseclib3\File\X509::getDN()
     */
    const DN_HASH = 5;

    /**
     * Save as PEM
     *
     * ie. a base64-encoded PEM with a header and a footer
     *
     * @see \phpseclib3\File\X509::saveX509()
     * @see \phpseclib3\File\X509::saveCSR()
     * @see \phpseclib3\File\X509::saveCRL()
     */
    const FORMAT_PEM = 0;
    /**
     * Save as DER
     *
     * @see \phpseclib3\File\X509::saveX509()
     * @see \phpseclib3\File\X509::saveCSR()
     * @see \phpseclib3\File\X509::saveCRL()
     */
    const FORMAT_DER = 1;
    /**
     * Save as a SPKAC
     *
     * @see \phpseclib3\File\X509::saveX509()
     * @see \phpseclib3\File\X509::saveCSR()
     * @see \phpseclib3\File\X509::saveCRL()
     *
     * Only works on CSRs. Not currently supported.
     */
    const FORMAT_SPKAC = 2;
    /**
     * Auto-detect the format
     *
     * Used only by the load*() functions
     *
     * @see \phpseclib3\File\X509::saveX509()
     * @see \phpseclib3\File\X509::saveCSR()
     * @see \phpseclib3\File\X509::saveCRL()
     */
    const FORMAT_AUTO_DETECT = 3;

    /**
     * Attribute value disposition.
     * If disposition is >= 0, this is the index of the target value.
     */
    const ATTR_ALL = -1; // All attribute values (array).
    const ATTR_APPEND = -2; // Add a value.
    const ATTR_REPLACE = -3; // Clear first, then add a value.

    /**
     * Distinguished Name
     *
     * @var array
     */
    private $dn;

    /**
     * Public key
     *
     * @var string|PublicKey
     */
    private $publicKey;

    /**
     * Private key
     *
     * @var string|PrivateKey
     */
    private $privateKey;

    /**
     * The certificate authorities
     *
     * @var array
     */
    private $CAs = [];

    /**
     * The currently loaded certificate
     *
     * @var array
     */
    private $currentCert;

    /**
     * The signature subject
     *
     * There's no guarantee \phpseclib3\File\X509 is going to re-encode an X.509 cert in the same way it was originally
     * encoded so we take save the portion of the original cert that the signature would have made for.
     *
     * @var string
     */
    private $signatureSubject;

    /**
     * Certificate Start Date
     *
     * @var string
     */
    private $startDate;

    /**
     * Certificate End Date
     *
     * @var string|Element
     */
    private $endDate;

    /**
     * Serial Number
     *
     * @var string
     */
    private $serialNumber;

    /**
     * Key Identifier
     *
     * See {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.1 RFC5280#section-4.2.1.1} and
     * {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.2 RFC5280#section-4.2.1.2}.
     *
     * @var string
     */
    private $currentKeyIdentifier;

    /**
     * CA Flag
     *
     * @var bool
     */
    private $caFlag = false;

    /**
     * SPKAC Challenge
     *
     * @var string
     */
    private $challenge;

    /**
     * @var array
     */
    private $extensionValues = [];

    /**
     * OIDs loaded
     *
     * @var bool
     */
    private static $oidsLoaded = false;

    /**
     * Recursion Limit
     *
     * @var int
     */
    private static $recur_limit = 5;

    /**
     * URL fetch flag
     *
     * @var bool
     */
    private static $disable_url_fetch = false;

    /**
     * @var array
     */
    private static $extensions = [];

    /**
     * @var ?array
     */
    private $ipAddresses = null;

    /**
     * @var ?array
     */
    private $domains = null;

    /**
     * URL fetch callback
     *
     * @var string|array|null
     */
    private static $urlFetchCallback = null;

    /**
     * Default Constructor.
     *
     * @return X509
     * @changed in phpseclib 4.0.0
     */
    public function __construct()
    {
        // Explicitly Tagged Module, 1988 Syntax
        // http://tools.ietf.org/html/rfc5280#appendix-A.1

        if (!self::$oidsLoaded) {
            // OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2
            ASN1::loadOIDs([
                //'id-pkix' => '1.3.6.1.5.5.7',
                //'id-pe' => '1.3.6.1.5.5.7.1',
                //'id-qt' => '1.3.6.1.5.5.7.2',
                //'id-kp' => '1.3.6.1.5.5.7.3',
                //'id-ad' => '1.3.6.1.5.5.7.48',
                'id-qt-cps' => '1.3.6.1.5.5.7.2.1',
                'id-qt-unotice' => '1.3.6.1.5.5.7.2.2',
                'id-ad-ocsp' => '1.3.6.1.5.5.7.48.1',
                'id-ad-caIssuers' => '1.3.6.1.5.5.7.48.2',
                'id-ad-timeStamping' => '1.3.6.1.5.5.7.48.3',
                'id-ad-caRepository' => '1.3.6.1.5.5.7.48.5',
                //'id-at' => '2.5.4',
                'id-at-name' => '2.5.4.41',
                'id-at-surname' => '2.5.4.4',
                'id-at-givenName' => '2.5.4.42',
                'id-at-initials' => '2.5.4.43',
                'id-at-generationQualifier' => '2.5.4.44',
                'id-at-commonName' => '2.5.4.3',
                'id-at-localityName' => '2.5.4.7',
                'id-at-stateOrProvinceName' => '2.5.4.8',
                'id-at-organizationName' => '2.5.4.10',
                'id-at-organizationalUnitName' => '2.5.4.11',
                'id-at-title' => '2.5.4.12',
                'id-at-description' => '2.5.4.13',
                'id-at-dnQualifier' => '2.5.4.46',
                'id-at-countryName' => '2.5.4.6',
                'id-at-serialNumber' => '2.5.4.5',
                'id-at-pseudonym' => '2.5.4.65',
                'id-at-postalCode' => '2.5.4.17',
                'id-at-streetAddress' => '2.5.4.9',
                'id-at-uniqueIdentifier' => '2.5.4.45',
                'id-at-role' => '2.5.4.72',
                'id-at-postalAddress' => '2.5.4.16',
                'id-at-organizationIdentifier' => '2.5.4.97',
                'jurisdictionOfIncorporationCountryName' => '1.3.6.1.4.1.311.60.2.1.3',
                'jurisdictionOfIncorporationStateOrProvinceName' => '1.3.6.1.4.1.311.60.2.1.2',
                'jurisdictionLocalityName' => '1.3.6.1.4.1.311.60.2.1.1',
                'id-at-businessCategory' => '2.5.4.15',

                //'id-domainComponent' => '0.9.2342.19200300.100.1.25',
                //'pkcs-9' => '1.2.840.113549.1.9',
                'pkcs-9-at-emailAddress' => '1.2.840.113549.1.9.1',
                //'id-ce' => '2.5.29',
                'id-ce-authorityKeyIdentifier' => '2.5.29.35',
                'id-ce-subjectKeyIdentifier' => '2.5.29.14',
                'id-ce-keyUsage' => '2.5.29.15',
                'id-ce-privateKeyUsagePeriod' => '2.5.29.16',
                'id-ce-certificatePolicies' => '2.5.29.32',
                //'anyPolicy' => '2.5.29.32.0',

                'id-ce-policyMappings' => '2.5.29.33',

                'id-ce-subjectAltName' => '2.5.29.17',
                'id-ce-issuerAltName' => '2.5.29.18',
                'id-ce-subjectDirectoryAttributes' => '2.5.29.9',
                'id-ce-basicConstraints' => '2.5.29.19',
                'id-ce-nameConstraints' => '2.5.29.30',
                'id-ce-policyConstraints' => '2.5.29.36',
                'id-ce-cRLDistributionPoints' => '2.5.29.31',
                'id-ce-extKeyUsage' => '2.5.29.37',
                //'anyExtendedKeyUsage' => '2.5.29.37.0',
                'id-kp-serverAuth' => '1.3.6.1.5.5.7.3.1',
                'id-kp-clientAuth' => '1.3.6.1.5.5.7.3.2',
                'id-kp-codeSigning' => '1.3.6.1.5.5.7.3.3',
                'id-kp-emailProtection' => '1.3.6.1.5.5.7.3.4',
                'id-kp-timeStamping' => '1.3.6.1.5.5.7.3.8',
                'id-kp-OCSPSigning' => '1.3.6.1.5.5.7.3.9',
                'id-ce-inhibitAnyPolicy' => '2.5.29.54',
                'id-ce-freshestCRL' => '2.5.29.46',
                'id-pe-authorityInfoAccess' => '1.3.6.1.5.5.7.1.1',
                'id-pe-subjectInfoAccess' => '1.3.6.1.5.5.7.1.11',
                'id-ce-cRLNumber' => '2.5.29.20',
                'id-ce-issuingDistributionPoint' => '2.5.29.28',
                'id-ce-deltaCRLIndicator' => '2.5.29.27',
                'id-ce-cRLReasons' => '2.5.29.21',
                'id-ce-certificateIssuer' => '2.5.29.29',
                'id-ce-holdInstructionCode' => '2.5.29.23',
                //'holdInstruction' => '1.2.840.10040.2',
                'id-holdinstruction-none' => '1.2.840.10040.2.1',
                'id-holdinstruction-callissuer' => '1.2.840.10040.2.2',
                'id-holdinstruction-reject' => '1.2.840.10040.2.3',
                'id-ce-invalidityDate' => '2.5.29.24',

                'rsaEncryption' => '1.2.840.113549.1.1.1',
                'md2WithRSAEncryption' => '1.2.840.113549.1.1.2',
                'md5WithRSAEncryption' => '1.2.840.113549.1.1.4',
                'sha1WithRSAEncryption' => '1.2.840.113549.1.1.5',
                'sha224WithRSAEncryption' => '1.2.840.113549.1.1.14',
                'sha256WithRSAEncryption' => '1.2.840.113549.1.1.11',
                'sha384WithRSAEncryption' => '1.2.840.113549.1.1.12',
                'sha512WithRSAEncryption' => '1.2.840.113549.1.1.13',

                'id-ecPublicKey' => '1.2.840.10045.2.1',
                'ecdsa-with-SHA1' => '1.2.840.10045.4.1',
                // from https://tools.ietf.org/html/rfc5758#section-3.2
                'ecdsa-with-SHA224' => '1.2.840.10045.4.3.1',
                'ecdsa-with-SHA256' => '1.2.840.10045.4.3.2',
                'ecdsa-with-SHA384' => '1.2.840.10045.4.3.3',
                'ecdsa-with-SHA512' => '1.2.840.10045.4.3.4',

                'id-dsa' => '1.2.840.10040.4.1',
                'id-dsa-with-sha1' => '1.2.840.10040.4.3',
                // from https://tools.ietf.org/html/rfc5758#section-3.1
                'id-dsa-with-sha224' => '2.16.840.1.101.3.4.3.1',
                'id-dsa-with-sha256' => '2.16.840.1.101.3.4.3.2',

                // from https://tools.ietf.org/html/rfc8410:
                'id-Ed25519' => '1.3.101.112',
                'id-Ed448' => '1.3.101.113',

                'id-RSASSA-PSS' => '1.2.840.113549.1.1.10',

                //'id-sha224' => '2.16.840.1.101.3.4.2.4',
                //'id-sha256' => '2.16.840.1.101.3.4.2.1',
                //'id-sha384' => '2.16.840.1.101.3.4.2.2',
                //'id-sha512' => '2.16.840.1.101.3.4.2.3',
                //'id-GostR3411-94-with-GostR3410-94' => '1.2.643.2.2.4',
                //'id-GostR3411-94-with-GostR3410-2001' => '1.2.643.2.2.3',
                //'id-GostR3410-2001' => '1.2.643.2.2.20',
                //'id-GostR3410-94' => '1.2.643.2.2.19',
                // Netscape Object Identifiers from "Netscape Certificate Extensions"
                'netscape' => '2.16.840.1.113730',
                'netscape-cert-extension' => '2.16.840.1.113730.1',
                'netscape-cert-type' => '2.16.840.1.113730.1.1',
                'netscape-comment' => '2.16.840.1.113730.1.13',
                'netscape-ca-policy-url' => '2.16.840.1.113730.1.8',
                // the following are X.509 extensions not supported by phpseclib
                'id-pe-logotype' => '1.3.6.1.5.5.7.1.12',
                'entrustVersInfo' => '1.2.840.113533.7.65.0',
                'verisignPrivate' => '2.16.840.1.113733.1.6.9',
                // for Certificate Signing Requests
                // see http://tools.ietf.org/html/rfc2985
                'pkcs-9-at-unstructuredName' => '1.2.840.113549.1.9.2', // PKCS #9 unstructured name
                'pkcs-9-at-challengePassword' => '1.2.840.113549.1.9.7', // Challenge password for certificate revocations
                'pkcs-9-at-extensionRequest' => '1.2.840.113549.1.9.14' // Certificate extension request
            ]);
        }
    }

    /**
     * Load X.509 certificate
     *
     * Returns an associative array describing the X.509 cert or a false if the cert failed to load
     *
     * @param array|string $cert
     * @param int $mode
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function loadX509($cert, $mode = self::FORMAT_AUTO_DETECT)
    {
        if (is_array($cert) && isset($cert['tbsCertificate'])) {
            unset($this->currentCert);
            unset($this->currentKeyIdentifier);
            $this->dn = $cert['tbsCertificate']['subject'];
            if (!isset($this->dn)) {
                return false;
            }
            $this->currentCert = $cert;

            $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
            $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;

            unset($this->signatureSubject);

            return $cert;
        }

        if ($mode != self::FORMAT_DER) {
            $newcert = ASN1::extractBER($cert);
            if ($mode == self::FORMAT_PEM && $cert == $newcert) {
                return false;
            }
            $cert = $newcert;
        }

        if ($cert === false) {
            $this->currentCert = false;
            return false;
        }

        $decoded = ASN1::decodeBER($cert);

        if ($decoded) {
            $x509 = ASN1::asn1map($decoded[0], Maps\Certificate::MAP);
        }
        if (!isset($x509) || $x509 === false) {
            $this->currentCert = false;
            return false;
        }

        $this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);

        if ($this->isSubArrayValid($x509, 'tbsCertificate/extensions')) {
            $this->mapInExtensions($x509, 'tbsCertificate/extensions');
        }
        $this->mapInDNs($x509, 'tbsCertificate/issuer/rdnSequence');
        $this->mapInDNs($x509, 'tbsCertificate/subject/rdnSequence');

        $key = $x509['tbsCertificate']['subjectPublicKeyInfo'];
        $key = ASN1::encodeDER($key, Maps\SubjectPublicKeyInfo::MAP);
        $x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] =
            "-----BEGIN PUBLIC KEY-----\r\n" .
            chunk_split(base64_encode($key), 64) .
            "-----END PUBLIC KEY-----";

        $this->currentCert = $x509;
        $this->dn = $x509['tbsCertificate']['subject'];

        $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier');
        $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null;

        return $x509;
    }

    /**
     * Save X.509 certificate
     *
     * @param array $cert
     * @param int $format optional
     * @return string
     * @removed in phpseclib 4.0.0
     */
    public function saveX509(array $cert, $format = self::FORMAT_PEM)
    {
        if (!is_array($cert) || !isset($cert['tbsCertificate'])) {
            return false;
        }

        switch (true) {
            // "case !$a: case !$b: break; default: whatever();" is the same thing as "if ($a && $b) whatever()"
            case !($algorithm = $this->subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')):
            case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
                break;
            default:
                $cert['tbsCertificate']['subjectPublicKeyInfo'] = new Element(
                    base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']))
                );
        }

        $filters = [];
        $type_utf8_string = ['type' => ASN1::TYPE_UTF8_STRING];
        $filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string;
        $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $type_utf8_string;
        $filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $type_utf8_string;
        $filters['tbsCertificate']['subject']['rdnSequence']['value'] = $type_utf8_string;
        $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $type_utf8_string;
        $filters['signatureAlgorithm']['parameters'] = $type_utf8_string;
        $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
        //$filters['policyQualifiers']['qualifier'] = $type_utf8_string;
        $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $type_utf8_string;
        $filters['directoryName']['rdnSequence']['value'] = $type_utf8_string;

        foreach (self::$extensions as $extension) {
            $filters['tbsCertificate']['extensions'][] = $extension;
        }

        /* in the case of policyQualifiers/qualifier, the type has to be \phpseclib3\File\ASN1::TYPE_IA5_STRING.
           \phpseclib3\File\ASN1::TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random
           characters.
         */
        $filters['policyQualifiers']['qualifier']
            = ['type' => ASN1::TYPE_IA5_STRING];

        ASN1::setFilters($filters);

        $this->mapOutExtensions($cert, 'tbsCertificate/extensions');
        $this->mapOutDNs($cert, 'tbsCertificate/issuer/rdnSequence');
        $this->mapOutDNs($cert, 'tbsCertificate/subject/rdnSequence');

        $cert = ASN1::encodeDER($cert, Maps\Certificate::MAP);

        switch ($format) {
            case self::FORMAT_DER:
                return $cert;
            // case self::FORMAT_PEM:
            default:
                return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(Strings::base64_encode($cert), 64) . '-----END CERTIFICATE-----';
        }
    }

    /**
     * Map extension values from octet string to extension-specific internal
     *   format.
     *
     * @param array $root (by reference)
     * @param string $path
     */
    private function mapInExtensions(array &$root, $path)
    {
        $extensions = &$this->subArrayUnchecked($root, $path);

        if ($extensions) {
            for ($i = 0; $i < count($extensions); $i++) {
                $id = $extensions[$i]['extnId'];
                $value = &$extensions[$i]['extnValue'];
                /* [extnValue] contains the DER encoding of an ASN.1 value
                   corresponding to the extension type identified by extnID */
                $map = $this->getMapping($id);
                if (!is_bool($map)) {
                    $decoder = $id == 'id-ce-nameConstraints' ?
                        [static::class, 'decodeNameConstraintIP'] :
                        [static::class, 'decodeIP'];
                    $decoded = ASN1::decodeBER($value);
                    if (!$decoded) {
                        continue;
                    }
                    $mapped = ASN1::asn1map($decoded[0], $map, ['iPAddress' => $decoder]);
                    $value = $mapped === false ? $decoded[0] : $mapped;

                    if ($id == 'id-ce-certificatePolicies') {
                        for ($j = 0; $j < count($value); $j++) {
                            if (!isset($value[$j]['policyQualifiers'])) {
                                continue;
                            }
                            for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
                                $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
                                $map = $this->getMapping($subid);
                                $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
                                if ($map !== false) {
                                    $decoded = ASN1::decodeBER($subvalue);
                                    if (!$decoded) {
                                        continue;
                                    }
                                    $mapped = ASN1::asn1map($decoded[0], $map);
                                    $subvalue = $mapped === false ? $decoded[0] : $mapped;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Map extension values from extension-specific internal format to
     *   octet string.
     *
     * @param array $root (by reference)
     * @param string $path
     */
    private function mapOutExtensions(array &$root, $path)
    {
        $extensions = &$this->subArray($root, $path, !empty($this->extensionValues));

        foreach ($this->extensionValues as $id => $data) {
            $critical = $data['critical'];
            $replace = $data['replace'];
            $value = $data['value'];
            $newext = [
                'extnId' => $id,
                'extnValue' => $value,
                'critical' => $critical
            ];
            if ($replace) {
                foreach ($extensions as $key => $value) {
                    if ($value['extnId'] == $id) {
                        $extensions[$key] = $newext;
                        continue 2;
                    }
                }
            }
            $extensions[] = $newext;
        }

        if (is_array($extensions)) {
            $size = count($extensions);
            for ($i = 0; $i < $size; $i++) {
                if ($extensions[$i] instanceof Element) {
                    continue;
                }

                $id = $extensions[$i]['extnId'];
                $value = &$extensions[$i]['extnValue'];

                switch ($id) {
                    case 'id-ce-certificatePolicies':
                        for ($j = 0; $j < count($value); $j++) {
                            if (!isset($value[$j]['policyQualifiers'])) {
                                continue;
                            }
                            for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) {
                                $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId'];
                                $map = $this->getMapping($subid);
                                $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier'];
                                if ($map !== false) {
                                    // by default \phpseclib3\File\ASN1 will try to render qualifier as a \phpseclib3\File\ASN1::TYPE_IA5_STRING since it's
                                    // actual type is \phpseclib3\File\ASN1::TYPE_ANY
                                    $subvalue = new Element(ASN1::encodeDER($subvalue, $map));
                                }
                            }
                        }
                        break;
                    case 'id-ce-authorityKeyIdentifier': // use 00 as the serial number instead of an empty string
                        if (isset($value['authorityCertSerialNumber'])) {
                            if ($value['authorityCertSerialNumber']->toBytes() == '') {
                                $temp = chr((ASN1::CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0";
                                $value['authorityCertSerialNumber'] = new Element($temp);
                            }
                        }
                }

                /* [extnValue] contains the DER encoding of an ASN.1 value
                   corresponding to the extension type identified by extnID */
                $map = $this->getMapping($id);
                if (is_bool($map)) {
                    if (!$map) {
                        //user_error($id . ' is not a currently supported extension');
                        unset($extensions[$i]);
                    }
                } else {
                    $value = ASN1::encodeDER($value, $map, ['iPAddress' => [static::class, 'encodeIP']]);
                }
            }
        }
    }

    /**
     * Map attribute values from ANY type to attribute-specific internal
     *   format.
     *
     * @param array $root (by reference)
     * @param string $path
     */
    private function mapInAttributes(&$root, $path)
    {
        $attributes = &$this->subArray($root, $path);

        if (is_array($attributes)) {
            for ($i = 0; $i < count($attributes); $i++) {
                $id = $attributes[$i]['type'];
                /* $value contains the DER encoding of an ASN.1 value
                   corresponding to the attribute type identified by type */
                $map = $this->getMapping($id);
                if (is_array($attributes[$i]['value'])) {
                    $values = &$attributes[$i]['value'];
                    for ($j = 0; $j < count($values); $j++) {
                        $value = ASN1::encodeDER($values[$j], Maps\AttributeValue::MAP);
                        $decoded = ASN1::decodeBER($value);
                        if (!is_bool($map)) {
                            if (!$decoded) {
                                continue;
                            }
                            $mapped = ASN1::asn1map($decoded[0], $map);
                            if ($mapped !== false) {
                                $values[$j] = $mapped;
                            }
                            if ($id == 'pkcs-9-at-extensionRequest' && $this->isSubArrayValid($values, $j)) {
                                $this->mapInExtensions($values, $j);
                            }
                        } elseif ($map) {
                            $values[$j] = $value;
                        }
                    }
                }
            }
        }
    }

    /**
     * Map attribute values from attribute-specific internal format to
     *   ANY type.
     *
     * @param array $root (by reference)
     * @param string $path
     */
    private function mapOutAttributes(&$root, $path)
    {
        $attributes = &$this->subArray($root, $path);

        if (is_array($attributes)) {
            $size = count($attributes);
            for ($i = 0; $i < $size; $i++) {
                /* [value] contains the DER encoding of an ASN.1 value
                   corresponding to the attribute type identified by type */
                $id = $attributes[$i]['type'];
                $map = $this->getMapping($id);
                if ($map === false) {
                    //user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
                    unset($attributes[$i]);
                } elseif (is_array($attributes[$i]['value'])) {
                    $values = &$attributes[$i]['value'];
                    for ($j = 0; $j < count($values); $j++) {
                        switch ($id) {
                            case 'pkcs-9-at-extensionRequest':
                                $this->mapOutExtensions($values, $j);
                                break;
                        }

                        if (!is_bool($map)) {
                            $temp = ASN1::encodeDER($values[$j], $map);
                            $decoded = ASN1::decodeBER($temp);
                            if (!$decoded) {
                                continue;
                            }
                            $values[$j] = ASN1::asn1map($decoded[0], Maps\AttributeValue::MAP);
                        }
                    }
                }
            }
        }
    }

    /**
     * Map DN values from ANY type to DN-specific internal
     *   format.
     *
     * @param array $root (by reference)
     * @param string $path
     */
    private function mapInDNs(array &$root, $path)
    {
        $dns = &$this->subArray($root, $path);

        if (is_array($dns)) {
            for ($i = 0; $i < count($dns); $i++) {
                for ($j = 0; $j < count($dns[$i]); $j++) {
                    $type = $dns[$i][$j]['type'];
                    $value = &$dns[$i][$j]['value'];
                    if (is_object($value) && $value instanceof Element) {
                        $map = $this->getMapping($type);
                        if (!is_bool($map)) {
                            $decoded = ASN1::decodeBER($value);
                            if (!$decoded) {
                                continue;
                            }
                            $value = ASN1::asn1map($decoded[0], $map);
                        }
                    }
                }
            }
        }
    }

    /**
     * Map DN values from DN-specific internal format to
     *   ANY type.
     *
     * @param array $root (by reference)
     * @param string $path
     */
    private function mapOutDNs(array &$root, $path)
    {
        $dns = &$this->subArray($root, $path);

        if (is_array($dns)) {
            $size = count($dns);
            for ($i = 0; $i < $size; $i++) {
                for ($j = 0; $j < count($dns[$i]); $j++) {
                    $type = $dns[$i][$j]['type'];
                    $value = &$dns[$i][$j]['value'];
                    if (is_object($value) && $value instanceof Element) {
                        continue;
                    }

                    $map = $this->getMapping($type);
                    if (!is_bool($map)) {
                        $value = new Element(ASN1::encodeDER($value, $map));
                    }
                }
            }
        }
    }

    /**
     * Associate an extension ID to an extension mapping
     *
     * @param string $extnId
     * @return mixed
     */
    private function getMapping($extnId)
    {
        if (!is_string($extnId)) { // eg. if it's a \phpseclib3\File\ASN1\Element object
            return true;
        }

        if (isset(self::$extensions[$extnId])) {
            return self::$extensions[$extnId];
        }

        switch ($extnId) {
            case 'id-ce-keyUsage':
                return Maps\KeyUsage::MAP;
            case 'id-ce-basicConstraints':
                return Maps\BasicConstraints::MAP;
            case 'id-ce-subjectKeyIdentifier':
                return Maps\KeyIdentifier::MAP;
            case 'id-ce-cRLDistributionPoints':
                return Maps\CRLDistributionPoints::MAP;
            case 'id-ce-authorityKeyIdentifier':
                return Maps\AuthorityKeyIdentifier::MAP;
            case 'id-ce-certificatePolicies':
                return Maps\CertificatePolicies::MAP;
            case 'id-ce-extKeyUsage':
                return Maps\ExtKeyUsageSyntax::MAP;
            case 'id-pe-authorityInfoAccess':
                return Maps\AuthorityInfoAccessSyntax::MAP;
            case 'id-ce-subjectAltName':
                return Maps\SubjectAltName::MAP;
            case 'id-ce-subjectDirectoryAttributes':
                return Maps\SubjectDirectoryAttributes::MAP;
            case 'id-ce-privateKeyUsagePeriod':
                return Maps\PrivateKeyUsagePeriod::MAP;
            case 'id-ce-issuerAltName':
                return Maps\IssuerAltName::MAP;
            case 'id-ce-policyMappings':
                return Maps\PolicyMappings::MAP;
            case 'id-ce-nameConstraints':
                return Maps\NameConstraints::MAP;

            case 'netscape-cert-type':
                return Maps\netscape_cert_type::MAP;
            case 'netscape-comment':
                return Maps\netscape_comment::MAP;
            case 'netscape-ca-policy-url':
                return Maps\netscape_ca_policy_url::MAP;

            // since id-qt-cps isn't a constructed type it will have already been decoded as a string by the time it gets
            // back around to asn1map() and we don't want it decoded again.
            //case 'id-qt-cps':
            //    return Maps\CPSuri::MAP;
            case 'id-qt-unotice':
                return Maps\UserNotice::MAP;

            // the following OIDs are unsupported but we don't want them to give notices when calling saveX509().
            case 'id-pe-logotype': // http://www.ietf.org/rfc/rfc3709.txt
            case 'entrustVersInfo':
            // http://support.microsoft.com/kb/287547
            case '1.3.6.1.4.1.311.20.2': // szOID_ENROLL_CERTTYPE_EXTENSION
            case '1.3.6.1.4.1.311.21.1': // szOID_CERTSRV_CA_VERSION
            // "SET Secure Electronic Transaction Specification"
            // http://www.maithean.com/docs/set_bk3.pdf
            case '2.23.42.7.0': // id-set-hashedRootKey
            // "Certificate Transparency"
            // https://tools.ietf.org/html/rfc6962
            case '1.3.6.1.4.1.11129.2.4.2':
            // "Qualified Certificate statements"
            // https://tools.ietf.org/html/rfc3739#section-3.2.6
            case '1.3.6.1.5.5.7.1.3':
                return true;

            // CSR attributes
            case 'pkcs-9-at-unstructuredName':
                return Maps\PKCS9String::MAP;
            case 'pkcs-9-at-challengePassword':
                return Maps\DirectoryString::MAP;
            case 'pkcs-9-at-extensionRequest':
                return Maps\Extensions::MAP;

            // CRL extensions.
            case 'id-ce-cRLNumber':
                return Maps\CRLNumber::MAP;
            case 'id-ce-deltaCRLIndicator':
                return Maps\CRLNumber::MAP;
            case 'id-ce-issuingDistributionPoint':
                return Maps\IssuingDistributionPoint::MAP;
            case 'id-ce-freshestCRL':
                return Maps\CRLDistributionPoints::MAP;
            case 'id-ce-cRLReasons':
                return Maps\CRLReason::MAP;
            case 'id-ce-invalidityDate':
                return Maps\InvalidityDate::MAP;
            case 'id-ce-certificateIssuer':
                return Maps\CertificateIssuer::MAP;
            case 'id-ce-holdInstructionCode':
                return Maps\HoldInstructionCode::MAP;
            case 'id-at-postalAddress':
                return Maps\PostalAddress::MAP;
        }

        return false;
    }

    /**
     * Load an X.509 certificate as a certificate authority
     *
     * @param string $cert
     * @return bool
     * @removed in phpseclib 4.0.0
     */
    public function loadCA($cert)
    {
        $olddn = $this->dn;
        $oldcert = $this->currentCert;
        $oldsigsubj = $this->signatureSubject;
        $oldkeyid = $this->currentKeyIdentifier;

        $cert = $this->loadX509($cert);
        if (!$cert) {
            $this->dn = $olddn;
            $this->currentCert = $oldcert;
            $this->signatureSubject = $oldsigsubj;
            $this->currentKeyIdentifier = $oldkeyid;

            return false;
        }

        /* From RFC5280 "PKIX Certificate and CRL Profile":

           If the keyUsage extension is present, then the subject public key
           MUST NOT be used to verify signatures on certificates or CRLs unless
           the corresponding keyCertSign or cRLSign bit is set. */
        //$keyUsage = $this->getExtension('id-ce-keyUsage');
        //if ($keyUsage && !in_array('keyCertSign', $keyUsage)) {
        //    return false;
        //}

        /* From RFC5280 "PKIX Certificate and CRL Profile":

           The cA boolean indicates whether the certified public key may be used
           to verify certificate signatures.  If the cA boolean is not asserted,
           then the keyCertSign bit in the key usage extension MUST NOT be
           asserted.  If the basic constraints extension is not present in a
           version 3 certificate, or the extension is present but the cA boolean
           is not asserted, then the certified public key MUST NOT be used to
           verify certificate signatures. */
        //$basicConstraints = $this->getExtension('id-ce-basicConstraints');
        //if (!$basicConstraints || !$basicConstraints['cA']) {
        //    return false;
        //}

        $this->CAs[] = $cert;

        $this->dn = $olddn;
        $this->currentCert = $oldcert;
        $this->signatureSubject = $oldsigsubj;

        return true;
    }

    /**
     * Validate an X.509 certificate against a URL
     *
     * From RFC2818 "HTTP over TLS":
     *
     * Matching is performed using the matching rules specified by
     * [RFC2459].  If more than one identity of a given type is present in
     * the certificate (e.g., more than one dNSName name, a match in any one
     * of the set is considered acceptable.) Names may contain the wildcard
     * character * which is considered to match any single domain name
     * component or component fragment. E.g., *.a.com matches foo.a.com but
     * not bar.foo.a.com. f*.com matches foo.com but not bar.com.
     *
     * @param string $url
     * @return bool
     */
    public function validateURL($url)
    {
        if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
            return false;
        }

        $components = parse_url($url);
        if (!isset($components['host'])) {
            return false;
        }

        if ($names = $this->getExtension('id-ce-subjectAltName')) {
            foreach ($names as $name) {
                foreach ($name as $key => $value) {
                    $value = preg_quote($value);
                    $value = str_replace('\*', '[^.]*', $value);
                    switch ($key) {
                        case 'dNSName':
                            /* From RFC2818 "HTTP over TLS":

                               If a subjectAltName extension of type dNSName is present, that MUST
                               be used as the identity. Otherwise, the (most specific) Common Name
                               field in the Subject field of the certificate MUST be used. Although
                               the use of the Common Name is existing practice, it is deprecated and
                               Certification Authorities are encouraged to use the dNSName instead. */
                            if (preg_match('#^' . $value . '$#', $components['host'])) {
                                return true;
                            }
                            break;
                        case 'iPAddress':
                            /* From RFC2818 "HTTP over TLS":

                               In some cases, the URI is specified as an IP address rather than a
                               hostname. In this case, the iPAddress subjectAltName must be present
                               in the certificate and must exactly match the IP in the URI. */
                            if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) {
                                return true;
                            }
                    }
                }
            }
            return false;
        }

        if ($value = $this->getDNProp('id-at-commonName')) {
            $value = str_replace(['.', '*'], ['\.', '[^.]*'], $value[0]);
            return preg_match('#^' . $value . '$#', $components['host']) === 1;
        }

        return false;
    }

    /**
     * Validate a date
     *
     * If $date isn't defined it is assumed to be the current date.
     *
     * @param \DateTimeInterface|string $date optional
     * @return bool
     * @removed in phpseclib 4.0.0
     */
    public function validateDate($date = null)
    {
        if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
            return false;
        }

        if (!isset($date)) {
            $date = new \DateTimeImmutable('now', new \DateTimeZone(@date_default_timezone_get()));
        }

        $notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore'];
        $notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime'];

        $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter'];
        $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime'];

        if (is_string($date)) {
            $date = new \DateTimeImmutable($date, new \DateTimeZone(@date_default_timezone_get()));
        }

        $notBefore = new \DateTimeImmutable($notBefore, new \DateTimeZone(@date_default_timezone_get()));
        $notAfter = new \DateTimeImmutable($notAfter, new \DateTimeZone(@date_default_timezone_get()));

        return $date >= $notBefore && $date <= $notAfter;
    }

    /**
     * Fetches a URL
     *
     * If a fetch callback is set via setURLFetchCallback(), the host is resolved
     * once and the connection is pinned to that IP (the callback judges the
     * resolved IP, preventing DNS-rebinding bypass).
     *
     * @param string $url
     * @return bool|string
     */
    private static function fetchURL($url)
    {
        if (self::$disable_url_fetch) {
            return false;
        }

        $parts = parse_url($url);
        if ($parts === false || !isset($parts['scheme']) || !isset($parts['host'])) {
            return false;
        }
        $host = $parts['host'];
        $port = isset($parts['port']) ? $parts['port'] : 80;

        if (isset(self::$urlFetchCallback)) {
            if (filter_var($host, FILTER_VALIDATE_IP)) {
                $ip = $host;
                // unwrap IPv4-mapped IPv6 so the callback judges the real v4 address
                if (preg_match('/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i', $ip, $m)) {
                    $ip = $m[1];
                }
            } else {
                $records = dns_get_record($host, DNS_A | DNS_AAAA);
                if (!$records) {
                    return false;
                }
                if (isset($records[0]['ip'])) {
                    $ip = $records[0]['ip'];
                } elseif (isset($records[0]['ipv6'])) {
                    $ip = $records[0]['ipv6'];
                } else {
                    return false;
                }
            }
            if (!call_user_func(self::$urlFetchCallback, $host, $ip, $port, $parts['scheme'])) {
                return false;
            }
            $target = strpos($ip, ':') !== false ? "[$ip]" : $ip;
        } else {
            $target = $host;
        }

        $data = '';
        switch ($parts['scheme']) {
            case 'http':
                $fsock = @fsockopen($target, $port);
                if (!$fsock) {
                    return false;
                }
                $path = isset($parts['path']) ? $parts['path'] : '/';
                if (isset($parts['query'])) {
                    $path .= '?' . $parts['query'];
                }
                fputs($fsock, "GET $path HTTP/1.0\r\n");
                fputs($fsock, "Host: $host\r\n\r\n");
                $line = fgets($fsock, 1024);
                if ($line === false || strlen($line) < 3) {
                    return false;
                }
                if (!preg_match('#HTTP/1.\d (\d{3})#', $line, $temp) || $temp[1] != '200') {
                    return false;
                }

                // skip the rest of the headers in the http response
                while (!feof($fsock) && fgets($fsock, 1024) != "\r\n") {
                }

                while (!feof($fsock)) {
                    $temp = fread($fsock, 1024);
                    if ($temp === false) {
                        return false;
                    }
                    $data .= $temp;
                }

                break;
            //case 'ftp':
            //case 'ldap':
            default:
                return false;
        }

        return $data;
    }

    /**
     * Validates an intermediate cert as identified via authority info access extension
     *
     * See https://tools.ietf.org/html/rfc4325 for more info
     *
     * @param bool $caonly
     * @param int $count
     * @return bool
     */
    private function testForIntermediate($caonly, $count)
    {
        $opts = $this->getExtension('id-pe-authorityInfoAccess');
        if (!is_array($opts)) {
            return false;
        }
        foreach ($opts as $opt) {
            if ($opt['accessMethod'] == 'id-ad-caIssuers') {
                // accessLocation is a GeneralName. GeneralName fields support stuff like email addresses, IP addresses, LDAP,
                // etc, but we're only supporting URI's. URI's and LDAP are the only thing https://tools.ietf.org/html/rfc4325
                // discusses
                if (isset($opt['accessLocation']['uniformResourceIdentifier'])) {
                    $url = $opt['accessLocation']['uniformResourceIdentifier'];
                    break;
                }
            }
        }

        if (!isset($url)) {
            return false;
        }

        $cert = static::fetchURL($url);
        if (!is_string($cert)) {
            return false;
        }

        $parent = new static();
        $parent->CAs = $this->CAs;
        /*
         "Conforming applications that support HTTP or FTP for accessing
          certificates MUST be able to accept .cer files and SHOULD be able
          to accept .p7c files." -- https://tools.ietf.org/html/rfc4325

         A .p7c file is 'a "certs-only" CMS message as specified in RFC 2797"

         These are currently unsupported
        */
        if (!is_array($parent->loadX509($cert))) {
            return false;
        }

        if (!$parent->validateSignatureCountable($caonly, ++$count)) {
            return false;
        }

        $this->CAs[] = $parent->currentCert;
        //$this->loadCA($cert);

        return true;
    }

    /**
     * Validate a signature
     *
     * Works on X.509 certs, CSR's and CRL's.
     * Returns true if the signature is verified, false if it is not correct or null on error
     *
     * By default returns false for self-signed certs. Call validateSignature(false) to make this support
     * self-signed.
     *
     * The behavior of this function is inspired by {@link http://php.net/openssl-verify openssl_verify}.
     *
     * @param bool $caonly optional
     * @return mixed
     * @changed in phpseclib 4.0.0
     */
    public function validateSignature($caonly = true)
    {
        return $this->validateSignatureCountable($caonly, 0);
    }

    /**
     * Validate a signature
     *
     * Performs said validation whilst keeping track of how many times validation method is called
     *
     * @param bool $caonly
     * @param int $count
     * @return mixed
     */
    private function validateSignatureCountable($caonly, $count)
    {
        if (!is_array($this->currentCert) || !isset($this->signatureSubject)) {
            return null;
        }

        if ($count == self::$recur_limit) {
            return false;
        }

        /* TODO:
           "emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")."
            -- http://tools.ietf.org/html/rfc5280#section-4.1.2.6

           implement pathLenConstraint in the id-ce-basicConstraints extension */

        switch (true) {
            case isset($this->currentCert['tbsCertificate']):
                // self-signed cert
                switch (true) {
                    case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']:
                    case defined('FILE_X509_IGNORE_TYPE') && $this->getIssuerDN(self::DN_STRING) === $this->getDN(self::DN_STRING):
                        $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
                        $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
                        switch (true) {
                            case !is_array($authorityKey):
                            case !$subjectKeyID:
                            case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
                                $signingCert = $this->currentCert; // working cert
                        }
                }

                if (!empty($this->CAs)) {
                    for ($i = 0; $i < count($this->CAs); $i++) {
                        // even if the cert is a self-signed one we still want to see if it's a CA;
                        // if not, we'll conditionally return an error
                        $ca = $this->CAs[$i];
                        switch (true) {
                            case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']:
                            case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertificate']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']):
                                $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
                                $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
                                switch (true) {
                                    case !is_array($authorityKey):
                                    case !$subjectKeyID:
                                    case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
                                        if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
                                            break 2; // serial mismatch - check other ca
                                        }
                                        $signingCert = $ca; // working cert
                                        break 3;
                                }
                        }
                    }
                    if (count($this->CAs) == $i && $caonly) {
                        return $this->testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
                    }
                } elseif (!isset($signingCert) || $caonly) {
                    return $this->testForIntermediate($caonly, $count) && $this->validateSignature($caonly);
                }
                return $this->validateSignatureHelper(
                    $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
                    $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
                    $this->currentCert['signatureAlgorithm']['algorithm'],
                    substr($this->currentCert['signature'], 1),
                    $this->signatureSubject
                );
            case isset($this->currentCert['certificationRequestInfo']):
                return $this->validateSignatureHelper(
                    $this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'],
                    $this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'],
                    $this->currentCert['signatureAlgorithm']['algorithm'],
                    substr($this->currentCert['signature'], 1),
                    $this->signatureSubject
                );
            case isset($this->currentCert['publicKeyAndChallenge']):
                return $this->validateSignatureHelper(
                    $this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'],
                    $this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'],
                    $this->currentCert['signatureAlgorithm']['algorithm'],
                    substr($this->currentCert['signature'], 1),
                    $this->signatureSubject
                );
            case isset($this->currentCert['tbsCertList']):
                if (!empty($this->CAs)) {
                    for ($i = 0; $i < count($this->CAs); $i++) {
                        $ca = $this->CAs[$i];
                        switch (true) {
                            case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']:
                            case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertList']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']):
                                $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
                                $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
                                switch (true) {
                                    case !is_array($authorityKey):
                                    case !$subjectKeyID:
                                    case isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
                                        if (is_array($authorityKey) && isset($authorityKey['authorityCertSerialNumber']) && !$authorityKey['authorityCertSerialNumber']->equals($ca['tbsCertificate']['serialNumber'])) {
                                            break 2; // serial mismatch - check other ca
                                        }
                                        $signingCert = $ca; // working cert
                                        break 3;
                                }
                        }
                    }
                }
                if (!isset($signingCert)) {
                    return false;
                }
                return $this->validateSignatureHelper(
                    $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
                    $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
                    $this->currentCert['signatureAlgorithm']['algorithm'],
                    substr($this->currentCert['signature'], 1),
                    $this->signatureSubject
                );
            default:
                return false;
        }
    }

    /**
     * Validates a signature
     *
     * Returns true if the signature is verified and false if it is not correct.
     * If the algorithms are unsupposed an exception is thrown.
     *
     * @param string $publicKeyAlgorithm
     * @param string $publicKey
     * @param string $signatureAlgorithm
     * @param string $signature
     * @param string $signatureSubject
     * @throws UnsupportedAlgorithmException if the algorithm is unsupported
     * @return bool
     */
    private function validateSignatureHelper($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
    {
        switch ($publicKeyAlgorithm) {
            case 'id-RSASSA-PSS':
                $key = RSA::loadFormat('PSS', $publicKey);
                break;
            case 'rsaEncryption':
                $key = RSA::loadFormat('PKCS8', $publicKey);
                switch ($signatureAlgorithm) {
                    case 'id-RSASSA-PSS':
                        break;
                    case 'md2WithRSAEncryption':
                    case 'md5WithRSAEncryption':
                    case 'sha1WithRSAEncryption':
                    case 'sha224WithRSAEncryption':
                    case 'sha256WithRSAEncryption':
                    case 'sha384WithRSAEncryption':
                    case 'sha512WithRSAEncryption':
                        $key = $key
                            ->withHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm))
                            ->withPadding(RSA::SIGNATURE_PKCS1);
                        break;
                    default:
                        throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
                }
                break;
            case 'id-Ed25519':
            case 'id-Ed448':
                $key = EC::loadFormat('PKCS8', $publicKey);
                break;
            case 'id-ecPublicKey':
                $key = EC::loadFormat('PKCS8', $publicKey);
                switch ($signatureAlgorithm) {
                    case 'ecdsa-with-SHA1':
                    case 'ecdsa-with-SHA224':
                    case 'ecdsa-with-SHA256':
                    case 'ecdsa-with-SHA384':
                    case 'ecdsa-with-SHA512':
                        $key = $key
                            ->withHash(preg_replace('#^ecdsa-with-#', '', strtolower($signatureAlgorithm)));
                        break;
                    default:
                        throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
                }
                break;
            case 'id-dsa':
                $key = DSA::loadFormat('PKCS8', $publicKey);
                switch ($signatureAlgorithm) {
                    case 'id-dsa-with-sha1':
                    case 'id-dsa-with-sha224':
                    case 'id-dsa-with-sha256':
                        $key = $key
                            ->withHash(preg_replace('#^id-dsa-with-#', '', strtolower($signatureAlgorithm)));
                        break;
                    default:
                        throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
                }
                break;
            default:
                throw new UnsupportedAlgorithmException('Public key algorithm unsupported');
        }

        return $key->verify($signatureSubject, $signature);
    }

    /**
     * Sets the recursion limit
     *
     * When validating a signature it may be necessary to download intermediate certs from URI's.
     * An intermediate cert that linked to itself would result in an infinite loop so to prevent
     * that we set a recursion limit. A negative number means that there is no recursion limit.
     *
     * @param int $count
     */
    public static function setRecurLimit($count)
    {
        self::$recur_limit = $count;
    }

    /**
     * Prevents URIs from being automatically retrieved
     *
     * @removed in phpseclib 4.0.0
     */
    public static function disableURLFetch()
    {
        self::$disable_url_fetch = true;
    }

    /**
     * Allows URIs to be automatically retrieved
     *
     * @removed in phpseclib 4.0.0
     */
    public static function enableURLFetch()
    {
        self::$disable_url_fetch = false;
    }

    /**
     * Decodes an IP address
     *
     * Takes in a base64 encoded "blob" and returns a human readable IP address
     *
     * @param string $ip
     * @return string
     * @removed in phpseclib 4.0.0
     */
    public static function decodeIP($ip)
    {
        return inet_ntop($ip);
    }

    /**
     * Decodes an IP address in a name constraints extension
     *
     * Takes in a base64 encoded "blob" and returns a human readable IP address / mask
     *
     * @param string $ip
     * @return array
     * @removed in phpseclib 4.0.0
     */
    public static function decodeNameConstraintIP($ip)
    {
        $size = strlen($ip) >> 1;
        $mask = substr($ip, $size);
        $ip = substr($ip, 0, $size);
        return [inet_ntop($ip), inet_ntop($mask)];
    }

    /**
     * Encodes an IP address
     *
     * Takes a human readable IP address into a base64-encoded "blob"
     *
     * @param string|array $ip
     * @return string
     * @removed in phpseclib 4.0.0
     */
    public static function encodeIP($ip)
    {
        return is_string($ip) ?
            inet_pton($ip) :
            inet_pton($ip[0]) . inet_pton($ip[1]);
    }

    /**
     * "Normalizes" a Distinguished Name property
     *
     * @param string $propName
     * @return mixed
     */
    private function translateDNProp($propName)
    {
        switch (strtolower($propName)) {
            case 'jurisdictionofincorporationcountryname':
            case 'jurisdictioncountryname':
            case 'jurisdictionc':
                return 'jurisdictionOfIncorporationCountryName';
            case 'jurisdictionofincorporationstateorprovincename':
            case 'jurisdictionstateorprovincename':
            case 'jurisdictionst':
                return 'jurisdictionOfIncorporationStateOrProvinceName';
            case 'jurisdictionlocalityname':
            case 'jurisdictionl':
                return 'jurisdictionLocalityName';
            case 'id-at-businesscategory':
            case 'businesscategory':
                return 'id-at-businessCategory';
            case 'id-at-countryname':
            case 'countryname':
            case 'c':
                return 'id-at-countryName';
            case 'id-at-organizationname':
            case 'organizationname':
            case 'o':
                return 'id-at-organizationName';
            case 'id-at-dnqualifier':
            case 'dnqualifier':
                return 'id-at-dnQualifier';
            case 'id-at-commonname':
            case 'commonname':
            case 'cn':
                return 'id-at-commonName';
            case 'id-at-stateorprovincename':
            case 'stateorprovincename':
            case 'state':
            case 'province':
            case 'provincename':
            case 'st':
                return 'id-at-stateOrProvinceName';
            case 'id-at-localityname':
            case 'localityname':
            case 'l':
                return 'id-at-localityName';
            case 'id-emailaddress':
            case 'emailaddress':
                return 'pkcs-9-at-emailAddress';
            case 'id-at-serialnumber':
            case 'serialnumber':
                return 'id-at-serialNumber';
            case 'id-at-postalcode':
            case 'postalcode':
                return 'id-at-postalCode';
            case 'id-at-streetaddress':
            case 'streetaddress':
                return 'id-at-streetAddress';
            case 'id-at-name':
            case 'name':
                return 'id-at-name';
            case 'id-at-givenname':
            case 'givenname':
                return 'id-at-givenName';
            case 'id-at-surname':
            case 'surname':
            case 'sn':
                return 'id-at-surname';
            case 'id-at-initials':
            case 'initials':
                return 'id-at-initials';
            case 'id-at-generationqualifier':
            case 'generationqualifier':
                return 'id-at-generationQualifier';
            case 'id-at-organizationalunitname':
            case 'organizationalunitname':
            case 'ou':
                return 'id-at-organizationalUnitName';
            case 'id-at-organizationidentifier':
            case 'organizationIdentifier':
                return 'id-at-organizationIdentifier';
            case 'id-at-pseudonym':
            case 'pseudonym':
                return 'id-at-pseudonym';
            case 'id-at-title':
            case 'title':
                return 'id-at-title';
            case 'id-at-description':
            case 'description':
                return 'id-at-description';
            case 'id-at-role':
            case 'role':
                return 'id-at-role';
            case 'id-at-uniqueidentifier':
            case 'uniqueidentifier':
            case 'x500uniqueidentifier':
                return 'id-at-uniqueIdentifier';
            case 'postaladdress':
            case 'id-at-postaladdress':
                return 'id-at-postalAddress';
            default:
                return false;
        }
    }

    /**
     * Set a Distinguished Name property
     *
     * @param string $propName
     * @param mixed $propValue
     * @param string $type optional
     * @return bool
     * @removed in phpseclib 4.0.0
     */
    public function setDNProp($propName, $propValue, $type = 'utf8String')
    {
        if (empty($this->dn)) {
            $this->dn = ['rdnSequence' => []];
        }

        if (($propName = $this->translateDNProp($propName)) === false) {
            return false;
        }

        foreach ((array) $propValue as $v) {
            if (!is_array($v) && isset($type)) {
                $v = [$type => $v];
            }
            $this->dn['rdnSequence'][] = [
                [
                    'type' => $propName,
                    'value' => $v
                ]
            ];
        }

        return true;
    }

    /**
     * Remove Distinguished Name properties
     *
     * @param string $propName
     * @removed in phpseclib 4.0.0
     */
    public function removeDNProp($propName)
    {
        if (empty($this->dn)) {
            return;
        }

        if (($propName = $this->translateDNProp($propName)) === false) {
            return;
        }

        $dn = &$this->dn['rdnSequence'];
        $size = count($dn);
        for ($i = 0; $i < $size; $i++) {
            if ($dn[$i][0]['type'] == $propName) {
                unset($dn[$i]);
            }
        }

        $dn = array_values($dn);
        // fix for https://bugs.php.net/75433 affecting PHP 7.2
        if (!isset($dn[0])) {
            $dn = array_splice($dn, 0, 0);
        }
    }

    /**
     * Get Distinguished Name properties
     *
     * @param string $propName
     * @param array $dn optional
     * @param bool $withType optional
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function getDNProp($propName, $dn = null, $withType = false)
    {
        if (!isset($dn)) {
            $dn = $this->dn;
        }

        if (empty($dn)) {
            return false;
        }

        if (($propName = $this->translateDNProp($propName)) === false) {
            return false;
        }

        $filters = [];
        $filters['value'] = ['type' => ASN1::TYPE_UTF8_STRING];
        ASN1::setFilters($filters);
        $this->mapOutDNs($dn, 'rdnSequence');
        $dn = $dn['rdnSequence'];
        $result = [];
        for ($i = 0; $i < count($dn); $i++) {
            if ($dn[$i][0]['type'] == $propName) {
                $v = $dn[$i][0]['value'];
                if (!$withType) {
                    if (is_array($v)) {
                        foreach ($v as $type => $s) {
                            $type = array_search($type, ASN1::ANY_MAP);
                            if ($type !== false && array_key_exists($type, ASN1::STRING_TYPE_SIZE)) {
                                $s = ASN1::convert($s, $type);
                                if ($s !== false) {
                                    $v = $s;
                                    break;
                                }
                            }
                        }
                        if (is_array($v)) {
                            $v = array_pop($v); // Always strip data type.
                        }
                    } elseif (is_object($v) && $v instanceof Element) {
                        $map = $this->getMapping($propName);
                        if (!is_bool($map)) {
                            $decoded = ASN1::decodeBER($v);
                            if (!$decoded) {
                                return false;
                            }
                            $v = ASN1::asn1map($decoded[0], $map);
                        }
                    }
                }
                $result[] = $v;
            }
        }

        return $result;
    }

    /**
     * Set a Distinguished Name
     *
     * @param mixed $dn
     * @param bool $merge optional
     * @param string $type optional
     * @return bool
     * @changed in phpseclib 4.0.0
     */
    public function setDN($dn, $merge = false, $type = 'utf8String')
    {
        if (!$merge) {
            $this->dn = null;
        }

        if (is_array($dn)) {
            if (isset($dn['rdnSequence'])) {
                $this->dn = $dn; // No merge here.
                return true;
            }

            // handles stuff generated by openssl_x509_parse()
            foreach ($dn as $prop => $value) {
                if (!$this->setDNProp($prop, $value, $type)) {
                    return false;
                }
            }
            return true;
        }

        // handles everything else
        $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=|postalAddress=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
        for ($i = 1; $i < count($results); $i += 2) {
            $prop = trim($results[$i], ', =/');
            $value = $results[$i + 1];
            if (!$this->setDNProp($prop, $value, $type)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Get the Distinguished Name for a certificates subject
     *
     * @param mixed $format optional
     * @param array $dn optional
     * @return array|bool|string
     * @changed in phpseclib 4.0.0
     */
    public function getDN($format = self::DN_ARRAY, $dn = null)
    {
        if (!isset($dn)) {
            $dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn;
        }

        switch ((int) $format) {
            case self::DN_ARRAY:
                return $dn;
            case self::DN_ASN1:
                $filters = [];
                $filters['rdnSequence']['value'] = ['type' => ASN1::TYPE_UTF8_STRING];
                ASN1::setFilters($filters);
                $this->mapOutDNs($dn, 'rdnSequence');
                return ASN1::encodeDER($dn, Maps\Name::MAP);
            case self::DN_CANON:
                //  No SEQUENCE around RDNs and all string values normalized as
                // trimmed lowercase UTF-8 with all spacing as one blank.
                // constructed RDNs will not be canonicalized
                $filters = [];
                $filters['value'] = ['type' => ASN1::TYPE_UTF8_STRING];
                ASN1::setFilters($filters);
                $result = '';
                $this->mapOutDNs($dn, 'rdnSequence');
                foreach ($dn['rdnSequence'] as $rdn) {
                    foreach ($rdn as $i => $attr) {
                        $attr = &$rdn[$i];
                        if (is_array($attr['value'])) {
                            foreach ($attr['value'] as $type => $v) {
                                $type = array_search($type, ASN1::ANY_MAP, true);
                                if ($type !== false && array_key_exists($type, ASN1::STRING_TYPE_SIZE)) {
                                    $v = ASN1::convert($v, $type);
                                    if ($v !== false) {
                                        $v = preg_replace('/\s+/', ' ', $v);
                                        $attr['value'] = strtolower(trim($v));
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    $result .= ASN1::encodeDER($rdn, Maps\RelativeDistinguishedName::MAP);
                }
                return $result;
            case self::DN_HASH:
                $dn = $this->getDN(self::DN_CANON, $dn);
                $hash = new Hash('sha1');
                $hash = $hash->hash($dn);
                $hash = unpack('Vhash', $hash)['hash'];
                return strtolower(Strings::bin2hex(pack('N', $hash)));
        }

        // Default is to return a string.
        $start = true;
        $output = '';

        $result = [];
        $filters = [];
        $filters['rdnSequence']['value'] = ['type' => ASN1::TYPE_UTF8_STRING];
        ASN1::setFilters($filters);
        $this->mapOutDNs($dn, 'rdnSequence');

        foreach ($dn['rdnSequence'] as $field) {
            $prop = $field[0]['type'];
            $value = $field[0]['value'];

            $delim = ', ';
            switch ($prop) {
                case 'id-at-countryName':
                    $desc = 'C';
                    break;
                case 'id-at-stateOrProvinceName':
                    $desc = 'ST';
                    break;
                case 'id-at-organizationName':
                    $desc = 'O';
                    break;
                case 'id-at-organizationalUnitName':
                    $desc = 'OU';
                    break;
                case 'id-at-commonName':
                    $desc = 'CN';
                    break;
                case 'id-at-localityName':
                    $desc = 'L';
                    break;
                case 'id-at-surname':
                    $desc = 'SN';
                    break;
                case 'id-at-uniqueIdentifier':
                    $delim = '/';
                    $desc = 'x500UniqueIdentifier';
                    break;
                case 'id-at-postalAddress':
                    $delim = '/';
                    $desc = 'postalAddress';
                    break;
                default:
                    $delim = '/';
                    $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop);
            }

            if (!$start) {
                $output .= $delim;
            }
            if (is_array($value)) {
                foreach ($value as $type => $v) {
                    $type = array_search($type, ASN1::ANY_MAP, true);
                    if ($type !== false && array_key_exists($type, ASN1::STRING_TYPE_SIZE)) {
                        $v = ASN1::convert($v, $type);
                        if ($v !== false) {
                            $value = $v;
                            break;
                        }
                    }
                }
                if (is_array($value)) {
                    $value = array_pop($value); // Always strip data type.
                }
            } elseif (is_object($value) && $value instanceof Element) {
                $callback = function ($x) {
                    return '\x' . bin2hex($x[0]);
                };
                $value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element));
            }
            $output .= $desc . '=' . $value;
            $result[$desc] = isset($result[$desc]) ?
                array_merge((array) $result[$desc], [$value]) :
                $value;
            $start = false;
        }

        return $format == self::DN_OPENSSL ? $result : $output;
    }

    /**
     * Get the Distinguished Name for a certificate/crl issuer
     *
     * @param int $format optional
     * @return mixed
     * @changed in phpseclib 4.0.0
     */
    public function getIssuerDN($format = self::DN_ARRAY)
    {
        switch (true) {
            case !isset($this->currentCert) || !is_array($this->currentCert):
                break;
            case isset($this->currentCert['tbsCertificate']):
                return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']);
            case isset($this->currentCert['tbsCertList']):
                return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']);
        }

        return false;
    }

    /**
     * Get the Distinguished Name for a certificate/csr subject
     * Alias of getDN()
     *
     * @param int $format optional
     * @return mixed
     * @changed in phpseclib 4.0.0
     */
    public function getSubjectDN($format = self::DN_ARRAY)
    {
        switch (true) {
            case !empty($this->dn):
                return $this->getDN($format);
            case !isset($this->currentCert) || !is_array($this->currentCert):
                break;
            case isset($this->currentCert['tbsCertificate']):
                return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']);
            case isset($this->currentCert['certificationRequestInfo']):
                return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']);
        }

        return false;
    }

    /**
     * Get an individual Distinguished Name property for a certificate/crl issuer
     *
     * @param string $propName
     * @param bool $withType optional
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function getIssuerDNProp($propName, $withType = false)
    {
        switch (true) {
            case !isset($this->currentCert) || !is_array($this->currentCert):
                break;
            case isset($this->currentCert['tbsCertificate']):
                return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType);
            case isset($this->currentCert['tbsCertList']):
                return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType);
        }

        return false;
    }

    /**
     * Get an individual Distinguished Name property for a certificate/csr subject
     *
     * @param string $propName
     * @param bool $withType optional
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function getSubjectDNProp($propName, $withType = false)
    {
        switch (true) {
            case !empty($this->dn):
                return $this->getDNProp($propName, null, $withType);
            case !isset($this->currentCert) || !is_array($this->currentCert):
                break;
            case isset($this->currentCert['tbsCertificate']):
                return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType);
            case isset($this->currentCert['certificationRequestInfo']):
                return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType);
        }

        return false;
    }

    /**
     * Get the certificate chain for the current cert
     *
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function getChain()
    {
        $chain = [$this->currentCert];

        if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) {
            return false;
        }
        while (true) {
            $currentCert = $chain[count($chain) - 1];
            for ($i = 0; $i < count($this->CAs); $i++) {
                $ca = $this->CAs[$i];
                if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
                    $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert);
                    $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
                    switch (true) {
                        case !is_array($authorityKey):
                        case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
                            if ($currentCert === $ca) {
                                break 3;
                            }
                            $chain[] = $ca;
                            break 2;
                    }
                }
            }
            if ($i == count($this->CAs)) {
                break;
            }
        }
        foreach ($chain as $key => $value) {
            $chain[$key] = new X509();
            $chain[$key]->loadX509($value);
        }
        return $chain;
    }

    /**
     * Returns the current cert
     *
     * @return array|bool
     * @removed in phpseclib 4.0.0
     */
    public function &getCurrentCert()
    {
        return $this->currentCert;
    }

    /**
     * Set public key
     *
     * Key needs to be a \phpseclib3\Crypt\RSA object
     *
     * @param PublicKey $key
     * @return void
     */
    public function setPublicKey(PublicKey $key)
    {
        $this->publicKey = $key;
    }

    /**
     * Set private key
     *
     * Key needs to be a \phpseclib3\Crypt\RSA object
     *
     * @param PrivateKey $key
     * @removed in phpseclib 4.0.0
     */
    public function setPrivateKey(PrivateKey $key)
    {
        $this->privateKey = $key;
    }

    /**
     * Set challenge
     *
     * Used for SPKAC CSR's
     *
     * @param string $challenge
     * @removed in phpseclib 4.0.0
     */
    public function setChallenge($challenge)
    {
        $this->challenge = $challenge;
    }

    /**
     * Gets the public key
     *
     * Returns a \phpseclib3\Crypt\RSA object or a false.
     *
     * @return mixed
     */
    public function getPublicKey()
    {
        if (isset($this->publicKey)) {
            return $this->publicKey;
        }

        if (isset($this->currentCert) && is_array($this->currentCert)) {
            $paths = [
                'tbsCertificate/subjectPublicKeyInfo',
                'certificationRequestInfo/subjectPKInfo',
                'publicKeyAndChallenge/spki'
            ];
            foreach ($paths as $path) {
                $keyinfo = $this->subArray($this->currentCert, $path);
                if (!empty($keyinfo)) {
                    break;
                }
            }
        }
        if (empty($keyinfo)) {
            return false;
        }

        $key = $keyinfo['subjectPublicKey'];

        switch ($keyinfo['algorithm']['algorithm']) {
            case 'id-RSASSA-PSS':
                return RSA::loadFormat('PSS', $key);
            case 'rsaEncryption':
                return RSA::loadFormat('PKCS8', $key)->withPadding(RSA::SIGNATURE_PKCS1);
            case 'id-ecPublicKey':
            case 'id-Ed25519':
            case 'id-Ed448':
                return EC::loadFormat('PKCS8', $key);
            case 'id-dsa':
                return DSA::loadFormat('PKCS8', $key);
        }

        return false;
    }

    /**
     * Load a Certificate Signing Request
     *
     * @param string $csr
     * @param int $mode
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function loadCSR($csr, $mode = self::FORMAT_AUTO_DETECT)
    {
        if (is_array($csr) && isset($csr['certificationRequestInfo'])) {
            unset($this->currentCert);
            unset($this->currentKeyIdentifier);
            unset($this->signatureSubject);
            $this->dn = $csr['certificationRequestInfo']['subject'];
            if (!isset($this->dn)) {
                return false;
            }

            $this->currentCert = $csr;
            return $csr;
        }

        // see http://tools.ietf.org/html/rfc2986

        if ($mode != self::FORMAT_DER) {
            $newcsr = ASN1::extractBER($csr);
            if ($mode == self::FORMAT_PEM && $csr == $newcsr) {
                return false;
            }
            $csr = $newcsr;
        }
        $orig = $csr;

        if ($csr === false) {
            $this->currentCert = false;
            return false;
        }

        $decoded = ASN1::decodeBER($csr);

        if (!$decoded) {
            $this->currentCert = false;
            return false;
        }

        $csr = ASN1::asn1map($decoded[0], Maps\CertificationRequest::MAP);
        if (!isset($csr) || $csr === false) {
            $this->currentCert = false;
            return false;
        }

        $this->mapInAttributes($csr, 'certificationRequestInfo/attributes');
        $this->mapInDNs($csr, 'certificationRequestInfo/subject/rdnSequence');

        $this->dn = $csr['certificationRequestInfo']['subject'];

        $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);

        $key = $csr['certificationRequestInfo']['subjectPKInfo'];
        $key = ASN1::encodeDER($key, Maps\SubjectPublicKeyInfo::MAP);
        $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'] =
            "-----BEGIN PUBLIC KEY-----\r\n" .
            chunk_split(base64_encode($key), 64) .
            "-----END PUBLIC KEY-----";

        $this->currentKeyIdentifier = null;
        $this->currentCert = $csr;

        $this->publicKey = null;
        $this->publicKey = $this->getPublicKey();

        return $csr;
    }

    /**
     * Save CSR request
     *
     * @param array $csr
     * @param int $format optional
     * @return string
     * @removed in phpseclib 4.0.0
     */
    public function saveCSR(array $csr, $format = self::FORMAT_PEM)
    {
        if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) {
            return false;
        }

        switch (true) {
            case !($algorithm = $this->subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')):
            case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
                break;
            default:
                $csr['certificationRequestInfo']['subjectPKInfo'] = new Element(
                    base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']))
                );
        }

        $filters = [];
        $filters['certificationRequestInfo']['subject']['rdnSequence']['value']
            = ['type' => ASN1::TYPE_UTF8_STRING];

        ASN1::setFilters($filters);

        $this->mapOutDNs($csr, 'certificationRequestInfo/subject/rdnSequence');
        $this->mapOutAttributes($csr, 'certificationRequestInfo/attributes');
        $csr = ASN1::encodeDER($csr, Maps\CertificationRequest::MAP);

        switch ($format) {
            case self::FORMAT_DER:
                return $csr;
            // case self::FORMAT_PEM:
            default:
                return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(Strings::base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----';
        }
    }

    /**
     * Load a SPKAC CSR
     *
     * SPKAC's are produced by the HTML5 keygen element:
     *
     * https://developer.mozilla.org/en-US/docs/HTML/Element/keygen
     *
     * @param string $spkac
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function loadSPKAC($spkac)
    {
        if (is_array($spkac) && isset($spkac['publicKeyAndChallenge'])) {
            unset($this->currentCert);
            unset($this->currentKeyIdentifier);
            unset($this->signatureSubject);
            $this->currentCert = $spkac;
            return $spkac;
        }

        // see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge

        // OpenSSL produces SPKAC's that are preceded by the string SPKAC=
        $temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac);
        $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? Strings::base64_decode($temp) : false;
        if ($temp != false) {
            $spkac = $temp;
        }
        $orig = $spkac;

        if ($spkac === false) {
            $this->currentCert = false;
            return false;
        }

        $decoded = ASN1::decodeBER($spkac);

        if (!$decoded) {
            $this->currentCert = false;
            return false;
        }

        $spkac = ASN1::asn1map($decoded[0], Maps\SignedPublicKeyAndChallenge::MAP);

        if (!isset($spkac) || !is_array($spkac)) {
            $this->currentCert = false;
            return false;
        }

        $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);

        $key = $spkac['publicKeyAndChallenge']['spki'];
        $key = ASN1::encodeDER($key, Maps\SubjectPublicKeyInfo::MAP);
        $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'] =
            "-----BEGIN PUBLIC KEY-----\r\n" .
            chunk_split(base64_encode($key), 64) .
            "-----END PUBLIC KEY-----";

        $this->currentKeyIdentifier = null;
        $this->currentCert = $spkac;

        $this->publicKey = null;
        $this->publicKey = $this->getPublicKey();

        return $spkac;
    }

    /**
     * Save a SPKAC CSR request
     *
     * @param array $spkac
     * @param int $format optional
     * @return string
     * @removed in phpseclib 4.0.0
     */
    public function saveSPKAC(array $spkac, $format = self::FORMAT_PEM)
    {
        if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) {
            return false;
        }

        $algorithm = $this->subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm');
        switch (true) {
            case !$algorithm:
            case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']):
                break;
            default:
                $spkac['publicKeyAndChallenge']['spki'] = new Element(
                    base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']))
                );
        }

        $spkac = ASN1::encodeDER($spkac, Maps\SignedPublicKeyAndChallenge::MAP);

        switch ($format) {
            case self::FORMAT_DER:
                return $spkac;
            // case self::FORMAT_PEM:
            default:
                // OpenSSL's implementation of SPKAC requires the SPKAC be preceded by SPKAC= and since there are pretty much
                // no other SPKAC decoders phpseclib will use that same format
                return 'SPKAC=' . Strings::base64_encode($spkac);
        }
    }

    /**
     * Load a Certificate Revocation List
     *
     * @param string $crl
     * @param int $mode
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function loadCRL($crl, $mode = self::FORMAT_AUTO_DETECT)
    {
        if (is_array($crl) && isset($crl['tbsCertList'])) {
            $this->currentCert = $crl;
            unset($this->signatureSubject);
            return $crl;
        }

        if ($mode != self::FORMAT_DER) {
            $newcrl = ASN1::extractBER($crl);
            if ($mode == self::FORMAT_PEM && $crl == $newcrl) {
                return false;
            }
            $crl = $newcrl;
        }
        $orig = $crl;

        if ($crl === false) {
            $this->currentCert = false;
            return false;
        }

        $decoded = ASN1::decodeBER($crl);

        if (!$decoded) {
            $this->currentCert = false;
            return false;
        }

        $crl = ASN1::asn1map($decoded[0], Maps\CertificateList::MAP);
        if (!isset($crl) || $crl === false) {
            $this->currentCert = false;
            return false;
        }

        $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);

        $this->mapInDNs($crl, 'tbsCertList/issuer/rdnSequence');
        if ($this->isSubArrayValid($crl, 'tbsCertList/crlExtensions')) {
            $this->mapInExtensions($crl, 'tbsCertList/crlExtensions');
        }
        if ($this->isSubArrayValid($crl, 'tbsCertList/revokedCertificates')) {
            $rclist_ref = &$this->subArrayUnchecked($crl, 'tbsCertList/revokedCertificates');
            if ($rclist_ref) {
                $rclist = $crl['tbsCertList']['revokedCertificates'];
                foreach ($rclist as $i => $extension) {
                    if ($this->isSubArrayValid($rclist, "$i/crlEntryExtensions")) {
                        $this->mapInExtensions($rclist_ref, "$i/crlEntryExtensions");
                    }
                }
            }
        }

        $this->currentKeyIdentifier = null;
        $this->currentCert = $crl;

        return $crl;
    }

    /**
     * Save Certificate Revocation List.
     *
     * @param array $crl
     * @param int $format optional
     * @return string
     * @removed in phpseclib 4.0.0
     */
    public function saveCRL(array $crl, $format = self::FORMAT_PEM)
    {
        if (!is_array($crl) || !isset($crl['tbsCertList'])) {
            return false;
        }

        $filters = [];
        $filters['tbsCertList']['issuer']['rdnSequence']['value']
            = ['type' => ASN1::TYPE_UTF8_STRING];
        $filters['tbsCertList']['signature']['parameters']
            = ['type' => ASN1::TYPE_UTF8_STRING];
        $filters['signatureAlgorithm']['parameters']
            = ['type' => ASN1::TYPE_UTF8_STRING];

        if (empty($crl['tbsCertList']['signature']['parameters'])) {
            $filters['tbsCertList']['signature']['parameters']
                = ['type' => ASN1::TYPE_NULL];
        }

        if (empty($crl['signatureAlgorithm']['parameters'])) {
            $filters['signatureAlgorithm']['parameters']
                = ['type' => ASN1::TYPE_NULL];
        }

        ASN1::setFilters($filters);

        $this->mapOutDNs($crl, 'tbsCertList/issuer/rdnSequence');
        $this->mapOutExtensions($crl, 'tbsCertList/crlExtensions');
        $rclist = &$this->subArray($crl, 'tbsCertList/revokedCertificates');
        if (is_array($rclist)) {
            foreach ($rclist as $i => $extension) {
                $this->mapOutExtensions($rclist, "$i/crlEntryExtensions");
            }
        }

        $crl = ASN1::encodeDER($crl, Maps\CertificateList::MAP);

        switch ($format) {
            case self::FORMAT_DER:
                return $crl;
            // case self::FORMAT_PEM:
            default:
                return "-----BEGIN X509 CRL-----\r\n" . chunk_split(Strings::base64_encode($crl), 64) . '-----END X509 CRL-----';
        }
    }

    /**
     * Helper function to build a time field according to RFC 3280 section
     *  - 4.1.2.5 Validity
     *  - 5.1.2.4 This Update
     *  - 5.1.2.5 Next Update
     *  - 5.1.2.6 Revoked Certificates
     * by choosing utcTime iff year of date given is before 2050 and generalTime else.
     *
     * @param string $date in format date('D, d M Y H:i:s O')
     * @return array|Element
     */
    private function timeField($date)
    {
        if ($date instanceof Element) {
            return $date;
        }
        $dateObj = new \DateTimeImmutable($date, new \DateTimeZone('GMT'));
        $year = $dateObj->format('Y'); // the same way ASN1.php parses this
        if ($year < 2050) {
            return ['utcTime' => $date];
        } else {
            return ['generalTime' => $date];
        }
    }

    /**
     * Sign an X.509 certificate
     *
     * $issuer's private key needs to be loaded.
     * $subject can be either an existing X.509 cert (if you want to resign it),
     * a CSR or something with the DN and public key explicitly set.
     *
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function sign(X509 $issuer, X509 $subject)
    {
        if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
            return false;
        }

        if (isset($subject->publicKey) && !($subjectPublicKey = $subject->formatSubjectPublicKey())) {
            return false;
        }

        $currentCert = isset($this->currentCert) ? $this->currentCert : null;
        $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
        $signatureAlgorithm = self::identifySignatureAlgorithm($issuer->privateKey);

        if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
            $this->currentCert = $subject->currentCert;
            $this->currentCert['tbsCertificate']['signature'] = $signatureAlgorithm;
            $this->currentCert['signatureAlgorithm'] = $signatureAlgorithm;

            if (!empty($this->startDate)) {
                $this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->timeField($this->startDate);
            }
            if (!empty($this->endDate)) {
                $this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->timeField($this->endDate);
            }
            if (!empty($this->serialNumber)) {
                $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
            }
            if (!empty($subject->dn)) {
                $this->currentCert['tbsCertificate']['subject'] = $subject->dn;
            }
            if (!empty($subject->publicKey)) {
                $this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey;
            }
            $this->removeExtension('id-ce-authorityKeyIdentifier');
            if (isset($subject->domains)) {
                $this->removeExtension('id-ce-subjectAltName');
            }
        } elseif (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) {
            return false;
        } else {
            if (!isset($subject->publicKey)) {
                return false;
            }

            $startDate = new \DateTimeImmutable('now', new \DateTimeZone(@date_default_timezone_get()));
            $startDate = !empty($this->startDate) ? $this->startDate : $startDate->format('D, d M Y H:i:s O');

            $endDate = new \DateTimeImmutable('+1 year', new \DateTimeZone(@date_default_timezone_get()));
            $endDate = !empty($this->endDate) ? $this->endDate : $endDate->format('D, d M Y H:i:s O');

            /* "The serial number MUST be a positive integer"
               "Conforming CAs MUST NOT use serialNumber values longer than 20 octets."
                -- https://tools.ietf.org/html/rfc5280#section-4.1.2.2

               for the integer to be positive the leading bit needs to be 0 hence the
               application of a bitmap
            */
            $serialNumber = !empty($this->serialNumber) ?
                $this->serialNumber :
                new BigInteger(Random::string(20) & ("\x7F" . str_repeat("\xFF", 19)), 256);

            $this->currentCert = [
                'tbsCertificate' =>
                    [
                        'version' => 'v3',
                        'serialNumber' => $serialNumber, // $this->setSerialNumber()
                        'signature' => $signatureAlgorithm,
                        'issuer' => false, // this is going to be overwritten later
                        'validity' => [
                            'notBefore' => $this->timeField($startDate), // $this->setStartDate()
                            'notAfter' => $this->timeField($endDate)   // $this->setEndDate()
                        ],
                        'subject' => $subject->dn,
                        'subjectPublicKeyInfo' => $subjectPublicKey
                    ],
                    'signatureAlgorithm' => $signatureAlgorithm,
                    'signature'          => false // this is going to be overwritten later
            ];

            // Copy extensions from CSR.
            $csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0);

            if (!empty($csrexts)) {
                $this->currentCert['tbsCertificate']['extensions'] = $csrexts;
            }
        }

        $this->currentCert['tbsCertificate']['issuer'] = $issuer->dn;

        if (isset($issuer->currentKeyIdentifier)) {
            $this->setExtension('id-ce-authorityKeyIdentifier', [
                    //'authorityCertIssuer' => array(
                    //    array(
                    //        'directoryName' => $issuer->dn
                    //    )
                    //),
                    'keyIdentifier' => $issuer->currentKeyIdentifier
                ]);
            //$extensions = &$this->currentCert['tbsCertificate']['extensions'];
            //if (isset($issuer->serialNumber)) {
            //    $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
            //}
            //unset($extensions);
        }

        if (isset($subject->currentKeyIdentifier)) {
            $this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier);
        }

        $altName = [];

        if (isset($subject->domains) && count($subject->domains)) {
            $altName = array_map(['\phpseclib3\File\X509', 'dnsName'], $subject->domains);
        }

        if (isset($subject->ipAddresses) && count($subject->ipAddresses)) {
            // should an IP address appear as the CN if no domain name is specified? idk
            //$ips = count($subject->domains) ? $subject->ipAddresses : array_slice($subject->ipAddresses, 1);
            $ipAddresses = [];
            foreach ($subject->ipAddresses as $ipAddress) {
                $encoded = $subject->ipAddress($ipAddress);
                if ($encoded !== false) {
                    $ipAddresses[] = $encoded;
                }
            }
            if (count($ipAddresses)) {
                $altName = array_merge($altName, $ipAddresses);
            }
        }

        if (!empty($altName)) {
            $this->setExtension('id-ce-subjectAltName', $altName);
        }

        if ($this->caFlag) {
            $keyUsage = $this->getExtension('id-ce-keyUsage');
            if (!$keyUsage) {
                $keyUsage = [];
            }

            $this->setExtension(
                'id-ce-keyUsage',
                array_values(array_unique(array_merge($keyUsage, ['cRLSign', 'keyCertSign'])))
            );

            $basicConstraints = $this->getExtension('id-ce-basicConstraints');
            if (!$basicConstraints) {
                $basicConstraints = [];
            }

            $this->setExtension(
                'id-ce-basicConstraints',
                array_merge(['cA' => true], $basicConstraints),
                true
            );

            if (!isset($subject->currentKeyIdentifier)) {
                $this->setExtension('id-ce-subjectKeyIdentifier', $this->computeKeyIdentifier($this->currentCert), false, false);
            }
        }

        // resync $this->signatureSubject
        // save $tbsCertificate in case there are any \phpseclib3\File\ASN1\Element objects in it
        $tbsCertificate = $this->currentCert['tbsCertificate'];
        $this->loadX509($this->saveX509($this->currentCert));

        $result = $this->currentCert;
        $this->currentCert['signature'] = $result['signature'] = "\0" . $issuer->privateKey->sign($this->signatureSubject);
        $result['tbsCertificate'] = $tbsCertificate;

        $this->currentCert = $currentCert;
        $this->signatureSubject = $signatureSubject;

        return $result;
    }

    /**
     * Sign a CSR
     *
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function signCSR()
    {
        if (!is_object($this->privateKey) || empty($this->dn)) {
            return false;
        }

        $origPublicKey = $this->publicKey;
        $this->publicKey = $this->privateKey->getPublicKey();
        $publicKey = $this->formatSubjectPublicKey();
        $this->publicKey = $origPublicKey;

        $currentCert = isset($this->currentCert) ? $this->currentCert : null;
        $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
        $signatureAlgorithm = self::identifySignatureAlgorithm($this->privateKey);

        if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) {
            $this->currentCert['signatureAlgorithm'] = $signatureAlgorithm;
            if (!empty($this->dn)) {
                $this->currentCert['certificationRequestInfo']['subject'] = $this->dn;
            }
            $this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey;
        } else {
            $this->currentCert = [
                'certificationRequestInfo' =>
                    [
                        'version' => 'v1',
                        'subject' => $this->dn,
                        'subjectPKInfo' => $publicKey,
                        'attributes' => []
                    ],
                    'signatureAlgorithm' => $signatureAlgorithm,
                    'signature'          => false // this is going to be overwritten later
            ];
        }

        // resync $this->signatureSubject
        // save $certificationRequestInfo in case there are any \phpseclib3\File\ASN1\Element objects in it
        $certificationRequestInfo = $this->currentCert['certificationRequestInfo'];
        $this->loadCSR($this->saveCSR($this->currentCert));

        $result = $this->currentCert;
        $this->currentCert['signature'] = $result['signature'] = "\0" . $this->privateKey->sign($this->signatureSubject);
        $result['certificationRequestInfo'] = $certificationRequestInfo;

        $this->currentCert = $currentCert;
        $this->signatureSubject = $signatureSubject;

        return $result;
    }

    /**
     * Sign a SPKAC
     *
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function signSPKAC()
    {
        if (!is_object($this->privateKey)) {
            return false;
        }

        $origPublicKey = $this->publicKey;
        $this->publicKey = $this->privateKey->getPublicKey();
        $publicKey = $this->formatSubjectPublicKey();
        $this->publicKey = $origPublicKey;

        $currentCert = isset($this->currentCert) ? $this->currentCert : null;
        $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
        $signatureAlgorithm = self::identifySignatureAlgorithm($this->privateKey);

        // re-signing a SPKAC seems silly but since everything else supports re-signing why not?
        if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) {
            $this->currentCert['signatureAlgorithm'] = $signatureAlgorithm;
            $this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey;
            if (!empty($this->challenge)) {
                // the bitwise AND ensures that the output is a valid IA5String
                $this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge));
            }
        } else {
            $this->currentCert = [
                'publicKeyAndChallenge' =>
                    [
                        'spki' => $publicKey,
                        // quoting <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen>,
                        // "A challenge string that is submitted along with the public key. Defaults to an empty string if not specified."
                        // both Firefox and OpenSSL ("openssl spkac -key private.key") behave this way
                        // we could alternatively do this instead if we ignored the specs:
                        // Random::string(8) & str_repeat("\x7F", 8)
                        'challenge' => !empty($this->challenge) ? $this->challenge : ''
                    ],
                    'signatureAlgorithm' => $signatureAlgorithm,
                    'signature'          => false // this is going to be overwritten later
            ];
        }

        // resync $this->signatureSubject
        // save $publicKeyAndChallenge in case there are any \phpseclib3\File\ASN1\Element objects in it
        $publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge'];
        $this->loadSPKAC($this->saveSPKAC($this->currentCert));

        $result = $this->currentCert;
        $this->currentCert['signature'] = $result['signature'] = "\0" . $this->privateKey->sign($this->signatureSubject);
        $result['publicKeyAndChallenge'] = $publicKeyAndChallenge;

        $this->currentCert = $currentCert;
        $this->signatureSubject = $signatureSubject;

        return $result;
    }

    /**
     * Sign a CRL
     *
     * $issuer's private key needs to be loaded.
     *
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function signCRL(X509 $issuer, X509 $crl)
    {
        if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
            return false;
        }

        $currentCert = isset($this->currentCert) ? $this->currentCert : null;
        $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
        $signatureAlgorithm = self::identifySignatureAlgorithm($issuer->privateKey);

        $thisUpdate = new \DateTimeImmutable('now', new \DateTimeZone(@date_default_timezone_get()));
        $thisUpdate = !empty($this->startDate) ? $this->startDate : $thisUpdate->format('D, d M Y H:i:s O');

        if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) {
            $this->currentCert = $crl->currentCert;
            $this->currentCert['tbsCertList']['signature'] = $signatureAlgorithm;
            $this->currentCert['signatureAlgorithm'] = $signatureAlgorithm;
        } else {
            $this->currentCert = [
                'tbsCertList' =>
                    [
                        'version' => 'v2',
                        'signature' => $signatureAlgorithm,
                        'issuer' => false, // this is going to be overwritten later
                        'thisUpdate' => $this->timeField($thisUpdate) // $this->setStartDate()
                    ],
                    'signatureAlgorithm' => $signatureAlgorithm,
                    'signature'          => false // this is going to be overwritten later
            ];
        }

        $tbsCertList = &$this->currentCert['tbsCertList'];
        $tbsCertList['issuer'] = $issuer->dn;
        $tbsCertList['thisUpdate'] = $this->timeField($thisUpdate);

        if (!empty($this->endDate)) {
            $tbsCertList['nextUpdate'] = $this->timeField($this->endDate); // $this->setEndDate()
        } else {
            unset($tbsCertList['nextUpdate']);
        }

        if (!empty($this->serialNumber)) {
            $crlNumber = $this->serialNumber;
        } else {
            $crlNumber = $this->getExtension('id-ce-cRLNumber');
            // "The CRL number is a non-critical CRL extension that conveys a
            //  monotonically increasing sequence number for a given CRL scope and
            //  CRL issuer.  This extension allows users to easily determine when a
            //  particular CRL supersedes another CRL."
            // -- https://tools.ietf.org/html/rfc5280#section-5.2.3
            $crlNumber = $crlNumber !== false ? $crlNumber->add(new BigInteger(1)) : null;
        }

        $this->removeExtension('id-ce-authorityKeyIdentifier');
        $this->removeExtension('id-ce-issuerAltName');

        // Be sure version >= v2 if some extension found.
        $version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0;
        if (!$version) {
            if (!empty($tbsCertList['crlExtensions'])) {
                $version = 'v2'; // v2.
            } elseif (!empty($tbsCertList['revokedCertificates'])) {
                foreach ($tbsCertList['revokedCertificates'] as $cert) {
                    if (!empty($cert['crlEntryExtensions'])) {
                        $version = 'v2'; // v2.
                    }
                }
            }

            if ($version) {
                $tbsCertList['version'] = $version;
            }
        }

        // Store additional extensions.
        if (!empty($tbsCertList['version'])) { // At least v2.
            if (!empty($crlNumber)) {
                $this->setExtension('id-ce-cRLNumber', $crlNumber);
            }

            if (isset($issuer->currentKeyIdentifier)) {
                $this->setExtension('id-ce-authorityKeyIdentifier', [
                        //'authorityCertIssuer' => array(
                        //    ]
                        //        'directoryName' => $issuer->dn
                        //    ]
                        //),
                        'keyIdentifier' => $issuer->currentKeyIdentifier
                    ]);
                //$extensions = &$tbsCertList['crlExtensions'];
                //if (isset($issuer->serialNumber)) {
                //    $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
                //}
                //unset($extensions);
            }

            $issuerAltName = $this->getExtension('id-ce-subjectAltName', $issuer->currentCert);

            if ($issuerAltName !== false) {
                $this->setExtension('id-ce-issuerAltName', $issuerAltName);
            }
        }

        if (empty($tbsCertList['revokedCertificates'])) {
            unset($tbsCertList['revokedCertificates']);
        }

        unset($tbsCertList);

        // resync $this->signatureSubject
        // save $tbsCertList in case there are any \phpseclib3\File\ASN1\Element objects in it
        $tbsCertList = $this->currentCert['tbsCertList'];
        $this->loadCRL($this->saveCRL($this->currentCert));

        $result = $this->currentCert;
        $this->currentCert['signature'] = $result['signature'] = "\0" . $issuer->privateKey->sign($this->signatureSubject);
        $result['tbsCertList'] = $tbsCertList;

        $this->currentCert = $currentCert;
        $this->signatureSubject = $signatureSubject;

        return $result;
    }

    /**
     * Identify signature algorithm from key settings
     *
     * @param PrivateKey $key
     * @throws UnsupportedAlgorithmException if the algorithm is unsupported
     * @return array
     */
    private static function identifySignatureAlgorithm(PrivateKey $key)
    {
        if ($key instanceof RSA) {
            if ($key->getPadding() & RSA::SIGNATURE_PSS) {
                $r = PSS::load($key->withPassword()->toString('PSS'));
                return [
                    'algorithm' => 'id-RSASSA-PSS',
                    'parameters' => PSS::savePSSParams($r)
                ];
            }
            switch ($key->getHash()) {
                case 'md2':
                case 'md5':
                case 'sha1':
                case 'sha224':
                case 'sha256':
                case 'sha384':
                case 'sha512':
                    return [
                        'algorithm' => $key->getHash() . 'WithRSAEncryption',
                        'parameters' => null
                    ];
            }
            throw new UnsupportedAlgorithmException('The only supported hash algorithms for RSA are: md2, md5, sha1, sha224, sha256, sha384, sha512');
        }

        if ($key instanceof DSA) {
            switch ($key->getHash()) {
                case 'sha1':
                case 'sha224':
                case 'sha256':
                    return ['algorithm' => 'id-dsa-with-' . $key->getHash()];
            }
            throw new UnsupportedAlgorithmException('The only supported hash algorithms for DSA are: sha1, sha224, sha256');
        }

        if ($key instanceof EC) {
            switch ($key->getCurve()) {
                case 'Ed25519':
                case 'Ed448':
                    return ['algorithm' => 'id-' . $key->getCurve()];
            }
            switch ($key->getHash()) {
                case 'sha1':
                case 'sha224':
                case 'sha256':
                case 'sha384':
                case 'sha512':
                    return ['algorithm' => 'ecdsa-with-' . strtoupper($key->getHash())];
            }
            throw new UnsupportedAlgorithmException('The only supported hash algorithms for EC are: sha1, sha224, sha256, sha384, sha512');
        }

        throw new UnsupportedAlgorithmException('The only supported public key classes are: RSA, DSA, EC');
    }

    /**
     * Set certificate start date
     *
     * @param \DateTimeInterface|string $date
     */
    public function setStartDate($date)
    {
        if (!is_object($date) || !($date instanceof \DateTimeInterface)) {
            $date = new \DateTimeImmutable($date, new \DateTimeZone(@date_default_timezone_get()));
        }

        $this->startDate = $date->format('D, d M Y H:i:s O');
    }

    /**
     * Set certificate end date
     *
     * @param \DateTimeInterface|string $date
     */
    public function setEndDate($date)
    {
        /*
          To indicate that a certificate has no well-defined expiration date,
          the notAfter SHOULD be assigned the GeneralizedTime value of
          99991231235959Z.

          -- http://tools.ietf.org/html/rfc5280#section-4.1.2.5
        */
        if (is_string($date) && strtolower($date) === 'lifetime') {
            $temp = '99991231235959Z';
            $temp = chr(ASN1::TYPE_GENERALIZED_TIME) . ASN1::encodeLength(strlen($temp)) . $temp;
            $this->endDate = new Element($temp);
        } else {
            if (!is_object($date) || !($date instanceof \DateTimeInterface)) {
                $date = new \DateTimeImmutable($date, new \DateTimeZone(@date_default_timezone_get()));
            }

            $this->endDate = $date->format('D, d M Y H:i:s O');
        }
    }

    /**
     * Set Serial Number
     *
     * @param string $serial
     * @param int $base optional
     */
    public function setSerialNumber($serial, $base = -256)
    {
        $this->serialNumber = new BigInteger($serial, $base);
    }

    /**
     * Turns the certificate into a certificate authority
     *
     */
    public function makeCA()
    {
        $this->caFlag = true;
    }

    /**
     * Check for validity of subarray
     *
     * This is intended for use in conjunction with _subArrayUnchecked(),
     * implementing the checks included in _subArray() but without copying
     * a potentially large array by passing its reference by-value to is_array().
     *
     * @param array $root
     * @param string $path
     * @return boolean
     */
    private function isSubArrayValid(array $root, $path)
    {
        if (!is_array($root)) {
            return false;
        }

        foreach (explode('/', $path) as $i) {
            if (!is_array($root)) {
                return false;
            }

            if (!isset($root[$i])) {
                return true;
            }

            $root = $root[$i];
        }

        return true;
    }

    /**
     * Get a reference to a subarray
     *
     * This variant of _subArray() does no is_array() checking,
     * so $root should be checked with _isSubArrayValid() first.
     *
     * This is here for performance reasons:
     * Passing a reference (i.e. $root) by-value (i.e. to is_array())
     * creates a copy. If $root is an especially large array, this is expensive.
     *
     * @param array $root
     * @param string $path  absolute path with / as component separator
     * @param bool $create optional
     * @return array|false
     */
    private function &subArrayUnchecked(array &$root, $path, $create = false)
    {
        $false = false;

        foreach (explode('/', $path) as $i) {
            if (!isset($root[$i])) {
                if (!$create) {
                    return $false;
                }

                $root[$i] = [];
            }

            $root = &$root[$i];
        }

        return $root;
    }

    /**
     * Get a reference to a subarray
     *
     * @param array $root
     * @param string $path  absolute path with / as component separator
     * @param bool $create optional
     * @return array|false
     */
    private function &subArray(&$root, $path, $create = false)
    {
        $false = false;

        if (!is_array($root)) {
            return $false;
        }

        foreach (explode('/', $path) as $i) {
            if (!is_array($root)) {
                return $false;
            }

            if (!isset($root[$i])) {
                if (!$create) {
                    return $false;
                }

                $root[$i] = [];
            }

            $root = &$root[$i];
        }

        return $root;
    }

    /**
     * Get a reference to an extension subarray
     *
     * @param array $root
     * @param string $path optional absolute path with / as component separator
     * @param bool $create optional
     * @return array|false
     */
    private function &extensions(&$root, $path = null, $create = false)
    {
        if (!isset($root)) {
            $root = $this->currentCert;
        }

        switch (true) {
            case !empty($path):
            case !is_array($root):
                break;
            case isset($root['tbsCertificate']):
                $path = 'tbsCertificate/extensions';
                break;
            case isset($root['tbsCertList']):
                $path = 'tbsCertList/crlExtensions';
                break;
            case isset($root['certificationRequestInfo']):
                $pth = 'certificationRequestInfo/attributes';
                $attributes = &$this->subArray($root, $pth, $create);

                if (is_array($attributes)) {
                    foreach ($attributes as $key => $value) {
                        if ($value['type'] == 'pkcs-9-at-extensionRequest') {
                            $path = "$pth/$key/value/0";
                            break 2;
                        }
                    }
                    if ($create) {
                        $key = count($attributes);
                        $attributes[] = ['type' => 'pkcs-9-at-extensionRequest', 'value' => []];
                        $path = "$pth/$key/value/0";
                    }
                }
                break;
        }

        $extensions = &$this->subArray($root, $path, $create);

        if (!is_array($extensions)) {
            $false = false;
            return $false;
        }

        return $extensions;
    }

    /**
     * Remove an Extension
     *
     * @param string $id
     * @param string $path optional
     * @return bool
     */
    private function removeExtensionHelper($id, $path = null)
    {
        $extensions = &$this->extensions($this->currentCert, $path);

        if (!is_array($extensions)) {
            return false;
        }

        $result = false;
        foreach ($extensions as $key => $value) {
            if ($value['extnId'] == $id) {
                unset($extensions[$key]);
                $result = true;
            }
        }

        $extensions = array_values($extensions);
        // fix for https://bugs.php.net/75433 affecting PHP 7.2
        if (!isset($extensions[0])) {
            $extensions = array_splice($extensions, 0, 0);
        }
        return $result;
    }

    /**
     * Get an Extension
     *
     * Returns the extension if it exists and false if not
     *
     * @param string $id
     * @param array $cert optional
     * @param string $path optional
     * @return mixed
     */
    private function getExtensionHelper($id, $cert = null, $path = null)
    {
        $extensions = $this->extensions($cert, $path);

        if (!is_array($extensions)) {
            return false;
        }

        foreach ($extensions as $key => $value) {
            if ($value['extnId'] == $id) {
                return $value['extnValue'];
            }
        }

        return false;
    }

    /**
     * Returns a list of all extensions in use
     *
     * @param array $cert optional
     * @param string $path optional
     * @return array
     */
    private function getExtensionsHelper($cert = null, $path = null)
    {
        $exts = $this->extensions($cert, $path);
        $extensions = [];

        if (is_array($exts)) {
            foreach ($exts as $extension) {
                $extensions[] = $extension['extnId'];
            }
        }

        return $extensions;
    }

    /**
     * Set an Extension
     *
     * @param string $id
     * @param mixed $value
     * @param bool $critical optional
     * @param bool $replace optional
     * @param string $path optional
     * @return bool
     */
    private function setExtensionHelper($id, $value, $critical = false, $replace = true, $path = null)
    {
        $extensions = &$this->extensions($this->currentCert, $path, true);

        if (!is_array($extensions)) {
            return false;
        }

        $newext = ['extnId'  => $id, 'critical' => $critical, 'extnValue' => $value];

        foreach ($extensions as $key => $value) {
            if ($value['extnId'] == $id) {
                if (!$replace) {
                    return false;
                }

                $extensions[$key] = $newext;
                return true;
            }
        }

        $extensions[] = $newext;
        return true;
    }

    /**
     * Remove a certificate, CSR or CRL Extension
     *
     * @param string $id
     * @return bool
     */
    public function removeExtension($id)
    {
        return $this->removeExtensionHelper($id);
    }

    /**
     * Get a certificate, CSR or CRL Extension
     *
     * Returns the extension if it exists and false if not
     *
     * @param string $id
     * @param array $cert optional
     * @param string $path
     * @return mixed
     */
    public function getExtension($id, $cert = null, $path = null)
    {
        return $this->getExtensionHelper($id, $cert, $path);
    }

    /**
     * Returns a list of all extensions in use in certificate, CSR or CRL
     *
     * @param array $cert optional
     * @param string $path optional
     * @return array
     * @removed in phpseclib 4.0.0
     */
    public function getExtensions($cert = null, $path = null)
    {
        return $this->getExtensionsHelper($cert, $path);
    }

    /**
     * Set a certificate, CSR or CRL Extension
     *
     * @param string $id
     * @param mixed $value
     * @param bool $critical optional
     * @param bool $replace optional
     * @return bool
     */
    public function setExtension($id, $value, $critical = false, $replace = true)
    {
        return $this->setExtensionHelper($id, $value, $critical, $replace);
    }

    /**
     * Remove a CSR attribute.
     *
     * @param string $id
     * @param int $disposition optional
     * @return bool
     * @removed in phpseclib 4.0.0
     */
    public function removeAttribute($id, $disposition = self::ATTR_ALL)
    {
        $attributes = &$this->subArray($this->currentCert, 'certificationRequestInfo/attributes');

        if (!is_array($attributes)) {
            return false;
        }

        $result = false;
        foreach ($attributes as $key => $attribute) {
            if ($attribute['type'] == $id) {
                $n = count($attribute['value']);
                switch (true) {
                    case $disposition == self::ATTR_APPEND:
                    case $disposition == self::ATTR_REPLACE:
                        return false;
                    case $disposition >= $n:
                        $disposition -= $n;
                        break;
                    case $disposition == self::ATTR_ALL:
                    case $n == 1:
                        unset($attributes[$key]);
                        $result = true;
                        break;
                    default:
                        unset($attributes[$key]['value'][$disposition]);
                        $attributes[$key]['value'] = array_values($attributes[$key]['value']);
                        $result = true;
                        break;
                }
                if ($result && $disposition != self::ATTR_ALL) {
                    break;
                }
            }
        }

        $attributes = array_values($attributes);
        return $result;
    }

    /**
     * Get a CSR attribute
     *
     * Returns the attribute if it exists and false if not
     *
     * @param string $id
     * @param int $disposition optional
     * @param array $csr optional
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function getAttribute($id, $disposition = self::ATTR_ALL, $csr = null)
    {
        if (empty($csr)) {
            $csr = $this->currentCert;
        }

        $attributes = $this->subArray($csr, 'certificationRequestInfo/attributes');

        if (!is_array($attributes)) {
            return false;
        }

        foreach ($attributes as $key => $attribute) {
            if ($attribute['type'] == $id) {
                $n = count($attribute['value']);
                switch (true) {
                    case $disposition == self::ATTR_APPEND:
                    case $disposition == self::ATTR_REPLACE:
                        return false;
                    case $disposition == self::ATTR_ALL:
                        return $attribute['value'];
                    case $disposition >= $n:
                        $disposition -= $n;
                        break;
                    default:
                        return $attribute['value'][$disposition];
                }
            }
        }

        return false;
    }

    /**
     * Get all requested CSR extensions
     *
     * Returns the list of extensions if there are any and false if not
     *
     * @param array $csr optional
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function getRequestedCertificateExtensions($csr = null)
    {
        if (empty($csr)) {
            $csr = $this->currentCert;
        }

        $requestedExtensions = $this->getAttribute('pkcs-9-at-extensionRequest');
        if ($requestedExtensions === false) {
            return false;
        }

        return $this->getAttribute('pkcs-9-at-extensionRequest')[0];
    }

    /**
     * Returns a list of all CSR attributes in use
     *
     * @param array $csr optional
     * @return array
     * @removed in phpseclib 4.0.0
     */
    public function getAttributes($csr = null)
    {
        if (empty($csr)) {
            $csr = $this->currentCert;
        }

        $attributes = $this->subArray($csr, 'certificationRequestInfo/attributes');
        $attrs = [];

        if (is_array($attributes)) {
            foreach ($attributes as $attribute) {
                $attrs[] = $attribute['type'];
            }
        }

        return $attrs;
    }

    /**
     * Set a CSR attribute
     *
     * @param string $id
     * @param mixed $value
     * @param int $disposition optional
     * @return bool
     * @removed in phpseclib 4.0.0
     */
    public function setAttribute($id, $value, $disposition = self::ATTR_ALL)
    {
        $attributes = &$this->subArray($this->currentCert, 'certificationRequestInfo/attributes', true);

        if (!is_array($attributes)) {
            return false;
        }

        switch ($disposition) {
            case self::ATTR_REPLACE:
                $disposition = self::ATTR_APPEND;
                // fall-through
            case self::ATTR_ALL:
                $this->removeAttribute($id);
                break;
        }

        foreach ($attributes as $key => $attribute) {
            if ($attribute['type'] == $id) {
                $n = count($attribute['value']);
                switch (true) {
                    case $disposition == self::ATTR_APPEND:
                        $last = $key;
                        break;
                    case $disposition >= $n:
                        $disposition -= $n;
                        break;
                    default:
                        $attributes[$key]['value'][$disposition] = $value;
                        return true;
                }
            }
        }

        switch (true) {
            case $disposition >= 0:
                return false;
            case isset($last):
                $attributes[$last]['value'][] = $value;
                break;
            default:
                $attributes[] = ['type' => $id, 'value' => $disposition == self::ATTR_ALL ? $value : [$value]];
                break;
        }

        return true;
    }

    /**
     * Sets the subject key identifier
     *
     * This is used by the id-ce-authorityKeyIdentifier and the id-ce-subjectKeyIdentifier extensions.
     *
     * @param string $value
     */
    public function setKeyIdentifier($value)
    {
        if (empty($value)) {
            unset($this->currentKeyIdentifier);
        } else {
            $this->currentKeyIdentifier = $value;
        }
    }

    /**
     * Compute a public key identifier.
     *
     * Although key identifiers may be set to any unique value, this function
     * computes key identifiers from public key according to the two
     * recommended methods (4.2.1.2 RFC 3280).
     * Highly polymorphic: try to accept all possible forms of key:
     * - Key object
     * - \phpseclib3\File\X509 object with public or private key defined
     * - Certificate or CSR array
     * - \phpseclib3\File\ASN1\Element object
     * - PEM or DER string
     *
     * @param mixed $key optional
     * @param int $method optional
     * @return string binary key identifier
     * @removed in phpseclib 4.0.0
     */
    public function computeKeyIdentifier($key = null, $method = 1)
    {
        if (is_null($key)) {
            $key = $this;
        }

        switch (true) {
            case is_string($key):
                break;
            case is_array($key) && isset($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
                return $this->computeKeyIdentifier($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $method);
            case is_array($key) && isset($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
                return $this->computeKeyIdentifier($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $method);
            case !is_object($key):
                return false;
            case $key instanceof Element:
                // Assume the element is a bitstring-packed key.
                $decoded = ASN1::decodeBER($key->element);
                if (!$decoded) {
                    return false;
                }
                $raw = ASN1::asn1map($decoded[0], ['type' => ASN1::TYPE_BIT_STRING]);
                if (empty($raw)) {
                    return false;
                }
                // If the key is private, compute identifier from its corresponding public key.
                $key = PublicKeyLoader::load($raw);
                if ($key instanceof PrivateKey) {  // If private.
                    return $this->computeKeyIdentifier($key, $method);
                }
                $key = $raw; // Is a public key.
                break;
            case $key instanceof X509:
                if (isset($key->publicKey)) {
                    return $this->computeKeyIdentifier($key->publicKey, $method);
                }
                if (isset($key->privateKey)) {
                    return $this->computeKeyIdentifier($key->privateKey, $method);
                }
                if (isset($key->currentCert['tbsCertificate']) || isset($key->currentCert['certificationRequestInfo'])) {
                    return $this->computeKeyIdentifier($key->currentCert, $method);
                }
                return false;
            default: // Should be a key object (i.e.: \phpseclib3\Crypt\RSA).
                $key = $key->getPublicKey();
                break;
        }

        // If in PEM format, convert to binary.
        $key = ASN1::extractBER($key);

        // Now we have the key string: compute its sha-1 sum.
        $hash = new Hash('sha1');
        $hash = $hash->hash($key);

        if ($method == 2) {
            $hash = substr($hash, -8);
            $hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40);
        }

        return $hash;
    }

    /**
     * Format a public key as appropriate
     *
     * @return array|false
     */
    private function formatSubjectPublicKey()
    {
        $format = $this->publicKey instanceof RSA && ($this->publicKey->getPadding() & RSA::SIGNATURE_PSS) ?
            'PSS' :
            'PKCS8';

        $publicKey = base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->toString($format)));

        $decoded = ASN1::decodeBER($publicKey);
        if (!$decoded) {
            return false;
        }
        $mapped = ASN1::asn1map($decoded[0], Maps\SubjectPublicKeyInfo::MAP);
        if (!is_array($mapped)) {
            return false;
        }

        $mapped['subjectPublicKey'] = $this->publicKey->toString($format);

        return $mapped;
    }

    /**
     * Set the domain name's which the cert is to be valid for
     *
     * @param mixed ...$domains
     * @return void
     * @removed in phpseclib 4.0.0
     */
    public function setDomain(...$domains)
    {
        $this->domains = $domains;
        $this->removeDNProp('id-at-commonName');
        $this->setDNProp('id-at-commonName', $this->domains[0]);
    }

    /**
     * Set the IP Addresses's which the cert is to be valid for
     *
     * @param mixed[] ...$ipAddresses
     * @removed in phpseclib 4.0.0
     */
    public function setIPAddress(...$ipAddresses)
    {
        $this->ipAddresses = $ipAddresses;
        /*
        if (!isset($this->domains)) {
            $this->removeDNProp('id-at-commonName');
            $this->setDNProp('id-at-commonName', $this->ipAddresses[0]);
        }
        */
    }

    /**
     * Helper function to build domain array
     *
     * @param string $domain
     * @return array
     */
    private static function dnsName($domain)
    {
        return ['dNSName' => $domain];
    }

    /**
     * Helper function to build IP Address array
     *
     * (IPv6 is not currently supported)
     *
     * @param string $address
     * @return array
     */
    private function iPAddress($address)
    {
        return ['iPAddress' => $address];
    }

    /**
     * Get the index of a revoked certificate.
     *
     * @param array $rclist
     * @param string $serial
     * @param bool $create optional
     * @return int|false
     */
    private function revokedCertificate(array &$rclist, $serial, $create = false)
    {
        $serial = new BigInteger($serial);

        foreach ($rclist as $i => $rc) {
            if (!($serial->compare($rc['userCertificate']))) {
                return $i;
            }
        }

        if (!$create) {
            return false;
        }

        $i = count($rclist);
        $revocationDate = new \DateTimeImmutable('now', new \DateTimeZone(@date_default_timezone_get()));
        $rclist[] = ['userCertificate' => $serial,
                          'revocationDate'  => $this->timeField($revocationDate->format('D, d M Y H:i:s O'))];
        return $i;
    }

    /**
     * Revoke a certificate.
     *
     * @param string $serial
     * @param string $date optional
     * @return bool
     */
    public function revoke($serial, $date = null)
    {
        if (isset($this->currentCert['tbsCertList'])) {
            if (is_array($rclist = &$this->subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
                if ($this->revokedCertificate($rclist, $serial) === false) { // If not yet revoked
                    if (($i = $this->revokedCertificate($rclist, $serial, true)) !== false) {
                        if (!empty($date)) {
                            $rclist[$i]['revocationDate'] = $this->timeField($date);
                        }

                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * Unrevoke a certificate.
     *
     * @param string $serial
     * @return bool
     * @removed in phpseclib 4.0.0
     */
    public function unrevoke($serial)
    {
        if (is_array($rclist = &$this->subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
            if (($i = $this->revokedCertificate($rclist, $serial)) !== false) {
                unset($rclist[$i]);
                $rclist = array_values($rclist);
                return true;
            }
        }

        return false;
    }

    /**
     * Get a revoked certificate.
     *
     * @param string $serial
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function getRevoked($serial)
    {
        if (is_array($rclist = $this->subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
            if (($i = $this->revokedCertificate($rclist, $serial)) !== false) {
                return $rclist[$i];
            }
        }

        return false;
    }

    /**
     * List revoked certificates
     *
     * @param array $crl optional
     * @return array|bool
     * @removed in phpseclib 4.0.0
     */
    public function listRevoked($crl = null)
    {
        if (!isset($crl)) {
            $crl = $this->currentCert;
        }

        if (!isset($crl['tbsCertList'])) {
            return false;
        }

        $result = [];

        if (is_array($rclist = $this->subArray($crl, 'tbsCertList/revokedCertificates'))) {
            foreach ($rclist as $rc) {
                $result[] = $rc['userCertificate']->toString();
            }
        }

        return $result;
    }

    /**
     * Remove a Revoked Certificate Extension
     *
     * @param string $serial
     * @param string $id
     * @return bool
     * @removed in phpseclib 4.0.0
     */
    public function removeRevokedCertificateExtension($serial, $id)
    {
        if (is_array($rclist = &$this->subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) {
            if (($i = $this->revokedCertificate($rclist, $serial)) !== false) {
                return $this->removeExtensionHelper($id, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
            }
        }

        return false;
    }

    /**
     * Get a Revoked Certificate Extension
     *
     * Returns the extension if it exists and false if not
     *
     * @param string $serial
     * @param string $id
     * @param array $crl optional
     * @return mixed
     * @removed in phpseclib 4.0.0
     */
    public function getRevokedCertificateExtension($serial, $id, $crl = null)
    {
        if (!isset($crl)) {
            $crl = $this->currentCert;
        }

        if (is_array($rclist = $this->subArray($crl, 'tbsCertList/revokedCertificates'))) {
            if (($i = $this->revokedCertificate($rclist, $serial)) !== false) {
                return $this->getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
            }
        }

        return false;
    }

    /**
     * Returns a list of all extensions in use for a given revoked certificate
     *
     * @param string $serial
     * @param array $crl optional
     * @return array|bool
     */
    public function getRevokedCertificateExtensions($serial, $crl = null)
    {
        if (!isset($crl)) {
            $crl = $this->currentCert;
        }

        if (is_array($rclist = $this->subArray($crl, 'tbsCertList/revokedCertificates'))) {
            if (($i = $this->revokedCertificate($rclist, $serial)) !== false) {
                return $this->getExtensions($crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
            }
        }

        return false;
    }

    /**
     * Set a Revoked Certificate Extension
     *
     * @param string $serial
     * @param string $id
     * @param mixed $value
     * @param bool $critical optional
     * @param bool $replace optional
     * @return bool
     * @removed in phpseclib 4.0.0
     */
    public function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true)
    {
        if (isset($this->currentCert['tbsCertList'])) {
            if (is_array($rclist = &$this->subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) {
                if (($i = $this->revokedCertificate($rclist, $serial, true)) !== false) {
                    return $this->setExtensionHelper($id, $value, $critical, $replace, "tbsCertList/revokedCertificates/$i/crlEntryExtensions");
                }
            }
        }

        return false;
    }

    /**
     * Register the mapping for a custom/unsupported extension.
     *
     * @param string $id
     * @param array $mapping
     */
    public static function registerExtension($id, array $mapping)
    {
        if (isset(self::$extensions[$id]) && self::$extensions[$id] !== $mapping) {
            throw new \RuntimeException(
                'Extension ' . $id . ' has already been defined with a different mapping.'
            );
        }

        self::$extensions[$id] = $mapping;
    }

    /**
     * Register the mapping for a custom/unsupported extension.
     *
     * @param string $id
     *
     * @return array|null
     */
    public static function getRegisteredExtension($id)
    {
        return isset(self::$extensions[$id]) ? self::$extensions[$id] : null;
    }

    /**
     * Register the mapping for a custom/unsupported extension.
     *
     * @param string $id
     * @param mixed $value
     * @param bool $critical
     * @param bool $replace
     * @removed in phpseclib 4.0.0
     */
    public function setExtensionValue($id, $value, $critical = false, $replace = false)
    {
        $this->extensionValues[$id] = compact('critical', 'replace', 'value');
    }

    /**
     * Returns the OID corresponding to a name
     *
     * @param ?callable $callback
     */
    public static function setURLFetchCallback($callback)
    {
        self::$urlFetchCallback = $callback;
    }
}
<?php

/**
 * Pure-PHP ANSI Decoder
 *
 * PHP version 5
 *
 * If you call read() in \phpseclib3\Net\SSH2 you may get {@link http://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape codes} back.
 * They'd look like chr(0x1B) . '[00m' or whatever (0x1B = ESC).  They tell a
 * {@link http://en.wikipedia.org/wiki/Terminal_emulator terminal emulator} how to format the characters, what
 * color to display them in, etc. \phpseclib3\File\ANSI is a {@link http://en.wikipedia.org/wiki/VT100 VT100} terminal emulator.
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2012 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File;

/**
 * Pure-PHP ANSI Decoder
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class ANSI
{
    /**
     * Max Width
     *
     * @var int
     */
    private $max_x;

    /**
     * Max Height
     *
     * @var int
     */
    private $max_y;

    /**
     * Max History
     *
     * @var int
     */
    private $max_history;

    /**
     * History
     *
     * @var array
     */
    private $history;

    /**
     * History Attributes
     *
     * @var array
     */
    private $history_attrs;

    /**
     * Current Column
     *
     * @var int
     */
    private $x;

    /**
     * Current Row
     *
     * @var int
     */
    private $y;

    /**
     * Old Column
     *
     * @var int
     */
    private $old_x;

    /**
     * Old Row
     *
     * @var int
     */
    private $old_y;

    /**
     * An empty attribute cell
     *
     * @var object
     */
    private $base_attr_cell;

    /**
     * The current attribute cell
     *
     * @var object
     */
    private $attr_cell;

    /**
     * An empty attribute row
     *
     * @var array
     */
    private $attr_row;

    /**
     * The current screen text
     *
     * @var list<string>
     */
    private $screen;

    /**
     * The current screen attributes
     *
     * @var array
     */
    private $attrs;

    /**
     * Current ANSI code
     *
     * @var string
     */
    private $ansi;

    /**
     * Tokenization
     *
     * @var array
     */
    private $tokenization;

    /**
     * Default Constructor.
     *
     * @return ANSI
     */
    public function __construct()
    {
        $attr_cell = new \stdClass();
        $attr_cell->bold = false;
        $attr_cell->underline = false;
        $attr_cell->blink = false;
        $attr_cell->background = 'black';
        $attr_cell->foreground = 'white';
        $attr_cell->reverse = false;
        $this->base_attr_cell = clone $attr_cell;
        $this->attr_cell = clone $attr_cell;

        $this->setHistory(200);
        $this->setDimensions(80, 24);
    }

    /**
     * Set terminal width and height
     *
     * Resets the screen as well
     *
     * @param int $x
     * @param int $y
     */
    public function setDimensions($x, $y)
    {
        $this->max_x = $x - 1;
        $this->max_y = $y - 1;
        $this->x = $this->y = 0;
        $this->history = $this->history_attrs = [];
        $this->attr_row = array_fill(0, $this->max_x + 2, $this->base_attr_cell);
        $this->screen = array_fill(0, $this->max_y + 1, '');
        $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row);
        $this->ansi = '';
    }

    /**
     * Set the number of lines that should be logged past the terminal height
     *
     * @param int $history
     */
    public function setHistory($history)
    {
        $this->max_history = $history;
    }

    /**
     * Load a string
     *
     * @param string $source
     */
    public function loadString($source)
    {
        $this->setDimensions($this->max_x + 1, $this->max_y + 1);
        $this->appendString($source);
    }

    /**
     * Appdend a string
     *
     * @param string $source
     */
    public function appendString($source)
    {
        $this->tokenization = [''];
        for ($i = 0; $i < strlen($source); $i++) {
            if (strlen($this->ansi)) {
                $this->ansi .= $source[$i];
                $chr = ord($source[$i]);
                // http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements
                // single character CSI's not currently supported
                switch (true) {
                    case $this->ansi == "\x1B=":
                        $this->ansi = '';
                        continue 2;
                    case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['):
                    case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126:
                        break;
                    default:
                        continue 2;
                }
                $this->tokenization[] = $this->ansi;
                $this->tokenization[] = '';
                // http://ascii-table.com/ansi-escape-sequences-vt-100.php
                switch ($this->ansi) {
                    case "\x1B[H": // Move cursor to upper left corner
                        $this->old_x = $this->x;
                        $this->old_y = $this->y;
                        $this->x = $this->y = 0;
                        break;
                    case "\x1B[J": // Clear screen from cursor down
                        $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y));
                        $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, ''));

                        $this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y));
                        $this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row));

                        if (count($this->history) == $this->max_history) {
                            array_shift($this->history);
                            array_shift($this->history_attrs);
                        }
                        // fall-through
                    case "\x1B[K": // Clear screen from cursor right
                        $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x);

                        array_splice($this->attrs[$this->y], $this->x + 1, $this->max_x - $this->x, array_fill($this->x, $this->max_x - ($this->x - 1), $this->base_attr_cell));
                        break;
                    case "\x1B[2K": // Clear entire line
                        $this->screen[$this->y] = str_repeat(' ', $this->x);
                        $this->attrs[$this->y] = $this->attr_row;
                        break;
                    case "\x1B[?1h": // set cursor key to application
                    case "\x1B[?25h": // show the cursor
                    case "\x1B(B": // set united states g0 character set
                        break;
                    case "\x1BE": // Move to next line
                        $this->newLine();
                        $this->x = 0;
                        break;
                    default:
                        switch (true) {
                            case preg_match('#\x1B\[(\d+)B#', $this->ansi, $match): // Move cursor down n lines
                                $this->old_y = $this->y;
                                $this->y += (int) $match[1];
                                break;
                            case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h
                                $this->old_x = $this->x;
                                $this->old_y = $this->y;
                                $this->x = $match[2] - 1;
                                $this->y = (int) $match[1] - 1;
                                break;
                            case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines
                                $this->old_x = $this->x;
                                $this->x += $match[1];
                                break;
                            case preg_match('#\x1B\[(\d+)D#', $this->ansi, $match): // Move cursor left n lines
                                $this->old_x = $this->x;
                                $this->x -= $match[1];
                                if ($this->x < 0) {
                                    $this->x = 0;
                                }
                                break;
                            case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window
                                break;
                            case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes
                                $attr_cell = &$this->attr_cell;
                                $mods = explode(';', $match[1]);
                                foreach ($mods as $mod) {
                                    switch ($mod) {
                                        case '':
                                        case '0': // Turn off character attributes
                                            $attr_cell = clone $this->base_attr_cell;
                                            break;
                                        case '1': // Turn bold mode on
                                            $attr_cell->bold = true;
                                            break;
                                        case '4': // Turn underline mode on
                                            $attr_cell->underline = true;
                                            break;
                                        case '5': // Turn blinking mode on
                                            $attr_cell->blink = true;
                                            break;
                                        case '7': // Turn reverse video on
                                            $attr_cell->reverse = !$attr_cell->reverse;
                                            $temp = $attr_cell->background;
                                            $attr_cell->background = $attr_cell->foreground;
                                            $attr_cell->foreground = $temp;
                                            break;
                                        default: // set colors
                                            //$front = $attr_cell->reverse ? &$attr_cell->background : &$attr_cell->foreground;
                                            $front = &$attr_cell->{ $attr_cell->reverse ? 'background' : 'foreground' };
                                            //$back = $attr_cell->reverse ? &$attr_cell->foreground : &$attr_cell->background;
                                            $back = &$attr_cell->{ $attr_cell->reverse ? 'foreground' : 'background' };
                                            switch ($mod) {
                                                // @codingStandardsIgnoreStart
                                                case '30': $front = 'black'; break;
                                                case '31': $front = 'red'; break;
                                                case '32': $front = 'green'; break;
                                                case '33': $front = 'yellow'; break;
                                                case '34': $front = 'blue'; break;
                                                case '35': $front = 'magenta'; break;
                                                case '36': $front = 'cyan'; break;
                                                case '37': $front = 'white'; break;

                                                case '40': $back = 'black'; break;
                                                case '41': $back = 'red'; break;
                                                case '42': $back = 'green'; break;
                                                case '43': $back = 'yellow'; break;
                                                case '44': $back = 'blue'; break;
                                                case '45': $back = 'magenta'; break;
                                                case '46': $back = 'cyan'; break;
                                                case '47': $back = 'white'; break;
                                                // @codingStandardsIgnoreEnd

                                                default:
                                                    //user_error('Unsupported attribute: ' . $mod);
                                                    $this->ansi = '';
                                                    break 2;
                                            }
                                    }
                                }
                                break;
                            default:
                                //user_error("{$this->ansi} is unsupported\r\n");
                        }
                }
                $this->ansi = '';
                continue;
            }

            $this->tokenization[count($this->tokenization) - 1] .= $source[$i];
            switch ($source[$i]) {
                case "\r":
                    $this->x = 0;
                    break;
                case "\n":
                    $this->newLine();
                    break;
                case "\x08": // backspace
                    if ($this->x) {
                        $this->x--;
                        $this->attrs[$this->y][$this->x] = clone $this->base_attr_cell;
                        $this->screen[$this->y] = substr_replace(
                            $this->screen[$this->y],
                            $source[$i],
                            $this->x,
                            1
                        );
                    }
                    break;
                case "\x0F": // shift
                    break;
                case "\x1B": // start ANSI escape code
                    $this->tokenization[count($this->tokenization) - 1] = substr($this->tokenization[count($this->tokenization) - 1], 0, -1);
                    //if (!strlen($this->tokenization[count($this->tokenization) - 1])) {
                    //    array_pop($this->tokenization);
                    //}
                    $this->ansi .= "\x1B";
                    break;
                default:
                    $this->attrs[$this->y][$this->x] = clone $this->attr_cell;
                    if ($this->x > strlen($this->screen[$this->y])) {
                        $this->screen[$this->y] = str_repeat(' ', $this->x);
                    }
                    $this->screen[$this->y] = substr_replace(
                        $this->screen[$this->y],
                        $source[$i],
                        $this->x,
                        1
                    );

                    if ($this->x > $this->max_x) {
                        $this->x = 0;
                        $this->newLine();
                    } else {
                        $this->x++;
                    }
            }
        }
    }

    /**
     * Add a new line
     *
     * Also update the $this->screen and $this->history buffers
     *
     */
    private function newLine()
    {
        //if ($this->y < $this->max_y) {
        //    $this->y++;
        //}

        while ($this->y >= $this->max_y) {
            $this->history = array_merge($this->history, [array_shift($this->screen)]);
            $this->screen[] = '';

            $this->history_attrs = array_merge($this->history_attrs, [array_shift($this->attrs)]);
            $this->attrs[] = $this->attr_row;

            if (count($this->history) >= $this->max_history) {
                array_shift($this->history);
                array_shift($this->history_attrs);
            }

            $this->y--;
        }
        $this->y++;
    }

    /**
     * Returns the current coordinate without preformating
     *
     * @param \stdClass $last_attr
     * @param \stdClass $cur_attr
     * @param string $char
     * @return string
     */
    private function processCoordinate(\stdClass $last_attr, \stdClass $cur_attr, $char)
    {
        $output = '';

        if ($last_attr != $cur_attr) {
            $close = $open = '';
            if ($last_attr->foreground != $cur_attr->foreground) {
                if ($cur_attr->foreground != 'white') {
                    $open .= '<span style="color: ' . $cur_attr->foreground . '">';
                }
                if ($last_attr->foreground != 'white') {
                    $close = '</span>' . $close;
                }
            }
            if ($last_attr->background != $cur_attr->background) {
                if ($cur_attr->background != 'black') {
                    $open .= '<span style="background: ' . $cur_attr->background . '">';
                }
                if ($last_attr->background != 'black') {
                    $close = '</span>' . $close;
                }
            }
            if ($last_attr->bold != $cur_attr->bold) {
                if ($cur_attr->bold) {
                    $open .= '<b>';
                } else {
                    $close = '</b>' . $close;
                }
            }
            if ($last_attr->underline != $cur_attr->underline) {
                if ($cur_attr->underline) {
                    $open .= '<u>';
                } else {
                    $close = '</u>' . $close;
                }
            }
            if ($last_attr->blink != $cur_attr->blink) {
                if ($cur_attr->blink) {
                    $open .= '<blink>';
                } else {
                    $close = '</blink>' . $close;
                }
            }
            $output .= $close . $open;
        }

        $output .= htmlspecialchars($char);

        return $output;
    }

    /**
     * Returns the current screen without preformating
     *
     * @return string
     */
    private function getScreenHelper()
    {
        $output = '';
        $last_attr = $this->base_attr_cell;
        for ($i = 0; $i <= $this->max_y; $i++) {
            for ($j = 0; $j <= $this->max_x; $j++) {
                $cur_attr = $this->attrs[$i][$j];
                $output .= $this->processCoordinate($last_attr, $cur_attr, isset($this->screen[$i][$j]) ? $this->screen[$i][$j] : '');
                $last_attr = $this->attrs[$i][$j];
            }
            $output .= "\r\n";
        }
        $output = substr($output, 0, -2);
        // close any remaining open tags
        $output .= $this->processCoordinate($last_attr, $this->base_attr_cell, '');
        return rtrim($output);
    }

    /**
     * Returns the current screen
     *
     * @return string
     */
    public function getScreen()
    {
        return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $this->getScreenHelper() . '</pre>';
    }

    /**
     * Returns the current screen and the x previous lines
     *
     * @return string
     */
    public function getHistory()
    {
        $scrollback = '';
        $last_attr = $this->base_attr_cell;
        for ($i = 0; $i < count($this->history); $i++) {
            for ($j = 0; $j <= $this->max_x + 1; $j++) {
                $cur_attr = $this->history_attrs[$i][$j];
                $scrollback .= $this->processCoordinate($last_attr, $cur_attr, isset($this->history[$i][$j]) ? $this->history[$i][$j] : '');
                $last_attr = $this->history_attrs[$i][$j];
            }
            $scrollback .= "\r\n";
        }
        $base_attr_cell = $this->base_attr_cell;
        $this->base_attr_cell = $last_attr;
        $scrollback .= $this->getScreen();
        $this->base_attr_cell = $base_attr_cell;

        return '<pre width="' . ($this->max_x + 1) . '" style="color: white; background: black">' . $scrollback . '</span></pre>';
    }
}
<?php

/**
 * CertificateSerialNumber
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * CertificateSerialNumber
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CertificateSerialNumber
{
    const MAP = ['type' => ASN1::TYPE_INTEGER];
}
<?php

/**
 * ECPrivateKey
 *
 * From: https://tools.ietf.org/html/rfc5915
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * ECPrivateKey
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class ECPrivateKey
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'version' => [
                'type' => ASN1::TYPE_INTEGER,
                'mapping' => [1 => 'ecPrivkeyVer1']
            ],
            'privateKey' => ['type' => ASN1::TYPE_OCTET_STRING],
            'parameters' => [
                'constant' => 0,
                'optional' => true,
                'explicit' => true
            ] + ECParameters::MAP,
            'publicKey' => [
                'type' => ASN1::TYPE_BIT_STRING,
                'constant' => 1,
                'optional' => true,
                'explicit' => true
            ]
        ]
    ];
}
<?php

/**
 * EcdsaSigValue
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * EcdsaSigValue
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class EcdsaSigValue
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'r' => ['type' => ASN1::TYPE_INTEGER],
            's' => ['type' => ASN1::TYPE_INTEGER]
        ]
    ];
}
<?php

/**
 * Attribute
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Attribute
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Attribute
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'type' => AttributeType::MAP,
            'value' => [
                'type' => ASN1::TYPE_SET,
                'min' => 1,
                'max' => -1,
                'children' => AttributeValue::MAP
            ]
        ]
    ];
}
<?php

/**
 * CRLReason
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * CRLReason
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CRLReason
{
    const MAP = [
        'type' => ASN1::TYPE_ENUMERATED,
        'mapping' => [
            'unspecified',
            'keyCompromise',
            'cACompromise',
            'affiliationChanged',
            'superseded',
            'cessationOfOperation',
            'certificateHold',
            // Value 7 is not used.
            8 => 'removeFromCRL',
            'privilegeWithdrawn',
            'aACompromise'
        ]
    ];
}
<?php

/**
 * HashAglorithm
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

/**
 * HashAglorithm
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class HashAlgorithm
{
    const MAP = AlgorithmIdentifier::MAP;
}
<?php

/**
 * Curve
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Curve
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Curve
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'a' => FieldElement::MAP,
            'b' => FieldElement::MAP,
            'seed' => [
                'type' => ASN1::TYPE_BIT_STRING,
                'optional' => true
            ]
        ]
    ];
}
<?php

/**
 * HoldInstructionCode
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * HoldInstructionCode
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class HoldInstructionCode
{
    const MAP = ['type' => ASN1::TYPE_OBJECT_IDENTIFIER];
}
<?php

/**
 * CertificationRequest
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * CertificationRequest
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CertificationRequest
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'certificationRequestInfo' => CertificationRequestInfo::MAP,
            'signatureAlgorithm' => AlgorithmIdentifier::MAP,
            'signature' => ['type' => ASN1::TYPE_BIT_STRING]
        ]
    ];
}
<?php

/**
 * RSAPrivateKey
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * RSAPrivateKey
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class RSAPrivateKey
{
    // version must be multi if otherPrimeInfos present
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'version' => [
                'type' => ASN1::TYPE_INTEGER,
                'mapping' => ['two-prime', 'multi']
            ],
            'modulus' => ['type' => ASN1::TYPE_INTEGER],         // n
            'publicExponent' => ['type' => ASN1::TYPE_INTEGER],  // e
            'privateExponent' => ['type' => ASN1::TYPE_INTEGER], // d
            'prime1' => ['type' => ASN1::TYPE_INTEGER],          // p
            'prime2' => ['type' => ASN1::TYPE_INTEGER],          // q
            'exponent1' => ['type' => ASN1::TYPE_INTEGER],       // d mod (p-1)
            'exponent2' => ['type' => ASN1::TYPE_INTEGER],       // d mod (q-1)
            'coefficient' => ['type' => ASN1::TYPE_INTEGER],     // (inverse of q) mod p
            'otherPrimeInfos' => OtherPrimeInfos::MAP + ['optional' => true]
        ]
    ];
}
<?php

/**
 * CertificatePolicies
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * CertificatePolicies
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CertificatePolicies
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => -1,
        'children' => PolicyInformation::MAP
    ];
}
<?php

/**
 * IssuerAltName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

/**
 * IssuerAltName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class IssuerAltName
{
    const MAP = GeneralNames::MAP;
}
<?php

/**
 * EDIPartyName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * EDIPartyName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class EDIPartyName
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'nameAssigner' => [
                'constant' => 0,
                'optional' => true,
                'implicit' => true
            ] + DirectoryString::MAP,
            // partyName is technically required but \phpseclib3\File\ASN1 doesn't currently support non-optional constants and
            // setting it to optional gets the job done in any event.
            'partyName' => [
                'constant' => 1,
                'optional' => true,
                'implicit' => true
            ] + DirectoryString::MAP
        ]
    ];
}
<?php

/**
 * Prime_p
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Prime_p
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Prime_p
{
    const MAP = ['type' => ASN1::TYPE_INTEGER];
}
<?php

/**
 * CertificationRequestInfo
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * CertificationRequestInfo
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CertificationRequestInfo
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'version' => [
                'type' => ASN1::TYPE_INTEGER,
                'mapping' => ['v1']
            ],
            'subject' => Name::MAP,
            'subjectPKInfo' => SubjectPublicKeyInfo::MAP,
            'attributes' => [
                'constant' => 0,
                'optional' => true,
                'implicit' => true
            ] + Attributes::MAP,
        ]
    ];
}
<?php

/**
 * ECParameters
 *
 * From: https://tools.ietf.org/html/rfc5915
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * ECParameters
 *
 *  ECParameters ::= CHOICE {
 *    namedCurve         OBJECT IDENTIFIER
 *    -- implicitCurve   NULL
 *    -- specifiedCurve  SpecifiedECDomain
 *  }
 *    -- implicitCurve and specifiedCurve MUST NOT be used in PKIX.
 *    -- Details for SpecifiedECDomain can be found in [X9.62].
 *    -- Any future additions to this CHOICE should be coordinated
 *    -- with ANSI X9.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class ECParameters
{
    const MAP = [
        'type' => ASN1::TYPE_CHOICE,
        'children' => [
            'namedCurve' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER],
            'implicitCurve' => ['type' => ASN1::TYPE_NULL],
            'specifiedCurve' => SpecifiedECDomain::MAP
        ]
    ];
}
<?php

/**
 * BaseDistance
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * BaseDistance
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class BaseDistance
{
    const MAP = ['type' => ASN1::TYPE_INTEGER];
}
<?php

/**
 * NumericUserIdentifier
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * NumericUserIdentifier
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class NumericUserIdentifier
{
    const MAP = ['type' => ASN1::TYPE_NUMERIC_STRING];
}
<?php

/**
 * DistributionPoint
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * DistributionPoint
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DistributionPoint
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'distributionPoint' => [
                'constant' => 0,
                'optional' => true,
                'explicit' => true
            ] + DistributionPointName::MAP,
            'reasons' => [
                'constant' => 1,
                'optional' => true,
                'implicit' => true
            ] + ReasonFlags::MAP,
            'cRLIssuer' => [
                'constant' => 2,
                'optional' => true,
                'implicit' => true
            ] + GeneralNames::MAP
        ]
    ];
}
<?php

/**
 * TerminalIdentifier
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * TerminalIdentifier
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class TerminalIdentifier
{
    const MAP = ['type' => ASN1::TYPE_PRINTABLE_STRING];
}
<?php

/**
 * Trinomial
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Trinomial
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Trinomial
{
    const MAP = ['type' => ASN1::TYPE_INTEGER];
}
<?php

/**
 * SubjectInfoAccessSyntax
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * SubjectInfoAccessSyntax
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class SubjectInfoAccessSyntax
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => -1,
        'children' => AccessDescription::MAP
    ];
}
<?php

/**
 * RelativeDistinguishedName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * RelativeDistinguishedName
 *
 * In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare,
 * but they can be useful at times when either there is no unique attribute in the entry or you
 * want to ensure that the entry's DN contains some useful identifying information.
 *
 * - https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class RelativeDistinguishedName
{
    const MAP = [
        'type' => ASN1::TYPE_SET,
        'min' => 1,
        'max' => -1,
        'children' => AttributeTypeAndValue::MAP
    ];
}
<?php

/**
 * Validity
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Validity
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Validity
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'notBefore' => Time::MAP,
            'notAfter' => Time::MAP
        ]
    ];
}
<?php

/**
 * OneAsymmetricKey
 *
 * See https://tools.ietf.org/html/rfc5958
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * OneAsymmetricKey
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OneAsymmetricKey
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'version' => [
                'type' => ASN1::TYPE_INTEGER,
                'mapping' => ['v1', 'v2']
            ],
            'privateKeyAlgorithm' => AlgorithmIdentifier::MAP,
            'privateKey' => PrivateKey::MAP,
            'attributes' => [
                'constant' => 0,
                'optional' => true,
                'implicit' => true
            ] + Attributes::MAP,
            'publicKey' => [
                'constant' => 1,
                'optional' => true,
                'implicit' => true
            ] + PublicKey::MAP
        ]
    ];
}
<?php

/**
 * netscape_cert_type
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * netscape_cert_type
 *
 * mapping is from <http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html>
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class netscape_cert_type
{
    const MAP = [
        'type' => ASN1::TYPE_BIT_STRING,
        'mapping' => [
            'SSLClient',
            'SSLServer',
            'Email',
            'ObjectSigning',
            'Reserved',
            'SSLCA',
            'EmailCA',
            'ObjectSigningCA'
        ]
    ];
}
<?php

/**
 * DisplayText
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * DisplayText
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DisplayText
{
    const MAP = [
        'type' => ASN1::TYPE_CHOICE,
        'children' => [
            'ia5String' => ['type' => ASN1::TYPE_IA5_STRING],
            'visibleString' => ['type' => ASN1::TYPE_VISIBLE_STRING],
            'bmpString' => ['type' => ASN1::TYPE_BMP_STRING],
            'utf8String' => ['type' => ASN1::TYPE_UTF8_STRING]
        ]
    ];
}
<?php

/**
 * OrganizationalUnitNames
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * OrganizationalUnitNames
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OrganizationalUnitNames
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => 4, // ub-organizational-units
        'children' => ['type' => ASN1::TYPE_PRINTABLE_STRING]
    ];
}
<?php

/**
 * DSAParams
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * DSAParams
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DSAParams
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'p' => ['type' => ASN1::TYPE_INTEGER],
            'q' => ['type' => ASN1::TYPE_INTEGER],
            'g' => ['type' => ASN1::TYPE_INTEGER]
        ]
    ];
}
<?php

/**
 * DHParameter
 *
 * From: https://www.teletrust.de/fileadmin/files/oid/oid_pkcs-3v1-4.pdf#page=6
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * DHParameter
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DHParameter
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'prime' => ['type' => ASN1::TYPE_INTEGER],
            'base' => ['type' => ASN1::TYPE_INTEGER],
            'privateValueLength' => [
                'type' => ASN1::TYPE_INTEGER,
                'optional' => true
            ]
        ]
    ];
}
<?php

/**
 * NetworkAddress
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * NetworkAddress
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class NetworkAddress
{
    const MAP = ['type' => ASN1::TYPE_NUMERIC_STRING];
}
<?php

/**
 * MaskGenAglorithm
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

/**
 * MaskGenAglorithm
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class MaskGenAlgorithm
{
    const MAP = AlgorithmIdentifier::MAP;
}
<?php

/**
 * InvalidityDate
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * InvalidityDate
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class InvalidityDate
{
    const MAP = ['type' => ASN1::TYPE_GENERALIZED_TIME];
}
<?php

/**
 * PolicyQualifierInfo
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PolicyQualifierInfo
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PolicyQualifierInfo
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'policyQualifierId' => PolicyQualifierId::MAP,
            'qualifier' => ['type' => ASN1::TYPE_ANY]
        ]
    ];
}
<?php

/**
 * OrganizationName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * OrganizationName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OrganizationName
{
    const MAP = ['type' => ASN1::TYPE_PRINTABLE_STRING];
}
<?php

/**
 * Certificate
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Certificate
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Certificate
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'tbsCertificate' => TBSCertificate::MAP,
            'signatureAlgorithm' => AlgorithmIdentifier::MAP,
            'signature' => ['type' => ASN1::TYPE_BIT_STRING]
        ]
    ];
}
<?php

/**
 * SubjectDirectoryAttributes
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * SubjectDirectoryAttributes
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class SubjectDirectoryAttributes
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => -1,
        'children' => Attribute::MAP
    ];
}
<?php

/**
 * DigestInfo
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * DigestInfo
 *
 * from https://tools.ietf.org/html/rfc2898#appendix-A.3
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DigestInfo
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'digestAlgorithm' => AlgorithmIdentifier::MAP,
            'digest' => ['type' => ASN1::TYPE_OCTET_STRING]
        ]
    ];
}
<?php

/**
 * Characteristic_two
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Characteristic_two
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Characteristic_two
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'm' => ['type' => ASN1::TYPE_INTEGER], // field size 2**m
            'basis' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER],
            'parameters' => [
                'type' => ASN1::TYPE_ANY,
                'optional' => true
            ]
        ]
    ];
}
<?php

/**
 * RC2CBCParameter
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * RC2CBCParameter
 *
 * from https://tools.ietf.org/html/rfc2898#appendix-A.3
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class RC2CBCParameter
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'rc2ParametersVersion' => [
                'type' => ASN1::TYPE_INTEGER,
                'optional' => true
            ],
            'iv' => ['type' => ASN1::TYPE_OCTET_STRING]
        ]
    ];
}
<?php

/**
 * PKCS9String
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PKCS9String
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS9String
{
    const MAP = [
        'type' => ASN1::TYPE_CHOICE,
        'children' => [
            'ia5String' => ['type' => ASN1::TYPE_IA5_STRING],
            'directoryString' => DirectoryString::MAP
        ]
    ];
}
<?php

/**
 * AlgorithmIdentifier
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * AlgorithmIdentifier
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class AlgorithmIdentifier
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'algorithm' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER],
            'parameters' => [
                'type' => ASN1::TYPE_ANY,
                'optional' => true
            ]
        ]
    ];
}
<?php

/**
 * PrivateKey
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PrivateKey
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PrivateKey
{
    const MAP = ['type' => ASN1::TYPE_OCTET_STRING];
}
<?php

/**
 * DSAPublicKey
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * DSAPublicKey
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DSAPublicKey
{
    const MAP = ['type' => ASN1::TYPE_INTEGER];
}
<?php

/**
 * EncryptedPrivateKeyInfo
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * EncryptedPrivateKeyInfo
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class EncryptedPrivateKeyInfo
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'encryptionAlgorithm' => AlgorithmIdentifier::MAP,
            'encryptedData' => EncryptedData::MAP
        ]
    ];
}
<?php

/**
 * BuiltInDomainDefinedAttribute
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * BuiltInDomainDefinedAttribute
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class BuiltInDomainDefinedAttribute
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'type' => ['type' => ASN1::TYPE_PRINTABLE_STRING],
            'value' => ['type' => ASN1::TYPE_PRINTABLE_STRING]
        ]
    ];
}
<?php

/**
 * UserNotice
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * UserNotice
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class UserNotice
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'noticeRef' => [
                'optional' => true,
                'implicit' => true
            ] + NoticeReference::MAP,
            'explicitText' => [
                'optional' => true,
                'implicit' => true
            ] + DisplayText::MAP
        ]
    ];
}
<?php

/**
 * CertificateList
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * CertificateList
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CertificateList
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'tbsCertList' => TBSCertList::MAP,
            'signatureAlgorithm' => AlgorithmIdentifier::MAP,
            'signature' => ['type' => ASN1::TYPE_BIT_STRING]
        ]
    ];
}
<?php

/**
 * PostalAddress
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PostalAddress
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PostalAddress
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'optional' => true,
        'min' => 1,
        'max' => -1,
        'children' => DirectoryString::MAP
    ];
}
<?php

/**
 * FieldElement
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * FieldElement
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class FieldElement
{
    const MAP = ['type' => ASN1::TYPE_OCTET_STRING];
}
<?php

/**
 * BasicConstraints
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * BasicConstraints
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class BasicConstraints
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'cA' => [
                'type' => ASN1::TYPE_BOOLEAN,
                'optional' => true,
                'default' => false
            ],
            'pathLenConstraint' => [
                'type' => ASN1::TYPE_INTEGER,
                'optional' => true
            ]
        ]
    ];
}
<?php

/**
 * SignedPublicKeyAndChallenge
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * SignedPublicKeyAndChallenge
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class SignedPublicKeyAndChallenge
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'publicKeyAndChallenge' => PublicKeyAndChallenge::MAP,
            'signatureAlgorithm' => AlgorithmIdentifier::MAP,
            'signature' => ['type' => ASN1::TYPE_BIT_STRING]
        ]
    ];
}
<?php

/**
 * SpecifiedECDomain
 *
 * From: http://www.secg.org/sec1-v2.pdf#page=109
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * SpecifiedECDomain
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class SpecifiedECDomain
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'version' => [
                'type' => ASN1::TYPE_INTEGER,
                'mapping' => [1 => 'ecdpVer1', 'ecdpVer2', 'ecdpVer3']
            ],
            'fieldID' => FieldID::MAP,
            'curve' => Curve::MAP,
            'base' => ECPoint::MAP,
            'order' => ['type' => ASN1::TYPE_INTEGER],
            'cofactor' => [
                'type' => ASN1::TYPE_INTEGER,
                'optional' => true
            ],
            'hash' => ['optional' => true] + HashAlgorithm::MAP
        ]
    ];
}
<?php

/**
 * TBSCertList
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * TBSCertList
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class TBSCertList
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'version' => [
                'type' => ASN1::TYPE_INTEGER,
                'mapping' => ['v1', 'v2'],
                'optional' => true,
                'default' => 'v1'
            ],
            'signature' => AlgorithmIdentifier::MAP,
            'issuer' => Name::MAP,
            'thisUpdate' => Time::MAP,
            'nextUpdate' => [
                'optional' => true
            ] + Time::MAP,
            'revokedCertificates' => [
                'type' => ASN1::TYPE_SEQUENCE,
                'optional' => true,
                'min' => 0,
                'max' => -1,
                'children' => RevokedCertificate::MAP
            ],
            'crlExtensions' => [
                'constant' => 0,
                'optional' => true,
                'explicit' => true
            ] + Extensions::MAP
        ]
    ];
}
<?php

/**
 * DSAPrivateKey
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * DSAPrivateKey
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DSAPrivateKey
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'version' => ['type' => ASN1::TYPE_INTEGER],
            'p' => ['type' => ASN1::TYPE_INTEGER],
            'q' => ['type' => ASN1::TYPE_INTEGER],
            'g' => ['type' => ASN1::TYPE_INTEGER],
            'y' => ['type' => ASN1::TYPE_INTEGER],
            'x' => ['type' => ASN1::TYPE_INTEGER]
        ]
    ];
}
<?php

/**
 * DirectoryString
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * DirectoryString
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DirectoryString
{
    const MAP = [
        'type' => ASN1::TYPE_CHOICE,
        'children' => [
            'teletexString' => ['type' => ASN1::TYPE_TELETEX_STRING],
            'printableString' => ['type' => ASN1::TYPE_PRINTABLE_STRING],
            'universalString' => ['type' => ASN1::TYPE_UNIVERSAL_STRING],
            'utf8String' => ['type' => ASN1::TYPE_UTF8_STRING],
            'bmpString' => ['type' => ASN1::TYPE_BMP_STRING]
        ]
    ];
}
<?php

/**
 * KeyIdentifier
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * KeyIdentifier
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class KeyIdentifier
{
    const MAP = ['type' => ASN1::TYPE_OCTET_STRING];
}
<?php

/**
 * DssSigValue
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * DssSigValue
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DssSigValue
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'r' => ['type' => ASN1::TYPE_INTEGER],
            's' => ['type' => ASN1::TYPE_INTEGER]
        ]
    ];
}
<?php

/**
 * SubjectPublicKeyInfo
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * SubjectPublicKeyInfo
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class SubjectPublicKeyInfo
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'algorithm' => AlgorithmIdentifier::MAP,
            'subjectPublicKey' => ['type' => ASN1::TYPE_BIT_STRING]
        ]
    ];
}
<?php

/**
 * netscape_ca_policy_url
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * netscape_ca_policy_url
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class netscape_ca_policy_url
{
    const MAP = ['type' => ASN1::TYPE_IA5_STRING];
}
<?php

/**
 * CRLNumber
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * CRLNumber
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CRLNumber
{
    const MAP = ['type' => ASN1::TYPE_INTEGER];
}
<?php

/**
 * GeneralNames
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * GeneralNames
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class GeneralNames
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => -1,
        'children' => GeneralName::MAP
    ];
}
<?php

/**
 * Extension
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Extension
 *
 * A certificate using system MUST reject the certificate if it encounters
 * a critical extension it does not recognize; however, a non-critical
 * extension may be ignored if it is not recognized.
 *
 * http://tools.ietf.org/html/rfc5280#section-4.2
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Extension
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'extnId' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER],
            'critical' => [
                'type' => ASN1::TYPE_BOOLEAN,
                'optional' => true,
                'default' => false
            ],
            'extnValue' => ['type' => ASN1::TYPE_OCTET_STRING]
        ]
    ];
}
<?php

/**
 * PublicKeyInfo
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PublicKeyInfo
 *
 * this format is not formally defined anywhere but is none-the-less the form you
 * get when you do "openssl rsa -in private.pem -outform PEM -pubout"
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PublicKeyInfo
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'publicKeyAlgorithm' => AlgorithmIdentifier::MAP,
            'publicKey' => ['type' => ASN1::TYPE_BIT_STRING]
        ]
    ];
}
<?php

/**
 * RDNSequence
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * RDNSequence
 *
 * In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare,
 * but they can be useful at times when either there is no unique attribute in the entry or you
 * want to ensure that the entry's DN contains some useful identifying information.
 *
 * - https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class RDNSequence
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        // RDNSequence does not define a min or a max, which means it doesn't have one
        'min' => 0,
        'max' => -1,
        'children' => RelativeDistinguishedName::MAP
    ];
}
<?php

/**
 * CPSuri
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * CPSuri
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CPSuri
{
    const MAP = ['type' => ASN1::TYPE_IA5_STRING];
}
<?php

/**
 * PBKDF2params
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PBKDF2params
 *
 * from https://tools.ietf.org/html/rfc2898#appendix-A.3
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PBKDF2params
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            // technically, this is a CHOICE in RFC2898 but the other "choice" is, currently, more of a placeholder
            // in the RFC
            'salt' => ['type' => ASN1::TYPE_OCTET_STRING],
            'iterationCount' => ['type' => ASN1::TYPE_INTEGER],
            'keyLength' => [
                'type' => ASN1::TYPE_INTEGER,
                'optional' => true
            ],
            'prf' => AlgorithmIdentifier::MAP + ['optional' => true]
        ]
    ];
}
<?php

/**
 * GeneralSubtree
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * GeneralSubtree
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class GeneralSubtree
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'base' => GeneralName::MAP,
            'minimum' => [
                'constant' => 0,
                'optional' => true,
                'implicit' => true,
                'default' => '0'
            ] + BaseDistance::MAP,
            'maximum' => [
                'constant' => 1,
                'optional' => true,
                'implicit' => true,
            ] + BaseDistance::MAP
        ]
    ];
}
<?php

/**
 * CountryName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * CountryName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CountryName
{
    const MAP = [
        'type' => ASN1::TYPE_CHOICE,
        // if class isn't present it's assumed to be \phpseclib3\File\ASN1::CLASS_UNIVERSAL or
        // (if constant is present) \phpseclib3\File\ASN1::CLASS_CONTEXT_SPECIFIC
        'class' => ASN1::CLASS_APPLICATION,
        'cast' => 1,
        'children' => [
            'x121-dcc-code' => ['type' => ASN1::TYPE_NUMERIC_STRING],
            'iso-3166-alpha2-code' => ['type' => ASN1::TYPE_PRINTABLE_STRING]
        ]
    ];
}
<?php

/**
 * Name
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Name
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Name
{
    const MAP = [
        'type' => ASN1::TYPE_CHOICE,
        'children' => [
            'rdnSequence' => RDNSequence::MAP
        ]
    ];
}
<?php

/**
 * PBMAC1params
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PBMAC1params
 *
 * from https://tools.ietf.org/html/rfc2898#appendix-A.3
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PBMAC1params
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'keyDerivationFunc' => AlgorithmIdentifier::MAP,
            'messageAuthScheme' => AlgorithmIdentifier::MAP
        ]
    ];
}
<?php

/**
 * AdministrationDomainName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * AdministrationDomainName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class AdministrationDomainName
{
    const MAP = [
        'type' => ASN1::TYPE_CHOICE,
        // if class isn't present it's assumed to be \phpseclib3\File\ASN1::CLASS_UNIVERSAL or
        // (if constant is present) \phpseclib3\File\ASN1::CLASS_CONTEXT_SPECIFIC
        'class' => ASN1::CLASS_APPLICATION,
        'cast' => 2,
        'children' => [
            'numeric' => ['type' => ASN1::TYPE_NUMERIC_STRING],
            'printable' => ['type' => ASN1::TYPE_PRINTABLE_STRING]
        ]
    ];
}
<?php

/**
 * OtherPrimeInfo
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * OtherPrimeInfo
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OtherPrimeInfo
{
    // version must be multi if otherPrimeInfos present
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'prime' => ['type' => ASN1::TYPE_INTEGER],      // ri
            'exponent' => ['type' => ASN1::TYPE_INTEGER],   // di
            'coefficient' => ['type' => ASN1::TYPE_INTEGER] // ti
        ]
    ];
}
<?php

/**
 * BuiltInStandardAttributes
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * BuiltInStandardAttributes
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class BuiltInStandardAttributes
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'country-name' => ['optional' => true] + CountryName::MAP,
            'administration-domain-name' => ['optional' => true] + AdministrationDomainName::MAP,
            'network-address' => [
                'constant' => 0,
                'optional' => true,
                'implicit' => true
            ] + NetworkAddress::MAP,
            'terminal-identifier' => [
                'constant' => 1,
                'optional' => true,
                'implicit' => true
            ] + TerminalIdentifier::MAP,
            'private-domain-name' => [
                'constant' => 2,
                'optional' => true,
                'explicit' => true
            ] + PrivateDomainName::MAP,
            'organization-name' => [
                'constant' => 3,
                'optional' => true,
                'implicit' => true
            ] + OrganizationName::MAP,
            'numeric-user-identifier' => [
                'constant' => 4,
                'optional' => true,
                'implicit' => true
            ] + NumericUserIdentifier::MAP,
            'personal-name' => [
                'constant' => 5,
                'optional' => true,
                'implicit' => true
            ] + PersonalName::MAP,
            'organizational-unit-names' => [
                'constant' => 6,
                'optional' => true,
                'implicit' => true
            ] + OrganizationalUnitNames::MAP
        ]
    ];
}
<?php

/**
 * IssuingDistributionPoint
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * IssuingDistributionPoint
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class IssuingDistributionPoint
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'distributionPoint' => [
                'constant' => 0,
                'optional' => true,
                'explicit' => true
            ] + DistributionPointName::MAP,
            'onlyContainsUserCerts' => [
                'type' => ASN1::TYPE_BOOLEAN,
                'constant' => 1,
                'optional' => true,
                'default' => false,
                'implicit' => true
            ],
            'onlyContainsCACerts' => [
                'type' => ASN1::TYPE_BOOLEAN,
                'constant' => 2,
                'optional' => true,
                'default' => false,
                'implicit' => true
            ],
            'onlySomeReasons' => [
                'constant' => 3,
                'optional' => true,
                'implicit' => true
            ] + ReasonFlags::MAP,
            'indirectCRL' => [
                'type' => ASN1::TYPE_BOOLEAN,
                'constant' => 4,
                'optional' => true,
                'default' => false,
                'implicit' => true
            ],
            'onlyContainsAttributeCerts' => [
                'type' => ASN1::TYPE_BOOLEAN,
                'constant' => 5,
                'optional' => true,
                'default' => false,
                'implicit' => true
            ]
        ]
    ];
}
<?php

/**
 * RSASSA_PSS_params
 *
 * As defined in https://tools.ietf.org/html/rfc4055#section-3.1
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * RSASSA_PSS_params
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class RSASSA_PSS_params
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'hashAlgorithm' => [
                'constant' => 0,
                'optional' => true,
                'explicit' => true,
                //'default'  => 'sha1Identifier'
            ] + HashAlgorithm::MAP,
            'maskGenAlgorithm' => [
                'constant' => 1,
                'optional' => true,
                'explicit' => true,
                //'default'  => 'mgf1SHA1Identifier'
            ] + MaskGenAlgorithm::MAP,
            'saltLength' => [
                'type' => ASN1::TYPE_INTEGER,
                'constant' => 2,
                'optional' => true,
                'explicit' => true,
                'default' => 20
            ],
            'trailerField' => [
                'type' => ASN1::TYPE_INTEGER,
                'constant' => 3,
                'optional' => true,
                'explicit' => true,
                'default' => 1
            ]
        ]
    ];
}
<?php

/**
 * AccessDescription
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * AccessDescription
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class AccessDescription
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'accessMethod' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER],
            'accessLocation' => GeneralName::MAP
        ]
    ];
}
<?php

/**
 * PolicyInformation
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PolicyInformation
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PolicyInformation
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'policyIdentifier' => CertPolicyId::MAP,
            'policyQualifiers' => [
                'type' => ASN1::TYPE_SEQUENCE,
                'min' => 0,
                'max' => -1,
                'optional' => true,
                'children' => PolicyQualifierInfo::MAP
            ]
        ]
    ];
}
<?php

/**
 * netscape_comment
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * netscape_comment
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class netscape_comment
{
    const MAP = ['type' => ASN1::TYPE_IA5_STRING];
}
<?php

/**
 * BuiltInDomainDefinedAttributes
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * BuiltInDomainDefinedAttributes
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class BuiltInDomainDefinedAttributes
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => 4, // ub-domain-defined-attributes
        'children' => BuiltInDomainDefinedAttribute::MAP
    ];
}
<?php

/**
 * OtherPrimeInfos
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * OtherPrimeInfos
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OtherPrimeInfos
{
    // version must be multi if otherPrimeInfos present
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => -1,
        'children' => OtherPrimeInfo::MAP
    ];
}
<?php

/**
 * SubjectAltName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

/**
 * SubjectAltName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class SubjectAltName
{
    const MAP = GeneralNames::MAP;
}
<?php

/**
 * PBEParameter
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PBEParameter
 *
 * from https://tools.ietf.org/html/rfc2898#appendix-A.3
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PBEParameter
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'salt' => ['type' => ASN1::TYPE_OCTET_STRING],
            'iterationCount' => ['type' => ASN1::TYPE_INTEGER]
        ]
    ];
}
<?php

/**
 * ReasonFlags
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * ReasonFlags
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class ReasonFlags
{
    const MAP = [
        'type' => ASN1::TYPE_BIT_STRING,
        'mapping' => [
            'unused',
            'keyCompromise',
            'cACompromise',
            'affiliationChanged',
            'superseded',
            'cessationOfOperation',
            'certificateHold',
            'privilegeWithdrawn',
            'aACompromise'
        ]
    ];
}
<?php

/**
 * EncryptedData
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * EncryptedData
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class EncryptedData
{
    const MAP = ['type' => ASN1::TYPE_OCTET_STRING];
}
<?php

/**
 * PublicKey
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PublicKey
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PublicKey
{
    const MAP = ['type' => ASN1::TYPE_BIT_STRING];
}
<?php

/**
 * PBES2params
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PBES2params
 *
 * from https://tools.ietf.org/html/rfc2898#appendix-A.3
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PBES2params
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'keyDerivationFunc' => AlgorithmIdentifier::MAP,
            'encryptionScheme' => AlgorithmIdentifier::MAP
        ]
    ];
}
<?php

/**
 * PrivateDomainName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PrivateDomainName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PrivateDomainName
{
    const MAP = [
        'type' => ASN1::TYPE_CHOICE,
        'children' => [
            'numeric' => ['type' => ASN1::TYPE_NUMERIC_STRING],
            'printable' => ['type' => ASN1::TYPE_PRINTABLE_STRING]
        ]
    ];
}
<?php

/**
 * PublicKeyAndChallenge
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PublicKeyAndChallenge
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PublicKeyAndChallenge
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'spki' => SubjectPublicKeyInfo::MAP,
            'challenge' => ['type' => ASN1::TYPE_IA5_STRING]
        ]
    ];
}
<?php

/**
 * KeyPurposeId
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * KeyPurposeId
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class KeyPurposeId
{
    const MAP = ['type' => ASN1::TYPE_OBJECT_IDENTIFIER];
}
<?php

/**
 * CertPolicyId
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * CertPolicyId
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CertPolicyId
{
    const MAP = ['type' => ASN1::TYPE_OBJECT_IDENTIFIER];
}
<?php

/**
 * ORAddress
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * ORAddress
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class ORAddress
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'built-in-standard-attributes' => BuiltInStandardAttributes::MAP,
            'built-in-domain-defined-attributes' => ['optional' => true] + BuiltInDomainDefinedAttributes::MAP,
            'extension-attributes' => ['optional' => true] + ExtensionAttributes::MAP
        ]
    ];
}
<?php

/**
 * ExtensionAttribute
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * ExtensionAttribute
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class ExtensionAttribute
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'extension-attribute-type' => [
                'type' => ASN1::TYPE_PRINTABLE_STRING,
                'constant' => 0,
                'optional' => true,
                'implicit' => true
            ],
            'extension-attribute-value' => [
                'type' => ASN1::TYPE_ANY,
                'constant' => 1,
                'optional' => true,
                'explicit' => true
            ]
        ]
    ];
}
<?php

/**
 * KeyUsage
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * KeyUsage
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class KeyUsage
{
    const MAP = [
        'type' => ASN1::TYPE_BIT_STRING,
        'mapping' => [
            'digitalSignature',
            'nonRepudiation',
            'keyEncipherment',
            'dataEncipherment',
            'keyAgreement',
            'keyCertSign',
            'cRLSign',
            'encipherOnly',
            'decipherOnly'
        ]
    ];
}
<?php

/**
 * ExtKeyUsageSyntax
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * ExtKeyUsageSyntax
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class ExtKeyUsageSyntax
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => -1,
        'children' => KeyPurposeId::MAP
    ];
}
<?php

/**
 * AttributeValue
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * AttributeValue
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class AttributeValue
{
    const MAP = ['type' => ASN1::TYPE_ANY];
}
<?php

/**
 * PolicyQualifierId
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PolicyQualifierId
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PolicyQualifierId
{
    const MAP = ['type' => ASN1::TYPE_OBJECT_IDENTIFIER];
}
<?php

/**
 * DistributionPointName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * DistributionPointName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DistributionPointName
{
    const MAP = [
        'type' => ASN1::TYPE_CHOICE,
        'children' => [
            'fullName' => [
                'constant' => 0,
                'optional' => true,
                'implicit' => true
            ] + GeneralNames::MAP,
            'nameRelativeToCRLIssuer' => [
                'constant' => 1,
                'optional' => true,
                'implicit' => true
            ] + RelativeDistinguishedName::MAP
        ]
    ];
}
<?php

/**
 * NameConstraints
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * NameConstraints
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class NameConstraints
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'permittedSubtrees' => [
                'constant' => 0,
                'optional' => true,
                'implicit' => true
            ] + GeneralSubtrees::MAP,
            'excludedSubtrees' => [
                'constant' => 1,
                'optional' => true,
                'implicit' => true
            ] + GeneralSubtrees::MAP
        ]
    ];
}
<?php

/**
 * ExtensionAttributes
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * ExtensionAttributes
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class ExtensionAttributes
{
    const MAP = [
        'type' => ASN1::TYPE_SET,
        'min' => 1,
        'max' => 256, // ub-extension-attributes
        'children' => ExtensionAttribute::MAP
    ];
}
<?php

/**
 * AnotherName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * AnotherName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class AnotherName
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'type-id' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER],
            'value' => [
                'type' => ASN1::TYPE_ANY,
                'constant' => 0,
                'optional' => true,
                'explicit' => true
            ]
        ]
    ];
}
<?php

/**
 * RSAPublicKey
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * RSAPublicKey
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class RSAPublicKey
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'modulus' => ['type' => ASN1::TYPE_INTEGER],
            'publicExponent' => ['type' => ASN1::TYPE_INTEGER]
        ]
    ];
}
<?php

/**
 * AttributeTypeAndValue
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * AttributeTypeAndValue
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class AttributeTypeAndValue
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'type' => AttributeType::MAP,
            'value' => AttributeValue::MAP
        ]
    ];
}
<?php

/**
 * AuthorityKeyIdentifier
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * AuthorityKeyIdentifier
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class AuthorityKeyIdentifier
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'keyIdentifier' => [
                'constant' => 0,
                'optional' => true,
                'implicit' => true
            ] + KeyIdentifier::MAP,
            'authorityCertIssuer' => [
                'constant' => 1,
                'optional' => true,
                'implicit' => true
            ] + GeneralNames::MAP,
            'authorityCertSerialNumber' => [
                'constant' => 2,
                'optional' => true,
                'implicit' => true
            ] + CertificateSerialNumber::MAP
        ]
    ];
}
<?php

/**
 * UniqueIdentifier
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * UniqueIdentifier
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class UniqueIdentifier
{
    const MAP = ['type' => ASN1::TYPE_BIT_STRING];
}
<?php

/**
 * AuthorityInfoAccessSyntax
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * AuthorityInfoAccessSyntax
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class AuthorityInfoAccessSyntax
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => -1,
        'children' => AccessDescription::MAP
    ];
}
<?php

/**
 * GeneralName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * GeneralName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class GeneralName
{
    const MAP = [
        'type' => ASN1::TYPE_CHOICE,
        'children' => [
            'otherName' => [
                'constant' => 0,
                'optional' => true,
                'implicit' => true
            ] + AnotherName::MAP,
            'rfc822Name' => [
                'type' => ASN1::TYPE_IA5_STRING,
                'constant' => 1,
                'optional' => true,
                'implicit' => true
            ],
            'dNSName' => [
                'type' => ASN1::TYPE_IA5_STRING,
                'constant' => 2,
                'optional' => true,
                'implicit' => true
            ],
            'x400Address' => [
                'constant' => 3,
                'optional' => true,
                'implicit' => true
            ] + ORAddress::MAP,
            'directoryName' => [
                'constant' => 4,
                'optional' => true,
                'explicit' => true
            ] + Name::MAP,
            'ediPartyName' => [
                'constant' => 5,
                'optional' => true,
                'implicit' => true
            ] + EDIPartyName::MAP,
            'uniformResourceIdentifier' => [
                'type' => ASN1::TYPE_IA5_STRING,
                'constant' => 6,
                'optional' => true,
                'implicit' => true
            ],
            'iPAddress' => [
                'type' => ASN1::TYPE_OCTET_STRING,
                'constant' => 7,
                'optional' => true,
                'implicit' => true
            ],
            'registeredID' => [
                'type' => ASN1::TYPE_OBJECT_IDENTIFIER,
                'constant' => 8,
                'optional' => true,
                'implicit' => true
            ]
        ]
    ];
}
<?php

/**
 * Extensions
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Extensions
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Extensions
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        // technically, it's MAX, but we'll assume anything < 0 is MAX
        'max' => -1,
        // if 'children' isn't an array then 'min' and 'max' must be defined
        'children' => Extension::MAP
    ];
}
<?php

/**
 * ECPoint
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * ECPoint
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class ECPoint
{
    const MAP = ['type' => ASN1::TYPE_OCTET_STRING];
}
<?php

/**
 * PrivateKeyInfo
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PrivateKeyInfo
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PrivateKeyInfo
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'version' => [
                'type' => ASN1::TYPE_INTEGER,
                'mapping' => ['v1']
            ],
            'privateKeyAlgorithm' => AlgorithmIdentifier::MAP,
            'privateKey' => PrivateKey::MAP,
            'attributes' => [
                'constant' => 0,
                'optional' => true,
                'implicit' => true
            ] + Attributes::MAP
        ]
    ];
}
<?php

/**
 * PrivateKeyUsagePeriod
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PrivateKeyUsagePeriod
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PrivateKeyUsagePeriod
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'notBefore' => [
                'constant' => 0,
                'optional' => true,
                'implicit' => true,
                'type' => ASN1::TYPE_GENERALIZED_TIME],
            'notAfter' => [
                'constant' => 1,
                'optional' => true,
                'implicit' => true,
                'type' => ASN1::TYPE_GENERALIZED_TIME]
        ]
    ];
}
<?php

/**
 * Attributes
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Attributes
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Attributes
{
    const MAP = [
        'type' => ASN1::TYPE_SET,
        'min' => 1,
        'max' => -1,
        'children' => Attribute::MAP
    ];
}
<?php

/**
 * NoticeReference
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * NoticeReference
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class NoticeReference
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'organization' => DisplayText::MAP,
            'noticeNumbers' => [
                'type' => ASN1::TYPE_SEQUENCE,
                'min' => 1,
                'max' => 200,
                'children' => ['type' => ASN1::TYPE_INTEGER]
            ]
        ]
    ];
}
<?php

/**
 * PersonalName
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PersonalName
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PersonalName
{
    const MAP = [
        'type' => ASN1::TYPE_SET,
        'children' => [
            'surname' => [
                'type' => ASN1::TYPE_PRINTABLE_STRING,
                'constant' => 0,
                'optional' => true,
                'implicit' => true
            ],
            'given-name' => [
                'type' => ASN1::TYPE_PRINTABLE_STRING,
                'constant' => 1,
                'optional' => true,
                'implicit' => true
            ],
            'initials' => [
                'type' => ASN1::TYPE_PRINTABLE_STRING,
                'constant' => 2,
                'optional' => true,
                'implicit' => true
            ],
            'generation-qualifier' => [
                'type' => ASN1::TYPE_PRINTABLE_STRING,
                'constant' => 3,
                'optional' => true,
                'implicit' => true
            ]
        ]
    ];
}
<?php

/**
 * CRLDistributionPoints
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * CRLDistributionPoints
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CRLDistributionPoints
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => -1,
        'children' => DistributionPoint::MAP
    ];
}
<?php

/**
 * AttributeType
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * AttributeType
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class AttributeType
{
    const MAP = ['type' => ASN1::TYPE_OBJECT_IDENTIFIER];
}
<?php

/**
 * GeneralSubtrees
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * GeneralSubtrees
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class GeneralSubtrees
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => -1,
        'children' => GeneralSubtree::MAP
    ];
}
<?php

/**
 * FieldID
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * FieldID
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class FieldID
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'fieldType' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER],
            'parameters' => [
                'type' => ASN1::TYPE_ANY,
                'optional' => true
            ]
        ]
    ];
}
<?php

/**
 * Time
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Time
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Time
{
    const MAP = [
        'type' => ASN1::TYPE_CHOICE,
        'children' => [
            'utcTime' => ['type' => ASN1::TYPE_UTC_TIME],
            'generalTime' => ['type' => ASN1::TYPE_GENERALIZED_TIME]
        ]
    ];
}
<?php

/**
 * RevokedCertificate
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * RevokedCertificate
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class RevokedCertificate
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'userCertificate' => CertificateSerialNumber::MAP,
            'revocationDate' => Time::MAP,
            'crlEntryExtensions' => [
                'optional' => true
            ] + Extensions::MAP
        ]
    ];
}
<?php

/**
 * Pentanomial
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * Pentanomial
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Pentanomial
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            'k1' => ['type' => ASN1::TYPE_INTEGER], // k1 > 0
            'k2' => ['type' => ASN1::TYPE_INTEGER], // k2 > k1
            'k3' => ['type' => ASN1::TYPE_INTEGER], // k3 > h2
        ]
    ];
}
<?php

/**
 * PolicyMappings
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * PolicyMappings
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PolicyMappings
{
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'min' => 1,
        'max' => -1,
        'children' => [
            'type' => ASN1::TYPE_SEQUENCE,
            'children' => [
                'issuerDomainPolicy' => CertPolicyId::MAP,
                'subjectDomainPolicy' => CertPolicyId::MAP
            ]
        ]
    ];
}
<?php

/**
 * TBSCertificate
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

use phpseclib3\File\ASN1;

/**
 * TBSCertificate
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class TBSCertificate
{
    // assert($TBSCertificate['children']['signature'] == $Certificate['children']['signatureAlgorithm'])
    const MAP = [
        'type' => ASN1::TYPE_SEQUENCE,
        'children' => [
            // technically, default implies optional, but we'll define it as being optional, none-the-less, just to
            // reenforce that fact
            'version' => [
                'type' => ASN1::TYPE_INTEGER,
                'constant' => 0,
                'optional' => true,
                'explicit' => true,
                'mapping' => ['v1', 'v2', 'v3'],
                'default' => 'v1'
            ],
            'serialNumber' => CertificateSerialNumber::MAP,
            'signature' => AlgorithmIdentifier::MAP,
            'issuer' => Name::MAP,
            'validity' => Validity::MAP,
            'subject' => Name::MAP,
            'subjectPublicKeyInfo' => SubjectPublicKeyInfo::MAP,
            // implicit means that the T in the TLV structure is to be rewritten, regardless of the type
            'issuerUniqueID' => [
                'constant' => 1,
                'optional' => true,
                'implicit' => true
            ] + UniqueIdentifier::MAP,
            'subjectUniqueID' => [
                'constant' => 2,
                'optional' => true,
                'implicit' => true
            ] + UniqueIdentifier::MAP,
            // <http://tools.ietf.org/html/rfc2459#page-74> doesn't use the EXPLICIT keyword but if
            // it's not IMPLICIT, it's EXPLICIT
            'extensions' => [
                'constant' => 3,
                'optional' => true,
                'explicit' => true
            ] + Extensions::MAP
        ]
    ];
}
<?php

/**
 * CertificateIssuer
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1\Maps;

/**
 * CertificateIssuer
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class CertificateIssuer
{
    const MAP = GeneralNames::MAP;
}
<?php

/**
 * ASN.1 Raw Element
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2012 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\File\ASN1;

/**
 * ASN.1 Raw Element
 *
 * An ASN.1 ANY mapping will return an ASN1\Element object. Use of this object
 * will also bypass the normal encoding rules in ASN1::encodeDER()
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Element
{
    /**
     * Raw element value
     *
     * @var string
     */
    public $element;

    /**
     * Constructor
     *
     * @param string $encoded
     * @return Element
     */
    public function __construct($encoded)
    {
        $this->element = $encoded;
    }
}
# minimalist openssl.cnf file for use with phpseclib

HOME			= .
RANDFILE		= $ENV::HOME/.rnd
# without this line you'll get this error with openssl_pkey_new():
# Warning: openssl_pkey_new(): Private key length must be at least 384 bits, configured to 0
default_bits = 384

[ v3_ca ]
<?php

/**
 * SFTP Stream Wrapper
 *
 * Creates an sftp:// protocol handler that can be used with, for example, fopen(), dir(), etc.
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2013 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Net\SFTP;

use phpseclib3\Crypt\Common\PrivateKey;
use phpseclib3\Net\SFTP;
use phpseclib3\Net\SSH2;

/**
 * SFTP Stream Wrapper
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Stream
{
    /**
     * SFTP instances
     *
     * Rather than re-create the connection we re-use instances if possible
     *
     * @var array
     */
    public static $instances;

    /**
     * SFTP instance
     *
     * @var object
     */
    private $sftp;

    /**
     * Path
     *
     * @var string
     */
    private $path;

    /**
     * Mode
     *
     * @var string
     */
    private $mode;

    /**
     * Position
     *
     * @var int
     */
    private $pos;

    /**
     * Size
     *
     * @var int
     */
    private $size;

    /**
     * Directory entries
     *
     * @var array
     */
    private $entries;

    /**
     * EOF flag
     *
     * @var bool
     */
    private $eof;

    /**
     * Context resource
     *
     * Technically this needs to be publicly accessible so PHP can set it directly
     *
     * @var resource
     */
    public $context;

    /**
     * Notification callback function
     *
     * @var callable
     */
    private $notification;

    /**
     * Registers this class as a URL wrapper.
     *
     * @param string $protocol The wrapper name to be registered.
     * @return bool True on success, false otherwise.
     */
    public static function register($protocol = 'sftp')
    {
        if (in_array($protocol, stream_get_wrappers(), true)) {
            return false;
        }
        return stream_wrapper_register($protocol, get_called_class());
    }

    /**
     * The Constructor
     *
     */
    public function __construct()
    {
        if (defined('NET_SFTP_STREAM_LOGGING')) {
            echo "__construct()\r\n";
        }
    }

    /**
     * Path Parser
     *
     * Extract a path from a URI and actually connect to an SSH server if appropriate
     *
     * If "notification" is set as a context parameter the message code for successful login is
     * NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE.
     *
     * @param string $path
     * @return string
     */
    protected function parse_path($path)
    {
        $orig = $path;
        $url = parse_url($path) + ['port' => 22];

        $keys = ['scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment'];
        foreach ($keys as $key) {
            if (isset($url[$key])) {
                $$key = $url[$key];
            }
        }

        if (isset($query)) {
            $path .= '?' . $query;
        } elseif (preg_match('/(\?|\?#)$/', $orig)) {
            $path .= '?';
        }
        if (isset($fragment)) {
            $path .= '#' . $fragment;
        } elseif ($orig[strlen($orig) - 1] == '#') {
            $path .= '#';
        }

        if (!isset($host)) {
            return false;
        }

        if (isset($this->context)) {
            $context = stream_context_get_params($this->context);
            if (isset($context['notification'])) {
                $this->notification = $context['notification'];
            }
        }

        if (preg_match('/^{[a-z0-9]+}$/i', $host)) {
            $host = SSH2::getConnectionByResourceId($host);
            if ($host === false) {
                return false;
            }
            $this->sftp = $host;
        } else {
            if (isset($this->context)) {
                $context = stream_context_get_options($this->context);
            }
            if (isset($context[$scheme]['session'])) {
                $sftp = $context[$scheme]['session'];
            }
            if (isset($context[$scheme]['sftp'])) {
                $sftp = $context[$scheme]['sftp'];
            }
            if (isset($sftp) && $sftp instanceof SFTP) {
                $this->sftp = $sftp;
                return $path;
            }
            if (isset($context[$scheme]['username'])) {
                $user = $context[$scheme]['username'];
            }
            if (isset($context[$scheme]['password'])) {
                $pass = $context[$scheme]['password'];
            }
            if (isset($context[$scheme]['privkey']) && $context[$scheme]['privkey'] instanceof PrivateKey) {
                $pass = $context[$scheme]['privkey'];
            }

            if (!isset($user) || !isset($pass)) {
                return false;
            }

            // casting $pass to a string is necessary in the event that it's a \phpseclib3\Crypt\RSA object
            if (isset(self::$instances[$host][$port][$user][(string) $pass])) {
                $this->sftp = self::$instances[$host][$port][$user][(string) $pass];
            } else {
                $this->sftp = new SFTP($host, $port);
                $this->sftp->disableStatCache();
                if (isset($this->notification) && is_callable($this->notification)) {
                    /* if !is_callable($this->notification) we could do this:

                       user_error('fopen(): failed to call user notifier', E_USER_WARNING);

                       the ftp wrapper gives errors like that when the notifier isn't callable.
                       i've opted not to do that, however, since the ftp wrapper gives the line
                       on which the fopen occurred as the line number - not the line that the
                       user_error is on.
                    */
                    call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
                    call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
                    if (!$this->sftp->login($user, $pass)) {
                        call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0);
                        return false;
                    }
                    call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0);
                } else {
                    if (!$this->sftp->login($user, $pass)) {
                        return false;
                    }
                }
                self::$instances[$host][$port][$user][(string) $pass] = $this->sftp;
            }
        }

        return $path;
    }

    /**
     * Opens file or URL
     *
     * @param string $path
     * @param string $mode
     * @param int $options
     * @param string $opened_path
     * @return bool
     */
    private function _stream_open($path, $mode, $options, &$opened_path)
    {
        $path = $this->parse_path($path);

        if ($path === false) {
            return false;
        }
        $this->path = $path;

        $this->size = $this->sftp->filesize($path);
        $this->mode = preg_replace('#[bt]$#', '', $mode);
        $this->eof = false;

        if ($this->size === false) {
            if ($this->mode[0] == 'r') {
                return false;
            } else {
                $this->sftp->touch($path);
                $this->size = 0;
            }
        } else {
            switch ($this->mode[0]) {
                case 'x':
                    return false;
                case 'w':
                    $this->sftp->truncate($path, 0);
                    $this->size = 0;
            }
        }

        $this->pos = $this->mode[0] != 'a' ? 0 : $this->size;

        return true;
    }

    /**
     * Read from stream
     *
     * @param int $count
     * @return mixed
     */
    private function _stream_read($count)
    {
        switch ($this->mode) {
            case 'w':
            case 'a':
            case 'x':
            case 'c':
                return false;
        }

        // commented out because some files - eg. /dev/urandom - will say their size is 0 when in fact it's kinda infinite
        //if ($this->pos >= $this->size) {
        //    $this->eof = true;
        //    return false;
        //}

        $result = $this->sftp->get($this->path, false, $this->pos, $count);
        if (isset($this->notification) && is_callable($this->notification)) {
            if ($result === false) {
                call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
                return 0;
            }
            // seems that PHP calls stream_read in 8k chunks
            call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $this->size);
        }

        if (empty($result)) { // ie. false or empty string
            $this->eof = true;
            return false;
        }
        $this->pos += strlen($result);

        return $result;
    }

    /**
     * Write to stream
     *
     * @param string $data
     * @return int|false
     */
    private function _stream_write($data)
    {
        switch ($this->mode) {
            case 'r':
                return false;
        }

        $result = $this->sftp->put($this->path, $data, SFTP::SOURCE_STRING, $this->pos);
        if (isset($this->notification) && is_callable($this->notification)) {
            if (!$result) {
                call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
                return 0;
            }
            // seems that PHP splits up strings into 8k blocks before calling stream_write
            call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data));
        }

        if ($result === false) {
            return false;
        }
        $this->pos += strlen($data);
        if ($this->pos > $this->size) {
            $this->size = $this->pos;
        }
        $this->eof = false;
        return strlen($data);
    }

    /**
     * Retrieve the current position of a stream
     *
     * @return int
     */
    private function _stream_tell()
    {
        return $this->pos;
    }

    /**
     * Tests for end-of-file on a file pointer
     *
     * In my testing there are four classes functions that normally effect the pointer:
     * fseek, fputs  / fwrite, fgets / fread and ftruncate.
     *
     * Only fgets / fread, however, results in feof() returning true. do fputs($fp, 'aaa') on a blank file and feof()
     * will return false. do fread($fp, 1) and feof() will then return true. do fseek($fp, 10) on ablank file and feof()
     * will return false. do fread($fp, 1) and feof() will then return true.
     *
     * @return bool
     */
    private function _stream_eof()
    {
        return $this->eof;
    }

    /**
     * Seeks to specific location in a stream
     *
     * @param int $offset
     * @param int $whence
     * @return bool
     */
    private function _stream_seek($offset, $whence)
    {
        switch ($whence) {
            case SEEK_SET:
                if ($offset < 0) {
                    return false;
                }
                break;
            case SEEK_CUR:
                $offset += $this->pos;
                break;
            case SEEK_END:
                $offset += $this->size;
        }

        $this->pos = $offset;
        $this->eof = false;
        return true;
    }

    /**
     * Change stream options
     *
     * @param string $path
     * @param int $option
     * @param mixed $var
     * @return bool
     */
    private function _stream_metadata($path, $option, $var)
    {
        $path = $this->parse_path($path);
        if ($path === false) {
            return false;
        }

        // stream_metadata was introduced in PHP 5.4.0 but as of 5.4.11 the constants haven't been defined
        // see http://www.php.net/streamwrapper.stream-metadata and https://bugs.php.net/64246
        //     and https://github.com/php/php-src/blob/master/main/php_streams.h#L592
        switch ($option) {
            case 1: // PHP_STREAM_META_TOUCH
                $time = isset($var[0]) ? $var[0] : null;
                $atime = isset($var[1]) ? $var[1] : null;
                return $this->sftp->touch($path, $time, $atime);
            case 2: // PHP_STREAM_OWNER_NAME
            case 3: // PHP_STREAM_GROUP_NAME
                return false;
            case 4: // PHP_STREAM_META_OWNER
                return $this->sftp->chown($path, $var);
            case 5: // PHP_STREAM_META_GROUP
                return $this->sftp->chgrp($path, $var);
            case 6: // PHP_STREAM_META_ACCESS
                return $this->sftp->chmod($path, $var) !== false;
        }
    }

    /**
     * Retrieve the underlaying resource
     *
     * @param int $cast_as
     * @return resource
     */
    private function _stream_cast($cast_as)
    {
        return $this->sftp->fsock;
    }

    /**
     * Advisory file locking
     *
     * @param int $operation
     * @return bool
     */
    private function _stream_lock($operation)
    {
        return false;
    }

    /**
     * Renames a file or directory
     *
     * Attempts to rename oldname to newname, moving it between directories if necessary.
     * If newname exists, it will be overwritten.  This is a departure from what \phpseclib3\Net\SFTP
     * does.
     *
     * @param string $path_from
     * @param string $path_to
     * @return bool
     */
    private function _rename($path_from, $path_to)
    {
        $path1 = parse_url($path_from);
        $path2 = parse_url($path_to);
        unset($path1['path'], $path2['path']);
        if ($path1 != $path2) {
            return false;
        }

        $path_from = $this->parse_path($path_from);
        $path_to = parse_url($path_to);
        if ($path_from === false) {
            return false;
        }

        $path_to = $path_to['path']; // the $component part of parse_url() was added in PHP 5.1.2
        // "It is an error if there already exists a file with the name specified by newpath."
        //  -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5
        if (!$this->sftp->rename($path_from, $path_to)) {
            if ($this->sftp->stat($path_to)) {
                return $this->sftp->delete($path_to, true) && $this->sftp->rename($path_from, $path_to);
            }
            return false;
        }

        return true;
    }

    /**
     * Open directory handle
     *
     * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and
     * removed in 5.4 I'm just going to ignore it.
     *
     * Also, nlist() is the best that this function is realistically going to be able to do. When an SFTP client
     * sends a SSH_FXP_READDIR packet you don't generally get info on just one file but on multiple files. Quoting
     * the SFTP specs:
     *
     *    The SSH_FXP_NAME response has the following format:
     *
     *        uint32     id
     *        uint32     count
     *        repeats count times:
     *                string     filename
     *                string     longname
     *                ATTRS      attrs
     *
     * @param string $path
     * @param int $options
     * @return bool
     */
    private function _dir_opendir($path, $options)
    {
        $path = $this->parse_path($path);
        if ($path === false) {
            return false;
        }
        $this->pos = 0;
        $this->entries = $this->sftp->nlist($path);
        return $this->entries !== false;
    }

    /**
     * Read entry from directory handle
     *
     * @return mixed
     */
    private function _dir_readdir()
    {
        if (isset($this->entries[$this->pos])) {
            return $this->entries[$this->pos++];
        }
        return false;
    }

    /**
     * Rewind directory handle
     *
     * @return bool
     */
    private function _dir_rewinddir()
    {
        $this->pos = 0;
        return true;
    }

    /**
     * Close directory handle
     *
     * @return bool
     */
    private function _dir_closedir()
    {
        return true;
    }

    /**
     * Create a directory
     *
     * Only valid $options is STREAM_MKDIR_RECURSIVE
     *
     * @param string $path
     * @param int $mode
     * @param int $options
     * @return bool
     */
    private function _mkdir($path, $mode, $options)
    {
        $path = $this->parse_path($path);
        if ($path === false) {
            return false;
        }

        return $this->sftp->mkdir($path, $mode, $options & STREAM_MKDIR_RECURSIVE);
    }

    /**
     * Removes a directory
     *
     * Only valid $options is STREAM_MKDIR_RECURSIVE per <http://php.net/streamwrapper.rmdir>, however,
     * <http://php.net/rmdir>  does not have a $recursive parameter as mkdir() does so I don't know how
     * STREAM_MKDIR_RECURSIVE is supposed to be set. Also, when I try it out with rmdir() I get 8 as
     * $options. What does 8 correspond to?
     *
     * @param string $path
     * @param int $options
     * @return bool
     */
    private function _rmdir($path, $options)
    {
        $path = $this->parse_path($path);
        if ($path === false) {
            return false;
        }

        return $this->sftp->rmdir($path);
    }

    /**
     * Flushes the output
     *
     * See <http://php.net/fflush>. Always returns true because \phpseclib3\Net\SFTP doesn't cache stuff before writing
     *
     * @return bool
     */
    private function _stream_flush()
    {
        return true;
    }

    /**
     * Retrieve information about a file resource
     *
     * @return mixed
     */
    private function _stream_stat()
    {
        $results = $this->sftp->stat($this->path);
        if ($results === false) {
            return false;
        }
        return $results;
    }

    /**
     * Delete a file
     *
     * @param string $path
     * @return bool
     */
    private function _unlink($path)
    {
        $path = $this->parse_path($path);
        if ($path === false) {
            return false;
        }

        return $this->sftp->delete($path, false);
    }

    /**
     * Retrieve information about a file
     *
     * Ignores the STREAM_URL_STAT_QUIET flag because the entirety of \phpseclib3\Net\SFTP\Stream is quiet by default
     * might be worthwhile to reconstruct bits 12-16 (ie. the file type) if mode doesn't have them but we'll
     * cross that bridge when and if it's reached
     *
     * @param string $path
     * @param int $flags
     * @return mixed
     */
    private function _url_stat($path, $flags)
    {
        $path = $this->parse_path($path);
        if ($path === false) {
            return false;
        }

        $results = $flags & STREAM_URL_STAT_LINK ? $this->sftp->lstat($path) : $this->sftp->stat($path);
        if ($results === false) {
            return false;
        }

        return $results;
    }

    /**
     * Truncate stream
     *
     * @param int $new_size
     * @return bool
     */
    private function _stream_truncate($new_size)
    {
        if (!$this->sftp->truncate($this->path, $new_size)) {
            return false;
        }

        $this->eof = false;
        $this->size = $new_size;

        return true;
    }

    /**
     * Change stream options
     *
     * STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush isn't.
     * The other two aren't supported because of limitations in \phpseclib3\Net\SFTP.
     *
     * @param int $option
     * @param int $arg1
     * @param int $arg2
     * @return bool
     */
    private function _stream_set_option($option, $arg1, $arg2)
    {
        return false;
    }

    /**
     * Close an resource
     *
     */
    private function _stream_close()
    {
    }

    /**
     * __call Magic Method
     *
     * When you're utilizing an SFTP stream you're not calling the methods in this class directly - PHP is calling them for you.
     * Which kinda begs the question... what methods is PHP calling and what parameters is it passing to them? This function
     * lets you figure that out.
     *
     * If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not
     * NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method.
     *
     * @param string $name
     * @param array $arguments
     * @return mixed
     */
    public function __call($name, array $arguments)
    {
        if (defined('NET_SFTP_STREAM_LOGGING')) {
            echo $name . '(';
            $last = count($arguments) - 1;
            foreach ($arguments as $i => $argument) {
                var_export($argument);
                if ($i != $last) {
                    echo ',';
                }
            }
            echo ")\r\n";
        }
        $name = '_' . $name;
        if (!method_exists($this, $name)) {
            return false;
        }
        return $this->$name(...$arguments);
    }
}
<?php

/**
 * Pure-PHP implementation of SCP.
 *
 * PHP version 5
 *
 * The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $scp = new \phpseclib3\Net\SCP('www.domain.tld');
 *    if (!$scp->login('username', 'password')) {
 *        exit('Login Failed');
 *    }
 *
 *    echo $scp->exec('pwd') . "\r\n";
 *    $scp->put('filename.ext', 'hello, world!');
 *    echo $scp->exec('ls -latr');
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2009 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Net;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Exception\FileNotFoundException;

/**
 * Pure-PHP implementations of SCP.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class SCP extends SSH2
{
    /**
     * Reads data from a local file.
     *
     * @see \phpseclib3\Net\SCP::put()
     */
    const SOURCE_LOCAL_FILE = 1;
    /**
     * Reads data from a string.
     *
     * @see \phpseclib3\Net\SCP::put()
     */
    // this value isn't really used anymore but i'm keeping it reserved for historical reasons
    const SOURCE_STRING = 2;
    /**
     * SCP.php doesn't support SOURCE_CALLBACK because, with that one, we don't know the size, in advance
     */
    //const SOURCE_CALLBACK = 16;

    /**
     * Error information
     *
     * @see self::getSCPErrors()
     * @see self::getLastSCPError()
     * @var array
     */
    private $scp_errors = [];

    /**
     * Uploads a file to the SCP server.
     *
     * By default, \phpseclib\Net\SCP::put() does not read from the local filesystem.  $data is dumped directly into $remote_file.
     * So, for example, if you set $data to 'filename.ext' and then do \phpseclib\Net\SCP::get(), you will get a file, twelve bytes
     * long, containing 'filename.ext' as its contents.
     *
     * Setting $mode to self::SOURCE_LOCAL_FILE will change the above behavior.  With self::SOURCE_LOCAL_FILE, $remote_file will
     * contain as many bytes as filename.ext does on your local filesystem.  If your filename.ext is 1MB then that is how
     * large $remote_file will be, as well.
     *
     * Currently, only binary mode is supported.  As such, if the line endings need to be adjusted, you will need to take
     * care of that, yourself.
     *
     * @param string $remote_file
     * @param string $data
     * @param int $mode
     * @param callable $callback
     * @return bool
     * @access public
     */
    public function put($remote_file, $data, $mode = self::SOURCE_STRING, $callback = null)
    {
        if (!($this->bitmap & self::MASK_LOGIN)) {
            return false;
        }

        if (empty($remote_file)) {
            // remote file cannot be blank
            return false;
        }

        if (!$this->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
            return false;
        }

        $temp = $this->get_channel_packet(self::CHANNEL_EXEC, true);
        if ($temp !== chr(0)) {
            $this->close_channel(self::CHANNEL_EXEC, true);
            return false;
        }

        $packet_size = $this->packet_size_client_to_server[self::CHANNEL_EXEC] - 4;

        $remote_file = basename($remote_file);

        $dataCallback = false;
        switch (true) {
            case is_resource($data):
                $mode = $mode & ~self::SOURCE_LOCAL_FILE;
                $info = stream_get_meta_data($data);
                if (isset($info['wrapper_type']) && $info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') {
                    $fp = fopen('php://memory', 'w+');
                    stream_copy_to_stream($data, $fp);
                    rewind($fp);
                } else {
                    $fp = $data;
                }
                break;
            case $mode & self::SOURCE_LOCAL_FILE:
                if (!is_file($data)) {
                    throw new FileNotFoundException("$data is not a valid file");
                }
                $fp = @fopen($data, 'rb');
                if (!$fp) {
                    $this->close_channel(self::CHANNEL_EXEC, true);
                    return false;
                }
        }

        if (isset($fp)) {
            $stat = fstat($fp);
            $size = !empty($stat) ? $stat['size'] : 0;
        } else {
            $size = strlen($data);
        }

        $sent = 0;
        $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;

        $temp = 'C0644 ' . $size . ' ' . $remote_file . "\n";
        $this->send_channel_packet(self::CHANNEL_EXEC, $temp);

        $temp = $this->get_channel_packet(self::CHANNEL_EXEC, true);
        if ($temp !== chr(0)) {
            $this->close_channel(self::CHANNEL_EXEC, true);
            return false;
        }

        $sent = 0;
        while ($sent < $size) {
            $temp = $mode & self::SOURCE_STRING ? substr($data, $sent, $packet_size) : fread($fp, $packet_size);
            $this->send_channel_packet(self::CHANNEL_EXEC, $temp);
            $sent += strlen($temp);

            if (is_callable($callback)) {
                call_user_func($callback, $sent);
            }
        }
        $this->close_channel(self::CHANNEL_EXEC, true);

        if ($mode != self::SOURCE_STRING) {
            fclose($fp);
        }

        return true;
    }

    /**
     * Downloads a file from the SCP server.
     *
     * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
     * the operation was unsuccessful.  If $local_file is defined, returns true or false depending on the success of the
     * operation
     *
     * @param string $remote_file
     * @param string $local_file
     * @return mixed
     * @access public
     */
    public function get($remote_file, $local_file = null, $progressCallback = null)
    {
        if (!($this->bitmap & self::MASK_LOGIN)) {
            return false;
        }

        if (!$this->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from
            return false;
        }

        $this->send_channel_packet(self::CHANNEL_EXEC, chr(0));

        $info = $this->get_channel_packet(self::CHANNEL_EXEC, true);
        // per https://goteleport.com/blog/scp-familiar-simple-insecure-slow/ non-zero responses mean there are errors
        if ($info[0] === chr(1) || $info[0] == chr(2)) {
            $type = $info[0] === chr(1) ? 'warning' : 'error';
            $this->scp_errors[] = "$type: " . substr($info, 1);
            $this->close_channel(self::CHANNEL_EXEC, true);
            return false;
        }

        $this->send_channel_packet(self::CHANNEL_EXEC, chr(0));

        if (!preg_match('#(?<perms>[^ ]+) (?<size>\d+) (?<name>.+)#', rtrim($info), $info)) {
            $this->close_channel(self::CHANNEL_EXEC, true);
            return false;
        }

        $fclose_check = false;
        if (is_resource($local_file)) {
            $fp = $local_file;
        } elseif (!is_null($local_file)) {
            $fp = @fopen($local_file, 'wb');
            if (!$fp) {
                $this->close_channel(self::CHANNEL_EXEC, true);
                return false;
            }
            $fclose_check = true;
        } else {
            $content = '';
        }

        $size = 0;
        while (true) {
            $data = $this->get_channel_packet(self::CHANNEL_EXEC, true);
            // Terminate the loop in case the server repeatedly sends an empty response
            if ($data === false) {
                $this->close_channel(self::CHANNEL_EXEC, true);
                // no data received from server
                return false;
            }
            // SCP usually seems to split stuff out into 16k chunks
            $length = strlen($data);
            $size += $length;
            $end = $size > $info['size'];
            if ($end) {
                $diff = $size - $info['size'];
                $offset = $length - $diff;
                if ($data[$offset] === chr(0)) {
                    $data = substr($data, 0, -$diff);
                } else {
                    $type = $data[$offset] === chr(1) ? 'warning' : 'error';
                    $this->scp_errors[] = "$type: " . substr($data, 1);
                    $this->close_channel(self::CHANNEL_EXEC, true);
                    return false;
                }
            }

            if (is_null($local_file)) {
                $content .= $data;
            } else {
                fputs($fp, $data);
            }

            if (is_callable($progressCallback)) {
                call_user_func($progressCallback, $size);
            }

            if ($end) {
                break;
            }
        }

        $this->close_channel(self::CHANNEL_EXEC, true);

        if ($fclose_check) {
            fclose($fp);
        }

        // if $content isn't set that means a file was written to
        return isset($content) ? $content : true;
    }

    /**
     * Returns all errors on the SCP layer
     *
     * @return array
     */
    public function getSCPErrors()
    {
        return $this->scp_errors;
    }

    /**
     * Returns the last error on the SCP layer
     *
     * @return string
     */
    public function getLastSCPError()
    {
        return count($this->scp_errors) ? $this->scp_errors[count($this->scp_errors) - 1] : '';
    }
}
<?php

/**
 * Pure-PHP implementation of SFTP.
 *
 * PHP version 5
 *
 * Supports SFTPv2/3/4/5/6. Defaults to v3.
 *
 * The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $sftp = new \phpseclib3\Net\SFTP('www.domain.tld');
 *    if (!$sftp->login('username', 'password')) {
 *        exit('Login Failed');
 *    }
 *
 *    echo $sftp->pwd() . "\r\n";
 *    $sftp->put('filename.ext', 'hello, world!');
 *    print_r($sftp->nlist());
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2009 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Net;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Exception\FileNotFoundException;

/**
 * Pure-PHP implementations of SFTP.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class SFTP extends SSH2
{
    /**
     * SFTP channel constant
     *
     * \phpseclib3\Net\SSH2::exec() uses 0 and \phpseclib3\Net\SSH2::read() / \phpseclib3\Net\SSH2::write() use 1.
     *
     * @see \phpseclib3\Net\SSH2::send_channel_packet()
     * @see \phpseclib3\Net\SSH2::get_channel_packet()
     */
    const CHANNEL = 0x100;

    /**
     * Reads data from a local file.
     *
     * @see \phpseclib3\Net\SFTP::put()
     */
    const SOURCE_LOCAL_FILE = 1;
    /**
     * Reads data from a string.
     *
     * @see \phpseclib3\Net\SFTP::put()
     */
    // this value isn't really used anymore but i'm keeping it reserved for historical reasons
    const SOURCE_STRING = 2;
    /**
     * Reads data from callback:
     * function callback($length) returns string to proceed, null for EOF
     *
     * @see \phpseclib3\Net\SFTP::put()
     */
    const SOURCE_CALLBACK = 16;
    /**
     * Resumes an upload
     *
     * @see \phpseclib3\Net\SFTP::put()
     */
    const RESUME = 4;
    /**
     * Append a local file to an already existing remote file
     *
     * @see \phpseclib3\Net\SFTP::put()
     */
    const RESUME_START = 8;

    /**
     * Packet Types
     *
     * @see self::__construct()
     * @var array
     * @access private
     */
    private static $packet_types = [];

    /**
     * Status Codes
     *
     * @see self::__construct()
     * @var array
     * @access private
     */
    private static $status_codes = [];

    /** @var array<int, string> */
    private static $attributes;

    /** @var array<int, string> */
    private static $open_flags;

    /** @var array<int, string> */
    private static $open_flags5;

    /** @var array<int, string> */
    private static $file_types;

    /**
     * The Request ID
     *
     * The request ID exists in the off chance that a packet is sent out-of-order.  Of course, this library doesn't support
     * concurrent actions, so it's somewhat academic, here.
     *
     * @var boolean
     * @see self::_send_sftp_packet()
     */
    private $use_request_id = false;

    /**
     * The Packet Type
     *
     * The request ID exists in the off chance that a packet is sent out-of-order.  Of course, this library doesn't support
     * concurrent actions, so it's somewhat academic, here.
     *
     * @var int
     * @see self::_get_sftp_packet()
     */
    private $packet_type = -1;

    /**
     * Packet Buffer
     *
     * @var string
     * @see self::_get_sftp_packet()
     */
    private $packet_buffer = '';

    /**
     * Extensions supported by the server
     *
     * @var array
     * @see self::_initChannel()
     */
    private $extensions = [];

    /**
     * Server SFTP version
     *
     * @var int
     * @see self::_initChannel()
     */
    private $version;

    /**
     * Default Server SFTP version
     *
     * @var int
     * @see self::_initChannel()
     */
    private $defaultVersion;

    /**
     * Preferred SFTP version
     *
     * @var int
     * @see self::_initChannel()
     */
    private $preferredVersion = 3;

    /**
     * Current working directory
     *
     * @var string|bool
     * @see self::realpath()
     * @see self::chdir()
     */
    private $pwd = false;

    /**
     * Packet Type Log
     *
     * @see self::getLog()
     * @var array
     */
    private $packet_type_log = [];

    /**
     * Packet Log
     *
     * @see self::getLog()
     * @var array
     */
    private $packet_log = [];

    /**
     * Real-time log file pointer
     *
     * @see self::_append_log()
     * @var resource|closed-resource
     */
    private $realtime_log_file;

    /**
     * Real-time log file size
     *
     * @see self::_append_log()
     * @var int
     */
    private $realtime_log_size;

    /**
     * Real-time log file wrap boolean
     *
     * @see self::_append_log()
     * @var bool
     */
    private $realtime_log_wrap;

    /**
     * Current log size
     *
     * Should never exceed self::LOG_MAX_SIZE
     *
     * @var int
     */
    private $log_size;

    /**
     * Error information
     *
     * @see self::getSFTPErrors()
     * @see self::getLastSFTPError()
     * @var array
     */
    private $sftp_errors = [];

    /**
     * Stat Cache
     *
     * Rather than always having to open a directory and close it immediately there after to see if a file is a directory
     * we'll cache the results.
     *
     * @see self::_update_stat_cache()
     * @see self::_remove_from_stat_cache()
     * @see self::_query_stat_cache()
     * @var array
     */
    private $stat_cache = [];

    /**
     * Max SFTP Packet Size
     *
     * @see self::__construct()
     * @see self::get()
     * @var int
     */
    private $max_sftp_packet;

    /**
     * Stat Cache Flag
     *
     * @see self::disableStatCache()
     * @see self::enableStatCache()
     * @var bool
     */
    private $use_stat_cache = true;

    /**
     * Sort Options
     *
     * @see self::_comparator()
     * @see self::setListOrder()
     * @var array
     */
    protected $sortOptions = [];

    /**
     * Canonicalization Flag
     *
     * Determines whether or not paths should be canonicalized before being
     * passed on to the remote server.
     *
     * @see self::enablePathCanonicalization()
     * @see self::disablePathCanonicalization()
     * @see self::realpath()
     * @var bool
     */
    private $canonicalize_paths = true;

    /**
     * Request Buffers
     *
     * @see self::_get_sftp_packet()
     * @var array
     */
    private $requestBuffer = [];

    /**
     * Preserve timestamps on file downloads / uploads
     *
     * @see self::get()
     * @see self::put()
     * @var bool
     */
    private $preserveTime = false;

    /**
     * Arbitrary Length Packets Flag
     *
     * Determines whether or not packets of any length should be allowed,
     * in cases where the server chooses the packet length (such as
     * directory listings). By default, packets are only allowed to be
     * 256 * 1024 bytes (SFTP_MAX_MSG_LENGTH from OpenSSH's sftp-common.h)
     *
     * @see self::enableArbitraryLengthPackets()
     * @see self::_get_sftp_packet()
     * @var bool
     */
    private $allow_arbitrary_length_packets = false;

    /**
     * Was the last packet due to the channels being closed or not?
     *
     * @see self::get()
     * @see self::get_sftp_packet()
     * @var bool
     */
    private $channel_close = false;

    /**
     * Has the SFTP channel been partially negotiated?
     *
     * @var bool
     */
    private $partial_init = false;

    /**
     * Default Constructor.
     *
     * Connects to an SFTP server
     *
     * $host can either be a string, representing the host, or a stream resource.
     *
     * @param mixed $host
     * @param int $port
     * @param int $timeout
     */
    public function __construct($host, $port = 22, $timeout = 10)
    {
        parent::__construct($host, $port, $timeout);

        $this->max_sftp_packet = 1 << 15;

        if (empty(self::$packet_types)) {
            self::$packet_types = [
                1  => 'NET_SFTP_INIT',
                2  => 'NET_SFTP_VERSION',
                3  => 'NET_SFTP_OPEN',
                4  => 'NET_SFTP_CLOSE',
                5  => 'NET_SFTP_READ',
                6  => 'NET_SFTP_WRITE',
                7  => 'NET_SFTP_LSTAT',
                9  => 'NET_SFTP_SETSTAT',
                10 => 'NET_SFTP_FSETSTAT',
                11 => 'NET_SFTP_OPENDIR',
                12 => 'NET_SFTP_READDIR',
                13 => 'NET_SFTP_REMOVE',
                14 => 'NET_SFTP_MKDIR',
                15 => 'NET_SFTP_RMDIR',
                16 => 'NET_SFTP_REALPATH',
                17 => 'NET_SFTP_STAT',
                18 => 'NET_SFTP_RENAME',
                19 => 'NET_SFTP_READLINK',
                20 => 'NET_SFTP_SYMLINK',
                21 => 'NET_SFTP_LINK',

                101 => 'NET_SFTP_STATUS',
                102 => 'NET_SFTP_HANDLE',
                103 => 'NET_SFTP_DATA',
                104 => 'NET_SFTP_NAME',
                105 => 'NET_SFTP_ATTRS',

                200 => 'NET_SFTP_EXTENDED',
                201 => 'NET_SFTP_EXTENDED_REPLY'
            ];
            self::$status_codes = [
                0 => 'NET_SFTP_STATUS_OK',
                1 => 'NET_SFTP_STATUS_EOF',
                2 => 'NET_SFTP_STATUS_NO_SUCH_FILE',
                3 => 'NET_SFTP_STATUS_PERMISSION_DENIED',
                4 => 'NET_SFTP_STATUS_FAILURE',
                5 => 'NET_SFTP_STATUS_BAD_MESSAGE',
                6 => 'NET_SFTP_STATUS_NO_CONNECTION',
                7 => 'NET_SFTP_STATUS_CONNECTION_LOST',
                8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED',
                9 => 'NET_SFTP_STATUS_INVALID_HANDLE',
                10 => 'NET_SFTP_STATUS_NO_SUCH_PATH',
                11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS',
                12 => 'NET_SFTP_STATUS_WRITE_PROTECT',
                13 => 'NET_SFTP_STATUS_NO_MEDIA',
                14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM',
                15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED',
                16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL',
                17 => 'NET_SFTP_STATUS_LOCK_CONFLICT',
                18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY',
                19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY',
                20 => 'NET_SFTP_STATUS_INVALID_FILENAME',
                21 => 'NET_SFTP_STATUS_LINK_LOOP',
                22 => 'NET_SFTP_STATUS_CANNOT_DELETE',
                23 => 'NET_SFTP_STATUS_INVALID_PARAMETER',
                24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY',
                25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT',
                26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED',
                27 => 'NET_SFTP_STATUS_DELETE_PENDING',
                28 => 'NET_SFTP_STATUS_FILE_CORRUPT',
                29 => 'NET_SFTP_STATUS_OWNER_INVALID',
                30 => 'NET_SFTP_STATUS_GROUP_INVALID',
                31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK'
            ];
            // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1
            // the order, in this case, matters quite a lot - see \phpseclib3\Net\SFTP::_parseAttributes() to understand why
            self::$attributes = [
                0x00000001 => 'NET_SFTP_ATTR_SIZE',
                0x00000002 => 'NET_SFTP_ATTR_UIDGID',          // defined in SFTPv3, removed in SFTPv4+
                0x00000080 => 'NET_SFTP_ATTR_OWNERGROUP',      // defined in SFTPv4+
                0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
                0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
                0x00000010 => 'NET_SFTP_ATTR_CREATETIME',      // SFTPv4+
                0x00000020 => 'NET_SFTP_ATTR_MODIFYTIME',
                0x00000040 => 'NET_SFTP_ATTR_ACL',
                0x00000100 => 'NET_SFTP_ATTR_SUBSECOND_TIMES',
                0x00000200 => 'NET_SFTP_ATTR_BITS',            // SFTPv5+
                0x00000400 => 'NET_SFTP_ATTR_ALLOCATION_SIZE', // SFTPv6+
                0x00000800 => 'NET_SFTP_ATTR_TEXT_HINT',
                0x00001000 => 'NET_SFTP_ATTR_MIME_TYPE',
                0x00002000 => 'NET_SFTP_ATTR_LINK_COUNT',
                0x00004000 => 'NET_SFTP_ATTR_UNTRANSLATED_NAME',
                0x00008000 => 'NET_SFTP_ATTR_CTIME',
                // 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers
                // yields inconsistent behavior depending on how php is compiled.  so we left shift -1 (which, in
                // two's compliment, consists of all 1 bits) by 31.  on 64-bit systems this'll yield 0xFFFFFFFF80000000.
                // that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
                (PHP_INT_SIZE == 4 ? (-1 << 31) : 0x80000000) => 'NET_SFTP_ATTR_EXTENDED'
            ];
            // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
            // the flag definitions change somewhat in SFTPv5+.  if SFTPv5+ support is added to this library, maybe name
            // the array for that $this->open5_flags and similarly alter the constant names.
            self::$open_flags = [
                0x00000001 => 'NET_SFTP_OPEN_READ',
                0x00000002 => 'NET_SFTP_OPEN_WRITE',
                0x00000004 => 'NET_SFTP_OPEN_APPEND',
                0x00000008 => 'NET_SFTP_OPEN_CREATE',
                0x00000010 => 'NET_SFTP_OPEN_TRUNCATE',
                0x00000020 => 'NET_SFTP_OPEN_EXCL',
                0x00000040 => 'NET_SFTP_OPEN_TEXT' // defined in SFTPv4
            ];
            // SFTPv5+ changed the flags up:
            // https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-8.1.1.3
            self::$open_flags5 = [
                // when SSH_FXF_ACCESS_DISPOSITION is a 3 bit field that controls how the file is opened
                0x00000000 => 'NET_SFTP_OPEN_CREATE_NEW',
                0x00000001 => 'NET_SFTP_OPEN_CREATE_TRUNCATE',
                0x00000002 => 'NET_SFTP_OPEN_OPEN_EXISTING',
                0x00000003 => 'NET_SFTP_OPEN_OPEN_OR_CREATE',
                0x00000004 => 'NET_SFTP_OPEN_TRUNCATE_EXISTING',
                // the rest of the flags are not supported
                0x00000008 => 'NET_SFTP_OPEN_APPEND_DATA', // "the offset field of SS_FXP_WRITE requests is ignored"
                0x00000010 => 'NET_SFTP_OPEN_APPEND_DATA_ATOMIC',
                0x00000020 => 'NET_SFTP_OPEN_TEXT_MODE',
                0x00000040 => 'NET_SFTP_OPEN_BLOCK_READ',
                0x00000080 => 'NET_SFTP_OPEN_BLOCK_WRITE',
                0x00000100 => 'NET_SFTP_OPEN_BLOCK_DELETE',
                0x00000200 => 'NET_SFTP_OPEN_BLOCK_ADVISORY',
                0x00000400 => 'NET_SFTP_OPEN_NOFOLLOW',
                0x00000800 => 'NET_SFTP_OPEN_DELETE_ON_CLOSE',
                0x00001000 => 'NET_SFTP_OPEN_ACCESS_AUDIT_ALARM_INFO',
                0x00002000 => 'NET_SFTP_OPEN_ACCESS_BACKUP',
                0x00004000 => 'NET_SFTP_OPEN_BACKUP_STREAM',
                0x00008000 => 'NET_SFTP_OPEN_OVERRIDE_OWNER',
            ];
            // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2
            // see \phpseclib3\Net\SFTP::_parseLongname() for an explanation
            self::$file_types = [
                1 => 'NET_SFTP_TYPE_REGULAR',
                2 => 'NET_SFTP_TYPE_DIRECTORY',
                3 => 'NET_SFTP_TYPE_SYMLINK',
                4 => 'NET_SFTP_TYPE_SPECIAL',
                5 => 'NET_SFTP_TYPE_UNKNOWN',
                // the following types were first defined for use in SFTPv5+
                // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
                6 => 'NET_SFTP_TYPE_SOCKET',
                7 => 'NET_SFTP_TYPE_CHAR_DEVICE',
                8 => 'NET_SFTP_TYPE_BLOCK_DEVICE',
                9 => 'NET_SFTP_TYPE_FIFO'
            ];
            self::define_array(
                self::$packet_types,
                self::$status_codes,
                self::$attributes,
                self::$open_flags,
                self::$open_flags5,
                self::$file_types
            );
        }

        if (!defined('NET_SFTP_QUEUE_SIZE')) {
            define('NET_SFTP_QUEUE_SIZE', 32);
        }
        if (!defined('NET_SFTP_UPLOAD_QUEUE_SIZE')) {
            define('NET_SFTP_UPLOAD_QUEUE_SIZE', 1024);
        }
    }

    /**
     * Check a few things before SFTP functions are called
     *
     * @return bool
     */
    private function precheck()
    {
        if (!($this->bitmap & SSH2::MASK_LOGIN)) {
            return false;
        }

        if ($this->pwd === false) {
            return $this->init_sftp_connection();
        }

        return true;
    }

    /**
     * Partially initialize an SFTP connection
     *
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @return bool
     */
    private function partial_init_sftp_connection()
    {
        $response = $this->open_channel(self::CHANNEL, true);
        if ($response === true && $this->isTimeout()) {
            return false;
        }

        $packet = Strings::packSSH2(
            'CNsbs',
            NET_SSH2_MSG_CHANNEL_REQUEST,
            $this->server_channels[self::CHANNEL],
            'subsystem',
            true,
            'sftp'
        );
        $this->send_binary_packet($packet);

        $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;

        $response = $this->get_channel_packet(self::CHANNEL, true);
        if ($response === false) {
            // from PuTTY's psftp.exe
            $command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" .
                       "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" .
                       "exec sftp-server";
            // we don't do $this->exec($command, false) because exec() operates on a different channel and plus the SSH_MSG_CHANNEL_OPEN that exec() does
            // is redundant
            $packet = Strings::packSSH2(
                'CNsCs',
                NET_SSH2_MSG_CHANNEL_REQUEST,
                $this->server_channels[self::CHANNEL],
                'exec',
                1,
                $command
            );
            $this->send_binary_packet($packet);

            $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;

            $response = $this->get_channel_packet(self::CHANNEL, true);
            if ($response === false) {
                return false;
            }
        } elseif ($response === true && $this->isTimeout()) {
            return false;
        }

        $this->channel_status[self::CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
        $this->send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3");

        $response = $this->get_sftp_packet();
        if ($this->packet_type != NET_SFTP_VERSION) {
            throw new \UnexpectedValueException('Expected NET_SFTP_VERSION. '
                                              . 'Got packet type: ' . $this->packet_type);
        }

        $this->use_request_id = true;

        list($this->defaultVersion) = Strings::unpackSSH2('N', $response);
        while (!empty($response)) {
            list($key, $value) = Strings::unpackSSH2('ss', $response);
            $this->extensions[$key] = $value;
        }

        $this->partial_init = true;

        return true;
    }

    /**
     * (Re)initializes the SFTP channel
     *
     * @return bool
     */
    private function init_sftp_connection()
    {
        if (!$this->partial_init && !$this->partial_init_sftp_connection()) {
            return false;
        }

        /*
         A Note on SFTPv4/5/6 support:
         <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.1> states the following:

         "If the client wishes to interoperate with servers that support noncontiguous version
          numbers it SHOULD send '3'"

         Given that the server only sends its version number after the client has already done so, the above
         seems to be suggesting that v3 should be the default version.  This makes sense given that v3 is the
         most popular.

         <http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.5> states the following;

         "If the server did not send the "versions" extension, or the version-from-list was not included, the
          server MAY send a status response describing the failure, but MUST then close the channel without
          processing any further requests."

         So what do you do if you have a client whose initial SSH_FXP_INIT packet says it implements v3 and
         a server whose initial SSH_FXP_VERSION reply says it implements v4 and only v4?  If it only implements
         v4, the "versions" extension is likely not going to have been sent so version re-negotiation as discussed
         in draft-ietf-secsh-filexfer-13 would be quite impossible.  As such, what \phpseclib3\Net\SFTP would do is close the
         channel and reopen it with a new and updated SSH_FXP_INIT packet.
        */
        $this->version = $this->defaultVersion;
        if (isset($this->extensions['versions']) && (!$this->preferredVersion || $this->preferredVersion != $this->version)) {
            $versions = explode(',', $this->extensions['versions']);
            $supported = [6, 5, 4];
            if ($this->preferredVersion) {
                $supported = array_diff($supported, [$this->preferredVersion]);
                array_unshift($supported, $this->preferredVersion);
            }
            foreach ($supported as $ver) {
                if (in_array($ver, $versions)) {
                    if ($ver === $this->version) {
                        break;
                    }
                    $this->version = (int) $ver;
                    $packet = Strings::packSSH2('ss', 'version-select', "$ver");
                    $this->send_sftp_packet(NET_SFTP_EXTENDED, $packet);
                    $response = $this->get_sftp_packet();
                    if ($this->packet_type != NET_SFTP_STATUS) {
                        throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                            . 'Got packet type: ' . $this->packet_type);
                    }
                    list($status) = Strings::unpackSSH2('N', $response);
                    if ($status != NET_SFTP_STATUS_OK) {
                        $this->logError($response, $status);
                        throw new \UnexpectedValueException('Expected NET_SFTP_STATUS_OK. '
                            . ' Got ' . $status);
                    }
                    break;
                }
            }
        }

        /*
         SFTPv4+ defines a 'newline' extension.  SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com',
         however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's
         not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for
         one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that
         'newline@vandyke.com' would.
        */
        /*
        if (isset($this->extensions['newline@vandyke.com'])) {
            $this->extensions['newline'] = $this->extensions['newline@vandyke.com'];
            unset($this->extensions['newline@vandyke.com']);
        }
        */
        if ($this->version < 2 || $this->version > 6) {
            return false;
        }

        $this->pwd = true;
        try {
            $this->pwd = $this->realpath('.');
        } catch (\UnexpectedValueException $e) {
            if (!$this->canonicalize_paths) {
                throw $e;
            }
            $this->canonicalize_paths = false;
            $this->reset_sftp();
            return $this->init_sftp_connection();
        }

        $this->update_stat_cache($this->pwd, []);

        return true;
    }

    /**
     * Disable the stat cache
     *
     */
    public function disableStatCache()
    {
        $this->use_stat_cache = false;
    }

    /**
     * Enable the stat cache
     *
     */
    public function enableStatCache()
    {
        $this->use_stat_cache = true;
    }

    /**
     * Clear the stat cache
     *
     */
    public function clearStatCache()
    {
        $this->stat_cache = [];
    }

    /**
     * Enable path canonicalization
     *
     */
    public function enablePathCanonicalization()
    {
        $this->canonicalize_paths = true;
    }

    /**
     * Disable path canonicalization
     *
     * If this is enabled then $sftp->pwd() will not return the canonicalized absolute path
     *
     */
    public function disablePathCanonicalization()
    {
        $this->canonicalize_paths = false;
    }

    /**
     * Enable arbitrary length packets
     *
     */
    public function enableArbitraryLengthPackets()
    {
        $this->allow_arbitrary_length_packets = true;
    }

    /**
     * Disable arbitrary length packets
     *
     */
    public function disableArbitraryLengthPackets()
    {
        $this->allow_arbitrary_length_packets = false;
    }

    /**
     * Returns the current directory name
     *
     * @return string|bool
     */
    public function pwd()
    {
        if (!$this->precheck()) {
            return false;
        }

        return $this->pwd;
    }

    /**
     * Logs errors
     *
     * @param string $response
     * @param int $status
     */
    private function logError($response, $status = -1)
    {
        if ($status == -1) {
            list($status) = Strings::unpackSSH2('N', $response);
        }

        $error = self::$status_codes[$status];

        if ($this->version > 2) {
            list($message) = Strings::unpackSSH2('s', $response);
            $this->sftp_errors[] = "$error: $message";
        } else {
            $this->sftp_errors[] = $error;
        }
    }

    /**
     * Canonicalize the Server-Side Path Name
     *
     * SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it.  Returns
     * the absolute (canonicalized) path.
     *
     * If canonicalize_paths has been disabled using disablePathCanonicalization(), $path is returned as-is.
     *
     * @see self::chdir()
     * @see self::disablePathCanonicalization()
     * @param string $path
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @return mixed
     */
    public function realpath($path)
    {
        if ($this->precheck() === false) {
            return false;
        }

        $path = (string) $path;

        if (!$this->canonicalize_paths) {
            if ($this->pwd === true) {
                return '.';
            }
            if (!strlen($path) || $path[0] != '/') {
                $path = $this->pwd . '/' . $path;
            }
            $parts = explode('/', $path);
            $afterPWD = $beforePWD = [];
            foreach ($parts as $part) {
                switch ($part) {
                    //case '': // some SFTP servers /require/ double /'s. see https://github.com/phpseclib/phpseclib/pull/1137
                    case '.':
                        break;
                    case '..':
                        if (!empty($afterPWD)) {
                            array_pop($afterPWD);
                        } else {
                            $beforePWD[] = '..';
                        }
                        break;
                    default:
                        $afterPWD[] = $part;
                }
            }
            $beforePWD = count($beforePWD) ? implode('/', $beforePWD) : '.';
            return $beforePWD . '/' . implode('/', $afterPWD);
        }

        if ($this->pwd === true) {
            // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
            $this->send_sftp_packet(NET_SFTP_REALPATH, Strings::packSSH2('s', $path));

            $response = $this->get_sftp_packet();
            switch ($this->packet_type) {
                case NET_SFTP_NAME:
                    // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following
                    // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
                    // at is the first part and that part is defined the same in SFTP versions 3 through 6.
                    list(, $filename) = Strings::unpackSSH2('Ns', $response);
                    return $filename;
                case NET_SFTP_STATUS:
                    $this->logError($response);
                    return false;
                default:
                    throw new \UnexpectedValueException('Expected NET_SFTP_NAME or NET_SFTP_STATUS. '
                                                      . 'Got packet type: ' . $this->packet_type);
            }
        }

        if (!strlen($path) || $path[0] != '/') {
            $path = $this->pwd . '/' . $path;
        }

        $path = explode('/', $path);
        $new = [];
        foreach ($path as $dir) {
            if (!strlen($dir)) {
                continue;
            }
            switch ($dir) {
                case '..':
                    array_pop($new);
                    // fall-through
                case '.':
                    break;
                default:
                    $new[] = $dir;
            }
        }

        return '/' . implode('/', $new);
    }

    /**
     * Changes the current directory
     *
     * @param string $dir
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @return bool
     */
    public function chdir($dir)
    {
        if (!$this->precheck()) {
            return false;
        }

        $dir = (string) $dir;

        // assume current dir if $dir is empty
        if ($dir === '') {
            $dir = './';
        // suffix a slash if needed
        } elseif ($dir[strlen($dir) - 1] != '/') {
            $dir .= '/';
        }

        $dir = $this->realpath($dir);
        if ($dir === false) {
            return false;
        }

        // confirm that $dir is, in fact, a valid directory
        if ($this->use_stat_cache && is_array($this->query_stat_cache($dir))) {
            $this->pwd = $dir;
            return true;
        }

        // we could do a stat on the alleged $dir to see if it's a directory but that doesn't tell us
        // the currently logged in user has the appropriate permissions or not. maybe you could see if
        // the file's uid / gid match the currently logged in user's uid / gid but how there's no easy
        // way to get those with SFTP

        $this->send_sftp_packet(NET_SFTP_OPENDIR, Strings::packSSH2('s', $dir));

        // see \phpseclib3\Net\SFTP::nlist() for a more thorough explanation of the following
        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_HANDLE:
                $handle = substr($response, 4);
                break;
            case NET_SFTP_STATUS:
                $this->logError($response);
                return false;
            default:
                throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS' .
                                                    'Got packet type: ' . $this->packet_type);
        }

        if (!$this->close_handle($handle)) {
            return false;
        }

        $this->update_stat_cache($dir, []);

        $this->pwd = $dir;
        return true;
    }

    /**
     * Returns a list of files in the given directory
     *
     * @param string $dir
     * @param bool $recursive
     * @return array|false
     */
    public function nlist($dir = '.', $recursive = false)
    {
        return $this->nlist_helper($dir, $recursive, '');
    }

    /**
     * Helper method for nlist
     *
     * @param string $dir
     * @param bool $recursive
     * @param string $relativeDir
     * @return array|false
     */
    private function nlist_helper($dir, $recursive, $relativeDir)
    {
        $files = $this->readlist($dir, false);

        // If we get an int back, then that is an "unexpected" status.
        // We do not have a file list, so return false.
        if (is_int($files)) {
            return false;
        }

        if (!$recursive || $files === false) {
            return $files;
        }

        $result = [];
        foreach ($files as $value) {
            if ($value == '.' || $value == '..') {
                $result[] = $relativeDir . $value;
                continue;
            }
            if (is_array($this->query_stat_cache($this->realpath($dir . '/' . $value)))) {
                $temp = $this->nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/');
                $temp = is_array($temp) ? $temp : [];
                $result = array_merge($result, $temp);
            } else {
                $result[] = $relativeDir . $value;
            }
        }

        return $result;
    }

    /**
     * Returns a detailed list of files in the given directory
     *
     * @param string $dir
     * @param bool $recursive
     * @return array|false
     */
    public function rawlist($dir = '.', $recursive = false)
    {
        $files = $this->readlist($dir, true);

        // If we get an int back, then that is an "unexpected" status.
        // We do not have a file list, so return false.
        if (is_int($files)) {
            return false;
        }

        if (!$recursive || $files === false) {
            return $files;
        }

        static $depth = 0;

        foreach ($files as $key => $value) {
            if ($depth != 0 && $key == '..') {
                unset($files[$key]);
                continue;
            }
            $is_directory = false;
            if ($key != '.' && $key != '..') {
                if ($this->use_stat_cache) {
                    $is_directory = is_array($this->query_stat_cache($this->realpath($dir . '/' . $key)));
                } else {
                    $stat = $this->lstat($dir . '/' . $key);
                    $is_directory = $stat && $stat['type'] === NET_SFTP_TYPE_DIRECTORY;
                }
            }

            if ($is_directory) {
                $depth++;
                $files[$key] = $this->rawlist($dir . '/' . $key, true);
                $depth--;
            } else {
                $files[$key] = (object) $value;
            }
        }

        return $files;
    }

    /**
     * Reads a list, be it detailed or not, of files in the given directory
     *
     * @param string $dir
     * @param bool $raw
     * @return array|false
     * @throws \UnexpectedValueException on receipt of unexpected packets
     */
    private function readlist($dir, $raw = true)
    {
        if (!$this->precheck()) {
            return false;
        }

        $dir = $this->realpath($dir . '/');
        if ($dir === false) {
            return false;
        }

        // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2
        $this->send_sftp_packet(NET_SFTP_OPENDIR, Strings::packSSH2('s', $dir));

        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_HANDLE:
                // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.2
                // since 'handle' is the last field in the SSH_FXP_HANDLE packet, we'll just remove the first four bytes that
                // represent the length of the string and leave it at that
                $handle = substr($response, 4);
                break;
            case NET_SFTP_STATUS:
                // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
                list($status) = Strings::unpackSSH2('N', $response);
                $this->logError($response, $status);
                return $status;
            default:
                throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. '
                                                  . 'Got packet type: ' . $this->packet_type);
        }

        $this->update_stat_cache($dir, []);

        $contents = [];
        while (true) {
            // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2
            // why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many
            // SSH_MSG_CHANNEL_DATA messages is not known to me.
            $this->send_sftp_packet(NET_SFTP_READDIR, Strings::packSSH2('s', $handle));

            $response = $this->get_sftp_packet();
            switch ($this->packet_type) {
                case NET_SFTP_NAME:
                    list($count) = Strings::unpackSSH2('N', $response);
                    for ($i = 0; $i < $count; $i++) {
                        list($shortname) = Strings::unpackSSH2('s', $response);
                        // SFTPv4 "removed the long filename from the names structure-- it can now be
                        //         built from information available in the attrs structure."
                        if ($this->version < 4) {
                            list($longname) = Strings::unpackSSH2('s', $response);
                        }
                        $attributes = $this->parseAttributes($response);
                        if (!isset($attributes['type']) && $this->version < 4) {
                            $fileType = $this->parseLongname($longname);
                            if ($fileType) {
                                $attributes['type'] = $fileType;
                            }
                        }
                        $contents[$shortname] = $attributes + ['filename' => $shortname];

                        if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
                            $this->update_stat_cache($dir . '/' . $shortname, []);
                        } else {
                            if ($shortname == '..') {
                                $temp = $this->realpath($dir . '/..') . '/.';
                            } else {
                                $temp = $dir . '/' . $shortname;
                            }
                            $this->update_stat_cache($temp, (object) ['lstat' => $attributes]);
                        }
                        // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
                        // final SSH_FXP_STATUS packet should tell us that, already.
                    }
                    break;
                case NET_SFTP_STATUS:
                    list($status) = Strings::unpackSSH2('N', $response);
                    if ($status != NET_SFTP_STATUS_EOF) {
                        $this->logError($response, $status);
                        return $status;
                    }
                    break 2;
                default:
                    throw new \UnexpectedValueException('Expected NET_SFTP_NAME or NET_SFTP_STATUS. '
                                                      . 'Got packet type: ' . $this->packet_type);
            }
        }

        if (!$this->close_handle($handle)) {
            return false;
        }

        if (count($this->sortOptions)) {
            uasort($contents, [&$this, 'comparator']);
        }

        return $raw ? $contents : array_map('strval', array_keys($contents));
    }

    /**
     * Compares two rawlist entries using parameters set by setListOrder()
     *
     * Intended for use with uasort()
     *
     * @param array $a
     * @param array $b
     * @return int
     */
    private function comparator(array $a, array $b)
    {
        switch (true) {
            case $a['filename'] === '.' || $b['filename'] === '.':
                if ($a['filename'] === $b['filename']) {
                    return 0;
                }
                return $a['filename'] === '.' ? -1 : 1;
            case $a['filename'] === '..' || $b['filename'] === '..':
                if ($a['filename'] === $b['filename']) {
                    return 0;
                }
                return $a['filename'] === '..' ? -1 : 1;
            case isset($a['type']) && $a['type'] === NET_SFTP_TYPE_DIRECTORY:
                if (!isset($b['type'])) {
                    return 1;
                }
                if ($b['type'] !== $a['type']) {
                    return -1;
                }
                break;
            case isset($b['type']) && $b['type'] === NET_SFTP_TYPE_DIRECTORY:
                return 1;
        }
        foreach ($this->sortOptions as $sort => $order) {
            if (!isset($a[$sort]) || !isset($b[$sort])) {
                if (isset($a[$sort])) {
                    return -1;
                }
                if (isset($b[$sort])) {
                    return 1;
                }
                return 0;
            }
            switch ($sort) {
                case 'filename':
                    $result = strcasecmp($a['filename'], $b['filename']);
                    if ($result) {
                        return $order === SORT_DESC ? -$result : $result;
                    }
                    break;
                case 'mode':
                    $a[$sort] &= 07777;
                    $b[$sort] &= 07777;
                    // fall-through
                default:
                    if ($a[$sort] === $b[$sort]) {
                        break;
                    }
                    return $order === SORT_ASC ? $a[$sort] - $b[$sort] : $b[$sort] - $a[$sort];
            }
        }
    }

    /**
     * Defines how nlist() and rawlist() will be sorted - if at all.
     *
     * If sorting is enabled directories and files will be sorted independently with
     * directories appearing before files in the resultant array that is returned.
     *
     * Any parameter returned by stat is a valid sort parameter for this function.
     * Filename comparisons are case insensitive.
     *
     * Examples:
     *
     * $sftp->setListOrder('filename', SORT_ASC);
     * $sftp->setListOrder('size', SORT_DESC, 'filename', SORT_ASC);
     * $sftp->setListOrder(true);
     *    Separates directories from files but doesn't do any sorting beyond that
     * $sftp->setListOrder();
     *    Don't do any sort of sorting
     *
     * @param string ...$args
     */
    public function setListOrder(...$args)
    {
        $this->sortOptions = [];
        if (empty($args)) {
            return;
        }
        $len = count($args) & 0x7FFFFFFE;
        for ($i = 0; $i < $len; $i += 2) {
            $this->sortOptions[$args[$i]] = $args[$i + 1];
        }
        if (!count($this->sortOptions)) {
            $this->sortOptions = ['bogus' => true];
        }
    }

    /**
     * Save files / directories to cache
     *
     * @param string $path
     * @param mixed $value
     */
    private function update_stat_cache($path, $value)
    {
        if ($this->use_stat_cache === false) {
            return;
        }

        // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/'))
        $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));

        $temp = &$this->stat_cache;
        $max = count($dirs) - 1;
        foreach ($dirs as $i => $dir) {
            // if $temp is an object that means one of two things.
            //  1. a file was deleted and changed to a directory behind phpseclib's back
            //  2. it's a symlink. when lstat is done it's unclear what it's a symlink to
            if (is_object($temp)) {
                $temp = [];
            }
            if (!isset($temp[$dir])) {
                $temp[$dir] = [];
            }
            if ($i === $max) {
                if (is_object($temp[$dir]) && is_object($value)) {
                    if (!isset($value->stat) && isset($temp[$dir]->stat)) {
                        $value->stat = $temp[$dir]->stat;
                    }
                    if (!isset($value->lstat) && isset($temp[$dir]->lstat)) {
                        $value->lstat = $temp[$dir]->lstat;
                    }
                }
                $temp[$dir] = $value;
                break;
            }
            $temp = &$temp[$dir];
        }
    }

    /**
     * Remove files / directories from cache
     *
     * @param string $path
     * @return bool
     */
    private function remove_from_stat_cache($path)
    {
        $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));

        $temp = &$this->stat_cache;
        $max = count($dirs) - 1;
        foreach ($dirs as $i => $dir) {
            if (!is_array($temp)) {
                return false;
            }
            if ($i === $max) {
                unset($temp[$dir]);
                return true;
            }
            if (!isset($temp[$dir])) {
                return false;
            }
            $temp = &$temp[$dir];
        }
    }

    /**
     * Checks cache for path
     *
     * Mainly used by file_exists
     *
     * @param string $path
     * @return mixed
     */
    private function query_stat_cache($path)
    {
        $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));

        $temp = &$this->stat_cache;
        foreach ($dirs as $dir) {
            if (!is_array($temp)) {
                return null;
            }
            if (!isset($temp[$dir])) {
                return null;
            }
            $temp = &$temp[$dir];
        }
        return $temp;
    }

    /**
     * Returns general information about a file.
     *
     * Returns an array on success and false otherwise.
     *
     * @param string $filename
     * @return array|false
     */
    public function stat($filename)
    {
        if (!$this->precheck()) {
            return false;
        }

        $filename = $this->realpath($filename);
        if ($filename === false) {
            return false;
        }

        if ($this->use_stat_cache) {
            $result = $this->query_stat_cache($filename);
            if (is_array($result) && isset($result['.']) && isset($result['.']->stat)) {
                return $result['.']->stat;
            }
            if (is_object($result) && isset($result->stat)) {
                return $result->stat;
            }
        }

        $stat = $this->stat_helper($filename, NET_SFTP_STAT);
        if ($stat === false) {
            $this->remove_from_stat_cache($filename);
            return false;
        }
        if (isset($stat['type'])) {
            if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
                $filename .= '/.';
            }
            $this->update_stat_cache($filename, (object) ['stat' => $stat]);
            return $stat;
        }

        $pwd = $this->pwd;
        $stat['type'] = $this->chdir($filename) ?
            NET_SFTP_TYPE_DIRECTORY :
            NET_SFTP_TYPE_REGULAR;
        $this->pwd = $pwd;

        if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
            $filename .= '/.';
        }
        $this->update_stat_cache($filename, (object) ['stat' => $stat]);

        return $stat;
    }

    /**
     * Returns general information about a file or symbolic link.
     *
     * Returns an array on success and false otherwise.
     *
     * @param string $filename
     * @return array|false
     */
    public function lstat($filename)
    {
        if (!$this->precheck()) {
            return false;
        }

        $filename = $this->realpath($filename);
        if ($filename === false) {
            return false;
        }

        if ($this->use_stat_cache) {
            $result = $this->query_stat_cache($filename);
            if (is_array($result) && isset($result['.']) && isset($result['.']->lstat)) {
                return $result['.']->lstat;
            }
            if (is_object($result) && isset($result->lstat)) {
                return $result->lstat;
            }
        }

        $lstat = $this->stat_helper($filename, NET_SFTP_LSTAT);
        if ($lstat === false) {
            $this->remove_from_stat_cache($filename);
            return false;
        }
        if (isset($lstat['type'])) {
            if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
                $filename .= '/.';
            }
            $this->update_stat_cache($filename, (object) ['lstat' => $lstat]);
            return $lstat;
        }

        $stat = $this->stat_helper($filename, NET_SFTP_STAT);

        if ($lstat != $stat) {
            $lstat = array_merge($lstat, ['type' => NET_SFTP_TYPE_SYMLINK]);
            $this->update_stat_cache($filename, (object) ['lstat' => $lstat]);
            return $stat;
        }

        $pwd = $this->pwd;
        $lstat['type'] = $this->chdir($filename) ?
            NET_SFTP_TYPE_DIRECTORY :
            NET_SFTP_TYPE_REGULAR;
        $this->pwd = $pwd;

        if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
            $filename .= '/.';
        }
        $this->update_stat_cache($filename, (object) ['lstat' => $lstat]);

        return $lstat;
    }

    /**
     * Returns general information about a file or symbolic link
     *
     * Determines information without calling \phpseclib3\Net\SFTP::realpath().
     * The second parameter can be either NET_SFTP_STAT or NET_SFTP_LSTAT.
     *
     * @param string $filename
     * @param int $type
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @return array|false
     */
    private function stat_helper($filename, $type)
    {
        // SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
        $packet = Strings::packSSH2('s', $filename);
        $this->send_sftp_packet($type, $packet);

        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_ATTRS:
                return $this->parseAttributes($response);
            case NET_SFTP_STATUS:
                $this->logError($response);
                return false;
        }

        throw new \UnexpectedValueException('Expected NET_SFTP_ATTRS or NET_SFTP_STATUS. '
                                          . 'Got packet type: ' . $this->packet_type);
    }

    /**
     * Truncates a file to a given length
     *
     * @param string $filename
     * @param int $new_size
     * @return bool
     */
    public function truncate($filename, $new_size)
    {
        $attr = Strings::packSSH2('NQ', NET_SFTP_ATTR_SIZE, $new_size);

        return $this->setstat($filename, $attr, false);
    }

    /**
     * Sets access and modification time of file.
     *
     * If the file does not exist, it will be created.
     *
     * @param string $filename
     * @param int $time
     * @param int $atime
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @return bool
     */
    public function touch($filename, $time = null, $atime = null)
    {
        if (!$this->precheck()) {
            return false;
        }

        $filename = $this->realpath($filename);
        if ($filename === false) {
            return false;
        }

        if (!isset($time)) {
            $time = time();
        }
        if (!isset($atime)) {
            $atime = $time;
        }

        $attr = $this->version < 4 ?
            pack('N3', NET_SFTP_ATTR_ACCESSTIME, $atime, $time) :
            Strings::packSSH2('NQ2', NET_SFTP_ATTR_ACCESSTIME | NET_SFTP_ATTR_MODIFYTIME, $atime, $time);

        $packet = Strings::packSSH2('s', $filename);
        $packet .= $this->version >= 5 ?
            pack('N2', 0, NET_SFTP_OPEN_OPEN_EXISTING) :
            pack('N', NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL);
        $packet .= $attr;

        $this->send_sftp_packet(NET_SFTP_OPEN, $packet);

        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_HANDLE:
                return $this->close_handle(substr($response, 4));
            case NET_SFTP_STATUS:
                $this->logError($response);
                break;
            default:
                throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. '
                                                  . 'Got packet type: ' . $this->packet_type);
        }

        return $this->setstat($filename, $attr, false);
    }

    /**
     * Changes file or directory owner
     *
     * $uid should be an int for SFTPv3 and a string for SFTPv4+. Ideally the string
     * would be of the form "user@dns_domain" but it does not need to be.
     * `$sftp->getSupportedVersions()['version']` will return the specific version
     * that's being used.
     *
     * Returns true on success or false on error.
     *
     * @param string $filename
     * @param int|string $uid
     * @param bool $recursive
     * @return bool
     */
    public function chown($filename, $uid, $recursive = false)
    {
        /*
         quoting <https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.5>,

         "To avoid a representation that is tied to a particular underlying
          implementation at the client or server, the use of UTF-8 strings has
          been chosen.  The string should be of the form "user@dns_domain".
          This will allow for a client and server that do not use the same
          local representation the ability to translate to a common syntax that
          can be interpreted by both.  In the case where there is no
          translation available to the client or server, the attribute value
          must be constructed without the "@"."

         phpseclib _could_ auto append the dns_domain to $uid BUT what if it shouldn't
         have one? phpseclib would have no way of knowing so rather than guess phpseclib
         will just use whatever value the user provided
       */

        $attr = $this->version < 4 ?
            // quoting <http://www.kernel.org/doc/man-pages/online/pages/man2/chown.2.html>,
            // "if the owner or group is specified as -1, then that ID is not changed"
            pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1) :
            // quoting <https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.5>,
            // "If either the owner or group field is zero length, the field should be
            //  considered absent, and no change should be made to that specific field
            //  during a modification operation"
            Strings::packSSH2('Nss', NET_SFTP_ATTR_OWNERGROUP, $uid, '');

        return $this->setstat($filename, $attr, $recursive);
    }

    /**
     * Changes file or directory group
     *
     * $gid should be an int for SFTPv3 and a string for SFTPv4+. Ideally the string
     * would be of the form "user@dns_domain" but it does not need to be.
     * `$sftp->getSupportedVersions()['version']` will return the specific version
     * that's being used.
     *
     * Returns true on success or false on error.
     *
     * @param string $filename
     * @param int|string $gid
     * @param bool $recursive
     * @return bool
     */
    public function chgrp($filename, $gid, $recursive = false)
    {
        $attr = $this->version < 4 ?
            pack('N3', NET_SFTP_ATTR_UIDGID, -1, $gid) :
            Strings::packSSH2('Nss', NET_SFTP_ATTR_OWNERGROUP, '', $gid);

        return $this->setstat($filename, $attr, $recursive);
    }

    /**
     * Set permissions on a file.
     *
     * Returns the new file permissions on success or false on error.
     * If $recursive is true than this just returns true or false.
     *
     * @param int $mode
     * @param string $filename
     * @param bool $recursive
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @return mixed
     * @changed in phpseclib 4.0.0
     */
    public function chmod($mode, $filename, $recursive = false)
    {
        if (is_string($mode) && is_int($filename)) {
            $temp = $mode;
            $mode = $filename;
            $filename = $temp;
        }

        $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
        if (!$this->setstat($filename, $attr, $recursive)) {
            return false;
        }
        if ($recursive) {
            return true;
        }

        $filename = $this->realpath($filename);
        // rather than return what the permissions *should* be, we'll return what they actually are.  this will also
        // tell us if the file actually exists.
        // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
        $packet = pack('Na*', strlen($filename), $filename);
        $this->send_sftp_packet(NET_SFTP_STAT, $packet);

        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_ATTRS:
                $attrs = $this->parseAttributes($response);
                return $attrs['mode'];
            case NET_SFTP_STATUS:
                $this->logError($response);
                return false;
        }

        throw new \UnexpectedValueException('Expected NET_SFTP_ATTRS or NET_SFTP_STATUS. '
                                          . 'Got packet type: ' . $this->packet_type);
    }

    /**
     * Sets information about a file
     *
     * @param string $filename
     * @param string $attr
     * @param bool $recursive
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @return bool
     */
    private function setstat($filename, $attr, $recursive)
    {
        if (!$this->precheck()) {
            return false;
        }

        $filename = $this->realpath($filename);
        if ($filename === false) {
            return false;
        }

        $this->remove_from_stat_cache($filename);

        if ($recursive) {
            $i = 0;
            $result = $this->setstat_recursive($filename, $attr, $i);
            $this->read_put_responses($i);
            return $result;
        }

        $packet = Strings::packSSH2('s', $filename);
        $packet .= $this->version >= 4 ?
            pack('a*Ca*', substr($attr, 0, 4), NET_SFTP_TYPE_UNKNOWN, substr($attr, 4)) :
            $attr;
        $this->send_sftp_packet(NET_SFTP_SETSTAT, $packet);

        /*
         "Because some systems must use separate system calls to set various attributes, it is possible that a failure
          response will be returned, but yet some of the attributes may be have been successfully modified.  If possible,
          servers SHOULD avoid this situation; however, clients MUST be aware that this is possible."

          -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6
        */
        $response = $this->get_sftp_packet();
        if ($this->packet_type != NET_SFTP_STATUS) {
            throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                                              . 'Got packet type: ' . $this->packet_type);
        }

        list($status) = Strings::unpackSSH2('N', $response);
        if ($status != NET_SFTP_STATUS_OK) {
            $this->logError($response, $status);
            return false;
        }

        return true;
    }

    /**
     * Recursively sets information on directories on the SFTP server
     *
     * Minimizes directory lookups and SSH_FXP_STATUS requests for speed.
     *
     * @param string $path
     * @param string $attr
     * @param int $i
     * @return bool
     */
    private function setstat_recursive($path, $attr, &$i)
    {
        if (!$this->read_put_responses($i)) {
            return false;
        }
        $i = 0;
        $entries = $this->readlist($path, true);

        if ($entries === false || is_int($entries)) {
            return $this->setstat($path, $attr, false);
        }

        // normally $entries would have at least . and .. but it might not if the directories
        // permissions didn't allow reading
        if (empty($entries)) {
            return false;
        }

        unset($entries['.'], $entries['..']);
        foreach ($entries as $filename => $props) {
            if (!isset($props['type'])) {
                return false;
            }

            $temp = $path . '/' . $filename;
            if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
                if (!$this->setstat_recursive($temp, $attr, $i)) {
                    return false;
                }
            } else {
                $packet = Strings::packSSH2('s', $temp);
                $packet .= $this->version >= 4 ?
                    pack('Ca*', NET_SFTP_TYPE_UNKNOWN, $attr) :
                    $attr;
                $this->send_sftp_packet(NET_SFTP_SETSTAT, $packet);

                $i++;

                if ($i >= NET_SFTP_QUEUE_SIZE) {
                    if (!$this->read_put_responses($i)) {
                        return false;
                    }
                    $i = 0;
                }
            }
        }

        $packet = Strings::packSSH2('s', $path);
        $packet .= $this->version >= 4 ?
            pack('Ca*', NET_SFTP_TYPE_UNKNOWN, $attr) :
            $attr;
        $this->send_sftp_packet(NET_SFTP_SETSTAT, $packet);

        $i++;

        if ($i >= NET_SFTP_QUEUE_SIZE) {
            if (!$this->read_put_responses($i)) {
                return false;
            }
            $i = 0;
        }

        return true;
    }

    /**
     * Return the target of a symbolic link
     *
     * @param string $link
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @return mixed
     */
    public function readlink($link)
    {
        if (!$this->precheck()) {
            return false;
        }

        $link = $this->realpath($link);

        $this->send_sftp_packet(NET_SFTP_READLINK, Strings::packSSH2('s', $link));

        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_NAME:
                break;
            case NET_SFTP_STATUS:
                $this->logError($response);
                return false;
            default:
                throw new \UnexpectedValueException('Expected NET_SFTP_NAME or NET_SFTP_STATUS. '
                                                  . 'Got packet type: ' . $this->packet_type);
        }

        list($count) = Strings::unpackSSH2('N', $response);
        // the file isn't a symlink
        if (!$count) {
            return false;
        }

        list($filename) = Strings::unpackSSH2('s', $response);

        return $filename;
    }

    /**
     * Create a symlink
     *
     * symlink() creates a symbolic link to the existing target with the specified name link.
     *
     * @param string $target
     * @param string $link
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @return bool
     */
    public function symlink($target, $link)
    {
        if (!$this->precheck()) {
            return false;
        }

        //$target = $this->realpath($target);
        $link = $this->realpath($link);

        /* quoting https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-09#section-12.1 :

           Changed the SYMLINK packet to be LINK and give it the ability to
           create hard links.  Also change it's packet number because many
           implementation implemented SYMLINK with the arguments reversed.
           Hopefully the new argument names make it clear which way is which.
        */
        if ($this->version == 6) {
            $type = NET_SFTP_LINK;
            $packet = Strings::packSSH2('ssC', $link, $target, 1);
        } else {
            $type = NET_SFTP_SYMLINK;
            /* quoting http://bxr.su/OpenBSD/usr.bin/ssh/PROTOCOL#347 :

               3.1. sftp: Reversal of arguments to SSH_FXP_SYMLINK

               When OpenSSH's sftp-server was implemented, the order of the arguments
               to the SSH_FXP_SYMLINK method was inadvertently reversed. Unfortunately,
               the reversal was not noticed until the server was widely deployed. Since
               fixing this to follow the specification would cause incompatibility, the
               current order was retained. For correct operation, clients should send
               SSH_FXP_SYMLINK as follows:

                   uint32      id
                   string      targetpath
                   string      linkpath */
            $packet = substr($this->server_identifier, 0, 15) == 'SSH-2.0-OpenSSH' ?
                Strings::packSSH2('ss', $target, $link) :
                Strings::packSSH2('ss', $link, $target);
        }
        $this->send_sftp_packet($type, $packet);

        $response = $this->get_sftp_packet();
        if ($this->packet_type != NET_SFTP_STATUS) {
            throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                                              . 'Got packet type: ' . $this->packet_type);
        }

        list($status) = Strings::unpackSSH2('N', $response);
        if ($status != NET_SFTP_STATUS_OK) {
            $this->logError($response, $status);
            return false;
        }

        return true;
    }

    /**
     * Creates a directory.
     *
     * @param string $dir
     * @param int $mode
     * @param bool $recursive
     * @return bool
     */
    public function mkdir($dir, $mode = -1, $recursive = false)
    {
        if (!$this->precheck()) {
            return false;
        }

        $dir = $this->realpath($dir);

        if ($recursive) {
            $dirs = explode('/', preg_replace('#/(?=/)|/$#', '', $dir));
            if (empty($dirs[0])) {
                array_shift($dirs);
                $dirs[0] = '/' . $dirs[0];
            }
            for ($i = 0; $i < count($dirs); $i++) {
                $temp = array_slice($dirs, 0, $i + 1);
                $temp = implode('/', $temp);
                $result = $this->mkdir_helper($temp, $mode);
            }
            return $result;
        }

        return $this->mkdir_helper($dir, $mode);
    }

    /**
     * Helper function for directory creation
     *
     * @param string $dir
     * @param int $mode
     * @return bool
     */
    private function mkdir_helper($dir, $mode)
    {
        // send SSH_FXP_MKDIR without any attributes (that's what the \0\0\0\0 is doing)
        $this->send_sftp_packet(NET_SFTP_MKDIR, Strings::packSSH2('s', $dir) . "\0\0\0\0");

        $response = $this->get_sftp_packet();
        if ($this->packet_type != NET_SFTP_STATUS) {
            throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                                              . 'Got packet type: ' . $this->packet_type);
        }

        list($status) = Strings::unpackSSH2('N', $response);
        if ($status != NET_SFTP_STATUS_OK) {
            $this->logError($response, $status);
            return false;
        }

        if ($mode !== -1) {
            $this->chmod($mode, $dir);
        }

        return true;
    }

    /**
     * Removes a directory.
     *
     * @param string $dir
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @return bool
     */
    public function rmdir($dir)
    {
        if (!$this->precheck()) {
            return false;
        }

        $dir = $this->realpath($dir);
        if ($dir === false) {
            return false;
        }

        $this->send_sftp_packet(NET_SFTP_RMDIR, Strings::packSSH2('s', $dir));

        $response = $this->get_sftp_packet();
        if ($this->packet_type != NET_SFTP_STATUS) {
            throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                                              . 'Got packet type: ' . $this->packet_type);
        }

        list($status) = Strings::unpackSSH2('N', $response);
        if ($status != NET_SFTP_STATUS_OK) {
            // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
            $this->logError($response, $status);
            return false;
        }

        $this->remove_from_stat_cache($dir);
        // the following will do a soft delete, which would be useful if you deleted a file
        // and then tried to do a stat on the deleted file. the above, in contrast, does
        // a hard delete
        //$this->update_stat_cache($dir, false);

        return true;
    }

    /**
     * Uploads a file to the SFTP server.
     *
     * By default, \phpseclib3\Net\SFTP::put() does not read from the local filesystem.  $data is dumped directly into $remote_file.
     * So, for example, if you set $data to 'filename.ext' and then do \phpseclib3\Net\SFTP::get(), you will get a file, twelve bytes
     * long, containing 'filename.ext' as its contents.
     *
     * Setting $mode to self::SOURCE_LOCAL_FILE will change the above behavior.  With self::SOURCE_LOCAL_FILE, $remote_file will
     * contain as many bytes as filename.ext does on your local filesystem.  If your filename.ext is 1MB then that is how
     * large $remote_file will be, as well.
     *
     * Setting $mode to self::SOURCE_CALLBACK will use $data as callback function, which gets only one parameter -- number
     * of bytes to return, and returns a string if there is some data or null if there is no more data
     *
     * If $data is a resource then it'll be used as a resource instead.
     *
     * Currently, only binary mode is supported.  As such, if the line endings need to be adjusted, you will need to take
     * care of that, yourself.
     *
     * $mode can take an additional two parameters - self::RESUME and self::RESUME_START. These are bitwise AND'd with
     * $mode. So if you want to resume upload of a 300mb file on the local file system you'd set $mode to the following:
     *
     * self::SOURCE_LOCAL_FILE | self::RESUME
     *
     * If you wanted to simply append the full contents of a local file to the full contents of a remote file you'd replace
     * self::RESUME with self::RESUME_START.
     *
     * If $mode & (self::RESUME | self::RESUME_START) then self::RESUME_START will be assumed.
     *
     * $start and $local_start give you more fine grained control over this process and take precident over self::RESUME
     * when they're non-negative. ie. $start could let you write at the end of a file (like self::RESUME) or in the middle
     * of one. $local_start could let you start your reading from the end of a file (like self::RESUME_START) or in the
     * middle of one.
     *
     * Setting $local_start to > 0 or $mode | self::RESUME_START doesn't do anything unless $mode | self::SOURCE_LOCAL_FILE.
     *
     * {@internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - \phpseclib3\Net\SFTP::setMode().}
     *
     * @param string $remote_file
     * @param string|resource $data
     * @param int $mode
     * @param int $start
     * @param int $local_start
     * @param callable|null $progressCallback
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @throws \BadFunctionCallException if you're uploading via a callback and the callback function is invalid
     * @throws FileNotFoundException if you're uploading via a file and the file doesn't exist
     * @return bool
     */
    public function put($remote_file, $data, $mode = self::SOURCE_STRING, $start = -1, $local_start = -1, $progressCallback = null)
    {
        if (!$this->precheck()) {
            return false;
        }

        $remote_file = $this->realpath($remote_file);
        if ($remote_file === false) {
            return false;
        }

        $this->remove_from_stat_cache($remote_file);

        if ($this->version >= 5) {
            $flags = NET_SFTP_OPEN_OPEN_OR_CREATE;
        } else {
            $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE;
            // according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file."
            // in practice, it doesn't seem to do that.
            //$flags|= ($mode & self::RESUME) ? NET_SFTP_OPEN_APPEND : NET_SFTP_OPEN_TRUNCATE;
        }

        if ($start >= 0) {
            $offset = $start;
        } elseif ($mode & (self::RESUME | self::RESUME_START)) {
            // if NET_SFTP_OPEN_APPEND worked as it should _size() wouldn't need to be called
            $stat = $this->stat($remote_file);
            $offset = $stat !== false && $stat['size'] ? $stat['size'] : 0;
        } else {
            $offset = 0;
            if ($this->version >= 5) {
                $flags = NET_SFTP_OPEN_CREATE_TRUNCATE;
            } else {
                $flags |= NET_SFTP_OPEN_TRUNCATE;
            }
        }

        $this->remove_from_stat_cache($remote_file);

        $packet = Strings::packSSH2('s', $remote_file);
        $packet .= $this->version >= 5 ?
            pack('N3', 0, $flags, 0) :
            pack('N2', $flags, 0);
        $this->send_sftp_packet(NET_SFTP_OPEN, $packet);

        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_HANDLE:
                $handle = substr($response, 4);
                break;
            case NET_SFTP_STATUS:
                $this->logError($response);
                return false;
            default:
                throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. '
                                                  . 'Got packet type: ' . $this->packet_type);
        }

        // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
        $dataCallback = false;
        switch (true) {
            case $mode & self::SOURCE_CALLBACK:
                if (!is_callable($data)) {
                    throw new \BadFunctionCallException("\$data should be is_callable() if you specify SOURCE_CALLBACK flag");
                }
                $dataCallback = $data;
                // do nothing
                break;
            case is_resource($data):
                $mode = $mode & ~self::SOURCE_LOCAL_FILE;
                $info = stream_get_meta_data($data);
                if (isset($info['wrapper_type']) && $info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') {
                    $fp = fopen('php://memory', 'w+');
                    stream_copy_to_stream($data, $fp);
                    rewind($fp);
                } else {
                    $fp = $data;
                }
                break;
            case $mode & self::SOURCE_LOCAL_FILE:
                if (!is_file($data)) {
                    throw new FileNotFoundException("$data is not a valid file");
                }
                $fp = @fopen($data, 'rb');
                if (!$fp) {
                    return false;
                }
        }

        if (isset($fp)) {
            $stat = fstat($fp);
            $size = !empty($stat) ? $stat['size'] : 0;

            if ($local_start >= 0) {
                fseek($fp, $local_start);
                $size -= $local_start;
            } elseif ($mode & self::RESUME) {
                fseek($fp, $offset);
                $size -= $offset;
            }
        } elseif ($dataCallback) {
            $size = 0;
        } else {
            $size = strlen($data);
        }

        $sent = 0;
        $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;

        $sftp_packet_size = $this->max_sftp_packet;
        // make the SFTP packet be exactly the SFTP packet size by including the bytes in the NET_SFTP_WRITE packets "header"
        $sftp_packet_size -= strlen($handle) + 25;
        $i = $j = 0;
        while ($dataCallback || ($size === 0 || $sent < $size)) {
            if ($dataCallback) {
                $temp = $dataCallback($sftp_packet_size);
                if (is_null($temp)) {
                    break;
                }
            } else {
                $temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size);
                if ($temp === false || $temp === '') {
                    break;
                }
            }

            $subtemp = $offset + $sent;
            $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp);
            try {
                $this->send_sftp_packet(NET_SFTP_WRITE, $packet, $j);
            } catch (\Exception $e) {
                if ($mode & self::SOURCE_LOCAL_FILE) {
                    fclose($fp);
                }
                throw $e;
            }
            $sent += strlen($temp);
            if (is_callable($progressCallback)) {
                $progressCallback($sent);
            }

            $i++;
            $j++;
            if ($i == NET_SFTP_UPLOAD_QUEUE_SIZE) {
                if (!$this->read_put_responses($i)) {
                    $i = 0;
                    break;
                }
                $i = 0;
            }
        }

        $result = $this->close_handle($handle);

        if (!$this->read_put_responses($i)) {
            if ($mode & self::SOURCE_LOCAL_FILE) {
                fclose($fp);
            }
            $this->close_handle($handle);
            return false;
        }

        if ($mode & SFTP::SOURCE_LOCAL_FILE) {
            if (isset($fp) && is_resource($fp)) {
                fclose($fp);
            }

            if ($this->preserveTime) {
                $stat = stat($data);
                $attr = $this->version < 4 ?
                    pack('N3', NET_SFTP_ATTR_ACCESSTIME, $stat['atime'], $stat['mtime']) :
                    Strings::packSSH2('NQ2', NET_SFTP_ATTR_ACCESSTIME | NET_SFTP_ATTR_MODIFYTIME, $stat['atime'], $stat['mtime']);
                if (!$this->setstat($remote_file, $attr, false)) {
                    throw new \RuntimeException('Error setting file time');
                }
            }
        }

        return $result;
    }

    /**
     * Reads multiple successive SSH_FXP_WRITE responses
     *
     * Sending an SSH_FXP_WRITE packet and immediately reading its response isn't as efficient as blindly sending out $i
     * SSH_FXP_WRITEs, in succession, and then reading $i responses.
     *
     * @param int $i
     * @return bool
     * @throws \UnexpectedValueException on receipt of unexpected packets
     */
    private function read_put_responses($i)
    {
        while ($i--) {
            $response = $this->get_sftp_packet();
            if ($this->packet_type != NET_SFTP_STATUS) {
                throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                                                  . 'Got packet type: ' . $this->packet_type);
            }

            list($status) = Strings::unpackSSH2('N', $response);
            if ($status != NET_SFTP_STATUS_OK) {
                $this->logError($response, $status);
                break;
            }
        }

        return $i < 0;
    }

    /**
     * Close handle
     *
     * @param string $handle
     * @return bool
     * @throws \UnexpectedValueException on receipt of unexpected packets
     */
    private function close_handle($handle)
    {
        $this->send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle));

        // "The client MUST release all resources associated with the handle regardless of the status."
        //  -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
        $response = $this->get_sftp_packet();
        if ($this->packet_type != NET_SFTP_STATUS) {
            throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                                              . 'Got packet type: ' . $this->packet_type);
        }

        list($status) = Strings::unpackSSH2('N', $response);
        if ($status != NET_SFTP_STATUS_OK) {
            $this->logError($response, $status);
            return false;
        }

        return true;
    }

    /**
     * Downloads a file from the SFTP server.
     *
     * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
     * the operation was unsuccessful.  If $local_file is defined, returns true or false depending on the success of the
     * operation.
     *
     * $offset and $length can be used to download files in chunks.
     *
     * @param string $remote_file
     * @param string|bool|resource|callable $local_file
     * @param int $offset
     * @param int $length
     * @param callable|null $progressCallback
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @return string|bool
     */
    public function get($remote_file, $local_file = false, $offset = 0, $length = -1, $progressCallback = null)
    {
        if (!$this->precheck()) {
            return false;
        }

        $remote_file = $this->realpath($remote_file);
        if ($remote_file === false) {
            return false;
        }

        $packet = Strings::packSSH2('s', $remote_file);
        $packet .= $this->version >= 5 ?
            pack('N3', 0, NET_SFTP_OPEN_OPEN_EXISTING, 0) :
            pack('N2', NET_SFTP_OPEN_READ, 0);
        $this->send_sftp_packet(NET_SFTP_OPEN, $packet);

        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_HANDLE:
                $handle = substr($response, 4);
                break;
            case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
                $this->logError($response);
                return false;
            default:
                throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. '
                                                  . 'Got packet type: ' . $this->packet_type);
        }

        if (is_resource($local_file)) {
            $fp = $local_file;
            $stat = fstat($fp);
            $res_offset = $stat['size'];
        } else {
            $res_offset = 0;
            if ($local_file !== false && !is_callable($local_file)) {
                $fp = fopen($local_file, 'wb');
                if (!$fp) {
                    return false;
                }
            } else {
                $content = '';
            }
        }

        $fclose_check = $local_file !== false && !is_callable($local_file) && !is_resource($local_file);

        $start = $offset;
        $read = 0;
        while (true) {
            $i = 0;

            while ($i < NET_SFTP_QUEUE_SIZE && ($length < 0 || $read < $length)) {
                $tempoffset = $start + $read;

                $packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet;

                $packet = Strings::packSSH2('sN3', $handle, $tempoffset / 4294967296, $tempoffset, $packet_size);
                try {
                    $this->send_sftp_packet(NET_SFTP_READ, $packet, $i);
                } catch (\Exception $e) {
                    if ($fclose_check) {
                        fclose($fp);
                    }
                    throw $e;
                }
                $packet = null;
                $read += $packet_size;
                $i++;
            }

            if (!$i) {
                break;
            }

            $packets_sent = $i - 1;

            $clear_responses = false;
            while ($i > 0) {
                $i--;

                if ($clear_responses) {
                    $this->get_sftp_packet($packets_sent - $i);
                    continue;
                } else {
                    $response = $this->get_sftp_packet($packets_sent - $i);
                }

                switch ($this->packet_type) {
                    case NET_SFTP_DATA:
                        $temp = substr($response, 4);
                        $offset += strlen($temp);
                        if ($local_file === false) {
                            $content .= $temp;
                        } elseif (is_callable($local_file)) {
                            $local_file($temp);
                        } else {
                            fputs($fp, $temp);
                        }
                        if (is_callable($progressCallback)) {
                            call_user_func($progressCallback, $offset);
                        }
                        $temp = null;
                        break;
                    case NET_SFTP_STATUS:
                        // could, in theory, return false if !strlen($content) but we'll hold off for the time being
                        $this->logError($response);
                        $clear_responses = true; // don't break out of the loop yet, so we can read the remaining responses
                        break;
                    default:
                        if ($fclose_check) {
                            fclose($fp);
                        }
                        if ($this->channel_close) {
                            $this->partial_init = false;
                            $this->init_sftp_connection();
                            return false;
                        } else {
                            throw new \UnexpectedValueException('Expected NET_SFTP_DATA or NET_SFTP_STATUS. '
                                                              . 'Got packet type: ' . $this->packet_type);
                        }
                }
                $response = null;
            }

            if ($clear_responses) {
                break;
            }
        }

        if ($fclose_check) {
            fclose($fp);

            if ($this->preserveTime) {
                $stat = $this->stat($remote_file);
                touch($local_file, $stat['mtime'], $stat['atime']);
            }
        }

        if (!$this->close_handle($handle)) {
            return false;
        }

        // if $content isn't set that means a file was written to
        return isset($content) ? $content : true;
    }

    /**
     * Deletes a file on the SFTP server.
     *
     * @param string $path
     * @param bool $recursive
     * @return bool
     * @throws \UnexpectedValueException on receipt of unexpected packets
     */
    public function delete($path, $recursive = true)
    {
        if (!$this->precheck()) {
            return false;
        }

        if (is_object($path)) {
            // It's an object. Cast it as string before we check anything else.
            $path = (string) $path;
        }

        if (!is_string($path) || $path == '') {
            return false;
        }

        $path = $this->realpath($path);
        if ($path === false) {
            return false;
        }

        // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
        $this->send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path));

        $response = $this->get_sftp_packet();
        if ($this->packet_type != NET_SFTP_STATUS) {
            throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                                              . 'Got packet type: ' . $this->packet_type);
        }

        // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
        list($status) = Strings::unpackSSH2('N', $response);
        if ($status != NET_SFTP_STATUS_OK) {
            $this->logError($response, $status);
            if (!$recursive) {
                return false;
            }

            $i = 0;
            $result = $this->delete_recursive($path, $i);
            $this->read_put_responses($i);
            return $result;
        }

        $this->remove_from_stat_cache($path);

        return true;
    }

    /**
     * Recursively deletes directories on the SFTP server
     *
     * Minimizes directory lookups and SSH_FXP_STATUS requests for speed.
     *
     * @param string $path
     * @param int $i
     * @return bool
     */
    private function delete_recursive($path, &$i)
    {
        if (!$this->read_put_responses($i)) {
            return false;
        }
        $i = 0;
        $entries = $this->readlist($path, true);

        // The folder does not exist at all, so we cannot delete it.
        if ($entries === NET_SFTP_STATUS_NO_SUCH_FILE) {
            return false;
        }

        // Normally $entries would have at least . and .. but it might not if the directories
        // permissions didn't allow reading. If this happens then default to an empty list of files.
        if ($entries === false || is_int($entries)) {
            $entries = [];
        }

        unset($entries['.'], $entries['..']);
        foreach ($entries as $filename => $props) {
            if (!isset($props['type'])) {
                return false;
            }

            $temp = $path . '/' . $filename;
            if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
                if (!$this->delete_recursive($temp, $i)) {
                    return false;
                }
            } else {
                $this->send_sftp_packet(NET_SFTP_REMOVE, Strings::packSSH2('s', $temp));
                $this->remove_from_stat_cache($temp);

                $i++;

                if ($i >= NET_SFTP_QUEUE_SIZE) {
                    if (!$this->read_put_responses($i)) {
                        return false;
                    }
                    $i = 0;
                }
            }
        }

        $this->send_sftp_packet(NET_SFTP_RMDIR, Strings::packSSH2('s', $path));
        $this->remove_from_stat_cache($path);

        $i++;

        if ($i >= NET_SFTP_QUEUE_SIZE) {
            if (!$this->read_put_responses($i)) {
                return false;
            }
            $i = 0;
        }

        return true;
    }

    /**
     * Checks whether a file or directory exists
     *
     * @param string $path
     * @return bool
     */
    public function file_exists($path)
    {
        if ($this->use_stat_cache) {
            if (!$this->precheck()) {
                return false;
            }

            $path = $this->realpath($path);

            $result = $this->query_stat_cache($path);

            if (isset($result)) {
                // return true if $result is an array or if it's an stdClass object
                return $result !== false;
            }
        }

        return $this->stat($path) !== false;
    }

    /**
     * Tells whether the filename is a directory
     *
     * @param string $path
     * @return bool
     */
    public function is_dir($path)
    {
        $result = $this->get_stat_cache_prop($path, 'type');
        if ($result === false) {
            return false;
        }
        return $result === NET_SFTP_TYPE_DIRECTORY;
    }

    /**
     * Tells whether the filename is a regular file
     *
     * @param string $path
     * @return bool
     */
    public function is_file($path)
    {
        $result = $this->get_stat_cache_prop($path, 'type');
        if ($result === false) {
            return false;
        }
        return $result === NET_SFTP_TYPE_REGULAR;
    }

    /**
     * Tells whether the filename is a symbolic link
     *
     * @param string $path
     * @return bool
     */
    public function is_link($path)
    {
        $result = $this->get_lstat_cache_prop($path, 'type');
        if ($result === false) {
            return false;
        }
        return $result === NET_SFTP_TYPE_SYMLINK;
    }

    /**
     * Tells whether a file exists and is readable
     *
     * @param string $path
     * @return bool
     */
    public function is_readable($path)
    {
        if (!$this->precheck()) {
            return false;
        }

        $packet = Strings::packSSH2('sNN', $this->realpath($path), NET_SFTP_OPEN_READ, 0);
        $this->send_sftp_packet(NET_SFTP_OPEN, $packet);

        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_HANDLE:
                return true;
            case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
                return false;
            default:
                throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. '
                                                  . 'Got packet type: ' . $this->packet_type);
        }
    }

    /**
     * Tells whether the filename is writable
     *
     * @param string $path
     * @return bool
     */
    public function is_writable($path)
    {
        if (!$this->precheck()) {
            return false;
        }

        $packet = Strings::packSSH2('sNN', $this->realpath($path), NET_SFTP_OPEN_WRITE, 0);
        $this->send_sftp_packet(NET_SFTP_OPEN, $packet);

        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_HANDLE:
                return true;
            case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
                return false;
            default:
                throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS. '
                                                  . 'Got packet type: ' . $this->packet_type);
        }
    }

    /**
     * Tells whether the filename is writeable
     *
     * Alias of is_writable
     *
     * @param string $path
     * @return bool
     */
    public function is_writeable($path)
    {
        return $this->is_writable($path);
    }

    /**
     * Gets last access time of file
     *
     * @param string $path
     * @return mixed
     */
    public function fileatime($path)
    {
        return $this->get_stat_cache_prop($path, 'atime');
    }

    /**
     * Gets file modification time
     *
     * @param string $path
     * @return mixed
     */
    public function filemtime($path)
    {
        return $this->get_stat_cache_prop($path, 'mtime');
    }

    /**
     * Gets file permissions
     *
     * @param string $path
     * @return mixed
     */
    public function fileperms($path)
    {
        return $this->get_stat_cache_prop($path, 'mode');
    }

    /**
     * Gets file owner
     *
     * @param string $path
     * @return mixed
     */
    public function fileowner($path)
    {
        return $this->get_stat_cache_prop($path, 'uid');
    }

    /**
     * Gets file group
     *
     * @param string $path
     * @return mixed
     */
    public function filegroup($path)
    {
        return $this->get_stat_cache_prop($path, 'gid');
    }

    /**
     * Recursively go through rawlist() output to get the total filesize
     *
     * @return int
     */
    private static function recursiveFilesize(array $files)
    {
        $size = 0;
        foreach ($files as $name => $file) {
            if ($name == '.' || $name == '..') {
                continue;
            }
            $size += is_array($file) ?
                self::recursiveFilesize($file) :
                $file->size;
        }
        return $size;
    }

    /**
     * Gets file size
     *
     * @param string $path
     * @param bool $recursive
     * @return mixed
     */
    public function filesize($path, $recursive = false)
    {
        return !$recursive || $this->filetype($path) != 'dir' ?
            $this->get_stat_cache_prop($path, 'size') :
            self::recursiveFilesize($this->rawlist($path, true));
    }

    /**
     * Gets file type
     *
     * @param string $path
     * @return string|false
     */
    public function filetype($path)
    {
        $type = $this->get_stat_cache_prop($path, 'type');
        if ($type === false) {
            return false;
        }

        switch ($type) {
            case NET_SFTP_TYPE_BLOCK_DEVICE:
                return 'block';
            case NET_SFTP_TYPE_CHAR_DEVICE:
                return 'char';
            case NET_SFTP_TYPE_DIRECTORY:
                return 'dir';
            case NET_SFTP_TYPE_FIFO:
                return 'fifo';
            case NET_SFTP_TYPE_REGULAR:
                return 'file';
            case NET_SFTP_TYPE_SYMLINK:
                return 'link';
            default:
                return false;
        }
    }

    /**
     * Return a stat properity
     *
     * Uses cache if appropriate.
     *
     * @param string $path
     * @param string $prop
     * @return mixed
     */
    private function get_stat_cache_prop($path, $prop)
    {
        return $this->get_xstat_cache_prop($path, $prop, 'stat');
    }

    /**
     * Return an lstat properity
     *
     * Uses cache if appropriate.
     *
     * @param string $path
     * @param string $prop
     * @return mixed
     */
    private function get_lstat_cache_prop($path, $prop)
    {
        return $this->get_xstat_cache_prop($path, $prop, 'lstat');
    }

    /**
     * Return a stat or lstat properity
     *
     * Uses cache if appropriate.
     *
     * @param string $path
     * @param string $prop
     * @param string $type
     * @return mixed
     */
    private function get_xstat_cache_prop($path, $prop, $type)
    {
        if (!$this->precheck()) {
            return false;
        }

        if ($this->use_stat_cache) {
            $path = $this->realpath($path);

            $result = $this->query_stat_cache($path);

            if (is_object($result) && isset($result->$type)) {
                return $result->{$type}[$prop];
            }
        }

        $result = $this->$type($path);

        if ($result === false || !isset($result[$prop])) {
            return false;
        }

        return $result[$prop];
    }

    /**
     * Renames a file or a directory on the SFTP server.
     *
     * If the file already exists this will return false
     *
     * @param string $oldname
     * @param string $newname
     * @return bool
     * @throws \UnexpectedValueException on receipt of unexpected packets
     */
    public function rename($oldname, $newname)
    {
        if (!$this->precheck()) {
            return false;
        }

        $oldname = $this->realpath($oldname);
        $newname = $this->realpath($newname);
        if ($oldname === false || $newname === false) {
            return false;
        }

        // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
        $packet = Strings::packSSH2('ss', $oldname, $newname);
        if ($this->version >= 5) {
            /* quoting https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-05#section-6.5 ,

               'flags' is 0 or a combination of:

                   SSH_FXP_RENAME_OVERWRITE  0x00000001
                   SSH_FXP_RENAME_ATOMIC     0x00000002
                   SSH_FXP_RENAME_NATIVE     0x00000004

               (none of these are currently supported) */
            $packet .= "\0\0\0\0";
        }
        $this->send_sftp_packet(NET_SFTP_RENAME, $packet);

        $response = $this->get_sftp_packet();
        if ($this->packet_type != NET_SFTP_STATUS) {
            throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                                              . 'Got packet type: ' . $this->packet_type);
        }

        // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
        list($status) = Strings::unpackSSH2('N', $response);
        if ($status != NET_SFTP_STATUS_OK) {
            $this->logError($response, $status);
            return false;
        }

        // don't move the stat cache entry over since this operation could very well change the
        // atime and mtime attributes
        //$this->update_stat_cache($newname, $this->query_stat_cache($oldname));
        $this->remove_from_stat_cache($oldname);
        $this->remove_from_stat_cache($newname);

        return true;
    }

    /**
     * Parse Time
     *
     * See '7.7.  Times' of draft-ietf-secsh-filexfer-13 for more info.
     *
     * @param string $key
     * @param int $flags
     * @param string $response
     * @return array
     */
    private function parseTime($key, $flags, &$response)
    {
        $attr = [];
        list($attr[$key]) = Strings::unpackSSH2('Q', $response);
        if ($flags & NET_SFTP_ATTR_SUBSECOND_TIMES) {
            list($attr[$key . '-nseconds']) = Strings::unpackSSH2('N', $response);
        }
        return $attr;
    }

    /**
     * Parse Attributes
     *
     * See '7.  File Attributes' of draft-ietf-secsh-filexfer-13 for more info.
     *
     * @param string $response
     * @return array
     */
    protected function parseAttributes(&$response)
    {
        $attr = [];

        if ($this->version >= 4) {
            list($flags, $attr['type']) = Strings::unpackSSH2('NC', $response);
        } else {
            list($flags) = Strings::unpackSSH2('N', $response);
        }

        foreach (self::$attributes as $key => $value) {
            switch ($flags & $key) {
                case NET_SFTP_ATTR_UIDGID:
                    if ($this->version > 3) {
                        continue 2;
                    }
                    break;
                case NET_SFTP_ATTR_CREATETIME:
                case NET_SFTP_ATTR_MODIFYTIME:
                case NET_SFTP_ATTR_ACL:
                case NET_SFTP_ATTR_OWNERGROUP:
                case NET_SFTP_ATTR_SUBSECOND_TIMES:
                    if ($this->version < 4) {
                        continue 2;
                    }
                    break;
                case NET_SFTP_ATTR_BITS:
                    if ($this->version < 5) {
                        continue 2;
                    }
                    break;
                case NET_SFTP_ATTR_ALLOCATION_SIZE:
                case NET_SFTP_ATTR_TEXT_HINT:
                case NET_SFTP_ATTR_MIME_TYPE:
                case NET_SFTP_ATTR_LINK_COUNT:
                case NET_SFTP_ATTR_UNTRANSLATED_NAME:
                case NET_SFTP_ATTR_CTIME:
                    if ($this->version < 6) {
                        continue 2;
                    }
            }
            switch ($flags & $key) {
                case NET_SFTP_ATTR_SIZE:             // 0x00000001
                    // The size attribute is defined as an unsigned 64-bit integer.
                    // The following will use floats on 32-bit platforms, if necessary.
                    // As can be seen in the BigInteger class, floats are generally
                    // IEEE 754 binary64 "double precision" on such platforms and
                    // as such can represent integers of at least 2^50 without loss
                    // of precision. Interpreted in filesize, 2^50 bytes = 1024 TiB.
                    list($attr['size']) = Strings::unpackSSH2('Q', $response);
                    break;
                case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only)
                    list($attr['uid'], $attr['gid']) = Strings::unpackSSH2('NN', $response);
                    break;
                case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
                    list($attr['mode']) = Strings::unpackSSH2('N', $response);
                    $fileType = $this->parseMode($attr['mode']);
                    if ($this->version < 4 && $fileType !== false) {
                        $attr += ['type' => $fileType];
                    }
                    break;
                case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
                    if ($this->version >= 4) {
                        $attr += $this->parseTime('atime', $flags, $response);
                        break;
                    }
                    list($attr['atime'], $attr['mtime']) = Strings::unpackSSH2('NN', $response);
                    break;
                case NET_SFTP_ATTR_CREATETIME:       // 0x00000010 (SFTPv4+)
                    $attr += $this->parseTime('createtime', $flags, $response);
                    break;
                case NET_SFTP_ATTR_MODIFYTIME:       // 0x00000020
                    $attr += $this->parseTime('mtime', $flags, $response);
                    break;
                case NET_SFTP_ATTR_ACL:              // 0x00000040
                    // access control list
                    // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-04#section-5.7
                    // currently unsupported
                    list($count) = Strings::unpackSSH2('N', $response);
                    for ($i = 0; $i < $count; $i++) {
                        list($type, $flag, $mask, $who) = Strings::unpackSSH2('N3s', $result);
                    }
                    break;
                case NET_SFTP_ATTR_OWNERGROUP:       // 0x00000080
                    list($attr['owner'], $attr['$group']) = Strings::unpackSSH2('ss', $response);
                    break;
                case NET_SFTP_ATTR_SUBSECOND_TIMES:  // 0x00000100
                    break;
                case NET_SFTP_ATTR_BITS:             // 0x00000200 (SFTPv5+)
                    // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-05#section-5.8
                    // currently unsupported
                    // tells if you file is:
                    // readonly, system, hidden, case inensitive, archive, encrypted, compressed, sparse
                    // append only, immutable, sync
                    list($attrib_bits, $attrib_bits_valid) = Strings::unpackSSH2('N2', $response);
                    // if we were actually gonna implement the above it ought to be
                    // $attr['attrib-bits'] and $attr['attrib-bits-valid']
                    // eg. - instead of _
                    break;
                case NET_SFTP_ATTR_ALLOCATION_SIZE:  // 0x00000400 (SFTPv6+)
                    // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.4
                    // represents the number of bytes that the file consumes on the disk. will
                    // usually be larger than the 'size' field
                    list($attr['allocation-size']) = Strings::unpackSSH2('Q', $response);
                    break;
                case NET_SFTP_ATTR_TEXT_HINT:        // 0x00000800
                    // https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.10
                    // currently unsupported
                    // tells if file is "known text", "guessed text", "known binary", "guessed binary"
                    list($text_hint) = Strings::unpackSSH2('C', $response);
                    // the above should be $attr['text-hint']
                    break;
                case NET_SFTP_ATTR_MIME_TYPE:        // 0x00001000
                    // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.11
                    list($attr['mime-type']) = Strings::unpackSSH2('s', $response);
                    break;
                case NET_SFTP_ATTR_LINK_COUNT:       // 0x00002000
                    // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.12
                    list($attr['link-count']) = Strings::unpackSSH2('N', $response);
                    break;
                case NET_SFTP_ATTR_UNTRANSLATED_NAME:// 0x00004000
                    // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.13
                    list($attr['untranslated-name']) = Strings::unpackSSH2('s', $response);
                    break;
                case NET_SFTP_ATTR_CTIME:            // 0x00008000
                    // 'ctime' contains the last time the file attributes were changed.  The
                    // exact meaning of this field depends on the server.
                    $attr += $this->parseTime('ctime', $flags, $response);
                    break;
                case NET_SFTP_ATTR_EXTENDED: // 0x80000000
                    list($count) = Strings::unpackSSH2('N', $response);
                    for ($i = 0; $i < $count; $i++) {
                        list($key, $value) = Strings::unpackSSH2('ss', $response);
                        $attr[$key] = $value;
                    }
            }
        }
        return $attr;
    }

    /**
     * Attempt to identify the file type
     *
     * Quoting the SFTP RFC, "Implementations MUST NOT send bits that are not defined" but they seem to anyway
     *
     * @param int $mode
     * @return int
     */
    private function parseMode($mode)
    {
        // values come from http://lxr.free-electrons.com/source/include/uapi/linux/stat.h#L12
        // see, also, http://linux.die.net/man/2/stat
        switch ($mode & 0170000) {// ie. 1111 0000 0000 0000
            case 0000000: // no file type specified - figure out the file type using alternative means
                return false;
            case 0040000:
                return NET_SFTP_TYPE_DIRECTORY;
            case 0100000:
                return NET_SFTP_TYPE_REGULAR;
            case 0120000:
                return NET_SFTP_TYPE_SYMLINK;
            // new types introduced in SFTPv5+
            // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
            case 0010000: // named pipe (fifo)
                return NET_SFTP_TYPE_FIFO;
            case 0020000: // character special
                return NET_SFTP_TYPE_CHAR_DEVICE;
            case 0060000: // block special
                return NET_SFTP_TYPE_BLOCK_DEVICE;
            case 0140000: // socket
                return NET_SFTP_TYPE_SOCKET;
            case 0160000: // whiteout
                // "SPECIAL should be used for files that are of
                //  a known type which cannot be expressed in the protocol"
                return NET_SFTP_TYPE_SPECIAL;
            default:
                return NET_SFTP_TYPE_UNKNOWN;
        }
    }

    /**
     * Parse Longname
     *
     * SFTPv3 doesn't provide any easy way of identifying a file type.  You could try to open
     * a file as a directory and see if an error is returned or you could try to parse the
     * SFTPv3-specific longname field of the SSH_FXP_NAME packet.  That's what this function does.
     * The result is returned using the
     * {@link http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 SFTPv4 type constants}.
     *
     * If the longname is in an unrecognized format bool(false) is returned.
     *
     * @param string $longname
     * @return mixed
     */
    private function parseLongname($longname)
    {
        // http://en.wikipedia.org/wiki/Unix_file_types
        // http://en.wikipedia.org/wiki/Filesystem_permissions#Notation_of_traditional_Unix_permissions
        if (preg_match('#^[^/]([r-][w-][xstST-]){3}#', $longname)) {
            switch ($longname[0]) {
                case '-':
                    return NET_SFTP_TYPE_REGULAR;
                case 'd':
                    return NET_SFTP_TYPE_DIRECTORY;
                case 'l':
                    return NET_SFTP_TYPE_SYMLINK;
                default:
                    return NET_SFTP_TYPE_SPECIAL;
            }
        }

        return false;
    }

    /**
     * Sends SFTP Packets
     *
     * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info.
     *
     * @param int $type
     * @param string $data
     * @param int $request_id
     * @see self::_get_sftp_packet()
     * @see self::send_channel_packet()
     * @return void
     */
    private function send_sftp_packet($type, $data, $request_id = 1)
    {
        // in SSH2.php the timeout is cumulative per function call. eg. exec() will
        // timeout after 10s. but for SFTP.php it's cumulative per packet
        $this->curTimeout = $this->timeout;
        $this->is_timeout = false;

        $packet = $this->use_request_id ?
            pack('NCNa*', strlen($data) + 5, $type, $request_id, $data) :
            pack('NCa*', strlen($data) + 1, $type, $data);

        $start = microtime(true);
        $this->send_channel_packet(self::CHANNEL, $packet);
        $stop = microtime(true);

        if (defined('NET_SFTP_LOGGING')) {
            $packet_type = '-> ' . self::$packet_types[$type] .
                           ' (' . round($stop - $start, 4) . 's)';
            $this->append_log($packet_type, $data);
        }
    }

    /**
     * Resets the SFTP channel for re-use
     */
    private function reset_sftp()
    {
        $this->use_request_id = false;
        $this->pwd = false;
        $this->requestBuffer = [];
        $this->partial_init = false;
    }

    /**
     * Resets a connection for re-use
     */
    protected function reset_connection()
    {
        parent::reset_connection();
        $this->reset_sftp();
    }

    /**
     * Receives SFTP Packets
     *
     * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info.
     *
     * Incidentally, the number of SSH_MSG_CHANNEL_DATA messages has no bearing on the number of SFTP packets present.
     * There can be one SSH_MSG_CHANNEL_DATA messages containing two SFTP packets or there can be two SSH_MSG_CHANNEL_DATA
     * messages containing one SFTP packet.
     *
     * @see self::_send_sftp_packet()
     * @return string
     */
    private function get_sftp_packet($request_id = null)
    {
        $this->channel_close = false;

        if (isset($request_id) && isset($this->requestBuffer[$request_id])) {
            $this->packet_type = $this->requestBuffer[$request_id]['packet_type'];
            $temp = $this->requestBuffer[$request_id]['packet'];
            unset($this->requestBuffer[$request_id]);
            return $temp;
        }

        // in SSH2.php the timeout is cumulative per function call. eg. exec() will
        // timeout after 10s. but for SFTP.php it's cumulative per packet
        $this->curTimeout = $this->timeout;
        $this->is_timeout = false;

        $start = microtime(true);

        // SFTP packet length
        while (strlen($this->packet_buffer) < 4) {
            $temp = $this->get_channel_packet(self::CHANNEL, true);
            if ($temp === true) {
                if ($this->channel_status[self::CHANNEL] === NET_SSH2_MSG_CHANNEL_CLOSE) {
                    $this->channel_close = true;
                }
                $this->packet_type = false;
                $this->packet_buffer = '';
                return false;
            }
            $this->packet_buffer .= $temp;
        }
        if (strlen($this->packet_buffer) < 4) {
            throw new \RuntimeException('Packet is too small');
        }
        $length = unpack('Nlength', Strings::shift($this->packet_buffer, 4))['length'];

        $tempLength = $length;
        $tempLength -= strlen($this->packet_buffer);

        // 256 * 1024 is what SFTP_MAX_MSG_LENGTH is set to in OpenSSH's sftp-common.h
        if (!$this->allow_arbitrary_length_packets && !$this->use_request_id && $tempLength > 256 * 1024) {
            throw new \RuntimeException('Invalid Size');
        }

        // SFTP packet type and data payload
        while ($tempLength > 0) {
            $temp = $this->get_channel_packet(self::CHANNEL, true);
            if ($temp === true) {
                if ($this->channel_status[self::CHANNEL] === NET_SSH2_MSG_CHANNEL_CLOSE) {
                    $this->channel_close = true;
                }
                $this->packet_type = false;
                $this->packet_buffer = '';
                return false;
            }
            $this->packet_buffer .= $temp;
            $tempLength -= strlen($temp);
        }

        $stop = microtime(true);

        $this->packet_type = ord(Strings::shift($this->packet_buffer));

        if ($this->use_request_id) {
            $packet_id = unpack('Npacket_id', Strings::shift($this->packet_buffer, 4))['packet_id']; // remove the request id
            $length -= 5; // account for the request id and the packet type
        } else {
            $length -= 1; // account for the packet type
        }

        $packet = Strings::shift($this->packet_buffer, $length);

        if (defined('NET_SFTP_LOGGING')) {
            $packet_type = '<- ' . self::$packet_types[$this->packet_type] .
                           ' (' . round($stop - $start, 4) . 's)';
            $this->append_log($packet_type, $packet);
        }

        if (isset($request_id) && $this->use_request_id && $packet_id != $request_id) {
            $this->requestBuffer[$packet_id] = [
                'packet_type' => $this->packet_type,
                'packet' => $packet
            ];
            return $this->get_sftp_packet($request_id);
        }

        return $packet;
    }

    /**
     * Logs data packets
     *
     * Makes sure that only the last 1MB worth of packets will be logged
     *
     * @param string $message_number
     * @param string $message
     */
    private function append_log($message_number, $message)
    {
        $this->append_log_helper(
            NET_SFTP_LOGGING,
            $message_number,
            $message,
            $this->packet_type_log,
            $this->packet_log,
            $this->log_size,
            $this->realtime_log_file,
            $this->realtime_log_wrap,
            $this->realtime_log_size
        );
    }

    /**
     * Returns a log of the packets that have been sent and received.
     *
     * Returns a string if NET_SFTP_LOGGING == self::LOG_COMPLEX, an array if NET_SFTP_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING')
     *
     * @return array|string|false
     */
    public function getSFTPLog()
    {
        if (!defined('NET_SFTP_LOGGING')) {
            return false;
        }

        switch (NET_SFTP_LOGGING) {
            case self::LOG_COMPLEX:
                return $this->format_log($this->packet_log, $this->packet_type_log);
                break;
            //case self::LOG_SIMPLE:
            default:
                return $this->packet_type_log;
        }
    }
    /**
     * Returns all errors on the SFTP layer
     *
     * @return array
     * @removed in phpseclib 4.0.0
     */
    public function getSFTPErrors()
    {
        return $this->sftp_errors;
    }

    /**
     * Returns the last error on the SFTP layer
     *
     * @return string
     * @removed in phpseclib 4.0.0
     */
    public function getLastSFTPError()
    {
        return count($this->sftp_errors) ? $this->sftp_errors[count($this->sftp_errors) - 1] : '';
    }

    /**
     * Get supported SFTP versions
     *
     * @return array
     */
    public function getSupportedVersions()
    {
        if (!($this->bitmap & SSH2::MASK_LOGIN)) {
            return false;
        }

        if (!$this->partial_init) {
            $this->partial_init_sftp_connection();
        }

        $temp = ['version' => $this->defaultVersion];
        if (isset($this->extensions['versions'])) {
            $temp['extensions'] = $this->extensions['versions'];
        }
        return $temp;
    }

    /**
     * Get supported SFTP extensions
     *
     * @return array
     */
    public function getSupportedExtensions()
    {
        if (!($this->bitmap & SSH2::MASK_LOGIN)) {
            return false;
        }

        if (!$this->partial_init) {
            $this->partial_init_sftp_connection();
        }

        return $this->extensions;
    }

    /**
     * Get supported SFTP versions
     *
     * @return int|false
     */
    public function getNegotiatedVersion()
    {
        if (!$this->precheck()) {
            return false;
        }

        return $this->version;
    }

    /**
     * Set preferred version
     *
     * If you're preferred version isn't supported then the highest supported
     * version of SFTP will be utilized. Set to null or false or int(0) to
     * unset the preferred version
     *
     * @param int $version
     */
    public function setPreferredVersion($version)
    {
        $this->preferredVersion = $version;
    }

    /**
     * Disconnect
     *
     * @param int $reason
     * @return false
     */
    protected function disconnect_helper($reason)
    {
        $this->pwd = false;
        return parent::disconnect_helper($reason);
    }

    /**
     * Enable Date Preservation
     */
    public function enableDatePreservation()
    {
        $this->preserveTime = true;
    }

    /**
     * Disable Date Preservation
     */
    public function disableDatePreservation()
    {
        $this->preserveTime = false;
    }

    /**
     * Copy
     *
     * This method (currently) only works if the copy-data extension is available
     *
     * @param string $oldname
     * @param string $newname
     * @return bool
     */
    public function copy($oldname, $newname)
    {
        if (!$this->precheck()) {
            return false;
        }

        $oldname = $this->realpath($oldname);
        $newname = $this->realpath($newname);
        if ($oldname === false || $newname === false) {
            return false;
        }

        if (!isset($this->extensions['copy-data']) || $this->extensions['copy-data'] !== '1') {
            throw new \RuntimeException(
                "Extension 'copy-data' is not supported by the server. " .
                "Call getSupportedVersions() to see a list of supported extension"
            );
        }

        $size = $this->filesize($oldname);

        $packet = Strings::packSSH2('s', $oldname);
        $packet .= $this->version >= 5 ?
            pack('N3', 0, NET_SFTP_OPEN_OPEN_EXISTING, 0) :
            pack('N2', NET_SFTP_OPEN_READ, 0);
        $this->send_sftp_packet(NET_SFTP_OPEN, $packet);

        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_HANDLE:
                $oldhandle = substr($response, 4);
                break;
            case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
                $this->logError($response);
                return false;
            default:
                throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. '
                                                  . 'Got packet type: ' . $this->packet_type);
        }

        if ($this->version >= 5) {
            $flags = NET_SFTP_OPEN_OPEN_OR_CREATE;
        } else {
            $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE;
        }

        $packet = Strings::packSSH2('s', $newname);
        $packet .= $this->version >= 5 ?
            pack('N3', 0, $flags, 0) :
            pack('N2', $flags, 0);
        $this->send_sftp_packet(NET_SFTP_OPEN, $packet);

        $response = $this->get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_HANDLE:
                $newhandle = substr($response, 4);
                break;
            case NET_SFTP_STATUS:
                $this->logError($response);
                return false;
            default:
                throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. '
                                                  . 'Got packet type: ' . $this->packet_type);
        }

        $packet = Strings::packSSH2('ssQQsQ', 'copy-data', $oldhandle, 0, $size, $newhandle, 0);
        $this->send_sftp_packet(NET_SFTP_EXTENDED, $packet);

        $response = $this->get_sftp_packet();
        if ($this->packet_type != NET_SFTP_STATUS) {
            throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                                              . 'Got packet type: ' . $this->packet_type);
        }

        $this->close_handle($oldhandle);
        $this->close_handle($newhandle);

        return true;
    }

    /**
     * POSIX Rename
     *
     * Where rename() fails "if there already exists a file with the name specified by newpath"
     * (draft-ietf-secsh-filexfer-02#section-6.5), posix_rename() overwrites the existing file in an atomic fashion.
     * ie. "there is no observable instant in time where the name does not refer to either the old or the new file"
     * (draft-ietf-secsh-filexfer-13#page-39).
     *
     * @param string $oldname
     * @param string $newname
     * @return bool
     */
    public function posix_rename($oldname, $newname)
    {
        if (!$this->precheck()) {
            return false;
        }

        $oldname = $this->realpath($oldname);
        $newname = $this->realpath($newname);
        if ($oldname === false || $newname === false) {
            return false;
        }

        if ($this->version >= 5) {
            $packet = Strings::packSSH2('ssN', $oldname, $newname, 2); // 2 = SSH_FXP_RENAME_ATOMIC
            $this->send_sftp_packet(NET_SFTP_RENAME, $packet);
        } elseif (isset($this->extensions['posix-rename@openssh.com']) && $this->extensions['posix-rename@openssh.com'] === '1') {
            $packet = Strings::packSSH2('sss', 'posix-rename@openssh.com', $oldname, $newname);
            $this->send_sftp_packet(NET_SFTP_EXTENDED, $packet);
        } else {
            throw new \RuntimeException(
                "Extension 'posix-rename@openssh.com' is not supported by the server. " .
                "Call getSupportedVersions() to see a list of supported extension"
            );
        }

        $response = $this->get_sftp_packet();
        if ($this->packet_type != NET_SFTP_STATUS) {
            throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                                              . 'Got packet type: ' . $this->packet_type);
        }

        // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
        list($status) = Strings::unpackSSH2('N', $response);
        if ($status != NET_SFTP_STATUS_OK) {
            $this->logError($response, $status);
            return false;
        }

        // don't move the stat cache entry over since this operation could very well change the
        // atime and mtime attributes
        //$this->update_stat_cache($newname, $this->query_stat_cache($oldname));
        $this->remove_from_stat_cache($oldname);
        $this->remove_from_stat_cache($newname);

        return true;
    }

    /**
     * Returns general information about a file system.
     *
     * The function statvfs() returns information about a mounted filesystem.
     * @see https://man7.org/linux/man-pages/man3/statvfs.3.html
     *
     * @param string $path
     * @return false|array{bsize: int, frsize: int, blocks: int, bfree: int, bavail: int, files: int, ffree: int, favail: int, fsid: int, flag: int, namemax: int}
     */
    public function statvfs($path)
    {
        if (!$this->precheck()) {
            return false;
        }

        if (!isset($this->extensions['statvfs@openssh.com']) || $this->extensions['statvfs@openssh.com'] !== '2') {
            throw new \RuntimeException(
                "Extension 'statvfs@openssh.com' is not supported by the server. " .
                "Call getSupportedVersions() to see a list of supported extension"
            );
        }

        $realpath = $this->realpath($path);
        if ($realpath === false) {
            return false;
        }

        $packet = Strings::packSSH2('ss', 'statvfs@openssh.com', $realpath);
        $this->send_sftp_packet(NET_SFTP_EXTENDED, $packet);

        $response = $this->get_sftp_packet();
        if ($this->packet_type !== NET_SFTP_EXTENDED_REPLY) {
            throw new \UnexpectedValueException(
                'Expected SSH_FXP_EXTENDED_REPLY. '
                . 'Got packet type: ' . $this->packet_type
            );
        }

        /**
         * These requests return a SSH_FXP_STATUS reply on failure. On success they
         * return the following SSH_FXP_EXTENDED_REPLY reply:
         *
         * uint32        id
         * uint64        f_bsize     file system block size
         * uint64        f_frsize     fundamental fs block size
         * uint64        f_blocks     number of blocks (unit f_frsize)
         * uint64        f_bfree      free blocks in file system
         * uint64        f_bavail     free blocks for non-root
         * uint64        f_files      total file inodes
         * uint64        f_ffree      free file inodes
         * uint64        f_favail     free file inodes for to non-root
         * uint64        f_fsid       file system id
         * uint64        f_flag       bit mask of f_flag values
         * uint64        f_namemax    maximum filename length
         */
        return array_combine(
            ['bsize', 'frsize', 'blocks', 'bfree', 'bavail', 'files', 'ffree', 'favail', 'fsid', 'flag', 'namemax'],
            Strings::unpackSSH2('QQQQQQQQQQQ', $response)
        );
    }

    public function hardlink($oldpath, $newpath)
    {
        if (!$this->precheck()) {
            return false;
        }

        if (!isset($this->extensions['hardlink@openssh.com']) || $this->extensions['hardlink@openssh.com'] !== '1') {
            throw new \RuntimeException(
                "Extension 'hardlink@openssh.com' is not supported by the server. " .
                "Call getSupportedVersions() to see a list of supported extension"
            );
        }

        $oldpath = $this->realpath($oldpath);
        $newpath = $this->realpath($newpath);
        if ($oldpath === false || $newpath === false) {
            return false;
        }

        $packet = Strings::packSSH2('sss', 'hardlink@openssh.com', $oldpath, $newpath);
        $this->send_sftp_packet(NET_SFTP_EXTENDED, $packet);

        $response = $this->get_sftp_packet();
        if ($this->packet_type !== NET_SFTP_STATUS) {
            throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. '
                . 'Got packet type: ' . $this->packet_type);
        }

        // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
        list($status) = Strings::unpackSSH2('N', $response);
        if ($status !== NET_SFTP_STATUS_OK) {
            $this->logError($response, $status);
            return false;
        }

        // this operation will change the ctime and link-count attributes
        // which could be cached depending on sftp version
        $this->remove_from_stat_cache($oldpath);

        // hardlink creation should fail if $newpath exists;
        // removing it from the cache anyway, just to be sure
        $this->remove_from_stat_cache($newpath);

        return true;
    }
}
<?php

/**
 * Pure-PHP implementation of SSHv2.
 *
 * PHP version 5
 *
 * Here are some examples of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $ssh = new \phpseclib3\Net\SSH2('www.domain.tld');
 *    if (!$ssh->login('username', 'password')) {
 *        exit('Login Failed');
 *    }
 *
 *    echo $ssh->exec('pwd');
 *    echo $ssh->exec('ls -la');
 * ?>
 * </code>
 *
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $key = \phpseclib3\Crypt\PublicKeyLoader::load('...', '(optional) password');
 *
 *    $ssh = new \phpseclib3\Net\SSH2('www.domain.tld');
 *    if (!$ssh->login('username', $key)) {
 *        exit('Login Failed');
 *    }
 *
 *    echo $ssh->read('username@username:~$');
 *    $ssh->write("ls -la\n");
 *    echo $ssh->read('username@username:~$');
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Net;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Blowfish;
use phpseclib3\Crypt\ChaCha20;
use phpseclib3\Crypt\Common\AsymmetricKey;
use phpseclib3\Crypt\Common\PrivateKey;
use phpseclib3\Crypt\Common\PublicKey;
use phpseclib3\Crypt\Common\SymmetricKey;
use phpseclib3\Crypt\DH;
use phpseclib3\Crypt\DSA;
use phpseclib3\Crypt\EC;
use phpseclib3\Crypt\Hash;
use phpseclib3\Crypt\Random;
use phpseclib3\Crypt\RC4;
use phpseclib3\Crypt\Rijndael;
use phpseclib3\Crypt\RSA;
use phpseclib3\Crypt\TripleDES; // Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
use phpseclib3\Crypt\Twofish;
use phpseclib3\Exception\ConnectionClosedException;
use phpseclib3\Exception\InsufficientSetupException;
use phpseclib3\Exception\InvalidPacketLengthException;
use phpseclib3\Exception\NoSupportedAlgorithmsException;
use phpseclib3\Exception\TimeoutException;
use phpseclib3\Exception\UnableToConnectException;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\Exception\UnsupportedCurveException;
use phpseclib3\Math\BigInteger;
use phpseclib3\System\SSH\Agent;

/**
 * Pure-PHP implementation of SSHv2.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class SSH2
{
    /**#@+
     * Compression Types
     *
     */
    /**
     * No compression
     */
    const NET_SSH2_COMPRESSION_NONE = 1;
    /**
     * zlib compression
     */
    const NET_SSH2_COMPRESSION_ZLIB = 2;
    /**
     * zlib@openssh.com
     */
    const NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH = 3;
    /**#@-*/

    // Execution Bitmap Masks
    const MASK_CONSTRUCTOR   = 0x00000001;
    const MASK_CONNECTED     = 0x00000002;
    const MASK_LOGIN_REQ     = 0x00000004;
    const MASK_LOGIN         = 0x00000008;
    const MASK_SHELL         = 0x00000010;
    const MASK_DISCONNECT    = 0x00000020;

    /*
     * Channel constants
     *
     * RFC4254 refers not to client and server channels but rather to sender and recipient channels.  we don't refer
     * to them in that way because RFC4254 toggles the meaning. the client sends a SSH_MSG_CHANNEL_OPEN message with
     * a sender channel and the server sends a SSH_MSG_CHANNEL_OPEN_CONFIRMATION in response, with a sender and a
     * recipient channel.  at first glance, you might conclude that SSH_MSG_CHANNEL_OPEN_CONFIRMATION's sender channel
     * would be the same thing as SSH_MSG_CHANNEL_OPEN's sender channel, but it's not, per this snippet:
     *     The 'recipient channel' is the channel number given in the original
     *     open request, and 'sender channel' is the channel number allocated by
     *     the other side.
     *
     * @see \phpseclib3\Net\SSH2::send_channel_packet()
     * @see \phpseclib3\Net\SSH2::get_channel_packet()
     */
    const CHANNEL_EXEC          = 1; // PuTTy uses 0x100
    const CHANNEL_SHELL         = 2;
    const CHANNEL_SUBSYSTEM     = 3;
    const CHANNEL_AGENT_FORWARD = 4;
    const CHANNEL_KEEP_ALIVE    = 5;

    /**
     * Returns the message numbers
     *
     * @see \phpseclib3\Net\SSH2::getLog()
     */
    const LOG_SIMPLE = 1;
    /**
     * Returns the message content
     *
     * @see \phpseclib3\Net\SSH2::getLog()
     */
    const LOG_COMPLEX = 2;
    /**
     * Outputs the content real-time
     */
    const LOG_REALTIME = 3;
    /**
     * Dumps the content real-time to a file
     */
    const LOG_REALTIME_FILE = 4;
    /**
     * Outputs the message numbers real-time
     */
    const LOG_SIMPLE_REALTIME = 5;
    /*
     * Dumps the message numbers real-time
     */
    const LOG_REALTIME_SIMPLE = 5;
    /**
     * Make sure that the log never gets larger than this
     *
     * @see \phpseclib3\Net\SSH2::getLog()
     */
    const LOG_MAX_SIZE = 1048576; // 1024 * 1024

    /**
     * Returns when a string matching $expect exactly is found
     *
     * @see \phpseclib3\Net\SSH2::read()
     */
    const READ_SIMPLE = 1;
    /**
     * Returns when a string matching the regular expression $expect is found
     *
     * @see \phpseclib3\Net\SSH2::read()
     */
    const READ_REGEX = 2;
    /**
     * Returns whenever a data packet is received.
     *
     * Some data packets may only contain a single character so it may be necessary
     * to call read() multiple times when using this option
     *
     * @see \phpseclib3\Net\SSH2::read()
     */
    const READ_NEXT = 3;

    /**
     * The SSH identifier
     *
     * @var string
     */
    private $identifier;

    /**
     * The Socket Object
     *
     * @var resource|closed-resource|null
     */
    public $fsock;

    /**
     * Execution Bitmap
     *
     * The bits that are set represent functions that have been called already.  This is used to determine
     * if a requisite function has been successfully executed.  If not, an error should be thrown.
     *
     * @var int
     */
    protected $bitmap = 0;

    /**
     * Error information
     *
     * @see self::getErrors()
     * @see self::getLastError()
     * @var array
     */
    private $errors = [];

    /**
     * Server Identifier
     *
     * @see self::getServerIdentification()
     * @var string|false
     */
    protected $server_identifier = false;

    /**
     * Key Exchange Algorithms
     *
     * @see self::getKexAlgorithims()
     * @var array|false
     */
    private $kex_algorithms = false;

    /**
     * Key Exchange Algorithm
     *
     * @see self::getMethodsNegotiated()
     * @var string|false
     */
    private $kex_algorithm = false;

    /**
     * Minimum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
     *
     * @see self::_key_exchange()
     * @var int
     */
    private $kex_dh_group_size_min = 1536;

    /**
     * Preferred Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
     *
     * @see self::_key_exchange()
     * @var int
     */
    private $kex_dh_group_size_preferred = 2048;

    /**
     * Maximum Diffie-Hellman Group Bit Size in RFC 4419 Key Exchange Methods
     *
     * @see self::_key_exchange()
     * @var int
     */
    private $kex_dh_group_size_max = 4096;

    /**
     * Server Host Key Algorithms
     *
     * @see self::getServerHostKeyAlgorithms()
     * @var array|false
     */
    private $server_host_key_algorithms = false;

    /**
     * Supported Private Key Algorithms
     *
     * In theory this should be the same as the Server Host Key Algorithms but, in practice,
     * some servers (eg. Azure) will support rsa-sha2-512 as a server host key algorithm but
     * not a private key algorithm
     *
     * @see self::privatekey_login()
     * @var array|false
     */
    private $supported_private_key_algorithms = false;

    /**
     * Encryption Algorithms: Client to Server
     *
     * @see self::getEncryptionAlgorithmsClient2Server()
     * @var array|false
     */
    private $encryption_algorithms_client_to_server = false;

    /**
     * Encryption Algorithms: Server to Client
     *
     * @see self::getEncryptionAlgorithmsServer2Client()
     * @var array|false
     */
    private $encryption_algorithms_server_to_client = false;

    /**
     * MAC Algorithms: Client to Server
     *
     * @see self::getMACAlgorithmsClient2Server()
     * @var array|false
     */
    private $mac_algorithms_client_to_server = false;

    /**
     * MAC Algorithms: Server to Client
     *
     * @see self::getMACAlgorithmsServer2Client()
     * @var array|false
     */
    private $mac_algorithms_server_to_client = false;

    /**
     * Compression Algorithms: Client to Server
     *
     * @see self::getCompressionAlgorithmsClient2Server()
     * @var array|false
     */
    private $compression_algorithms_client_to_server = false;

    /**
     * Compression Algorithms: Server to Client
     *
     * @see self::getCompressionAlgorithmsServer2Client()
     * @var array|false
     */
    private $compression_algorithms_server_to_client = false;

    /**
     * Languages: Server to Client
     *
     * @see self::getLanguagesServer2Client()
     * @var array|false
     */
    private $languages_server_to_client = false;

    /**
     * Languages: Client to Server
     *
     * @see self::getLanguagesClient2Server()
     * @var array|false
     */
    private $languages_client_to_server = false;

    /**
     * Preferred Algorithms
     *
     * @see self::setPreferredAlgorithms()
     * @var array
     */
    private $preferred = [];

    /**
     * Block Size for Server to Client Encryption
     *
     * "Note that the length of the concatenation of 'packet_length',
     *  'padding_length', 'payload', and 'random padding' MUST be a multiple
     *  of the cipher block size or 8, whichever is larger.  This constraint
     *  MUST be enforced, even when using stream ciphers."
     *
     *  -- http://tools.ietf.org/html/rfc4253#section-6
     *
     * @see self::__construct()
     * @see self::_send_binary_packet()
     * @var int
     */
    private $encrypt_block_size = 8;

    /**
     * Block Size for Client to Server Encryption
     *
     * @see self::__construct()
     * @see self::_get_binary_packet()
     * @var int
     */
    private $decrypt_block_size = 8;

    /**
     * Server to Client Encryption Object
     *
     * @see self::_get_binary_packet()
     * @var SymmetricKey|false
     */
    private $decrypt = false;

    /**
     * Decryption Algorithm Name
     *
     * @var string|null
     */
    private $decryptName;

    /**
     * Decryption Invocation Counter
     *
     * Used by GCM
     *
     * @var string|null
     */
    private $decryptInvocationCounter;

    /**
     * Fixed Part of Nonce
     *
     * Used by GCM
     *
     * @var string|null
     */
    private $decryptFixedPart;

    /**
     * Server to Client Length Encryption Object
     *
     * @see self::_get_binary_packet()
     * @var object
     */
    private $lengthDecrypt = false;

    /**
     * Client to Server Encryption Object
     *
     * @see self::_send_binary_packet()
     * @var SymmetricKey|false
     */
    private $encrypt = false;

    /**
     * Encryption Algorithm Name
     *
     * @var string|null
     */
    private $encryptName;

    /**
     * Encryption Invocation Counter
     *
     * Used by GCM
     *
     * @var string|null
     */
    private $encryptInvocationCounter;

    /**
     * Fixed Part of Nonce
     *
     * Used by GCM
     *
     * @var string|null
     */
    private $encryptFixedPart;

    /**
     * Client to Server Length Encryption Object
     *
     * @see self::_send_binary_packet()
     * @var object
     */
    private $lengthEncrypt = false;

    /**
     * Client to Server HMAC Object
     *
     * @see self::_send_binary_packet()
     * @var object
     */
    private $hmac_create = false;

    /**
     * Client to Server HMAC Name
     *
     * @var string|false
     */
    private $hmac_create_name;

    /**
     * Client to Server ETM
     *
     * @var int|false
     */
    private $hmac_create_etm;

    /**
     * Server to Client HMAC Object
     *
     * @see self::_get_binary_packet()
     * @var object
     */
    private $hmac_check = false;

    /**
     * Server to Client HMAC Name
     *
     * @var string|false
     */
    private $hmac_check_name;

    /**
     * Server to Client ETM
     *
     * @var int|false
     */
    private $hmac_check_etm;

    /**
     * Size of server to client HMAC
     *
     * We need to know how big the HMAC will be for the server to client direction so that we know how many bytes to read.
     * For the client to server side, the HMAC object will make the HMAC as long as it needs to be.  All we need to do is
     * append it.
     *
     * @see self::_get_binary_packet()
     * @var int
     */
    private $hmac_size = false;

    /**
     * Server Public Host Key
     *
     * @see self::getServerPublicHostKey()
     * @var string
     */
    private $server_public_host_key;

    /**
     * Session identifier
     *
     * "The exchange hash H from the first key exchange is additionally
     *  used as the session identifier, which is a unique identifier for
     *  this connection."
     *
     *  -- http://tools.ietf.org/html/rfc4253#section-7.2
     *
     * @see self::_key_exchange()
     * @var string
     */
    private $session_id = false;

    /**
     * Exchange hash
     *
     * The current exchange hash
     *
     * @see self::_key_exchange()
     * @var string
     */
    private $exchange_hash = false;

    /**
     * Message Numbers
     *
     * @see self::__construct()
     * @var array
     * @access private
     */
    private static $message_numbers = [];

    /**
     * Disconnection Message 'reason codes' defined in RFC4253
     *
     * @see self::__construct()
     * @var array
     * @access private
     */
    private static $disconnect_reasons = [];

    /**
     * SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254
     *
     * @see self::__construct()
     * @var array
     * @access private
     */
    private static $channel_open_failure_reasons = [];

    /**
     * Terminal Modes
     *
     * @link http://tools.ietf.org/html/rfc4254#section-8
     * @see self::__construct()
     * @var array
     * @access private
     */
    private static $terminal_modes = [];

    /**
     * SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes
     *
     * @link http://tools.ietf.org/html/rfc4254#section-5.2
     * @see self::__construct()
     * @var array
     * @access private
     */
    private static $channel_extended_data_type_codes = [];

    /**
     * Send Sequence Number
     *
     * See 'Section 6.4.  Data Integrity' of rfc4253 for more info.
     *
     * @see self::_send_binary_packet()
     * @var int
     */
    private $send_seq_no = 0;

    /**
     * Get Sequence Number
     *
     * See 'Section 6.4.  Data Integrity' of rfc4253 for more info.
     *
     * @see self::_get_binary_packet()
     * @var int
     */
    private $get_seq_no = 0;

    /**
     * Server Channels
     *
     * Maps client channels to server channels
     *
     * @see self::get_channel_packet()
     * @see self::exec()
     * @var array
     */
    protected $server_channels = [];

    /**
     * Channel Read Buffers
     *
     * If a client requests a packet from one channel but receives two packets from another those packets should
     * be placed in a buffer
     *
     * @see self::get_channel_packet()
     * @see self::exec()
     * @var array
     */
    private $channel_buffers = [];

    /**
     * Channel Write Buffers
     *
     * If a client sends a packet and receives a timeout error mid-transmission, buffer the data written so it
     * can be de-duplicated upon resuming write
     *
     * @see self::send_channel_packet()
     * @var array
     */
    private $channel_buffers_write = [];

    /**
     * Channel Status
     *
     * Contains the type of the last sent message
     *
     * @see self::get_channel_packet()
     * @var array
     */
    protected $channel_status = [];

    /**
     * The identifier of the interactive channel which was opened most recently
     *
     * @see self::getInteractiveChannelId()
     * @var int
     */
    private $channel_id_last_interactive = 0;

    /**
     * Packet Size
     *
     * Maximum packet size indexed by channel
     *
     * @see self::send_channel_packet()
     * @var array
     */
    protected $packet_size_client_to_server = [];

    /**
     * Message Number Log
     *
     * @see self::getLog()
     * @var array
     */
    private $message_number_log = [];

    /**
     * Message Log
     *
     * @see self::getLog()
     * @var array
     */
    private $message_log = [];

    /**
     * The Window Size
     *
     * Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 2GB)
     *
     * @var int
     * @see self::send_channel_packet()
     * @see self::exec()
     */
    protected $window_size = 0x7FFFFFFF;

    /**
     * What we resize the window to
     *
     * When PuTTY resizes the window it doesn't add an additional 0x7FFFFFFF bytes - it adds 0x40000000 bytes.
     * Some SFTP clients (GoAnywhere) don't support adding 0x7FFFFFFF to the window size after the fact so
     * we'll just do what PuTTY does
     *
     * @var int
     * @see self::_send_channel_packet()
     * @see self::exec()
     */
    private $window_resize = 0x40000000;

    /**
     * Window size, server to client
     *
     * Window size indexed by channel
     *
     * @see self::send_channel_packet()
     * @var array
     */
    protected $window_size_server_to_client = [];

    /**
     * Window size, client to server
     *
     * Window size indexed by channel
     *
     * @see self::get_channel_packet()
     * @var array
     */
    private $window_size_client_to_server = [];

    /**
     * Server signature
     *
     * Verified against $this->session_id
     *
     * @see self::getServerPublicHostKey()
     * @var string
     */
    private $signature = '';

    /**
     * Server signature format
     *
     * ssh-rsa or ssh-dss.
     *
     * @see self::getServerPublicHostKey()
     * @var string
     */
    private $signature_format = '';

    /**
     * Interactive Buffer
     *
     * @see self::read()
     * @var string
     */
    private $interactiveBuffer = '';

    /**
     * Current log size
     *
     * Should never exceed self::LOG_MAX_SIZE
     *
     * @see self::_send_binary_packet()
     * @see self::_get_binary_packet()
     * @var int
     */
    private $log_size;

    /**
     * Timeout
     *
     * @see self::setTimeout()
     */
    protected $timeout;

    /**
     * Current Timeout
     *
     * @see self::get_channel_packet()
     */
    protected $curTimeout;

    /**
     * Keep Alive Interval
     *
     * @see self::setKeepAlive()
     */
    private $keepAlive;

    /**
     * Real-time log file pointer
     *
     * @see self::_append_log()
     * @var resource|closed-resource
     */
    private $realtime_log_file;

    /**
     * Real-time log file size
     *
     * @see self::_append_log()
     * @var int
     */
    private $realtime_log_size;

    /**
     * Has the signature been validated?
     *
     * @see self::getServerPublicHostKey()
     * @var bool
     */
    private $signature_validated = false;

    /**
     * Real-time log file wrap boolean
     *
     * @see self::_append_log()
     * @var bool
     */
    private $realtime_log_wrap;

    /**
     * Flag to suppress stderr from output
     *
     * @see self::enableQuietMode()
     */
    private $quiet_mode = false;

    /**
     * Time of last read/write network activity
     *
     * @var float
     */
    private $last_packet = null;

    /**
     * Exit status returned from ssh if any
     *
     * @var int
     */
    private $exit_status;

    /**
     * Flag to request a PTY when using exec()
     *
     * @var bool
     * @see self::enablePTY()
     */
    private $request_pty = false;

    /**
     * Contents of stdError
     *
     * @var string
     */
    private $stdErrorLog;

    /**
     * The Last Interactive Response
     *
     * @see self::_keyboard_interactive_process()
     * @var string
     */
    private $last_interactive_response = '';

    /**
     * Keyboard Interactive Request / Responses
     *
     * @see self::_keyboard_interactive_process()
     * @var array
     */
    private $keyboard_requests_responses = [];

    /**
     * Banner Message
     *
     * Quoting from the RFC, "in some jurisdictions, sending a warning message before
     * authentication may be relevant for getting legal protection."
     *
     * @see self::_filter()
     * @see self::getBannerMessage()
     * @var string
     */
    private $banner_message = '';

    /**
     * Did read() timeout or return normally?
     *
     * @see self::isTimeout()
     * @var bool
     */
    protected $is_timeout = false;

    /**
     * Log Boundary
     *
     * @see self::_format_log()
     * @var string
     */
    private $log_boundary = ':';

    /**
     * Log Long Width
     *
     * @see self::_format_log()
     * @var int
     */
    private $log_long_width = 65;

    /**
     * Log Short Width
     *
     * @see self::_format_log()
     * @var int
     */
    private $log_short_width = 16;

    /**
     * Hostname
     *
     * @see self::__construct()
     * @see self::_connect()
     * @var string
     */
    private $host;

    /**
     * Port Number
     *
     * @see self::__construct()
     * @see self::_connect()
     * @var int
     */
    private $port;

    /**
     * Number of columns for terminal window size
     *
     * @see self::getWindowColumns()
     * @see self::setWindowColumns()
     * @see self::setWindowSize()
     * @var int
     */
    private $windowColumns = 80;

    /**
     * Number of columns for terminal window size
     *
     * @see self::getWindowRows()
     * @see self::setWindowRows()
     * @see self::setWindowSize()
     * @var int
     */
    private $windowRows = 24;

    /**
     * Crypto Engine
     *
     * @see self::setCryptoEngine()
     * @see self::_key_exchange()
     * @var int
     */
    private static $crypto_engine = false;

    /**
     * A System_SSH_Agent for use in the SSH2 Agent Forwarding scenario
     *
     * @var Agent
     */
    private $agent;

    /**
     * Connection storage to replicates ssh2 extension functionality:
     * {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples}
     *
     * @var array<string, SSH2|\WeakReference<SSH2>>
     */
    private static $connections;

    /**
     * Send the identification string first?
     *
     * @var bool
     */
    private $send_id_string_first = true;

    /**
     * Send the key exchange initiation packet first?
     *
     * @var bool
     */
    private $send_kex_first = true;

    /**
     * Some versions of OpenSSH incorrectly calculate the key size
     *
     * @var bool
     */
    private $bad_key_size_fix = false;

    /**
     * Should we try to re-connect to re-establish keys?
     *
     * @var bool
     */
    private $login_credentials_finalized = false;

    /**
     * Binary Packet Buffer
     *
     * @var object|null
     */
    private $binary_packet_buffer = null;

    /**
     * Preferred Signature Format
     *
     * @var string|false
     */
    protected $preferred_signature_format = false;

    /**
     * Authentication Credentials
     *
     * @var array
     */
    protected $auth = [];

    /**
     * Terminal
     *
     * @var string
     */
    private $term = 'vt100';

    /**
     * The authentication methods that may productively continue authentication.
     *
     * @see https://tools.ietf.org/html/rfc4252#section-5.1
     * @var array|null
     */
    private $auth_methods_to_continue = null;

    /**
     * Compression method
     *
     * @var int
     */
    private $compress = self::NET_SSH2_COMPRESSION_NONE;

    /**
     * Decompression method
     *
     * @var int
     */
    private $decompress = self::NET_SSH2_COMPRESSION_NONE;

    /**
     * Compression context
     *
     * @var resource|false|null
     */
    private $compress_context;

    /**
     * Decompression context
     *
     * @var resource|object
     */
    private $decompress_context;

    /**
     * Regenerate Compression Context
     *
     * @var bool
     */
    private $regenerate_compression_context = false;

    /**
     * Regenerate Decompression Context
     *
     * @var bool
     */
    private $regenerate_decompression_context = false;

    /**
     * Smart multi-factor authentication flag
     *
     * @var bool
     */
    private $smartMFA = true;

    /**
     * How many channels are currently opened
     *
     * @var int
     */
    private $channelCount = 0;

    /**
     * Does the server support multiple channels? If not then error out
     * when multiple channels are attempted to be opened
     *
     * @var bool
     */
    private $errorOnMultipleChannels;

    /**
     * Bytes Transferred Since Last Key Exchange
     *
     * Includes outbound and inbound totals
     *
     * @var int
     */
    private $bytesTransferredSinceLastKEX = 0;

    /**
     * After how many transferred byte should phpseclib initiate a key re-exchange?
     *
     * @var int
     */
    private $doKeyReexchangeAfterXBytes = 1024 * 1024 * 1024;

    /**
     * Has a key re-exchange been initialized?
     *
     * @var bool
     * @access private
     */
    private $keyExchangeInProgress = false;

    /**
     * KEX Buffer
     *
     * If we're in the middle of a key exchange we want to buffer any additional packets we get until
     * the key exchange is over
     *
     * @see self::_get_binary_packet()
     * @see self::_key_exchange()
     * @see self::exec()
     * @var array
     * @access private
     */
    private $kex_buffer = [];

    /**
     * Strict KEX Flag
     *
     * If kex-strict-s-v00@openssh.com is present in the first KEX packet it need not
     * be present in subsequent packet
     *
     * @see self::_key_exchange()
     * @see self::exec()
     * @var array
     * @access private
     */
    private $strict_kex_flag = false;

    /**
     * Default Constructor.
     *
     * $host can either be a string, representing the host, or a stream resource.
     * If $host is a stream resource then $port doesn't do anything, altho $timeout
     * still will be used
     *
     * @param mixed $host
     * @param int $port
     * @param int $timeout
     * @see self::login()
     */
    public function __construct($host, $port = 22, $timeout = 10)
    {
        if (empty(self::$message_numbers)) {
            self::$message_numbers = [
                1 => 'NET_SSH2_MSG_DISCONNECT',
                2 => 'NET_SSH2_MSG_IGNORE',
                3 => 'NET_SSH2_MSG_UNIMPLEMENTED',
                4 => 'NET_SSH2_MSG_DEBUG',
                5 => 'NET_SSH2_MSG_SERVICE_REQUEST',
                6 => 'NET_SSH2_MSG_SERVICE_ACCEPT',
                7 => 'NET_SSH2_MSG_EXT_INFO', // RFC 8308
                20 => 'NET_SSH2_MSG_KEXINIT',
                21 => 'NET_SSH2_MSG_NEWKEYS',
                30 => 'NET_SSH2_MSG_KEXDH_INIT',
                31 => 'NET_SSH2_MSG_KEXDH_REPLY',
                50 => 'NET_SSH2_MSG_USERAUTH_REQUEST',
                51 => 'NET_SSH2_MSG_USERAUTH_FAILURE',
                52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS',
                53 => 'NET_SSH2_MSG_USERAUTH_BANNER',

                80 => 'NET_SSH2_MSG_GLOBAL_REQUEST',
                81 => 'NET_SSH2_MSG_REQUEST_SUCCESS',
                82 => 'NET_SSH2_MSG_REQUEST_FAILURE',
                90 => 'NET_SSH2_MSG_CHANNEL_OPEN',
                91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION',
                92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE',
                93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST',
                94 => 'NET_SSH2_MSG_CHANNEL_DATA',
                95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA',
                96 => 'NET_SSH2_MSG_CHANNEL_EOF',
                97 => 'NET_SSH2_MSG_CHANNEL_CLOSE',
                98 => 'NET_SSH2_MSG_CHANNEL_REQUEST',
                99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS',
                100 => 'NET_SSH2_MSG_CHANNEL_FAILURE'
            ];
            self::$disconnect_reasons = [
                1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
                2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
                3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
                4 => 'NET_SSH2_DISCONNECT_RESERVED',
                5 => 'NET_SSH2_DISCONNECT_MAC_ERROR',
                6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
                7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
                8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
                9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
                10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST',
                11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION',
                12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
                13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
                14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
                15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME'
            ];
            self::$channel_open_failure_reasons = [
                1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED'
            ];
            self::$terminal_modes = [
                0 => 'NET_SSH2_TTY_OP_END'
            ];
            self::$channel_extended_data_type_codes = [
                1 => 'NET_SSH2_EXTENDED_DATA_STDERR'
            ];

            self::define_array(
                self::$message_numbers,
                self::$disconnect_reasons,
                self::$channel_open_failure_reasons,
                self::$terminal_modes,
                self::$channel_extended_data_type_codes,
                [60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'],
                [60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'],
                [60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
                      61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE'],
                // RFC 4419 - diffie-hellman-group-exchange-sha{1,256}
                [30 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST_OLD',
                      31 => 'NET_SSH2_MSG_KEXDH_GEX_GROUP',
                      32 => 'NET_SSH2_MSG_KEXDH_GEX_INIT',
                      33 => 'NET_SSH2_MSG_KEXDH_GEX_REPLY',
                      34 => 'NET_SSH2_MSG_KEXDH_GEX_REQUEST'],
                // RFC 5656 - Elliptic Curves (for curve25519-sha256@libssh.org)
                [30 => 'NET_SSH2_MSG_KEX_ECDH_INIT',
                      31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY']
            );
        }

        /**
         * Typehint is required due to a bug in Psalm: https://github.com/vimeo/psalm/issues/7508
         * @var \WeakReference<SSH2>|SSH2
         */
        self::$connections[$this->getResourceId()] = class_exists('WeakReference')
            ? \WeakReference::create($this)
            : $this;

        $this->timeout = $timeout;

        if (is_resource($host)) {
            $this->fsock = $host;
            return;
        }

        if (Strings::is_stringable($host)) {
            $this->host = $host;
            $this->port = $port;
        }
    }

    /**
     * Set Crypto Engine Mode
     *
     * Possible $engine values:
     * OpenSSL, mcrypt, Eval, PHP
     *
     * @param int $engine
     */
    public static function setCryptoEngine($engine)
    {
        self::$crypto_engine = $engine;
    }

    /**
     * Send Identification String First
     *
     * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
     * both sides MUST send an identification string". It does not say which side sends it first. In
     * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
     *
     */
    public function sendIdentificationStringFirst()
    {
        $this->send_id_string_first = true;
    }

    /**
     * Send Identification String Last
     *
     * https://tools.ietf.org/html/rfc4253#section-4.2 says "when the connection has been established,
     * both sides MUST send an identification string". It does not say which side sends it first. In
     * theory it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
     *
     */
    public function sendIdentificationStringLast()
    {
        $this->send_id_string_first = false;
    }

    /**
     * Send SSH_MSG_KEXINIT First
     *
     * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
     * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
     * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
     *
     */
    public function sendKEXINITFirst()
    {
        $this->send_kex_first = true;
    }

    /**
     * Send SSH_MSG_KEXINIT Last
     *
     * https://tools.ietf.org/html/rfc4253#section-7.1 says "key exchange begins by each sending
     * sending the [SSH_MSG_KEXINIT] packet". It does not say which side sends it first. In theory
     * it shouldn't matter but it is a fact of life that some SSH servers are simply buggy
     *
     */
    public function sendKEXINITLast()
    {
        $this->send_kex_first = false;
    }

    /**
     * stream_select wrapper
     *
     * Quoting https://stackoverflow.com/a/14262151/569976,
     * "The general approach to `EINTR` is to simply handle the error and retry the operation again"
     *
     * This wrapper does that loop
     */
    private static function stream_select(&$read, &$write, &$except, $seconds, $microseconds = null)
    {
        $remaining = $seconds + $microseconds / 1000000;
        $start = microtime(true);
        while (true) {
            $result = @stream_select($read, $write, $except, $seconds, $microseconds);
            if ($result !== false) {
                return $result;
            }
            $elapsed = microtime(true) - $start;
            $seconds = (int) ($remaining - floor($elapsed));
            $microseconds = (int) (1000000 * ($remaining - $seconds));
            if ($elapsed >= $remaining) {
                return false;
            }
        }
    }

    /**
     * Connect to an SSHv2 server
     *
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @throws \RuntimeException on other errors
     */
    private function connect()
    {
        if ($this->bitmap & self::MASK_CONSTRUCTOR) {
            return;
        }

        $this->bitmap |= self::MASK_CONSTRUCTOR;

        $this->curTimeout = $this->timeout;

        if (!is_resource($this->fsock)) {
            $start = microtime(true);
            // with stream_select a timeout of 0 means that no timeout takes place;
            // with fsockopen a timeout of 0 means that you instantly timeout
            // to resolve this incompatibility a timeout of 100,000 will be used for fsockopen if timeout is 0
            $this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout == 0 ? 100000 : $this->curTimeout);
            if (!$this->fsock) {
                $host = $this->host . ':' . $this->port;
                throw new UnableToConnectException(rtrim("Cannot connect to $host. Error $errno. $errstr"));
            }
            $elapsed = microtime(true) - $start;

            if ($this->curTimeout) {
                $this->curTimeout -= $elapsed;
                if ($this->curTimeout < 0) {
                    throw new \RuntimeException('Connection timed out whilst attempting to open socket connection');
                }
            }

            if (defined('NET_SSH2_LOGGING')) {
                $this->append_log('(fsockopen took ' . round($elapsed, 4) . 's)', '');
            }
        }

        $this->identifier = $this->generate_identifier();

        if ($this->send_id_string_first) {
            $start = microtime(true);
            fputs($this->fsock, $this->identifier . "\r\n");
            $elapsed = round(microtime(true) - $start, 4);
            if (defined('NET_SSH2_LOGGING')) {
                $this->append_log("-> (network: $elapsed)", $this->identifier . "\r\n");
            }
        }

        /* According to the SSH2 specs,

          "The server MAY send other lines of data before sending the version
           string.  Each line SHOULD be terminated by a Carriage Return and Line
           Feed.  Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
           in ISO-10646 UTF-8 [RFC3629] (language is not specified).  Clients
           MUST be able to process such lines." */
        $data = '';
        $totalElapsed = 0;
        while (!feof($this->fsock) && !preg_match('#(.*)^(SSH-(\d\.\d+).*)#ms', $data, $matches)) {
            $line = '';
            while (true) {
                if ($this->curTimeout) {
                    if ($this->curTimeout < 0) {
                        throw new \RuntimeException('Connection timed out whilst receiving server identification string');
                    }
                    $read = [$this->fsock];
                    $write = $except = null;
                    $start = microtime(true);
                    $sec = (int) floor($this->curTimeout);
                    $usec = (int) (1000000 * ($this->curTimeout - $sec));
                    if (static::stream_select($read, $write, $except, $sec, $usec) === false) {
                        throw new \RuntimeException('Connection timed out whilst receiving server identification string');
                    }
                    $elapsed = microtime(true) - $start;
                    $totalElapsed += $elapsed;
                    $this->curTimeout -= $elapsed;
                }

                $temp = stream_get_line($this->fsock, 255, "\n");
                if ($temp === false) {
                    throw new \RuntimeException('Error reading SSH identification string; are you sure you\'re connecting to an SSH server?');
                }

                $line .= $temp;
                if (strlen($temp) == 255) {
                    continue;
                }

                $line .= "\n";

                break;
            }

            $data .= $line;
        }

        if (defined('NET_SSH2_LOGGING')) {
            $this->append_log('<- (network: ' . round($totalElapsed, 4) . ')', $data);
        }

        if (feof($this->fsock)) {
            $this->bitmap = 0;
            throw new ConnectionClosedException('Connection closed by server; are you sure you\'re connected to an SSH server?');
        }

        $extra = $matches[1];

        // earlier the SSH specs were quoted.
        // "The server MAY send other lines of data before sending the version string." they said.
        // the implication of this is that the lines of data before the server string are *not* a part of it
        // getting this right is important because the correct server identifier needs to be fed into the
        // exchange hash for the shared keys to be calculated correctly
        $data = explode("\r\n", trim($data, "\r\n"));
        $this->server_identifier = $data[count($data) - 1];
        if (strlen($extra)) {
            $this->errors[] = $data;
        }

        if (version_compare($matches[3], '1.99', '<')) {
            $this->bitmap = 0;
            throw new UnableToConnectException("Cannot connect to SSH $matches[3] servers");
        }

        // Ubuntu's OpenSSH from 5.8 to 6.9 didn't work with multiple channels. see
        // https://bugs.launchpad.net/ubuntu/+source/openssh/+bug/1334916 for more info.
        // https://lists.ubuntu.com/archives/oneiric-changes/2011-July/005772.html discusses
        // when consolekit was incorporated.
        // https://marc.info/?l=openssh-unix-dev&m=163409903417589&w=2 discusses some of the
        // issues with how Ubuntu incorporated consolekit
        $pattern = '#^SSH-2\.0-OpenSSH_([\d.]+)[^ ]* Ubuntu-.*$#';
        $match = preg_match($pattern, $this->server_identifier, $matches);
        $match = $match && version_compare('5.8', $matches[1], '<=');
        $match = $match && version_compare('6.9', $matches[1], '>=');
        $this->errorOnMultipleChannels = $match;

        if (!$this->send_id_string_first) {
            $start = microtime(true);
            fputs($this->fsock, $this->identifier . "\r\n");
            $elapsed = round(microtime(true) - $start, 4);
            if (defined('NET_SSH2_LOGGING')) {
                $this->append_log("-> (network: $elapsed)", $this->identifier . "\r\n");
            }
        }

        $this->last_packet = microtime(true);

        if (!$this->send_kex_first) {
            $response = $this->get_binary_packet_or_close(NET_SSH2_MSG_KEXINIT);
            $this->key_exchange($response);
        }

        if ($this->send_kex_first) {
            $this->key_exchange();
        }

        $this->bitmap |= self::MASK_CONNECTED;

        return true;
    }

    /**
     * Generates the SSH identifier
     *
     * You should overwrite this method in your own class if you want to use another identifier
     *
     * @return string
     */
    private function generate_identifier()
    {
        $identifier = 'SSH-2.0-phpseclib_3.0';

        $ext = [];
        if (extension_loaded('sodium')) {
            $ext[] = 'libsodium';
        }

        if (extension_loaded('openssl')) {
            $ext[] = 'openssl';
        } elseif (extension_loaded('mcrypt')) {
            $ext[] = 'mcrypt';
        }

        if (extension_loaded('gmp')) {
            $ext[] = 'gmp';
        } elseif (extension_loaded('bcmath')) {
            $ext[] = 'bcmath';
        }

        if (!empty($ext)) {
            $identifier .= ' (' . implode(', ', $ext) . ')';
        }

        return $identifier;
    }

    /**
     * Key Exchange
     *
     * @return bool
     * @param string|bool $kexinit_payload_server optional
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @throws \RuntimeException on other errors
     * @throws NoSupportedAlgorithmsException when none of the algorithms phpseclib has loaded are compatible
     */
    private function key_exchange($kexinit_payload_server = false)
    {
        $this->bytesTransferredSinceLastKEX = 0;

        $preferred = $this->preferred;
        // for the initial key exchange $send_kex is true (no key re-exchange has been started)
        // for phpseclib initiated key exchanges $send_kex is false
        $send_kex = !$this->keyExchangeInProgress;
        $this->keyExchangeInProgress = true;

        $kex_algorithms = isset($preferred['kex']) ?
            $preferred['kex'] :
            SSH2::getSupportedKEXAlgorithms();
        $server_host_key_algorithms = isset($preferred['hostkey']) ?
            $preferred['hostkey'] :
            SSH2::getSupportedHostKeyAlgorithms();
        $s2c_encryption_algorithms = isset($preferred['server_to_client']['crypt']) ?
            $preferred['server_to_client']['crypt'] :
            SSH2::getSupportedEncryptionAlgorithms();
        $c2s_encryption_algorithms = isset($preferred['client_to_server']['crypt']) ?
            $preferred['client_to_server']['crypt'] :
            SSH2::getSupportedEncryptionAlgorithms();
        $s2c_mac_algorithms = isset($preferred['server_to_client']['mac']) ?
            $preferred['server_to_client']['mac'] :
            SSH2::getSupportedMACAlgorithms();
        $c2s_mac_algorithms = isset($preferred['client_to_server']['mac']) ?
            $preferred['client_to_server']['mac'] :
            SSH2::getSupportedMACAlgorithms();
        $s2c_compression_algorithms = isset($preferred['server_to_client']['comp']) ?
            $preferred['server_to_client']['comp'] :
            SSH2::getSupportedCompressionAlgorithms();
        $c2s_compression_algorithms = isset($preferred['client_to_server']['comp']) ?
            $preferred['client_to_server']['comp'] :
            SSH2::getSupportedCompressionAlgorithms();

        $kex_algorithms = array_merge($kex_algorithms, ['ext-info-c', 'kex-strict-c-v00@openssh.com']);

        // some SSH servers have buggy implementations of some of the above algorithms
        switch (true) {
            case $this->server_identifier == 'SSH-2.0-SSHD':
            case substr($this->server_identifier, 0, 13) == 'SSH-2.0-DLINK':
                if (!isset($preferred['server_to_client']['mac'])) {
                    $s2c_mac_algorithms = array_values(array_diff(
                        $s2c_mac_algorithms,
                        ['hmac-sha1-96', 'hmac-md5-96']
                    ));
                }
                if (!isset($preferred['client_to_server']['mac'])) {
                    $c2s_mac_algorithms = array_values(array_diff(
                        $c2s_mac_algorithms,
                        ['hmac-sha1-96', 'hmac-md5-96']
                    ));
                }
                break;
            case substr($this->server_identifier, 0, 24) == 'SSH-2.0-TurboFTP_SERVER_':
                if (!isset($preferred['server_to_client']['crypt'])) {
                    $s2c_encryption_algorithms = array_values(array_diff(
                        $s2c_encryption_algorithms,
                        ['aes128-gcm@openssh.com', 'aes256-gcm@openssh.com']
                    ));
                }
                if (!isset($preferred['client_to_server']['crypt'])) {
                    $c2s_encryption_algorithms = array_values(array_diff(
                        $c2s_encryption_algorithms,
                        ['aes128-gcm@openssh.com', 'aes256-gcm@openssh.com']
                    ));
                }
        }

        $client_cookie = Random::string(16);

        $kexinit_payload_client = pack('Ca*', NET_SSH2_MSG_KEXINIT, $client_cookie);
        $kexinit_payload_client .= Strings::packSSH2(
            'L10bN',
            $kex_algorithms,
            $server_host_key_algorithms,
            $c2s_encryption_algorithms,
            $s2c_encryption_algorithms,
            $c2s_mac_algorithms,
            $s2c_mac_algorithms,
            $c2s_compression_algorithms,
            $s2c_compression_algorithms,
            [], // language, client to server
            [], // language, server to client
            false, // first_kex_packet_follows
            0 // reserved for future extension
        );

        if ($kexinit_payload_server === false && $send_kex) {
            $this->send_binary_packet($kexinit_payload_client);

            while (true) {
                $kexinit_payload_server = $this->get_binary_packet();
                switch (ord($kexinit_payload_server[0])) {
                    case NET_SSH2_MSG_KEXINIT:
                        break 2;
                    case NET_SSH2_MSG_DISCONNECT:
                        return $this->handleDisconnect($kexinit_payload_server);
                }
                $this->kex_buffer[] = $kexinit_payload_server;
            }

            $send_kex = false;
        }

        $response = $kexinit_payload_server;
        Strings::shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
        $server_cookie = Strings::shift($response, 16);

        list(
            $this->kex_algorithms,
            $this->server_host_key_algorithms,
            $this->encryption_algorithms_client_to_server,
            $this->encryption_algorithms_server_to_client,
            $this->mac_algorithms_client_to_server,
            $this->mac_algorithms_server_to_client,
            $this->compression_algorithms_client_to_server,
            $this->compression_algorithms_server_to_client,
            $this->languages_client_to_server,
            $this->languages_server_to_client,
            $first_kex_packet_follows
        ) = Strings::unpackSSH2('L10C', $response);
        if (in_array('kex-strict-s-v00@openssh.com', $this->kex_algorithms)) {
            if ($this->session_id === false) {
                // [kex-strict-s-v00@openssh.com is] only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored
                // if [it is] present in subsequent SSH2_MSG_KEXINIT packets
                $this->strict_kex_flag = true;
                if (count($this->kex_buffer)) {
                    throw new \UnexpectedValueException('Possible Terrapin Attack detected');
                }
            }
        }

        $this->supported_private_key_algorithms = $this->server_host_key_algorithms;

        if ($send_kex) {
            $this->send_binary_packet($kexinit_payload_client);
        }

        // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange

        // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
        // diffie-hellman key exchange as fast as possible
        $decrypt = self::array_intersect_first($s2c_encryption_algorithms, $this->encryption_algorithms_server_to_client);
        if (!$decrypt || ($decryptKeyLength = $this->encryption_algorithm_to_key_size($decrypt)) === null) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
            throw new NoSupportedAlgorithmsException('No compatible server to client encryption algorithms found');
        }

        $encrypt = self::array_intersect_first($c2s_encryption_algorithms, $this->encryption_algorithms_client_to_server);
        if (!$encrypt || ($encryptKeyLength = $this->encryption_algorithm_to_key_size($encrypt)) === null) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
            throw new NoSupportedAlgorithmsException('No compatible client to server encryption algorithms found');
        }

        // through diffie-hellman key exchange a symmetric key is obtained
        $this->kex_algorithm = self::array_intersect_first($kex_algorithms, $this->kex_algorithms);
        if ($this->kex_algorithm === false) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
            throw new NoSupportedAlgorithmsException('No compatible key exchange algorithms found');
        }

        $server_host_key_algorithm = self::array_intersect_first($server_host_key_algorithms, $this->server_host_key_algorithms);
        if ($server_host_key_algorithm === false) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
            throw new NoSupportedAlgorithmsException('No compatible server host key algorithms found');
        }

        $mac_algorithm_out = self::array_intersect_first($c2s_mac_algorithms, $this->mac_algorithms_client_to_server);
        if ($mac_algorithm_out === false) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
            throw new NoSupportedAlgorithmsException('No compatible client to server message authentication algorithms found');
        }

        $mac_algorithm_in = self::array_intersect_first($s2c_mac_algorithms, $this->mac_algorithms_server_to_client);
        if ($mac_algorithm_in === false) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
            throw new NoSupportedAlgorithmsException('No compatible server to client message authentication algorithms found');
        }

        $compression_map = [
            'none' => self::NET_SSH2_COMPRESSION_NONE,
            'zlib' => self::NET_SSH2_COMPRESSION_ZLIB,
            'zlib@openssh.com' => self::NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH
        ];

        $compression_algorithm_in = self::array_intersect_first($s2c_compression_algorithms, $this->compression_algorithms_server_to_client);
        if ($compression_algorithm_in === false) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
            throw new NoSupportedAlgorithmsException('No compatible server to client compression algorithms found');
        }
        $this->decompress = $compression_map[$compression_algorithm_in];

        $compression_algorithm_out = self::array_intersect_first($c2s_compression_algorithms, $this->compression_algorithms_client_to_server);
        if ($compression_algorithm_out === false) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
            throw new NoSupportedAlgorithmsException('No compatible client to server compression algorithms found');
        }
        $this->compress = $compression_map[$compression_algorithm_out];

        switch ($this->kex_algorithm) {
            case 'diffie-hellman-group15-sha512':
            case 'diffie-hellman-group16-sha512':
            case 'diffie-hellman-group17-sha512':
            case 'diffie-hellman-group18-sha512':
            case 'ecdh-sha2-nistp521':
                $kexHash = new Hash('sha512');
                break;
            case 'ecdh-sha2-nistp384':
                $kexHash = new Hash('sha384');
                break;
            case 'diffie-hellman-group-exchange-sha256':
            case 'diffie-hellman-group14-sha256':
            case 'ecdh-sha2-nistp256':
            case 'curve25519-sha256@libssh.org':
            case 'curve25519-sha256':
                $kexHash = new Hash('sha256');
                break;
            default:
                $kexHash = new Hash('sha1');
        }

        // Only relevant in diffie-hellman-group-exchange-sha{1,256}, otherwise empty.

        $exchange_hash_rfc4419 = '';

        if (strpos($this->kex_algorithm, 'curve25519-sha256') === 0 || strpos($this->kex_algorithm, 'ecdh-sha2-nistp') === 0) {
            $curve = strpos($this->kex_algorithm, 'curve25519-sha256') === 0 ?
                'Curve25519' :
                substr($this->kex_algorithm, 10);
            $ourPrivate = EC::createKey($curve);
            $ourPublicBytes = $ourPrivate->getPublicKey()->getEncodedCoordinates();
            $clientKexInitMessage = 'NET_SSH2_MSG_KEX_ECDH_INIT';
            $serverKexReplyMessage = 'NET_SSH2_MSG_KEX_ECDH_REPLY';
        } else {
            if (strpos($this->kex_algorithm, 'diffie-hellman-group-exchange') === 0) {
                $dh_group_sizes_packed = pack(
                    'NNN',
                    $this->kex_dh_group_size_min,
                    $this->kex_dh_group_size_preferred,
                    $this->kex_dh_group_size_max
                );
                $packet = pack(
                    'Ca*',
                    NET_SSH2_MSG_KEXDH_GEX_REQUEST,
                    $dh_group_sizes_packed
                );
                $this->send_binary_packet($packet);
                $this->updateLogHistory('UNKNOWN (34)', 'NET_SSH2_MSG_KEXDH_GEX_REQUEST');

                $response = $this->get_binary_packet_or_close(NET_SSH2_MSG_KEXDH_GEX_GROUP);
                list($type, $primeBytes, $gBytes) = Strings::unpackSSH2('Css', $response);
                $this->updateLogHistory('NET_SSH2_MSG_KEXDH_REPLY', 'NET_SSH2_MSG_KEXDH_GEX_GROUP');
                $prime = new BigInteger($primeBytes, -256);
                $g = new BigInteger($gBytes, -256);

                $exchange_hash_rfc4419 = $dh_group_sizes_packed . Strings::packSSH2(
                    'ss',
                    $primeBytes,
                    $gBytes
                );

                $params = DH::createParameters($prime, $g);
                $clientKexInitMessage = 'NET_SSH2_MSG_KEXDH_GEX_INIT';
                $serverKexReplyMessage = 'NET_SSH2_MSG_KEXDH_GEX_REPLY';
            } else {
                $params = DH::createParameters($this->kex_algorithm);
                $clientKexInitMessage = 'NET_SSH2_MSG_KEXDH_INIT';
                $serverKexReplyMessage = 'NET_SSH2_MSG_KEXDH_REPLY';
            }

            $keyLength = min($kexHash->getLengthInBytes(), max($encryptKeyLength, $decryptKeyLength));

            $ourPrivate = DH::createKey($params, 16 * $keyLength); // 2 * 8 * $keyLength
            $ourPublic = $ourPrivate->getPublicKey()->toBigInteger();
            $ourPublicBytes = $ourPublic->toBytes(true);
        }

        $data = pack('CNa*', constant($clientKexInitMessage), strlen($ourPublicBytes), $ourPublicBytes);

        $this->send_binary_packet($data);

        switch ($clientKexInitMessage) {
            case 'NET_SSH2_MSG_KEX_ECDH_INIT':
                $this->updateLogHistory('NET_SSH2_MSG_KEXDH_INIT', 'NET_SSH2_MSG_KEX_ECDH_INIT');
                break;
            case 'NET_SSH2_MSG_KEXDH_GEX_INIT':
                $this->updateLogHistory('UNKNOWN (32)', 'NET_SSH2_MSG_KEXDH_GEX_INIT');
        }

        $response = $this->get_binary_packet_or_close(constant($serverKexReplyMessage));

        list(
            $type,
            $server_public_host_key,
            $theirPublicBytes,
            $this->signature
        ) = Strings::unpackSSH2('Csss', $response);

        switch ($serverKexReplyMessage) {
            case 'NET_SSH2_MSG_KEX_ECDH_REPLY':
                $this->updateLogHistory('NET_SSH2_MSG_KEXDH_REPLY', 'NET_SSH2_MSG_KEX_ECDH_REPLY');
                break;
            case 'NET_SSH2_MSG_KEXDH_GEX_REPLY':
                $this->updateLogHistory('UNKNOWN (33)', 'NET_SSH2_MSG_KEXDH_GEX_REPLY');
        }

        $this->server_public_host_key = $server_public_host_key;
        list($public_key_format) = Strings::unpackSSH2('s', $server_public_host_key);
        if (strlen($this->signature) < 4) {
            throw new \LengthException('The signature needs at least four bytes');
        }
        $temp = unpack('Nlength', substr($this->signature, 0, 4));
        $this->signature_format = substr($this->signature, 4, $temp['length']);

        $keyBytes = DH::computeSecret($ourPrivate, $theirPublicBytes);
        if (($keyBytes & "\xFF\x80") === "\x00\x00") {
            $keyBytes = substr($keyBytes, 1);
        } elseif (($keyBytes[0] & "\x80") === "\x80") {
            $keyBytes = "\0$keyBytes";
        }

        $this->exchange_hash = Strings::packSSH2(
            's5',
            $this->identifier,
            $this->server_identifier,
            $kexinit_payload_client,
            $kexinit_payload_server,
            $this->server_public_host_key
        );
        $this->exchange_hash .= $exchange_hash_rfc4419;
        $this->exchange_hash .= Strings::packSSH2(
            's3',
            $ourPublicBytes,
            $theirPublicBytes,
            $keyBytes
        );

        $this->exchange_hash = $kexHash->hash($this->exchange_hash);

        if ($this->session_id === false) {
            $this->session_id = $this->exchange_hash;
        }

        switch ($server_host_key_algorithm) {
            case 'rsa-sha2-256':
            case 'rsa-sha2-512':
            //case 'ssh-rsa':
                $expected_key_format = 'ssh-rsa';
                break;
            default:
                $expected_key_format = $server_host_key_algorithm;
        }
        if ($public_key_format != $expected_key_format || $this->signature_format != $server_host_key_algorithm) {
            switch (true) {
                case $this->signature_format == $server_host_key_algorithm:
                case $server_host_key_algorithm != 'rsa-sha2-256' && $server_host_key_algorithm != 'rsa-sha2-512':
                case $this->signature_format != 'ssh-rsa':
                    $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
                    throw new \RuntimeException('Server Host Key Algorithm Mismatch (' . $this->signature_format . ' vs ' . $server_host_key_algorithm . ')');
            }
        }

        $packet = pack('C', NET_SSH2_MSG_NEWKEYS);
        $this->send_binary_packet($packet);
        $this->get_binary_packet_or_close(NET_SSH2_MSG_NEWKEYS);

        $this->keyExchangeInProgress = false;

        if ($this->strict_kex_flag) {
            $this->get_seq_no = $this->send_seq_no = 0;
        }

        $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);

        $this->encrypt = self::encryption_algorithm_to_crypt_instance($encrypt);
        if ($this->encrypt) {
            if (self::$crypto_engine) {
                $this->encrypt->setPreferredEngine(self::$crypto_engine);
            }
            if ($this->encrypt->getBlockLengthInBytes()) {
                $this->encrypt_block_size = $this->encrypt->getBlockLengthInBytes();
            }
            $this->encrypt->disablePadding();

            if ($this->encrypt->usesIV()) {
                $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id);
                while ($this->encrypt_block_size > strlen($iv)) {
                    $iv .= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
                }
                $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
            }

            switch ($encrypt) {
                case 'aes128-gcm@openssh.com':
                case 'aes256-gcm@openssh.com':
                    $nonce = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id);
                    $this->encryptFixedPart = substr($nonce, 0, 4);
                    $this->encryptInvocationCounter = substr($nonce, 4, 8);
                    // fall-through
                case 'chacha20-poly1305@openssh.com':
                    break;
                default:
                    $this->encrypt->enableContinuousBuffer();
            }

            $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id);
            while ($encryptKeyLength > strlen($key)) {
                $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
            }
            switch ($encrypt) {
                case 'chacha20-poly1305@openssh.com':
                    $encryptKeyLength = 32;
                    $this->lengthEncrypt = self::encryption_algorithm_to_crypt_instance($encrypt);
                    $this->lengthEncrypt->setKey(substr($key, 32, 32));
            }
            $this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
            $this->encryptName = $encrypt;
        }

        $this->decrypt = self::encryption_algorithm_to_crypt_instance($decrypt);
        if ($this->decrypt) {
            if (self::$crypto_engine) {
                $this->decrypt->setPreferredEngine(self::$crypto_engine);
            }
            if ($this->decrypt->getBlockLengthInBytes()) {
                $this->decrypt_block_size = $this->decrypt->getBlockLengthInBytes();
            }
            $this->decrypt->disablePadding();

            if ($this->decrypt->usesIV()) {
                $iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id);
                while ($this->decrypt_block_size > strlen($iv)) {
                    $iv .= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
                }
                $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
            }

            switch ($decrypt) {
                case 'aes128-gcm@openssh.com':
                case 'aes256-gcm@openssh.com':
                    // see https://tools.ietf.org/html/rfc5647#section-7.1
                    $nonce = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id);
                    $this->decryptFixedPart = substr($nonce, 0, 4);
                    $this->decryptInvocationCounter = substr($nonce, 4, 8);
                    // fall-through
                case 'chacha20-poly1305@openssh.com':
                    break;
                default:
                    $this->decrypt->enableContinuousBuffer();
            }

            $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id);
            while ($decryptKeyLength > strlen($key)) {
                $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
            }
            switch ($decrypt) {
                case 'chacha20-poly1305@openssh.com':
                    $decryptKeyLength = 32;
                    $this->lengthDecrypt = self::encryption_algorithm_to_crypt_instance($decrypt);
                    $this->lengthDecrypt->setKey(substr($key, 32, 32));
            }
            $this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
            $this->decryptName = $decrypt;
        }

        /* The "arcfour128" algorithm is the RC4 cipher, as described in
           [SCHNEIER], using a 128-bit key.  The first 1536 bytes of keystream
           generated by the cipher MUST be discarded, and the first byte of the
           first encrypted packet MUST be encrypted using the 1537th byte of
           keystream.

           -- http://tools.ietf.org/html/rfc4345#section-4 */
        if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
            $this->encrypt->encrypt(str_repeat("\0", 1536));
        }
        if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
            $this->decrypt->decrypt(str_repeat("\0", 1536));
        }

        if (!$this->encrypt->usesNonce()) {
            list($this->hmac_create, $createKeyLength) = self::mac_algorithm_to_hash_instance($mac_algorithm_out);
        } else {
            $this->hmac_create = new \stdClass();
            $this->hmac_create_name = $mac_algorithm_out;
            //$mac_algorithm_out = 'none';
            $createKeyLength = 0;
        }

        if ($this->hmac_create instanceof Hash) {
            $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id);
            while ($createKeyLength > strlen($key)) {
                $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
            }
            $this->hmac_create->setKey(substr($key, 0, $createKeyLength));
            $this->hmac_create_name = $mac_algorithm_out;
            $this->hmac_create_etm = preg_match('#-etm@openssh\.com$#', $mac_algorithm_out);
        }

        if (!$this->decrypt->usesNonce()) {
            list($this->hmac_check, $checkKeyLength) = self::mac_algorithm_to_hash_instance($mac_algorithm_in);
            $this->hmac_size = $this->hmac_check->getLengthInBytes();
        } else {
            $this->hmac_check = new \stdClass();
            $this->hmac_check_name = $mac_algorithm_in;
            //$mac_algorithm_in = 'none';
            $checkKeyLength = 0;
            $this->hmac_size = 0;
        }

        if ($this->hmac_check instanceof Hash) {
            $key = $kexHash->hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id);
            while ($checkKeyLength > strlen($key)) {
                $key .= $kexHash->hash($keyBytes . $this->exchange_hash . $key);
            }
            $this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
            $this->hmac_check_name = $mac_algorithm_in;
            $this->hmac_check_etm = preg_match('#-etm@openssh\.com$#', $mac_algorithm_in);
        }

        $this->regenerate_compression_context = $this->regenerate_decompression_context = true;

        return true;
    }

    /**
     * Maps an encryption algorithm name to the number of key bytes.
     *
     * @param string $algorithm Name of the encryption algorithm
     * @return int|null Number of bytes as an integer or null for unknown
     */
    private function encryption_algorithm_to_key_size($algorithm)
    {
        if ($this->bad_key_size_fix && self::bad_algorithm_candidate($algorithm)) {
            return 16;
        }

        switch ($algorithm) {
            case 'none':
                return 0;
            case 'aes128-gcm@openssh.com':
            case 'aes128-cbc':
            case 'aes128-ctr':
            case 'arcfour':
            case 'arcfour128':
            case 'blowfish-cbc':
            case 'blowfish-ctr':
            case 'twofish128-cbc':
            case 'twofish128-ctr':
                return 16;
            case '3des-cbc':
            case '3des-ctr':
            case 'aes192-cbc':
            case 'aes192-ctr':
            case 'twofish192-cbc':
            case 'twofish192-ctr':
                return 24;
            case 'aes256-gcm@openssh.com':
            case 'aes256-cbc':
            case 'aes256-ctr':
            case 'arcfour256':
            case 'twofish-cbc':
            case 'twofish256-cbc':
            case 'twofish256-ctr':
                return 32;
            case 'chacha20-poly1305@openssh.com':
                return 64;
        }
        return null;
    }

    /**
     * Maps an encryption algorithm name to an instance of a subclass of
     * \phpseclib3\Crypt\Common\SymmetricKey.
     *
     * @param string $algorithm Name of the encryption algorithm
     * @return SymmetricKey|null
     */
    private static function encryption_algorithm_to_crypt_instance($algorithm)
    {
        switch ($algorithm) {
            case '3des-cbc':
                return new TripleDES('cbc');
            case '3des-ctr':
                return new TripleDES('ctr');
            case 'aes256-cbc':
            case 'aes192-cbc':
            case 'aes128-cbc':
                return new Rijndael('cbc');
            case 'aes256-ctr':
            case 'aes192-ctr':
            case 'aes128-ctr':
                return new Rijndael('ctr');
            case 'blowfish-cbc':
                return new Blowfish('cbc');
            case 'blowfish-ctr':
                return new Blowfish('ctr');
            case 'twofish128-cbc':
            case 'twofish192-cbc':
            case 'twofish256-cbc':
            case 'twofish-cbc':
                return new Twofish('cbc');
            case 'twofish128-ctr':
            case 'twofish192-ctr':
            case 'twofish256-ctr':
                return new Twofish('ctr');
            case 'arcfour':
            case 'arcfour128':
            case 'arcfour256':
                return new RC4();
            case 'aes128-gcm@openssh.com':
            case 'aes256-gcm@openssh.com':
                return new Rijndael('gcm');
            case 'chacha20-poly1305@openssh.com':
                return new ChaCha20();
        }
        return null;
    }

    /**
     * Maps an encryption algorithm name to an instance of a subclass of
     * \phpseclib3\Crypt\Hash.
     *
     * @param string $algorithm Name of the encryption algorithm
     * @return array{Hash, int}|null
     */
    private static function mac_algorithm_to_hash_instance($algorithm)
    {
        switch ($algorithm) {
            case 'umac-64@openssh.com':
            case 'umac-64-etm@openssh.com':
                return [new Hash('umac-64'), 16];
            case 'umac-128@openssh.com':
            case 'umac-128-etm@openssh.com':
                return [new Hash('umac-128'), 16];
            case 'hmac-sha2-512':
            case 'hmac-sha2-512-etm@openssh.com':
                return [new Hash('sha512'), 64];
            case 'hmac-sha2-256':
            case 'hmac-sha2-256-etm@openssh.com':
                return [new Hash('sha256'), 32];
            case 'hmac-sha1':
            case 'hmac-sha1-etm@openssh.com':
                return [new Hash('sha1'), 20];
            case 'hmac-sha1-96':
                return [new Hash('sha1-96'), 20];
            case 'hmac-md5':
                return [new Hash('md5'), 16];
            case 'hmac-md5-96':
                return [new Hash('md5-96'), 16];
        }
    }

    /**
     * Tests whether or not proposed algorithm has a potential for issues
     *
     * @link https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/ssh2-aesctr-openssh.html
     * @link https://bugzilla.mindrot.org/show_bug.cgi?id=1291
     * @param string $algorithm Name of the encryption algorithm
     * @return bool
     */
    private static function bad_algorithm_candidate($algorithm)
    {
        switch ($algorithm) {
            case 'arcfour256':
            case 'aes192-ctr':
            case 'aes256-ctr':
                return true;
        }

        return false;
    }

    /**
     * Login
     *
     * The $password parameter can be a plaintext password, a \phpseclib3\Crypt\RSA|EC|DSA object, a \phpseclib3\System\SSH\Agent object or an array
     *
     * @param string $username
     * @param string|PrivateKey|array[]|Agent|null ...$args
     * @return bool
     * @see self::_login()
     */
    public function login($username, ...$args)
    {
        if (!$this->login_credentials_finalized) {
            $this->auth[] = func_get_args();
        }

        // try logging with 'none' as an authentication method first since that's what
        // PuTTY does
        if (substr($this->server_identifier, 0, 15) != 'SSH-2.0-CoreFTP' && $this->auth_methods_to_continue === null) {
            if ($this->sublogin($username)) {
                return true;
            }
            if (!count($args)) {
                return false;
            }
        }
        return $this->sublogin($username, ...$args);
    }

    /**
     * Login Helper
     *
     * @param string $username
     * @param string|PrivateKey|array[]|Agent|null ...$args
     * @return bool
     * @see self::_login_helper()
     */
    protected function sublogin($username, ...$args)
    {
        if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
            $this->connect();
        }

        if (empty($args)) {
            return $this->login_helper($username);
        }

        foreach ($args as $arg) {
            switch (true) {
                case $arg instanceof PublicKey:
                    throw new \UnexpectedValueException('A PublicKey object was passed to the login method instead of a PrivateKey object');
                case $arg instanceof PrivateKey:
                case $arg instanceof Agent:
                case is_array($arg):
                case Strings::is_stringable($arg):
                    break;
                default:
                    throw new \UnexpectedValueException('$password needs to either be an instance of \phpseclib3\Crypt\Common\PrivateKey, \System\SSH\Agent, an array or a string');
            }
        }

        while (count($args)) {
            if (!$this->auth_methods_to_continue || !$this->smartMFA) {
                $newargs = $args;
                $args = [];
            } else {
                $newargs = [];
                foreach ($this->auth_methods_to_continue as $method) {
                    switch ($method) {
                        case 'publickey':
                            foreach ($args as $key => $arg) {
                                if ($arg instanceof PrivateKey || $arg instanceof Agent) {
                                    $newargs[] = $arg;
                                    unset($args[$key]);
                                    break;
                                }
                            }
                            break;
                        case 'keyboard-interactive':
                            $hasArray = $hasString = false;
                            foreach ($args as $arg) {
                                if ($hasArray || is_array($arg)) {
                                    $hasArray = true;
                                    break;
                                }
                                if ($hasString || Strings::is_stringable($arg)) {
                                    $hasString = true;
                                    break;
                                }
                            }
                            if ($hasArray && $hasString) {
                                foreach ($args as $key => $arg) {
                                    if (is_array($arg)) {
                                        $newargs[] = $arg;
                                        break 2;
                                    }
                                }
                            }
                            // fall-through
                        case 'password':
                            foreach ($args as $key => $arg) {
                                $newargs[] = $arg;
                                unset($args[$key]);
                                break;
                            }
                    }
                }
            }

            if (!count($newargs)) {
                return false;
            }

            foreach ($newargs as $arg) {
                if ($this->login_helper($username, $arg)) {
                    $this->login_credentials_finalized = true;
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Login Helper
     *
     * {@internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
     *           by sending dummy SSH_MSG_IGNORE messages.}
     *
     * @param string $username
     * @param string|AsymmetricKey|array[]|Agent|null ...$args
     * @return bool
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @throws \RuntimeException on other errors
     */
    private function login_helper($username, $password = null)
    {
        if (!($this->bitmap & self::MASK_CONNECTED)) {
            return false;
        }

        if (!($this->bitmap & self::MASK_LOGIN_REQ)) {
            $packet = Strings::packSSH2('Cs', NET_SSH2_MSG_SERVICE_REQUEST, 'ssh-userauth');
            $this->send_binary_packet($packet);

            try {
                $response = $this->get_binary_packet_or_close(NET_SSH2_MSG_SERVICE_ACCEPT);
            } catch (InvalidPacketLengthException $e) {
                // the first opportunity to encounter the "bad key size" error
                if (!$this->bad_key_size_fix && $this->decryptName != null && self::bad_algorithm_candidate($this->decryptName)) {
                    // bad_key_size_fix is only ever re-assigned to true here
                    // retry the connection with that new setting but we'll
                    // only try it once.
                    $this->bad_key_size_fix = true;
                    return $this->reconnect();
                }
                throw $e;
            }

            list($type) = Strings::unpackSSH2('C', $response);
            list($service) = Strings::unpackSSH2('s', $response);

            if ($service != 'ssh-userauth') {
                $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR);
                throw new \UnexpectedValueException('Expected SSH_MSG_SERVICE_ACCEPT');
            }
            $this->bitmap |= self::MASK_LOGIN_REQ;
        }

        if (strlen($this->last_interactive_response)) {
            return !Strings::is_stringable($password) && !is_array($password) ? false : $this->keyboard_interactive_process($password);
        }

        if ($password instanceof PrivateKey) {
            return $this->privatekey_login($username, $password);
        }

        if ($password instanceof Agent) {
            return $this->ssh_agent_login($username, $password);
        }

        if (is_array($password)) {
            if ($this->keyboard_interactive_login($username, $password)) {
                $this->bitmap |= self::MASK_LOGIN;
                return true;
            }
            return false;
        }

        if (!isset($password)) {
            $packet = Strings::packSSH2(
                'Cs3',
                NET_SSH2_MSG_USERAUTH_REQUEST,
                $username,
                'ssh-connection',
                'none'
            );

            $this->send_binary_packet($packet);

            $response = $this->get_binary_packet_or_close();

            list($type) = Strings::unpackSSH2('C', $response);
            switch ($type) {
                case NET_SSH2_MSG_USERAUTH_SUCCESS:
                    $this->bitmap |= self::MASK_LOGIN;
                    return true;
                case NET_SSH2_MSG_USERAUTH_FAILURE:
                    list($auth_methods) = Strings::unpackSSH2('L', $response);
                    $this->auth_methods_to_continue = $auth_methods;
                    // fall-through
                default:
                    return false;
            }
        }

        $packet = Strings::packSSH2(
            'Cs3bs',
            NET_SSH2_MSG_USERAUTH_REQUEST,
            $username,
            'ssh-connection',
            'password',
            false,
            $password
        );

        // remove the username and password from the logged packet
        if (!defined('NET_SSH2_LOGGING')) {
            $logged = null;
        } else {
            $logged = Strings::packSSH2(
                'Cs3bs',
                NET_SSH2_MSG_USERAUTH_REQUEST,
                $username,
                'ssh-connection',
                'password',
                false,
                'password'
            );
        }

        $this->send_binary_packet($packet, $logged);

        $response = $this->get_binary_packet_or_close();
        list($type) = Strings::unpackSSH2('C', $response);
        switch ($type) {
            case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed
                $this->updateLogHistory('UNKNOWN (60)', 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ');

                list($message) = Strings::unpackSSH2('s', $response);
                $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . $message;

                return $this->disconnect_helper(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
            case NET_SSH2_MSG_USERAUTH_FAILURE:
                // can we use keyboard-interactive authentication?  if not then either the login is bad or the server employees
                // multi-factor authentication
                list($auth_methods, $partial_success) = Strings::unpackSSH2('Lb', $response);
                $this->auth_methods_to_continue = $auth_methods;
                if (!$partial_success && in_array('keyboard-interactive', $auth_methods)) {
                    if ($this->keyboard_interactive_login($username, $password)) {
                        $this->bitmap |= self::MASK_LOGIN;
                        return true;
                    }
                    return false;
                }
                return false;
            case NET_SSH2_MSG_USERAUTH_SUCCESS:
                $this->bitmap |= self::MASK_LOGIN;
                return true;
        }

        return false;
    }

    /**
     * Login via keyboard-interactive authentication
     *
     * See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details.  This is not a full-featured keyboard-interactive authenticator.
     *
     * @param string $username
     * @param string|array $password
     * @return bool
     */
    private function keyboard_interactive_login($username, $password)
    {
        $packet = Strings::packSSH2(
            'Cs5',
            NET_SSH2_MSG_USERAUTH_REQUEST,
            $username,
            'ssh-connection',
            'keyboard-interactive',
            '', // language tag
            '' // submethods
        );
        $this->send_binary_packet($packet);

        return $this->keyboard_interactive_process($password);
    }

    /**
     * Handle the keyboard-interactive requests / responses.
     *
     * @param string|array ...$responses
     * @return bool
     * @throws \RuntimeException on connection error
     */
    private function keyboard_interactive_process(...$responses)
    {
        if (strlen($this->last_interactive_response)) {
            $response = $this->last_interactive_response;
        } else {
            $orig = $response = $this->get_binary_packet_or_close();
        }

        list($type) = Strings::unpackSSH2('C', $response);
        switch ($type) {
            case NET_SSH2_MSG_USERAUTH_INFO_REQUEST:
                list(
                    , // name; may be empty
                    , // instruction; may be empty
                    , // language tag; may be empty
                    $num_prompts
                ) = Strings::unpackSSH2('s3N', $response);

                for ($i = 0; $i < count($responses); $i++) {
                    if (is_array($responses[$i])) {
                        foreach ($responses[$i] as $key => $value) {
                            $this->keyboard_requests_responses[$key] = $value;
                        }
                        unset($responses[$i]);
                    }
                }
                $responses = array_values($responses);

                if (isset($this->keyboard_requests_responses)) {
                    for ($i = 0; $i < $num_prompts; $i++) {
                        list(
                            $prompt, // prompt - ie. "Password: "; must not be empty
                            // echo
                        ) = Strings::unpackSSH2('sC', $response);
                        foreach ($this->keyboard_requests_responses as $key => $value) {
                            if (substr($prompt, 0, strlen($key)) == $key) {
                                $responses[] = $value;
                                break;
                            }
                        }
                    }
                }

                // see http://tools.ietf.org/html/rfc4256#section-3.2
                if (strlen($this->last_interactive_response)) {
                    $this->last_interactive_response = '';
                } else {
                    $this->updateLogHistory('UNKNOWN (60)', 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST');
                }

                if (!count($responses) && $num_prompts) {
                    $this->last_interactive_response = $orig;
                    return false;
                }

                /*
                   After obtaining the requested information from the user, the client
                   MUST respond with an SSH_MSG_USERAUTH_INFO_RESPONSE message.
                */
                // see http://tools.ietf.org/html/rfc4256#section-3.4
                $packet = $logged = pack('CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses));
                for ($i = 0; $i < count($responses); $i++) {
                    $packet .= Strings::packSSH2('s', $responses[$i]);
                    $logged .= Strings::packSSH2('s', 'dummy-answer');
                }

                $this->send_binary_packet($packet, $logged);

                $this->updateLogHistory('UNKNOWN (61)', 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE');

                /*
                   After receiving the response, the server MUST send either an
                   SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another
                   SSH_MSG_USERAUTH_INFO_REQUEST message.
                */
                // maybe phpseclib should force close the connection after x request / responses?  unless something like that is done
                // there could be an infinite loop of request / responses.
                return $this->keyboard_interactive_process();
            case NET_SSH2_MSG_USERAUTH_SUCCESS:
                return true;
            case NET_SSH2_MSG_USERAUTH_FAILURE:
                list($auth_methods) = Strings::unpackSSH2('L', $response);
                $this->auth_methods_to_continue = $auth_methods;
                return false;
        }

        return false;
    }

    /**
     * Login with an ssh-agent provided key
     *
     * @param string $username
     * @param Agent $agent
     * @return bool
     */
    private function ssh_agent_login($username, Agent $agent)
    {
        $this->agent = $agent;
        $keys = $agent->requestIdentities();
        $orig_algorithms = $this->supported_private_key_algorithms;
        foreach ($keys as $key) {
            if ($this->privatekey_login($username, $key)) {
                return true;
            }
            $this->supported_private_key_algorithms = $orig_algorithms;
        }

        return false;
    }

    /**
     * Login with an RSA private key
     *
     * {@internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
     *           by sending dummy SSH_MSG_IGNORE messages.}
     *
     * @param string $username
     * @param PrivateKey $privatekey
     * @return bool
     * @throws \RuntimeException on connection error
     */
    private function privatekey_login($username, PrivateKey $privatekey)
    {
        $publickey = $privatekey->getPublicKey();

        if ($publickey instanceof RSA) {
            $privatekey = $privatekey->withPadding(RSA::SIGNATURE_PKCS1);
            $algos = ['rsa-sha2-256', 'rsa-sha2-512', 'ssh-rsa'];
            if (isset($this->preferred['hostkey'])) {
                $algos = array_intersect($algos, $this->preferred['hostkey']);
            }
            $algo = self::array_intersect_first($algos, $this->supported_private_key_algorithms);
            switch ($algo) {
                case 'rsa-sha2-512':
                    $hash = 'sha512';
                    $signatureType = 'rsa-sha2-512';
                    break;
                case 'rsa-sha2-256':
                    $hash = 'sha256';
                    $signatureType = 'rsa-sha2-256';
                    break;
                //case 'ssh-rsa':
                default:
                    $hash = 'sha1';
                    $signatureType = 'ssh-rsa';
            }
        } elseif ($publickey instanceof EC) {
            $privatekey = $privatekey->withSignatureFormat('SSH2');
            $curveName = $privatekey->getCurve();
            switch ($curveName) {
                case 'Ed25519':
                    $hash = 'sha512';
                    $signatureType = 'ssh-ed25519';
                    break;
                case 'secp256r1': // nistp256
                    $hash = 'sha256';
                    $signatureType = 'ecdsa-sha2-nistp256';
                    break;
                case 'secp384r1': // nistp384
                    $hash = 'sha384';
                    $signatureType = 'ecdsa-sha2-nistp384';
                    break;
                case 'secp521r1': // nistp521
                    $hash = 'sha512';
                    $signatureType = 'ecdsa-sha2-nistp521';
                    break;
                default:
                    if (is_array($curveName)) {
                        throw new UnsupportedCurveException('Specified Curves are not supported by SSH2');
                    }
                    throw new UnsupportedCurveException('Named Curve of ' . $curveName . ' is not supported by phpseclib3\'s SSH2 implementation');
            }
        } elseif ($publickey instanceof DSA) {
            $privatekey = $privatekey->withSignatureFormat('SSH2');
            $hash = 'sha1';
            $signatureType = 'ssh-dss';
        } else {
            throw new UnsupportedAlgorithmException('Please use either an RSA key, an EC one or a DSA key');
        }

        $publickeyStr = $publickey->toString('OpenSSH', ['binary' => true]);

        $part1 = Strings::packSSH2(
            'Csss',
            NET_SSH2_MSG_USERAUTH_REQUEST,
            $username,
            'ssh-connection',
            'publickey'
        );
        $part2 = Strings::packSSH2('ss', $signatureType, $publickeyStr);

        $packet = $part1 . chr(0) . $part2;
        $this->send_binary_packet($packet);

        $response = $this->get_binary_packet_or_close(
            NET_SSH2_MSG_USERAUTH_SUCCESS,
            NET_SSH2_MSG_USERAUTH_FAILURE,
            NET_SSH2_MSG_USERAUTH_PK_OK
        );

        list($type) = Strings::unpackSSH2('C', $response);
        switch ($type) {
            case NET_SSH2_MSG_USERAUTH_FAILURE:
                list($auth_methods) = Strings::unpackSSH2('L', $response);
                if (in_array('publickey', $auth_methods) && substr($signatureType, 0, 9) == 'rsa-sha2-') {
                    $this->supported_private_key_algorithms = array_diff($this->supported_private_key_algorithms, ['rsa-sha2-256', 'rsa-sha2-512']);
                    return $this->privatekey_login($username, $privatekey);
                }
                $this->auth_methods_to_continue = $auth_methods;
                $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE';
                return false;
            case NET_SSH2_MSG_USERAUTH_PK_OK:
                // we'll just take it on faith that the public key blob and the public key algorithm name are as
                // they should be
                $this->updateLogHistory('UNKNOWN (60)', 'NET_SSH2_MSG_USERAUTH_PK_OK');
                break;
            case NET_SSH2_MSG_USERAUTH_SUCCESS:
                $this->bitmap |= self::MASK_LOGIN;
                return true;
        }

        $packet = $part1 . chr(1) . $part2;
        $privatekey = $privatekey->withHash($hash);
        $signature = $privatekey->sign(Strings::packSSH2('s', $this->session_id) . $packet);
        if ($publickey instanceof RSA) {
            $signature = Strings::packSSH2('ss', $signatureType, $signature);
        }
        $packet .= Strings::packSSH2('s', $signature);

        $this->send_binary_packet($packet);

        $response = $this->get_binary_packet_or_close(
            NET_SSH2_MSG_USERAUTH_SUCCESS,
            NET_SSH2_MSG_USERAUTH_FAILURE
        );

        list($type) = Strings::unpackSSH2('C', $response);
        switch ($type) {
            case NET_SSH2_MSG_USERAUTH_FAILURE:
                // either the login is bad or the server employs multi-factor authentication
                list($auth_methods) = Strings::unpackSSH2('L', $response);
                $this->auth_methods_to_continue = $auth_methods;
                return false;
            case NET_SSH2_MSG_USERAUTH_SUCCESS:
                $this->bitmap |= self::MASK_LOGIN;
                return true;
        }
    }

    /**
     * Return the currently configured timeout
     *
     * @return int
     */
    public function getTimeout()
    {
        return $this->timeout;
    }

    /**
     * Set Timeout
     *
     * $ssh->exec('ping 127.0.0.1'); on a Linux host will never return and will run indefinitely.  setTimeout() makes it so it'll timeout.
     * Setting $timeout to false or 0 will revert to the default socket timeout.
     *
     * @param mixed $timeout
     */
    public function setTimeout($timeout)
    {
        $this->timeout = $this->curTimeout = $timeout;
    }

    /**
     * Set Keep Alive
     *
     * Sends an SSH2_MSG_IGNORE message every x seconds, if x is a positive non-zero number.
     *
     * @param int $interval
     */
    public function setKeepAlive($interval)
    {
        $this->keepAlive = $interval;
    }

    /**
     * Get the output from stdError
     *
     */
    public function getStdError()
    {
        return $this->stdErrorLog;
    }

    /**
     * Execute Command
     *
     * If $callback is set to false then \phpseclib3\Net\SSH2::get_channel_packet(self::CHANNEL_EXEC) will need to be called manually.
     * In all likelihood, this is not a feature you want to be taking advantage of.
     *
     * @param string $command
     * @param callable $callback
     * @return string|bool
     * @psalm-return ($callback is callable ? bool : string|bool)
     * @throws \RuntimeException on connection error
     */
    public function exec($command, $callback = null)
    {
        $this->curTimeout = $this->timeout;
        $this->is_timeout = false;
        $this->stdErrorLog = '';

        if (!$this->isAuthenticated()) {
            return false;
        }

        //if ($this->isPTYOpen()) {
        //    throw new \RuntimeException('If you want to run multiple exec()\'s you will need to disable (and re-enable if appropriate) a PTY for each one.');
        //}

        $this->open_channel(self::CHANNEL_EXEC);

        if ($this->request_pty === true) {
            $terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
            $packet = Strings::packSSH2(
                'CNsCsN4s',
                NET_SSH2_MSG_CHANNEL_REQUEST,
                $this->server_channels[self::CHANNEL_EXEC],
                'pty-req',
                1,
                $this->term,
                $this->windowColumns,
                $this->windowRows,
                0,
                0,
                $terminal_modes
            );

            $this->send_binary_packet($packet);

            $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;
            if (!$this->get_channel_packet(self::CHANNEL_EXEC)) {
                $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
                throw new \RuntimeException('Unable to request pseudo-terminal');
            }
        }

        // sending a pty-req SSH_MSG_CHANNEL_REQUEST message is unnecessary and, in fact, in most cases, slows things
        // down.  the one place where it might be desirable is if you're doing something like \phpseclib3\Net\SSH2::exec('ping localhost &').
        // with a pty-req SSH_MSG_CHANNEL_REQUEST, exec() will return immediately and the ping process will then
        // then immediately terminate.  without such a request exec() will loop indefinitely.  the ping process won't end but
        // neither will your script.

        // although, in theory, the size of SSH_MSG_CHANNEL_REQUEST could exceed the maximum packet size established by
        // SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the
        // "maximum size of an individual data packet". ie. SSH_MSG_CHANNEL_DATA.  RFC4254#section-5.2 corroborates.
        $packet = Strings::packSSH2(
            'CNsCs',
            NET_SSH2_MSG_CHANNEL_REQUEST,
            $this->server_channels[self::CHANNEL_EXEC],
            'exec',
            1,
            $command
        );
        $this->send_binary_packet($packet);

        $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;

        if (!$this->get_channel_packet(self::CHANNEL_EXEC)) {
            return false;
        }

        $this->channel_status[self::CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA;

        if ($this->request_pty === true) {
            $this->channel_id_last_interactive = self::CHANNEL_EXEC;
            return true;
        }
        if ($callback === false) {
            return true;
        }

        $output = '';
        while (true) {
            $temp = $this->get_channel_packet(self::CHANNEL_EXEC);
            switch (true) {
                case $temp === true:
                    return is_callable($callback) ? true : $output;
                case $temp === false:
                    return false;
                default:
                    if (is_callable($callback)) {
                        if ($callback($temp) === true) {
                            $this->close_channel(self::CHANNEL_EXEC);
                            return true;
                        }
                    } else {
                        $output .= $temp;
                    }
            }
        }
    }

    /**
     * How many channels are currently open?
     *
     * @return int
     */
    public function getOpenChannelCount()
    {
        return $this->channelCount;
    }

    /**
     * Opens a channel
     *
     * @param string $channel
     * @param bool $skip_extended
     * @return bool
     */
    protected function open_channel($channel, $skip_extended = false)
    {
        if (isset($this->channel_status[$channel])) {
            throw new \RuntimeException('Please close the channel (' . $channel . ') before trying to open it again');
        }

        $this->channelCount++;

        if ($this->channelCount > 1 && $this->errorOnMultipleChannels) {
            throw new \RuntimeException("Ubuntu's OpenSSH from 5.8 to 6.9 doesn't work with multiple channels");
        }

        // RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to
        // be adjusted".  0x7FFFFFFF is, at 2GB, the max size.  technically, it should probably be decremented, but,
        // honestly, if you're transferring more than 2GB, you probably shouldn't be using phpseclib, anyway.
        // see http://tools.ietf.org/html/rfc4254#section-5.2 for more info
        $this->window_size_server_to_client[$channel] = $this->window_size;
        // 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy
        // uses 0x4000, that's what will be used here, as well.
        $packet_size = 0x4000;

        $packet = Strings::packSSH2(
            'CsN3',
            NET_SSH2_MSG_CHANNEL_OPEN,
            'session',
            $channel,
            $this->window_size_server_to_client[$channel],
            $packet_size
        );

        $this->send_binary_packet($packet);

        $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_OPEN;

        return $this->get_channel_packet($channel, $skip_extended);
    }

    /**
     * Creates an interactive shell
     *
     * Returns bool(true) if the shell was opened.
     * Returns bool(false) if the shell was already open.
     *
     * @see self::isShellOpen()
     * @see self::read()
     * @see self::write()
     * @return bool
     * @throws InsufficientSetupException if not authenticated
     * @throws \UnexpectedValueException on receipt of unexpected packets
     * @throws \RuntimeException on other errors
     */
    public function openShell()
    {
        if (!$this->isAuthenticated()) {
            throw new InsufficientSetupException('Operation disallowed prior to login()');
        }

        $this->open_channel(self::CHANNEL_SHELL);

        $terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
        $packet = Strings::packSSH2(
            'CNsbsN4s',
            NET_SSH2_MSG_CHANNEL_REQUEST,
            $this->server_channels[self::CHANNEL_SHELL],
            'pty-req',
            true, // want reply
            $this->term,
            $this->windowColumns,
            $this->windowRows,
            0,
            0,
            $terminal_modes
        );

        $this->send_binary_packet($packet);

        $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST;

        if (!$this->get_channel_packet(self::CHANNEL_SHELL)) {
            throw new \RuntimeException('Unable to request pty');
        }

        $packet = Strings::packSSH2(
            'CNsb',
            NET_SSH2_MSG_CHANNEL_REQUEST,
            $this->server_channels[self::CHANNEL_SHELL],
            'shell',
            true // want reply
        );
        $this->send_binary_packet($packet);

        $response = $this->get_channel_packet(self::CHANNEL_SHELL);
        if ($response === false) {
            throw new \RuntimeException('Unable to request shell');
        }

        $this->channel_status[self::CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA;

        $this->channel_id_last_interactive = self::CHANNEL_SHELL;

        $this->bitmap |= self::MASK_SHELL;

        return true;
    }

    /**
     * Return the channel to be used with read(), write(), and reset(), if none were specified
     * @deprecated for lack of transparency in intended channel target, to be potentially replaced
     *             with method which guarantees open-ness of all yielded channels and throws
     *             error for multiple open channels
     * @see self::read()
     * @see self::write()
     * @return int
     */
    private function get_interactive_channel()
    {
        switch (true) {
            case $this->is_channel_status_data(self::CHANNEL_SUBSYSTEM):
                return self::CHANNEL_SUBSYSTEM;
            case $this->is_channel_status_data(self::CHANNEL_EXEC):
                return self::CHANNEL_EXEC;
            default:
                return self::CHANNEL_SHELL;
        }
    }

    /**
     * Indicates the DATA status on the given channel
     *
     * @param int $channel The channel number to evaluate
     * @return bool
     */
    private function is_channel_status_data($channel)
    {
        return isset($this->channel_status[$channel]) && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA;
    }

    /**
     * Return an available open channel
     *
     * @return int
     */
    private function get_open_channel()
    {
        $channel = self::CHANNEL_EXEC;
        do {
            if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_OPEN) {
                return $channel;
            }
        } while ($channel++ < self::CHANNEL_SUBSYSTEM);

        return false;
    }

    /**
     * Request agent forwarding of remote server
     *
     * @return bool
     */
    public function requestAgentForwarding()
    {
        $request_channel = $this->get_open_channel();
        if ($request_channel === false) {
            return false;
        }

        $packet = Strings::packSSH2(
            'CNsC',
            NET_SSH2_MSG_CHANNEL_REQUEST,
            $this->server_channels[$request_channel],
            'auth-agent-req@openssh.com',
            1
        );

        $this->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST;

        $this->send_binary_packet($packet);

        if (!$this->get_channel_packet($request_channel)) {
            return false;
        }

        $this->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN;

        return true;
    }

    /**
     * Returns the output of an interactive shell
     *
     * Returns when there's a match for $expect, which can take the form of a string literal or,
     * if $mode == self::READ_REGEX, a regular expression.
     *
     * If not specifying a channel, an open interactive channel will be selected, or, if there are
     * no open channels, an interactive shell will be created. If there are multiple open
     * interactive channels, a legacy behavior will apply in which channel selection prioritizes
     * an active subsystem, the exec pty, and, lastly, the shell. If using multiple interactive
     * channels, callers are discouraged from relying on this legacy behavior and should specify
     * the intended channel.
     *
     * @see self::write()
     * @param string $expect
     * @param int $mode One of the self::READ_* constants
     * @param int|null $channel Channel id returned by self::getInteractiveChannelId()
     * @return string|bool|null
     * @throws \RuntimeException on connection error
     * @throws InsufficientSetupException on unexpected channel status, possibly due to closure
     */
    public function read($expect = '', $mode = self::READ_SIMPLE, $channel = null)
    {
        if (!$this->isAuthenticated()) {
            throw new InsufficientSetupException('Operation disallowed prior to login()');
        }

        $this->curTimeout = $this->timeout;
        $this->is_timeout = false;

        if ($channel === null) {
            $channel = $this->get_interactive_channel();
        }

        if (!$this->is_channel_status_data($channel) && empty($this->channel_buffers[$channel])) {
            if ($channel != self::CHANNEL_SHELL) {
                throw new InsufficientSetupException('Data is not available on channel');
            } elseif (!$this->openShell()) {
                throw new \RuntimeException('Unable to initiate an interactive shell session');
            }
        }

        if ($mode == self::READ_NEXT) {
            return $this->get_channel_packet($channel);
        }

        $match = $expect;
        while (true) {
            if ($mode == self::READ_REGEX) {
                preg_match($expect, substr($this->interactiveBuffer, -1024), $matches);
                $match = isset($matches[0]) ? $matches[0] : '';
            }
            $pos = strlen($match) ? strpos($this->interactiveBuffer, $match) : false;
            if ($pos !== false) {
                return Strings::shift($this->interactiveBuffer, $pos + strlen($match));
            }
            $response = $this->get_channel_packet($channel);
            if ($response === true) {
                return Strings::shift($this->interactiveBuffer, strlen($this->interactiveBuffer));
            }

            $this->interactiveBuffer .= $response;
        }
    }

    /**
     * Inputs a command into an interactive shell.
     *
     * If not specifying a channel, an open interactive channel will be selected, or, if there are
     * no open channels, an interactive shell will be created. If there are multiple open
     * interactive channels, a legacy behavior will apply in which channel selection prioritizes
     * an active subsystem, the exec pty, and, lastly, the shell. If using multiple interactive
     * channels, callers are discouraged from relying on this legacy behavior and should specify
     * the intended channel.
     *
     * @see SSH2::read()
     * @param string $cmd
     * @param int|null $channel Channel id returned by self::getInteractiveChannelId()
     * @return void
     * @throws \RuntimeException on connection error
     * @throws InsufficientSetupException on unexpected channel status, possibly due to closure
     * @throws TimeoutException if the write could not be completed within the requested self::setTimeout()
     */
    public function write($cmd, $channel = null)
    {
        if (!$this->isAuthenticated()) {
            throw new InsufficientSetupException('Operation disallowed prior to login()');
        }

        if ($channel === null) {
            $channel = $this->get_interactive_channel();
        }

        if (!$this->is_channel_status_data($channel)) {
            if ($channel != self::CHANNEL_SHELL) {
                throw new InsufficientSetupException('Data is not available on channel');
            } elseif (!$this->openShell()) {
                throw new \RuntimeException('Unable to initiate an interactive shell session');
            }
        }

        $this->curTimeout = $this->timeout;
        $this->is_timeout = false;
        $this->send_channel_packet($channel, $cmd);
    }

    /**
     * Start a subsystem.
     *
     * Right now only one subsystem at a time is supported. To support multiple subsystem's stopSubsystem() could accept
     * a string that contained the name of the subsystem, but at that point, only one subsystem of each type could be opened.
     * To support multiple subsystem's of the same name maybe it'd be best if startSubsystem() generated a new channel id and
     * returns that and then that that was passed into stopSubsystem() but that'll be saved for a future date and implemented
     * if there's sufficient demand for such a feature.
     *
     * @see self::stopSubsystem()
     * @param string $subsystem
     * @return bool
     */
    public function startSubsystem($subsystem)
    {
        $this->open_channel(self::CHANNEL_SUBSYSTEM);

        $packet = Strings::packSSH2(
            'CNsCs',
            NET_SSH2_MSG_CHANNEL_REQUEST,
            $this->server_channels[self::CHANNEL_SUBSYSTEM],
            'subsystem',
            1,
            $subsystem
        );
        $this->send_binary_packet($packet);

        $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST;

        if (!$this->get_channel_packet(self::CHANNEL_SUBSYSTEM)) {
            return false;
        }

        $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_DATA;

        $this->channel_id_last_interactive = self::CHANNEL_SUBSYSTEM;

        return true;
    }

    /**
     * Stops a subsystem.
     *
     * @see self::startSubsystem()
     * @return bool
     */
    public function stopSubsystem()
    {
        if ($this->isInteractiveChannelOpen(self::CHANNEL_SUBSYSTEM)) {
            $this->close_channel(self::CHANNEL_SUBSYSTEM);
        }
        return true;
    }

    /**
     * Closes a channel
     *
     * If read() timed out you might want to just close the channel and have it auto-restart on the next read() call
     *
     * If not specifying a channel, an open interactive channel will be selected. If there are
     * multiple open interactive channels, a legacy behavior will apply in which channel selection
     * prioritizes an active subsystem, the exec pty, and, lastly, the shell. If using multiple
     * interactive channels, callers are discouraged from relying on this legacy behavior and
     * should specify the intended channel.
     *
     * @param int|null $channel Channel id returned by self::getInteractiveChannelId()
     * @return void
     */
    public function reset($channel = null)
    {
        if ($channel === null) {
            $channel = $this->get_interactive_channel();
        }
        if ($this->isInteractiveChannelOpen($channel)) {
            $this->close_channel($channel);
        }
    }

    /**
     * Send EOF on a channel
     *
     * Sends an EOF to the stream; this is typically used to close standard
     * input, while keeping output and error alive.
     *
     * @param int|null $channel Channel id returned by self::getInteractiveChannelId()
     * @return void
     */
    public function sendEOF($channel = null)
    {
        if ($channel === null) {
            $channel = $this->get_interactive_channel();
        }

        $excludeStatuses = [NET_SSH2_MSG_CHANNEL_EOF, NET_SSH2_MSG_CHANNEL_CLOSE];
        if (isset($this->channel_status[$channel]) && !in_array($this->channel_status[$channel], $excludeStatuses)) {
            $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$channel]));
        }
    }

    /**
     * Is timeout?
     *
     * Did exec() or read() return because they timed out or because they encountered the end?
     *
     */
    public function isTimeout()
    {
        return $this->is_timeout;
    }

    /**
     * Disconnect
     *
     */
    public function disconnect()
    {
        $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
        if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
            fclose($this->realtime_log_file);
        }
        unset(self::$connections[$this->getResourceId()]);
    }

    /**
     * Destructor.
     *
     * Will be called, automatically, if you're supporting just PHP5.  If you're supporting PHP4, you'll need to call
     * disconnect().
     *
     */
    public function __destruct()
    {
        $this->disconnect();
    }

    /**
     * Is the connection still active?
     *
     * $level has 3x possible values:
     * 0 (default): phpseclib takes a passive approach to see if the connection is still active by calling feof()
     *    on the socket
     * 1: phpseclib takes an active approach to see if the connection is still active by sending an SSH_MSG_IGNORE
     *    packet that doesn't require a response
     * 2: phpseclib takes an active approach to see if the connection is still active by sending an SSH_MSG_CHANNEL_OPEN
     *    packet and imediately trying to close that channel. some routers, in particular, however, will only let you
     *    open one channel, so this approach could yield false positives
     *
     * @param int $level
     * @return bool
     */
    public function isConnected($level = 0)
    {
        if (!is_int($level) || $level < 0 || $level > 2) {
            throw new \InvalidArgumentException('$level must be 0, 1 or 2');
        }

        if ($level == 0) {
            return ($this->bitmap & self::MASK_CONNECTED) && is_resource($this->fsock) && !feof($this->fsock);
        }
        try {
            if ($level == 1) {
                $this->send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0));
            } else {
                $this->open_channel(self::CHANNEL_KEEP_ALIVE);
                $this->close_channel(self::CHANNEL_KEEP_ALIVE);
            }
            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * Have you successfully been logged in?
     *
     * @return bool
     */
    public function isAuthenticated()
    {
        return (bool) ($this->bitmap & self::MASK_LOGIN);
    }

    /**
     * Is the interactive shell active?
     *
     * @return bool
     */
    public function isShellOpen()
    {
        return $this->isInteractiveChannelOpen(self::CHANNEL_SHELL);
    }

    /**
     * Is the exec pty active?
     *
     * @return bool
     */
    public function isPTYOpen()
    {
        return $this->isInteractiveChannelOpen(self::CHANNEL_EXEC);
    }

    /**
     * Is the given interactive channel active?
     *
     * @param int $channel Channel id returned by self::getInteractiveChannelId()
     * @return bool
     */
    public function isInteractiveChannelOpen($channel)
    {
        return $this->isAuthenticated() && $this->is_channel_status_data($channel);
    }

    /**
     * Returns a channel identifier, presently of the last interactive channel opened, regardless of current status.
     * Returns 0 if no interactive channel has been opened.
     *
     * @see self::isInteractiveChannelOpen()
     * @return int
     */
    public function getInteractiveChannelId()
    {
        return $this->channel_id_last_interactive;
    }

    /**
     * Pings a server connection, or tries to reconnect if the connection has gone down
     *
     * Inspired by http://php.net/manual/en/mysqli.ping.php
     *
     * @return bool
     */
    public function ping()
    {
        if (!$this->isAuthenticated()) {
            if (!empty($this->auth)) {
                return $this->reconnect();
            }
            return false;
        }

        try {
            $this->open_channel(self::CHANNEL_KEEP_ALIVE);
        } catch (\RuntimeException $e) {
            return $this->reconnect();
        }

        $this->close_channel(self::CHANNEL_KEEP_ALIVE);
        return true;
    }

    /**
     * In situ reconnect method
     *
     * @return boolean
     */
    private function reconnect()
    {
        $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
        $this->connect();
        foreach ($this->auth as $auth) {
            $result = $this->login(...$auth);
        }
        return $result;
    }

    /**
     * Resets a connection for re-use
     */
    protected function reset_connection()
    {
        if (is_resource($this->fsock) && get_resource_type($this->fsock) === 'stream') {
            fclose($this->fsock);
        }
        $this->fsock = null;
        $this->bitmap = 0;
        $this->binary_packet_buffer = null;
        $this->decrypt = $this->encrypt = false;
        $this->decrypt_block_size = $this->encrypt_block_size = 8;
        $this->hmac_check = $this->hmac_create = false;
        $this->hmac_size = false;
        $this->session_id = false;
        $this->last_packet = null;
        $this->get_seq_no = $this->send_seq_no = 0;
        $this->channel_status = [];
        $this->channel_id_last_interactive = 0;
        $this->channel_buffers = [];
        $this->channel_buffers_write = [];
    }

    /**
     * @return int[] second and microsecond stream timeout options based on user-requested timeout and keep-alive, or the default socket timeout by default, which mirrors PHP socket streams.
     */
    private function get_stream_timeout()
    {
        $sec = ini_get('default_socket_timeout');
        $usec = 0;
        if ($this->curTimeout > 0) {
            $sec = (int) floor($this->curTimeout);
            $usec = (int) (1000000 * ($this->curTimeout - $sec));
        }
        if ($this->keepAlive > 0) {
            $elapsed = microtime(true) - $this->last_packet;
            $timeout = max($this->keepAlive - $elapsed, 0);
            if (!$this->curTimeout || $timeout < $this->curTimeout) {
                $sec = (int) floor($timeout);
                $usec = (int) (1000000 * ($timeout - $sec));
            }
        }
        return [$sec, $usec];
    }

    /**
     * Retrieves the next packet with added timeout and type handling
     *
     * @param string $message_types Message types to enforce in response, closing if not met
     * @return string
     * @throws ConnectionClosedException If an error has occurred preventing read of the next packet
     */
    private function get_binary_packet_or_close(...$message_types)
    {
        try {
            $packet = $this->get_binary_packet();
            if (count($message_types) > 0 && !in_array(ord($packet[0]), $message_types)) {
                $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR);
                throw new ConnectionClosedException('Bad message type. Expected: #'
                    . implode(', #', $message_types) . '. Got: #' . ord($packet[0]));
            }
            return $packet;
        } catch (TimeoutException $e) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
            throw new ConnectionClosedException('Connection closed due to timeout');
        }
    }

    /**
     * Gets Binary Packets
     *
     * See '6. Binary Packet Protocol' of rfc4253 for more info.
     *
     * @see self::_send_binary_packet()
     * @return string
     * @throws TimeoutException If user requested timeout was reached while waiting for next packet
     * @throws ConnectionClosedException If an error has occurred preventing read of the next packet
     */
    private function get_binary_packet()
    {
        if (!is_resource($this->fsock)) {
            throw new \InvalidArgumentException('fsock is not a resource.');
        }
        if (!$this->keyExchangeInProgress && count($this->kex_buffer)) {
            return $this->filter(array_shift($this->kex_buffer));
        }
        if ($this->binary_packet_buffer == null) {
            // buffer the packet to permit continued reads across timeouts
            $this->binary_packet_buffer = (object) [
                'read_time' => 0, // the time to read the packet from the socket
                'raw' => '', // the raw payload read from the socket
                'plain' => '', // the packet in plain text, excluding packet_length header
                'packet_length' => null, // the packet_length value pulled from the payload
                'size' => $this->decrypt_block_size, // the total size of this packet to be read from the socket
                                                     // initialize to read single block until packet_length is available
            ];
        }
        $packet = $this->binary_packet_buffer;
        while (strlen($packet->raw) < $packet->size) {
            if (feof($this->fsock)) {
                $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
                throw new ConnectionClosedException('Connection closed by server');
            }
            if ($this->curTimeout < 0) {
                $this->is_timeout = true;
                throw new TimeoutException('Timed out waiting for server');
            }
            $this->send_keep_alive();

            list($sec, $usec) = $this->get_stream_timeout();
            stream_set_timeout($this->fsock, $sec, $usec);
            $start = microtime(true);
            $raw = stream_get_contents($this->fsock, $packet->size - strlen($packet->raw));
            $elapsed = microtime(true) - $start;
            $packet->read_time += $elapsed;
            if ($this->curTimeout > 0) {
                $this->curTimeout -= $elapsed;
            }
            if ($raw === false) {
                $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
                throw new ConnectionClosedException('Connection closed by server');
            } elseif (!strlen($raw)) {
                continue;
            }
            $packet->raw .= $raw;
            if (!$packet->packet_length) {
                $this->get_binary_packet_size($packet);
            }
        }

        if (strlen($packet->raw) != $packet->size) {
            throw new \RuntimeException('Size of packet was not expected length');
        }
        // destroy buffer as packet represents the entire payload and should be processed in full
        $this->binary_packet_buffer = null;
        // copy the raw payload, so as not to destroy original
        $raw = $packet->raw;
        if ($this->hmac_check instanceof Hash) {
            $hmac = Strings::pop($raw, $this->hmac_size);
        }
        $packet_length_header_size = 4;
        if ($this->decrypt) {
            switch ($this->decryptName) {
                case 'aes128-gcm@openssh.com':
                case 'aes256-gcm@openssh.com':
                    $this->decrypt->setNonce(
                        $this->decryptFixedPart .
                        $this->decryptInvocationCounter
                    );
                    Strings::increment_str($this->decryptInvocationCounter);
                    $this->decrypt->setAAD(Strings::shift($raw, $packet_length_header_size));
                    $this->decrypt->setTag(Strings::pop($raw, $this->decrypt_block_size));
                    $packet->plain = $this->decrypt->decrypt($raw);
                    break;
                case 'chacha20-poly1305@openssh.com':
                    // This should be impossible, but we are checking anyway to narrow the type for Psalm.
                    if (!($this->decrypt instanceof ChaCha20)) {
                        throw new \LogicException('$this->decrypt is not a ' . ChaCha20::class);
                    }
                    $this->decrypt->setNonce(pack('N2', 0, $this->get_seq_no));
                    $this->decrypt->setCounter(0);
                    // this is the same approach that's implemented in Salsa20::createPoly1305Key()
                    // but we don't want to use the same AEAD construction that RFC8439 describes
                    // for ChaCha20-Poly1305 so we won't rely on it (see Salsa20::poly1305())
                    $this->decrypt->setPoly1305Key(
                        $this->decrypt->encrypt(str_repeat("\0", 32))
                    );
                    $this->decrypt->setAAD(Strings::shift($raw, $packet_length_header_size));
                    $this->decrypt->setCounter(1);
                    $this->decrypt->setTag(Strings::pop($raw, 16));
                    $packet->plain = $this->decrypt->decrypt($raw);
                    break;
                default:
                    if (!$this->hmac_check instanceof Hash || !$this->hmac_check_etm) {
                        // first block was already decrypted for contained packet_length header
                        Strings::shift($raw, $this->decrypt_block_size);
                        if (strlen($raw) > 0) {
                            $packet->plain .= $this->decrypt->decrypt($raw);
                        }
                    } else {
                        Strings::shift($raw, $packet_length_header_size);
                        $packet->plain = $this->decrypt->decrypt($raw);
                    }
                    break;
            }
        } else {
            Strings::shift($raw, $packet_length_header_size);
            $packet->plain = $raw;
        }
        if ($this->hmac_check instanceof Hash) {
            $reconstructed = !$this->hmac_check_etm ?
                pack('Na*', $packet->packet_length, $packet->plain) :
                substr($packet->raw, 0, -$this->hmac_size);
            if (($this->hmac_check->getHash() & "\xFF\xFF\xFF\xFF") == 'umac') {
                $this->hmac_check->setNonce("\0\0\0\0" . pack('N', $this->get_seq_no));
                if (!hash_equals($hmac, $this->hmac_check->hash($reconstructed))) {
                    $this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR);
                    throw new ConnectionClosedException('Invalid UMAC');
                }
            } else {
                if (!hash_equals($hmac, $this->hmac_check->hash(pack('Na*', $this->get_seq_no, $reconstructed)))) {
                    $this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR);
                    throw new ConnectionClosedException('Invalid HMAC');
                }
            }
        }
        $padding_length = 0;
        $payload = $packet->plain;
        $padding_length = unpack('Cpadding_length', Strings::shift($payload, 1))['padding_length'];
        if ($padding_length > 0) {
            Strings::pop($payload, $padding_length);
        }

        if (!$this->keyExchangeInProgress) {
            $this->bytesTransferredSinceLastKEX += $packet->packet_length + $padding_length + 5;
        }

        if (empty($payload)) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR);
            throw new ConnectionClosedException('Plaintext is too short');
        }

        switch ($this->decompress) {
            case self::NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH:
                if (!$this->isAuthenticated()) {
                    break;
                }
                // fall-through
            case self::NET_SSH2_COMPRESSION_ZLIB:
                if ($this->regenerate_decompression_context) {
                    $this->regenerate_decompression_context = false;

                    $cmf = ord($payload[0]);
                    $cm = $cmf & 0x0F;
                    if ($cm != 8) { // deflate
                        throw new UnsupportedAlgorithmException("Only CM = 8 ('deflate') is supported ($cm)");
                    }
                    $cinfo = ($cmf & 0xF0) >> 4;
                    if ($cinfo > 7) {
                        throw new \RuntimeException("CINFO above 7 is not allowed ($cinfo)");
                    }
                    $windowSize = 1 << ($cinfo + 8);

                    $flg = ord($payload[1]);
                    //$fcheck = $flg && 0x0F;
                    if ((($cmf << 8) | $flg) % 31) {
                        throw new \RuntimeException('fcheck failed');
                    }
                    $fdict = boolval($flg & 0x20);
                    $flevel = ($flg & 0xC0) >> 6;

                    $this->decompress_context = inflate_init(ZLIB_ENCODING_RAW, ['window' => $cinfo + 8]);
                    $payload = substr($payload, 2);
                }
                if ($this->decompress_context) {
                    $payload = inflate_add($this->decompress_context, $payload, ZLIB_PARTIAL_FLUSH);
                }
        }

        $this->get_seq_no++;

        if (defined('NET_SSH2_LOGGING')) {
            $current = microtime(true);
            $message_number = isset(self::$message_numbers[ord($payload[0])]) ? self::$message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')';
            $message_number = '<- ' . $message_number .
                              ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($packet->read_time, 4) . 's)';
            $this->append_log($message_number, $payload);
        }
        $this->last_packet = microtime(true);

        if ($this->bytesTransferredSinceLastKEX > $this->doKeyReexchangeAfterXBytes) {
            $this->key_exchange();
        }

        return $this->filter($payload);
    }

    /**
     * @param object $packet The packet object being constructed, passed by reference
     *        The size, packet_length, and plain properties of this object may be modified in processing
     * @throws InvalidPacketLengthException if the packet length header is invalid
     */
    private function get_binary_packet_size(&$packet)
    {
        $packet_length_header_size = 4;
        if (strlen($packet->raw) < $packet_length_header_size) {
            return;
        }
        $packet_length = 0;
        $added_validation_length = 0; // indicates when the packet length header is included when validating packet length against block size
        if ($this->decrypt) {
            switch ($this->decryptName) {
                case 'aes128-gcm@openssh.com':
                case 'aes256-gcm@openssh.com':
                    $packet_length = unpack('Npacket_length', substr($packet->raw, 0, $packet_length_header_size))['packet_length'];
                    $packet->size = $packet_length_header_size + $packet_length + $this->decrypt_block_size; // expect tag
                    break;
                case 'chacha20-poly1305@openssh.com':
                    $this->lengthDecrypt->setNonce(pack('N2', 0, $this->get_seq_no));
                    $packet_length_header = $this->lengthDecrypt->decrypt(substr($packet->raw, 0, $packet_length_header_size));
                    $packet_length = unpack('Npacket_length', $packet_length_header)['packet_length'];
                    $packet->size = $packet_length_header_size + $packet_length + 16; // expect tag
                    break;
                default:
                    if (!$this->hmac_check instanceof Hash || !$this->hmac_check_etm) {
                        if (strlen($packet->raw) < $this->decrypt_block_size) {
                            return;
                        }
                        $packet->plain = $this->decrypt->decrypt(substr($packet->raw, 0, $this->decrypt_block_size));
                        $packet_length = unpack('Npacket_length', Strings::shift($packet->plain, $packet_length_header_size))['packet_length'];
                        $packet->size = $packet_length_header_size + $packet_length;
                        $added_validation_length = $packet_length_header_size;
                    } else {
                        $packet_length = unpack('Npacket_length', substr($packet->raw, 0, $packet_length_header_size))['packet_length'];
                        $packet->size = $packet_length_header_size + $packet_length;
                    }
                    break;
            }
        } else {
            $packet_length = unpack('Npacket_length', substr($packet->raw, 0, $packet_length_header_size))['packet_length'];
            $packet->size = $packet_length_header_size + $packet_length;
            $added_validation_length = $packet_length_header_size;
        }
        // quoting <http://tools.ietf.org/html/rfc4253#section-6.1>,
        // "implementations SHOULD check that the packet length is reasonable"
        // PuTTY uses 0x9000 as the actual max packet size and so to shall we
        if (
            $packet_length <= 0 || $packet_length > 0x9000
            || ($packet_length + $added_validation_length) % $this->decrypt_block_size != 0
        ) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR);
            throw new InvalidPacketLengthException('Invalid packet length');
        }
        if ($this->hmac_check instanceof Hash) {
            $packet->size += $this->hmac_size;
        }
        $packet->packet_length = $packet_length;
    }

    /**
     * Handle Disconnect
     *
     * Because some binary packets need to be ignored...
     *
     * @see self::filter()
     * @see self::key_exchange()
     * @return boolean
     * @access private
     */
    private function handleDisconnect($payload)
    {
        Strings::shift($payload, 1);
        list($reason_code, $message) = Strings::unpackSSH2('Ns', $payload);
        $this->errors[] = 'SSH_MSG_DISCONNECT: ' . self::$disconnect_reasons[$reason_code] . "\r\n$message";
        $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
        throw new ConnectionClosedException('Connection closed by server');
    }

    /**
     * Filter Binary Packets
     *
     * Because some binary packets need to be ignored...
     *
     * @see self::_get_binary_packet()
     * @param string $payload
     * @return string
     */
    private function filter($payload)
    {
        if (ord($payload[0]) == NET_SSH2_MSG_DISCONNECT) {
            return $this->handleDisconnect($payload);
        }

        if ($this->session_id === false && $this->keyExchangeInProgress) {
            return $payload;
        }

        switch (ord($payload[0])) {
            case NET_SSH2_MSG_IGNORE:
                $payload = $this->get_binary_packet();
                break;
            case NET_SSH2_MSG_DEBUG:
                Strings::shift($payload, 2); // second byte is "always_display"
                list($message) = Strings::unpackSSH2('s', $payload);
                $this->errors[] = "SSH_MSG_DEBUG: $message";
                $payload = $this->get_binary_packet();
                break;
            case NET_SSH2_MSG_UNIMPLEMENTED:
                break; // return payload
            case NET_SSH2_MSG_KEXINIT:
                // this is here for server initiated key re-exchanges after the initial key exchange
                if (!$this->keyExchangeInProgress && $this->session_id !== false) {
                    if (!$this->key_exchange($payload)) {
                        $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
                        throw new ConnectionClosedException('Key exchange failed');
                    }
                    $payload = $this->get_binary_packet();
                }
                break;
            case NET_SSH2_MSG_EXT_INFO:
                Strings::shift($payload, 1);
                list($nr_extensions) = Strings::unpackSSH2('N', $payload);
                for ($i = 0; $i < $nr_extensions; $i++) {
                    list($extension_name, $extension_value) = Strings::unpackSSH2('ss', $payload);
                    if ($extension_name == 'server-sig-algs') {
                        $this->supported_private_key_algorithms = explode(',', $extension_value);
                    }
                }
                $payload = $this->get_binary_packet();
        }

        /*
           Once a party has sent a SSH_MSG_KEXINIT message for key exchange or
           re-exchange, until it has sent a SSH_MSG_NEWKEYS message (Section
           7.3), it MUST NOT send any messages other than:

           o  Transport layer generic messages (1 to 19) (but
              SSH_MSG_SERVICE_REQUEST and SSH_MSG_SERVICE_ACCEPT MUST NOT be
              sent);

           o  Algorithm negotiation messages (20 to 29) (but further
              SSH_MSG_KEXINIT messages MUST NOT be sent);

           o  Specific key exchange method messages (30 to 49).

           -- https://www.rfc-editor.org/rfc/rfc4253#section-7.1
        */
        if ($this->keyExchangeInProgress) {
            return $payload;
        }

        // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in
        if (($this->bitmap & self::MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
            Strings::shift($payload, 1);
            list($this->banner_message) = Strings::unpackSSH2('s', $payload);
            $payload = $this->get_binary_packet();
        }

        // only called when we've already logged in
        if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) {
            switch (ord($payload[0])) {
                case NET_SSH2_MSG_CHANNEL_REQUEST:
                    if (strlen($payload) == 31) {
                        $unpacked = unpack('cpacket_type/Nchannel/Nlength', $payload);
                        $packet_type = $unpacked['packet_type'];
                        $channel = $unpacked['channel'];
                        $length = $unpacked['length'];
                        if (substr($payload, 9, $length) == 'keepalive@openssh.com' && isset($this->server_channels[$channel])) {
                            if (ord(substr($payload, 9 + $length))) { // want reply
                                $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_SUCCESS, $this->server_channels[$channel]));
                            }
                            $payload = $this->get_binary_packet();
                        }
                    }
                    break;
                case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
                    Strings::shift($payload, 1);
                    list($request_name, $want_reply) = Strings::unpackSSH2('sb', $payload);
                    $this->errors[] = "SSH_MSG_GLOBAL_REQUEST: $request_name";
                    if ($want_reply) {
                        $this->send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE));
                    }
                    $payload = $this->get_binary_packet();
                    break;
                case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
                    Strings::shift($payload, 1);
                    list($data, $server_channel) = Strings::unpackSSH2('sN', $payload);
                    switch ($data) {
                        case 'auth-agent':
                        case 'auth-agent@openssh.com':
                            if (isset($this->agent)) {
                                $new_channel = self::CHANNEL_AGENT_FORWARD;

                                list(
                                    $remote_window_size,
                                    $remote_maximum_packet_size
                                ) = Strings::unpackSSH2('NN', $payload);

                                $this->packet_size_client_to_server[$new_channel] = $remote_window_size;
                                $this->window_size_server_to_client[$new_channel] = $remote_maximum_packet_size;
                                $this->window_size_client_to_server[$new_channel] = $this->window_size;

                                $packet_size = 0x4000;

                                $packet = pack(
                                    'CN4',
                                    NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION,
                                    $server_channel,
                                    $new_channel,
                                    $packet_size,
                                    $packet_size
                                );

                                $this->server_channels[$new_channel] = $server_channel;
                                $this->channel_status[$new_channel] = NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION;
                                $this->send_binary_packet($packet);
                            }
                            break;
                        default:
                            $packet = Strings::packSSH2(
                                'CN2ss',
                                NET_SSH2_MSG_CHANNEL_OPEN_FAILURE,
                                $server_channel,
                                NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED,
                                '', // description
                                '' // language tag
                            );
                            $this->send_binary_packet($packet);
                    }

                    $payload = $this->get_binary_packet();
                    break;
            }
        }

        return $payload;
    }

    /**
     * Enable Quiet Mode
     *
     * Suppress stderr from output
     *
     */
    public function enableQuietMode()
    {
        $this->quiet_mode = true;
    }

    /**
     * Disable Quiet Mode
     *
     * Show stderr in output
     *
     */
    public function disableQuietMode()
    {
        $this->quiet_mode = false;
    }

    /**
     * Returns whether Quiet Mode is enabled or not
     *
     * @see self::enableQuietMode()
     * @see self::disableQuietMode()
     * @return bool
     */
    public function isQuietModeEnabled()
    {
        return $this->quiet_mode;
    }

    /**
     * Enable request-pty when using exec()
     *
     */
    public function enablePTY()
    {
        $this->request_pty = true;
    }

    /**
     * Disable request-pty when using exec()
     *
     */
    public function disablePTY()
    {
        if ($this->isPTYOpen()) {
            $this->close_channel(self::CHANNEL_EXEC);
        }
        $this->request_pty = false;
    }

    /**
     * Returns whether request-pty is enabled or not
     *
     * @see self::enablePTY()
     * @see self::disablePTY()
     * @return bool
     */
    public function isPTYEnabled()
    {
        return $this->request_pty;
    }

    /**
     * Gets channel data
     *
     * Returns the data as a string. bool(true) is returned if:
     *
     * - the server closes the channel
     * - if the connection times out
     * - if a window adjust packet is received on the given negated client channel
     * - if the channel status is CHANNEL_OPEN and the response was CHANNEL_OPEN_CONFIRMATION
     * - if the channel status is CHANNEL_REQUEST and the response was CHANNEL_SUCCESS
     * - if the channel status is CHANNEL_CLOSE and the response was CHANNEL_CLOSE
     *
     * bool(false) is returned if:
     *
     * - if the channel status is CHANNEL_REQUEST and the response was CHANNEL_FAILURE
     *
     * @param int $client_channel Specifies the channel to return data for, and data received
     *        on other channels is buffered. The respective negative value of a channel is
     *        also supported for the case that the caller is awaiting adjustment of the data
     *        window, and where data received on that respective channel is also buffered.
     * @param bool $skip_extended
     * @return mixed
     * @throws \RuntimeException on connection error
     */
    protected function get_channel_packet($client_channel, $skip_extended = false)
    {
        if (!empty($this->channel_buffers[$client_channel])) {
            // in phpseclib 4.0 this should be changed to $this->channel_status[$client_channel] ?? null
            switch (isset($this->channel_status[$client_channel]) ? $this->channel_status[$client_channel] : null) {
                case NET_SSH2_MSG_CHANNEL_REQUEST:
                    foreach ($this->channel_buffers[$client_channel] as $i => $packet) {
                        switch (ord($packet[0])) {
                            case NET_SSH2_MSG_CHANNEL_SUCCESS:
                            case NET_SSH2_MSG_CHANNEL_FAILURE:
                                unset($this->channel_buffers[$client_channel][$i]);
                                return substr($packet, 1);
                        }
                    }
                    break;
                default:
                    return substr(array_shift($this->channel_buffers[$client_channel]), 1);
            }
        }

        while (true) {
            try {
                $response = $this->get_binary_packet();
            } catch (TimeoutException $e) {
                return true;
            }
            list($type) = Strings::unpackSSH2('C', $response);
            if (strlen($response) >= 4) {
                list($channel) = Strings::unpackSSH2('N', $response);
            }

            // will not be setup yet on incoming channel open request
            if (isset($channel) && isset($this->channel_status[$channel]) && isset($this->window_size_server_to_client[$channel])) {
                $this->window_size_server_to_client[$channel] -= strlen($response);

                // resize the window, if appropriate
                if ($this->window_size_server_to_client[$channel] < 0) {
                // PuTTY does something more analogous to the following:
                //if ($this->window_size_server_to_client[$channel] < 0x3FFFFFFF) {
                    $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$channel], $this->window_resize);
                    $this->send_binary_packet($packet);
                    $this->window_size_server_to_client[$channel] += $this->window_resize;
                }

                switch ($type) {
                    case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
                        list($window_size) = Strings::unpackSSH2('N', $response);
                        $this->window_size_client_to_server[$channel] += $window_size;
                        if ($channel == -$client_channel) {
                            return true;
                        }

                        continue 2;
                    case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
                        /*
                        if ($client_channel == self::CHANNEL_EXEC) {
                            $this->send_channel_packet($client_channel, chr(0));
                        }
                        */
                        // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
                        list($data_type_code, $data) = Strings::unpackSSH2('Ns', $response);
                        $this->stdErrorLog .= $data;
                        if ($skip_extended || $this->quiet_mode) {
                            continue 2;
                        }
                        if ($client_channel == $channel && $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA) {
                            return $data;
                        }
                        $this->channel_buffers[$channel][] = chr($type) . $data;

                        continue 2;
                    case NET_SSH2_MSG_CHANNEL_REQUEST:
                        if (!isset($this->channel_status[$channel])) {
                            continue 2;
                        }
                        list($value) = Strings::unpackSSH2('s', $response);
                        switch ($value) {
                            case 'exit-signal':
                                list(
                                    , // FALSE
                                    $signal_name,
                                    , // core dumped
                                    $error_message
                                ) = Strings::unpackSSH2('bsbs', $response);

                                $this->errors[] = "SSH_MSG_CHANNEL_REQUEST (exit-signal): $signal_name";
                                if (strlen($error_message)) {
                                    $this->errors[count($this->errors) - 1] .= "\r\n$error_message";
                                }
                                if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_CLOSE) {
                                    if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) {
                                        $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$channel]));
                                    }
                                    $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));

                                    $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
                                }
                                continue 3;
                            case 'exit-status':
                                list(, $this->exit_status) = Strings::unpackSSH2('CN', $response);

                                // "The client MAY ignore these messages."
                                // -- http://tools.ietf.org/html/rfc4254#section-6.10

                                continue 3;
                            default:
                                list($want_reply) = Strings::unpackSSH2('b', $response);
                                if ($want_reply) {
                                    // "If the request is not recognized or is not supported for the channel,
                                    //  SSH_MSG_CHANNEL_FAILURE is returned."
                                    // -- https://datatracker.ietf.org/doc/html/rfc4254#page-10
                                    $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_FAILURE, $this->server_channels[$channel]));
                                }
                                continue 3;
                        }
                }

                switch ($this->channel_status[$channel]) {
                    case NET_SSH2_MSG_CHANNEL_OPEN:
                        switch ($type) {
                            case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
                                list(
                                    $this->server_channels[$channel],
                                    $window_size,
                                    $this->packet_size_client_to_server[$channel]
                                ) = Strings::unpackSSH2('NNN', $response);

                                if ($window_size < 0) {
                                    $window_size &= 0x7FFFFFFF;
                                    $window_size += 0x80000000;
                                }
                                $this->window_size_client_to_server[$channel] = $window_size;
                                $result = $client_channel == $channel ? true : $this->get_channel_packet($client_channel, $skip_extended);
                                $this->on_channel_open();
                                return $result;
                            case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
                                $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
                                throw new \RuntimeException('Unable to open channel');
                            default:
                                if ($client_channel == $channel) {
                                    $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
                                    throw new \RuntimeException('Unexpected response to open request');
                                }
                                return $this->get_channel_packet($client_channel, $skip_extended);
                        }
                        break;
                    case NET_SSH2_MSG_CHANNEL_REQUEST:
                        switch ($type) {
                            case NET_SSH2_MSG_CHANNEL_SUCCESS:
                                return true;
                            case NET_SSH2_MSG_CHANNEL_FAILURE:
                                return false;
                            case NET_SSH2_MSG_CHANNEL_DATA:
                                list($data) = Strings::unpackSSH2('s', $response);
                                $this->channel_buffers[$channel][] = chr($type) . $data;
                                return $this->get_channel_packet($client_channel, $skip_extended);
                            default:
                                $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
                                throw new \RuntimeException('Unable to fulfill channel request');
                        }
                    case NET_SSH2_MSG_CHANNEL_CLOSE:
                        if ($client_channel == $channel && $type == NET_SSH2_MSG_CHANNEL_CLOSE) {
                            return true;
                        }
                        return $this->get_channel_packet($client_channel, $skip_extended);
                }
            }

            // ie. $this->channel_status[$channel] == NET_SSH2_MSG_CHANNEL_DATA

            switch ($type) {
                case NET_SSH2_MSG_CHANNEL_DATA:
                    /*
                    if ($channel == self::CHANNEL_EXEC) {
                        // SCP requires null packets, such as this, be sent.  further, in the case of the ssh.com SSH server
                        // this actually seems to make things twice as fast.  more to the point, the message right after
                        // SSH_MSG_CHANNEL_DATA (usually SSH_MSG_IGNORE) won't block for as long as it would have otherwise.
                        // in OpenSSH it slows things down but only by a couple thousandths of a second.
                        $this->send_channel_packet($channel, chr(0));
                    }
                    */
                    list($data) = Strings::unpackSSH2('s', $response);

                    if ($channel == self::CHANNEL_AGENT_FORWARD) {
                        $agent_response = $this->agent->forwardData($data);
                        if (!is_bool($agent_response)) {
                            $this->send_channel_packet($channel, $agent_response);
                        }
                        break;
                    }

                    if ($client_channel == $channel) {
                        return $data;
                    }
                    $this->channel_buffers[$channel][] = chr($type) . $data;
                    break;
                case NET_SSH2_MSG_CHANNEL_CLOSE:
                    $this->curTimeout = 5;

                    $this->close_channel_bitmap($channel);

                    if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_CLOSE) {
                        $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
                    }

                    unset($this->channel_status[$channel]);
                    $this->channelCount--;

                    if ($client_channel == $channel) {
                        return true;
                    }
                    // fall-through
                case NET_SSH2_MSG_CHANNEL_EOF:
                    break;
                default:
                    $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
                    throw new \RuntimeException("Error reading channel data ($type)");
            }
        }
    }

    /**
     * Sends Binary Packets
     *
     * See '6. Binary Packet Protocol' of rfc4253 for more info.
     *
     * @param string $data
     * @param string $logged
     * @see self::_get_binary_packet()
     * @return void
     */
    protected function send_binary_packet($data, $logged = null)
    {
        if (!is_resource($this->fsock) || feof($this->fsock)) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST);
            throw new ConnectionClosedException('Connection closed prematurely');
        }

        if (!isset($logged)) {
            $logged = $data;
        }

        switch ($this->compress) {
            case self::NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH:
                if (!$this->isAuthenticated()) {
                    break;
                }
                // fall-through
            case self::NET_SSH2_COMPRESSION_ZLIB:
                if (!$this->regenerate_compression_context) {
                    $header = '';
                } else {
                    $this->regenerate_compression_context = false;
                    $this->compress_context = deflate_init(ZLIB_ENCODING_RAW, ['window' => 15]);
                    $header = "\x78\x9C";
                }
                if ($this->compress_context) {
                    $data = $header . deflate_add($this->compress_context, $data, ZLIB_PARTIAL_FLUSH);
                }
        }

        // 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9
        $packet_length = strlen($data) + 9;
        if ($this->encrypt && $this->encrypt->usesNonce()) {
            $packet_length -= 4;
        }
        // round up to the nearest $this->encrypt_block_size
        $packet_length += (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size;
        // subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length
        $padding_length = $packet_length - strlen($data) - 5;
        switch (true) {
            case $this->encrypt && $this->encrypt->usesNonce():
            case $this->hmac_create instanceof Hash && $this->hmac_create_etm:
                $padding_length += 4;
                $packet_length += 4;
        }

        $padding = Random::string($padding_length);

        // we subtract 4 from packet_length because the packet_length field isn't supposed to include itself
        $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding);

        $hmac = '';
        if ($this->hmac_create instanceof Hash && !$this->hmac_create_etm) {
            if (($this->hmac_create->getHash() & "\xFF\xFF\xFF\xFF") == 'umac') {
                $this->hmac_create->setNonce("\0\0\0\0" . pack('N', $this->send_seq_no));
                $hmac = $this->hmac_create->hash($packet);
            } else {
                $hmac = $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet));
            }
        }

        if ($this->encrypt) {
            switch ($this->encryptName) {
                case 'aes128-gcm@openssh.com':
                case 'aes256-gcm@openssh.com':
                    $this->encrypt->setNonce(
                        $this->encryptFixedPart .
                        $this->encryptInvocationCounter
                    );
                    Strings::increment_str($this->encryptInvocationCounter);
                    $this->encrypt->setAAD($temp = ($packet & "\xFF\xFF\xFF\xFF"));
                    $packet = $temp . $this->encrypt->encrypt(substr($packet, 4));
                    break;
                case 'chacha20-poly1305@openssh.com':
                    // This should be impossible, but we are checking anyway to narrow the type for Psalm.
                    if (!($this->encrypt instanceof ChaCha20)) {
                        throw new \LogicException('$this->encrypt is not a ' . ChaCha20::class);
                    }

                    $nonce = pack('N2', 0, $this->send_seq_no);

                    $this->encrypt->setNonce($nonce);
                    $this->lengthEncrypt->setNonce($nonce);

                    $length = $this->lengthEncrypt->encrypt($packet & "\xFF\xFF\xFF\xFF");

                    $this->encrypt->setCounter(0);
                    // this is the same approach that's implemented in Salsa20::createPoly1305Key()
                    // but we don't want to use the same AEAD construction that RFC8439 describes
                    // for ChaCha20-Poly1305 so we won't rely on it (see Salsa20::poly1305())
                    $this->encrypt->setPoly1305Key(
                        $this->encrypt->encrypt(str_repeat("\0", 32))
                    );
                    $this->encrypt->setAAD($length);
                    $this->encrypt->setCounter(1);
                    $packet = $length . $this->encrypt->encrypt(substr($packet, 4));
                    break;
                default:
                    $packet = $this->hmac_create instanceof Hash && $this->hmac_create_etm ?
                        ($packet & "\xFF\xFF\xFF\xFF") . $this->encrypt->encrypt(substr($packet, 4)) :
                        $this->encrypt->encrypt($packet);
            }
        }

        if ($this->hmac_create instanceof Hash && $this->hmac_create_etm) {
            if (($this->hmac_create->getHash() & "\xFF\xFF\xFF\xFF") == 'umac') {
                $this->hmac_create->setNonce("\0\0\0\0" . pack('N', $this->send_seq_no));
                $hmac = $this->hmac_create->hash($packet);
            } else {
                $hmac = $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet));
            }
        }

        $this->send_seq_no++;

        $packet .= $this->encrypt && $this->encrypt->usesNonce() ? $this->encrypt->getTag() : $hmac;

        if (!$this->keyExchangeInProgress) {
            $this->bytesTransferredSinceLastKEX += strlen($packet);
        }

        $start = microtime(true);
        $sent = @fputs($this->fsock, $packet);
        $stop = microtime(true);

        if (defined('NET_SSH2_LOGGING')) {
            $current = microtime(true);
            $message_number = isset(self::$message_numbers[ord($logged[0])]) ? self::$message_numbers[ord($logged[0])] : 'UNKNOWN (' . ord($logged[0]) . ')';
            $message_number = '-> ' . $message_number .
                              ' (since last: ' . round($current - $this->last_packet, 4) . ', network: ' . round($stop - $start, 4) . 's)';
            $this->append_log($message_number, $logged);
        }
        $this->last_packet = microtime(true);

        if (strlen($packet) != $sent) {
            $this->disconnect_helper(NET_SSH2_DISCONNECT_BY_APPLICATION);
            $message = $sent === false ?
                'Unable to write ' . strlen($packet) . ' bytes' :
                "Only $sent of " . strlen($packet) . " bytes were sent";
            throw new \RuntimeException($message);
        }

        if ($this->bytesTransferredSinceLastKEX > $this->doKeyReexchangeAfterXBytes) {
            $this->key_exchange();
        }
    }

    /**
     * Sends a keep-alive message, if keep-alive is enabled and interval is met
     */
    private function send_keep_alive()
    {
        if ($this->bitmap & self::MASK_CONNECTED) {
            $elapsed = microtime(true) - $this->last_packet;
            if ($this->keepAlive > 0 && $elapsed >= $this->keepAlive) {
                $this->send_binary_packet(pack('CN', NET_SSH2_MSG_IGNORE, 0));
            }
        }
    }

    /**
     * Logs data packets
     *
     * Makes sure that only the last 1MB worth of packets will be logged
     *
     * @param string $message_number
     * @param string $message
     */
    private function append_log($message_number, $message)
    {
        $this->append_log_helper(
            NET_SSH2_LOGGING,
            $message_number,
            $message,
            $this->message_number_log,
            $this->message_log,
            $this->log_size,
            $this->realtime_log_file,
            $this->realtime_log_wrap,
            $this->realtime_log_size
        );
    }

    /**
     * Logs data packet helper
     *
     * @param int $constant
     * @param string $message_number
     * @param string $message
     * @param array &$message_number_log
     * @param array &$message_log
     * @param int &$log_size
     * @param resource &$realtime_log_file
     * @param bool &$realtime_log_wrap
     * @param int &$realtime_log_size
     */
    protected function append_log_helper($constant, $message_number, $message, array &$message_number_log, array &$message_log, &$log_size, &$realtime_log_file, &$realtime_log_wrap, &$realtime_log_size)
    {
        // remove the byte identifying the message type from all but the first two messages (ie. the identification strings)
        if (!in_array(substr($message_number, 0, 4), ['<- (', '-> (']) && strlen($message_number) > 2) {
            Strings::shift($message);
        }

        switch ($constant) {
            // useful for benchmarks
            case self::LOG_SIMPLE:
                $message_number_log[] = $message_number;
                break;
            case self::LOG_SIMPLE_REALTIME:
                echo $message_number;
                echo PHP_SAPI == 'cli' ? "\r\n" : '<br>';
                @flush();
                @ob_flush();
                break;
            // the most useful log for SSH2
            case self::LOG_COMPLEX:
                $message_number_log[] = $message_number;
                $log_size += strlen($message);
                $message_log[] = $message;
                while ($log_size > self::LOG_MAX_SIZE) {
                    $log_size -= strlen(array_shift($message_log));
                    array_shift($message_number_log);
                }
                break;
            // dump the output out realtime; packets may be interspersed with non packets,
            // passwords won't be filtered out and select other packets may not be correctly
            // identified
            case self::LOG_REALTIME:
                switch (PHP_SAPI) {
                    case 'cli':
                        $start = $stop = "\r\n";
                        break;
                    default:
                        $start = '<pre>';
                        $stop = '</pre>';
                }
                echo $start . $this->format_log([$message], [$message_number]) . $stop;
                @flush();
                @ob_flush();
                break;
            // basically the same thing as self::LOG_REALTIME with the caveat that NET_SSH2_LOG_REALTIME_FILENAME
            // needs to be defined and that the resultant log file will be capped out at self::LOG_MAX_SIZE.
            // the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
            // at the beginning of the file
            case self::LOG_REALTIME_FILE:
                if (!isset($realtime_log_file)) {
                    // PHP doesn't seem to like using constants in fopen()
                    $filename = NET_SSH2_LOG_REALTIME_FILENAME;
                    $fp = fopen($filename, 'w');
                    $realtime_log_file = $fp;
                }
                if (!is_resource($realtime_log_file)) {
                    break;
                }
                $entry = $this->format_log([$message], [$message_number]);
                if ($realtime_log_wrap) {
                    $temp = "<<< START >>>\r\n";
                    $entry .= $temp;
                    fseek($realtime_log_file, ftell($realtime_log_file) - strlen($temp));
                }
                $realtime_log_size += strlen($entry);
                if ($realtime_log_size > self::LOG_MAX_SIZE) {
                    fseek($realtime_log_file, 0);
                    $realtime_log_size = strlen($entry);
                    $realtime_log_wrap = true;
                }
                fputs($realtime_log_file, $entry);
                break;
            case self::LOG_REALTIME_SIMPLE:
                echo $message_number;
                echo PHP_SAPI == 'cli' ? "\r\n" : '<br>';
        }
    }

    /**
     * Sends channel data
     *
     * Spans multiple SSH_MSG_CHANNEL_DATAs if appropriate
     *
     * @param int $client_channel
     * @param string $data
     * @return void
     */
    protected function send_channel_packet($client_channel, $data)
    {
        if (
            isset($this->channel_buffers_write[$client_channel])
            && strpos($data, $this->channel_buffers_write[$client_channel]) === 0
        ) {
            // if buffer holds identical initial data content, resume send from the unmatched data portion
            $data = substr($data, strlen($this->channel_buffers_write[$client_channel]));
        } else {
            $this->channel_buffers_write[$client_channel] = '';
        }
        while (strlen($data)) {
            if (!$this->window_size_client_to_server[$client_channel]) {
                // using an invalid channel will let the buffers be built up for the valid channels
                $this->get_channel_packet(-$client_channel);
                if ($this->isTimeout()) {
                    throw new TimeoutException('Timed out waiting for server');
                } elseif (!$this->window_size_client_to_server[$client_channel]) {
                    throw new \RuntimeException('Data window was not adjusted');
                }
            }

            /* The maximum amount of data allowed is determined by the maximum
               packet size for the channel, and the current window size, whichever
               is smaller.
                 -- http://tools.ietf.org/html/rfc4254#section-5.2 */
            $max_size = min(
                $this->packet_size_client_to_server[$client_channel],
                $this->window_size_client_to_server[$client_channel]
            );

            $temp = Strings::shift($data, $max_size);
            $packet = Strings::packSSH2(
                'CNs',
                NET_SSH2_MSG_CHANNEL_DATA,
                $this->server_channels[$client_channel],
                $temp
            );
            $this->window_size_client_to_server[$client_channel] -= strlen($temp);
            $this->send_binary_packet($packet);
            $this->channel_buffers_write[$client_channel] .= $temp;
        }
        unset($this->channel_buffers_write[$client_channel]);
    }

    /**
     * Closes and flushes a channel
     *
     * \phpseclib3\Net\SSH2 doesn't properly close most channels.  For exec() channels are normally closed by the server
     * and for SFTP channels are presumably closed when the client disconnects.  This functions is intended
     * for SCP more than anything.
     *
     * @param int $client_channel
     * @param bool $want_reply
     * @return void
     */
    protected function close_channel($client_channel)
    {
        // see http://tools.ietf.org/html/rfc4254#section-5.3

        if ($this->channel_status[$client_channel] != NET_SSH2_MSG_CHANNEL_EOF) {
            $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$client_channel]));
        }
        $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$client_channel]));

        $this->channel_status[$client_channel] = NET_SSH2_MSG_CHANNEL_CLOSE;

        $this->channelCount--;

        $this->curTimeout = 5;
        while (!is_bool($this->get_channel_packet($client_channel))) {
        }

        unset($this->channel_status[$client_channel]);

        $this->close_channel_bitmap($client_channel);
    }

    /**
     * Maintains execution state bitmap in response to channel closure
     *
     * @param int $client_channel The channel number to maintain closure status of
     * @return void
     */
    private function close_channel_bitmap($client_channel)
    {
        switch ($client_channel) {
            case self::CHANNEL_SHELL:
                // Shell status has been maintained in the bitmap for backwards
                //  compatibility sake, but can be removed going forward
                if ($this->bitmap & self::MASK_SHELL) {
                    $this->bitmap &= ~self::MASK_SHELL;
                }
                break;
        }
    }

    /**
     * Disconnect
     *
     * @param int $reason
     * @return false
     */
    protected function disconnect_helper($reason)
    {
        if ($this->bitmap & self::MASK_DISCONNECT) {
            // Disregard subsequent disconnect requests
            return false;
        }
        $this->bitmap |= self::MASK_DISCONNECT;
        if ($this->isConnected()) {
            $data = Strings::packSSH2('CNss', NET_SSH2_MSG_DISCONNECT, $reason, '', '');
            try {
                $this->send_binary_packet($data);
            } catch (\Exception $e) {
            }
        }

        $this->reset_connection();

        return false;
    }

    /**
     * Define Array
     *
     * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
     * named constants from it, using the value as the name of the constant and the index as the value of the constant.
     * If any of the constants that would be defined already exists, none of the constants will be defined.
     *
     * @param mixed[] ...$args
     * @access protected
     */
    protected static function define_array(...$args)
    {
        foreach ($args as $arg) {
            foreach ($arg as $key => $value) {
                if (!defined($value)) {
                    define($value, $key);
                } else {
                    break 2;
                }
            }
        }
    }

    /**
     * Returns a log of the packets that have been sent and received.
     *
     * Returns a string if NET_SSH2_LOGGING == self::LOG_COMPLEX, an array if NET_SSH2_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING')
     *
     * @return array|false|string
     */
    public function getLog()
    {
        if (!defined('NET_SSH2_LOGGING')) {
            return false;
        }

        switch (NET_SSH2_LOGGING) {
            case self::LOG_SIMPLE:
                return $this->message_number_log;
            case self::LOG_COMPLEX:
                $log = $this->format_log($this->message_log, $this->message_number_log);
                return PHP_SAPI == 'cli' ? $log : '<pre>' . $log . '</pre>';
            default:
                return false;
        }
    }

    /**
     * Formats a log for printing
     *
     * @param array $message_log
     * @param array $message_number_log
     * @return string
     */
    protected function format_log(array $message_log, array $message_number_log)
    {
        $output = '';
        for ($i = 0; $i < count($message_log); $i++) {
            $output .= $message_number_log[$i];
            $current_log = $message_log[$i];
            $j = 0;
            if (strlen($current_log)) {
                $output .= "\r\n";
            }
            do {
                if (strlen($current_log)) {
                    $output .= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0  ';
                }
                $fragment = Strings::shift($current_log, $this->log_short_width);
                $hex = substr(preg_replace_callback('#.#s', function ($matches) {
                    return $this->log_boundary . str_pad(dechex(ord($matches[0])), 2, '0', STR_PAD_LEFT);
                }, $fragment), strlen($this->log_boundary));
                // replace non ASCII printable characters with dots
                // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
                // also replace < with a . since < messes up the output on web browsers
                $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
                $output .= str_pad($hex, $this->log_long_width - $this->log_short_width, ' ') . $raw . "\r\n";
                $j++;
            } while (strlen($current_log));
            $output .= "\r\n";
        }

        return $output;
    }

    /**
     * Helper function for agent->on_channel_open()
     *
     * Used when channels are created to inform agent
     * of said channel opening. Must be called after
     * channel open confirmation received
     *
     */
    private function on_channel_open()
    {
        if (isset($this->agent)) {
            $this->agent->registerChannelOpen($this);
        }
    }

    /**
     * Returns the first value of the intersection of two arrays or false if
     * the intersection is empty. The order is defined by the first parameter.
     *
     * @param array $array1
     * @param array $array2
     * @return mixed False if intersection is empty, else intersected value.
     */
    private static function array_intersect_first(array $array1, array $array2)
    {
        foreach ($array1 as $value) {
            if (in_array($value, $array2)) {
                return $value;
            }
        }
        return false;
    }

    /**
     * Returns all errors / debug messages on the SSH layer
     *
     * If you are looking for messages from the SFTP layer, please see SFTP::getSFTPErrors()
     *
     * @return string[]
     * @removed in phpseclib 4.0.0
     */
    public function getErrors()
    {
        return $this->errors;
    }

    /**
     * Returns the last error received on the SSH layer
     *
     * If you are looking for messages from the SFTP layer, please see SFTP::getLastSFTPError()
     *
     * @return string
     * @removed in phpseclib 4.0.0
     */
    public function getLastError()
    {
        $count = count($this->errors);

        if ($count > 0) {
            return $this->errors[$count - 1];
        }
    }

    /**
     * Return the server identification.
     *
     * @return string|false
     */
    public function getServerIdentification()
    {
        $this->connect();

        return $this->server_identifier;
    }

    /**
     * Returns a list of algorithms the server supports
     *
     * @return array
     */
    public function getServerAlgorithms()
    {
        $this->connect();

        return [
            'kex' => $this->kex_algorithms,
            'hostkey' => $this->server_host_key_algorithms,
            'client_to_server' => [
                'crypt' => $this->encryption_algorithms_client_to_server,
                'mac' => $this->mac_algorithms_client_to_server,
                'comp' => $this->compression_algorithms_client_to_server,
                'lang' => $this->languages_client_to_server
            ],
            'server_to_client' => [
                'crypt' => $this->encryption_algorithms_server_to_client,
                'mac' => $this->mac_algorithms_server_to_client,
                'comp' => $this->compression_algorithms_server_to_client,
                'lang' => $this->languages_server_to_client
            ]
        ];
    }

    /**
     * Returns a list of KEX algorithms that phpseclib supports
     *
     * @return array
     */
    public static function getSupportedKEXAlgorithms()
    {
        $kex_algorithms = [
            // Elliptic Curve Diffie-Hellman Key Agreement (ECDH) using
            // Curve25519. See doc/curve25519-sha256@libssh.org.txt in the
            // libssh repository for more information.
            'curve25519-sha256',
            'curve25519-sha256@libssh.org',

            'ecdh-sha2-nistp256', // RFC 5656
            'ecdh-sha2-nistp384', // RFC 5656
            'ecdh-sha2-nistp521', // RFC 5656

            'diffie-hellman-group-exchange-sha256',// RFC 4419
            'diffie-hellman-group-exchange-sha1',  // RFC 4419

            // Diffie-Hellman Key Agreement (DH) using integer modulo prime
            // groups.
            'diffie-hellman-group14-sha256',
            'diffie-hellman-group14-sha1', // REQUIRED
            'diffie-hellman-group15-sha512',
            'diffie-hellman-group16-sha512',
            'diffie-hellman-group17-sha512',
            'diffie-hellman-group18-sha512',

            'diffie-hellman-group1-sha1', // REQUIRED
        ];

        return $kex_algorithms;
    }

    /**
     * Returns a list of host key algorithms that phpseclib supports
     *
     * @return array
     */
    public static function getSupportedHostKeyAlgorithms()
    {
        return [
            'ssh-ed25519', // https://tools.ietf.org/html/draft-ietf-curdle-ssh-ed25519-02
            'ecdsa-sha2-nistp256', // RFC 5656
            'ecdsa-sha2-nistp384', // RFC 5656
            'ecdsa-sha2-nistp521', // RFC 5656
            'rsa-sha2-256', // RFC 8332
            'rsa-sha2-512', // RFC 8332
            'ssh-rsa', // RECOMMENDED  sign   Raw RSA Key
            'ssh-dss'  // REQUIRED     sign   Raw DSS Key
        ];
    }

    /**
     * Returns a list of symmetric key algorithms that phpseclib supports
     *
     * @return array
     */
    public static function getSupportedEncryptionAlgorithms()
    {
        $algos = [
            // from <https://tools.ietf.org/html/rfc5647>:
            'aes128-gcm@openssh.com',
            'aes256-gcm@openssh.com',

            // from <http://tools.ietf.org/html/rfc4345#section-4>:
            'arcfour256',
            'arcfour128',

            //'arcfour',      // OPTIONAL          the ARCFOUR stream cipher with a 128-bit key

            // CTR modes from <http://tools.ietf.org/html/rfc4344#section-4>:
            'aes128-ctr',     // RECOMMENDED       AES (Rijndael) in SDCTR mode, with 128-bit key
            'aes192-ctr',     // RECOMMENDED       AES with 192-bit key
            'aes256-ctr',     // RECOMMENDED       AES with 256-bit key

            // from <https://github.com/openssh/openssh-portable/blob/001aa55/PROTOCOL.chacha20poly1305>:
            // one of the big benefits of chacha20-poly1305 is speed. the problem is...
            // libsodium doesn't generate the poly1305 keys in the way ssh does and openssl's PHP bindings don't even
            // seem to support poly1305 currently. so even if libsodium or openssl are being used for the chacha20
            // part, pure-PHP has to be used for the poly1305 part and that's gonna cause a big slow down.
            // speed-wise it winds up being faster to use AES (when openssl or mcrypt are available) and some HMAC
            // (which is always gonna be super fast to compute thanks to the hash extension, which
            // "is bundled and compiled into PHP by default")
            'chacha20-poly1305@openssh.com',

            'twofish128-ctr', // OPTIONAL          Twofish in SDCTR mode, with 128-bit key
            'twofish192-ctr', // OPTIONAL          Twofish with 192-bit key
            'twofish256-ctr', // OPTIONAL          Twofish with 256-bit key

            'aes128-cbc',     // RECOMMENDED       AES with a 128-bit key
            'aes192-cbc',     // OPTIONAL          AES with a 192-bit key
            'aes256-cbc',     // OPTIONAL          AES in CBC mode, with a 256-bit key

            'twofish128-cbc', // OPTIONAL          Twofish with a 128-bit key
            'twofish192-cbc', // OPTIONAL          Twofish with a 192-bit key
            'twofish256-cbc',
            'twofish-cbc',    // OPTIONAL          alias for "twofish256-cbc"
                              //                   (this is being retained for historical reasons)

            'blowfish-ctr',   // OPTIONAL          Blowfish in SDCTR mode

            'blowfish-cbc',   // OPTIONAL          Blowfish in CBC mode

            '3des-ctr',       // RECOMMENDED       Three-key 3DES in SDCTR mode

            '3des-cbc',       // REQUIRED          three-key 3DES in CBC mode

             //'none'           // OPTIONAL          no encryption; NOT RECOMMENDED
        ];

        if (self::$crypto_engine) {
            $engines = [self::$crypto_engine];
        } else {
            $engines = [
                'libsodium',
                'OpenSSL (GCM)',
                'OpenSSL',
                'mcrypt',
                'Eval',
                'PHP'
            ];
        }

        $ciphers = [];

        foreach ($engines as $engine) {
            foreach ($algos as $algo) {
                $obj = self::encryption_algorithm_to_crypt_instance($algo);
                if ($obj instanceof Rijndael) {
                    $obj->setKeyLength(preg_replace('#[^\d]#', '', $algo));
                }
                switch ($algo) {
                    // Eval engines do not exist for ChaCha20 or RC4 because they would not benefit from one.
                    // to benefit from an Eval engine they'd need to loop a variable amount of times, they'd
                    // need to do table lookups (eg. sbox subsitutions). ChaCha20 doesn't do either because
                    // it's a so-called ARX cipher, meaning that the only operations it does are add (A), rotate (R)
                    // and XOR (X). RC4 does do table lookups but being a stream cipher it works differently than
                    // block ciphers. with RC4 you XOR the plaintext against a keystream and the keystream changes
                    // as you encrypt stuff. the only table lookups are made against this keystream and thus table
                    // lookups are kinda unavoidable. with AES and DES, however, the table lookups that are done
                    // are done against substitution boxes (sboxes), which are invariant.

                    // OpenSSL can't be used as an engine, either, because OpenSSL doesn't support continuous buffers
                    // as SSH2 uses and altho you can emulate a continuous buffer with block ciphers you can't do so
                    // with stream ciphers. As for ChaCha20...  for the ChaCha20 part OpenSSL could prob be used but
                    // the big slow down isn't with ChaCha20 - it's with Poly1305. SSH constructs the key for that
                    // differently than how OpenSSL does it (OpenSSL does it as the RFC describes, SSH doesn't).

                    // libsodium can't be used because it doesn't support RC4 and it doesn't construct the Poly1305
                    // keys in the same way that SSH does

                    // mcrypt could prob be used for RC4 but mcrypt hasn't been included in PHP core for yearss
                    case 'chacha20-poly1305@openssh.com':
                    case 'arcfour128':
                    case 'arcfour256':
                        if ($engine != 'PHP') {
                            continue 2;
                        }
                        break;
                    case 'aes128-gcm@openssh.com':
                    case 'aes256-gcm@openssh.com':
                        if ($engine == 'OpenSSL') {
                            continue 2;
                        }
                        $obj->setNonce('dummydummydu');
                }
                if ($obj->isValidEngine($engine)) {
                    $algos = array_diff($algos, [$algo]);
                    $ciphers[] = $algo;
                }
            }
        }

        return $ciphers;
    }

    /**
     * Returns a list of MAC algorithms that phpseclib supports
     *
     * @return array
     */
    public static function getSupportedMACAlgorithms()
    {
        return [
            'hmac-sha2-256-etm@openssh.com',
            'hmac-sha2-512-etm@openssh.com',
            'hmac-sha1-etm@openssh.com',

            // from <http://www.ietf.org/rfc/rfc6668.txt>:
            'hmac-sha2-256',// RECOMMENDED     HMAC-SHA256 (digest length = key length = 32)
            'hmac-sha2-512',// OPTIONAL        HMAC-SHA512 (digest length = key length = 64)

            'hmac-sha1-96', // RECOMMENDED     first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
            'hmac-sha1',    // REQUIRED        HMAC-SHA1 (digest length = key length = 20)
            'hmac-md5-96',  // OPTIONAL        first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
            'hmac-md5',     // OPTIONAL        HMAC-MD5 (digest length = key length = 16)

            'umac-64-etm@openssh.com',
            'umac-128-etm@openssh.com',

            // from <https://tools.ietf.org/html/draft-miller-secsh-umac-01>:
            'umac-64@openssh.com',
            'umac-128@openssh.com',

            //'none'          // OPTIONAL        no MAC; NOT RECOMMENDED
        ];
    }

    /**
     * Returns a list of compression algorithms that phpseclib supports
     *
     * @return array
     */
    public static function getSupportedCompressionAlgorithms()
    {
        $algos = ['none']; // REQUIRED        no compression
        if (function_exists('deflate_init')) {
            $algos[] = 'zlib@openssh.com'; // https://datatracker.ietf.org/doc/html/draft-miller-secsh-compression-delayed
            $algos[] = 'zlib';
        }
        return $algos;
    }

    /**
     * Return list of negotiated algorithms
     *
     * Uses the same format as https://www.php.net/ssh2-methods-negotiated
     *
     * @return array
     */
    public function getAlgorithmsNegotiated()
    {
        $this->connect();

        $compression_map = [
            self::NET_SSH2_COMPRESSION_NONE => 'none',
            self::NET_SSH2_COMPRESSION_ZLIB => 'zlib',
            self::NET_SSH2_COMPRESSION_ZLIB_AT_OPENSSH => 'zlib@openssh.com'
        ];

        return [
            'kex' => $this->kex_algorithm,
            'hostkey' => $this->signature_format,
            'client_to_server' => [
                'crypt' => $this->encryptName,
                'mac' => $this->hmac_create_name,
                'comp' => $compression_map[$this->compress],
            ],
            'server_to_client' => [
                'crypt' => $this->decryptName,
                'mac' => $this->hmac_check_name,
                'comp' => $compression_map[$this->decompress],
            ]
        ];
    }

    /**
     * Force multiple channels (even if phpseclib has decided to disable them)
     */
    public function forceMultipleChannels()
    {
        $this->errorOnMultipleChannels = false;
    }

    /**
     * Allows you to set the terminal
     *
     * @param string $term
     */
    public function setTerminal($term)
    {
        $this->term = $term;
    }

    /**
     * Accepts an associative array with up to four parameters as described at
     * <https://www.php.net/manual/en/function.ssh2-connect.php>
     *
     * @param array $methods
     */
    public function setPreferredAlgorithms(array $methods)
    {
        $keys = ['client_to_server', 'server_to_client'];

        if (isset($methods['kex']) && is_string($methods['kex'])) {
            $methods['kex'] = explode(',', $methods['kex']);
        }

        if (isset($methods['hostkey']) && is_string($methods['hostkey'])) {
            $methods['hostkey'] = explode(',', $methods['hostkey']);
        }

        foreach ($keys as $key) {
            if (isset($methods[$key])) {
                $a = &$methods[$key];
                if (isset($a['crypt']) && is_string($a['crypt'])) {
                    $a['crypt'] = explode(',', $a['crypt']);
                }
                if (isset($a['comp']) && is_string($a['comp'])) {
                    $a['comp'] = explode(',', $a['comp']);
                }
                if (isset($a['mac']) && is_string($a['mac'])) {
                    $a['mac'] = explode(',', $a['mac']);
                }
            }
        }

        $preferred = $methods;

        if (isset($preferred['kex'])) {
            $preferred['kex'] = array_intersect(
                $preferred['kex'],
                static::getSupportedKEXAlgorithms()
            );
        }

        if (isset($preferred['hostkey'])) {
            $preferred['hostkey'] = array_intersect(
                $preferred['hostkey'],
                static::getSupportedHostKeyAlgorithms()
            );
        }

        foreach ($keys as $key) {
            if (isset($preferred[$key])) {
                $a = &$preferred[$key];
                if (isset($a['crypt'])) {
                    $a['crypt'] = array_intersect(
                        $a['crypt'],
                        static::getSupportedEncryptionAlgorithms()
                    );
                }
                if (isset($a['comp'])) {
                    $a['comp'] = array_intersect(
                        $a['comp'],
                        static::getSupportedCompressionAlgorithms()
                    );
                }
                if (isset($a['mac'])) {
                    $a['mac'] = array_intersect(
                        $a['mac'],
                        static::getSupportedMACAlgorithms()
                    );
                }
            }
        }

        $keys = [
            'kex',
            'hostkey',
            'client_to_server/crypt',
            'client_to_server/comp',
            'client_to_server/mac',
            'server_to_client/crypt',
            'server_to_client/comp',
            'server_to_client/mac',
        ];
        foreach ($keys as $key) {
            $p = $preferred;
            $m = $methods;

            $subkeys = explode('/', $key);
            foreach ($subkeys as $subkey) {
                if (!isset($p[$subkey])) {
                    continue 2;
                }
                $p = $p[$subkey];
                $m = $m[$subkey];
            }

            if (count($p) != count($m)) {
                $diff = array_diff($m, $p);
                $msg = count($diff) == 1 ?
                    ' is not a supported algorithm' :
                    ' are not supported algorithms';
                throw new UnsupportedAlgorithmException(implode(', ', $diff) . $msg);
            }
        }

        $this->preferred = $preferred;
    }

    /**
     * Returns the banner message.
     *
     * Quoting from the RFC, "in some jurisdictions, sending a warning message before
     * authentication may be relevant for getting legal protection."
     *
     * @return string
     */
    public function getBannerMessage()
    {
        return $this->banner_message;
    }

    /**
     * Returns the server public host key.
     *
     * Caching this the first time you connect to a server and checking the result on subsequent connections
     * is recommended.  Returns false if the server signature is not signed correctly with the public host key.
     *
     * @return string|false
     * @throws \RuntimeException on badly formatted keys
     * @throws NoSupportedAlgorithmsException when the key isn't in a supported format
     */
    public function getServerPublicHostKey()
    {
        if (!($this->bitmap & self::MASK_CONSTRUCTOR)) {
            $this->connect();
        }

        $signature = $this->signature;
        $server_public_host_key = base64_encode($this->server_public_host_key);

        if ($this->signature_validated) {
            return $this->bitmap ?
                $this->signature_format . ' ' . $server_public_host_key :
                false;
        }

        $this->signature_validated = true;

        switch ($this->signature_format) {
            case 'ssh-ed25519':
            case 'ecdsa-sha2-nistp256':
            case 'ecdsa-sha2-nistp384':
            case 'ecdsa-sha2-nistp521':
                $key = EC::loadFormat('OpenSSH', $server_public_host_key)
                    ->withSignatureFormat('SSH2');
                switch ($this->signature_format) {
                    case 'ssh-ed25519':
                        $hash = 'sha512';
                        break;
                    case 'ecdsa-sha2-nistp256':
                        $hash = 'sha256';
                        break;
                    case 'ecdsa-sha2-nistp384':
                        $hash = 'sha384';
                        break;
                    case 'ecdsa-sha2-nistp521':
                        $hash = 'sha512';
                }
                $key = $key->withHash($hash);
                break;
            case 'ssh-dss':
                $key = DSA::loadFormat('OpenSSH', $server_public_host_key)
                    ->withSignatureFormat('SSH2')
                    ->withHash('sha1');
                break;
            case 'ssh-rsa':
            case 'rsa-sha2-256':
            case 'rsa-sha2-512':
                // could be ssh-rsa, rsa-sha2-256, rsa-sha2-512
                // we don't check here because we already checked in key_exchange
                // some signatures have the type embedded within the message and some don't
                list(, $signature) = Strings::unpackSSH2('ss', $signature);

                $key = RSA::loadFormat('OpenSSH', $server_public_host_key)
                    ->withPadding(RSA::SIGNATURE_PKCS1);
                switch ($this->signature_format) {
                    case 'rsa-sha2-512':
                        $hash = 'sha512';
                        break;
                    case 'rsa-sha2-256':
                        $hash = 'sha256';
                        break;
                    //case 'ssh-rsa':
                    default:
                        $hash = 'sha1';
                }
                $key = $key->withHash($hash);
                break;
            default:
                $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
                throw new NoSupportedAlgorithmsException('Unsupported signature format');
        }

        if (!$key->verify($this->exchange_hash, $signature)) {
            return $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
        };

        return $this->signature_format . ' ' . $server_public_host_key;
    }

    /**
     * Returns the exit status of an SSH command or false.
     *
     * @return false|int
     */
    public function getExitStatus()
    {
        if (is_null($this->exit_status)) {
            return false;
        }
        return $this->exit_status;
    }

    /**
     * Returns the number of columns for the terminal window size.
     *
     * @return int
     */
    public function getWindowColumns()
    {
        return $this->windowColumns;
    }

    /**
     * Returns the number of rows for the terminal window size.
     *
     * @return int
     */
    public function getWindowRows()
    {
        return $this->windowRows;
    }

    /**
     * Sets the number of columns for the terminal window size.
     *
     * @param int $value
     */
    public function setWindowColumns($value)
    {
        $this->windowColumns = $value;
    }

    /**
     * Sets the number of rows for the terminal window size.
     *
     * @param int $value
     */
    public function setWindowRows($value)
    {
        $this->windowRows = $value;
    }

    /**
     * Sets the number of columns and rows for the terminal window size.
     *
     * @param int $columns
     * @param int $rows
     */
    public function setWindowSize($columns = 80, $rows = 24)
    {
        $this->windowColumns = $columns;
        $this->windowRows = $rows;
    }

    /**
     * To String Magic Method
     *
     * @return string
     */
    #[\ReturnTypeWillChange]
    public function __toString()
    {
        return $this->getResourceId();
    }

    /**
     * Get Resource ID
     *
     * We use {} because that symbols should not be in URL according to
     * {@link http://tools.ietf.org/html/rfc3986#section-2 RFC}.
     * It will safe us from any conflicts, because otherwise regexp will
     * match all alphanumeric domains.
     *
     * @return string
     */
    public function getResourceId()
    {
        return '{' . spl_object_hash($this) . '}';
    }

    /**
     * Return existing connection
     *
     * @param string $id
     *
     * @return bool|SSH2 will return false if no such connection
     */
    public static function getConnectionByResourceId($id)
    {
        if (isset(self::$connections[$id])) {
            return self::$connections[$id] instanceof \WeakReference ? self::$connections[$id]->get() : self::$connections[$id];
        }
        return false;
    }

    /**
     * Return all excising connections
     *
     * @return array<string, SSH2>
     */
    public static function getConnections()
    {
        if (!class_exists('WeakReference')) {
            /** @var array<string, SSH2> */
            return self::$connections;
        }
        $temp = [];
        foreach (self::$connections as $key => $ref) {
            $temp[$key] = $ref->get();
        }
        return $temp;
    }

    /*
     * Update packet types in log history
     *
     * @param string $old
     * @param string $new
     */
    private function updateLogHistory($old, $new)
    {
        if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == self::LOG_COMPLEX) {
            $this->message_number_log[count($this->message_number_log) - 1] = str_replace(
                $old,
                $new,
                $this->message_number_log[count($this->message_number_log) - 1]
            );
        }
    }

    /**
     * Return the list of authentication methods that may productively continue authentication.
     *
     * @see https://tools.ietf.org/html/rfc4252#section-5.1
     * @return array|null
     */
    public function getAuthMethodsToContinue()
    {
        return $this->auth_methods_to_continue;
    }

    /**
     * Enables "smart" multi-factor authentication (MFA)
     */
    public function enableSmartMFA()
    {
        $this->smartMFA = true;
    }

    /**
     * Disables "smart" multi-factor authentication (MFA)
     */
    public function disableSmartMFA()
    {
        $this->smartMFA = false;
    }

    /**
     * How many bytes until the next key re-exchange?
     *
     * @param int $bytes
     */
    public function bytesUntilKeyReexchange($bytes)
    {
        $this->doKeyReexchangeAfterXBytes = $bytes;
    }
}
<?php

/**
 * Pure-PHP arbitrary precision integer arithmetic library.
 *
 * Supports base-2, base-10, base-16, and base-256 numbers.  Uses the GMP or BCMath extensions, if available,
 * and an internal implementation, otherwise.
 *
 * PHP version 5 and 7
 *
 * Here's an example of how to use this library:
 * <code>
 * <?php
 *    $a = new \phpseclib3\Math\BigInteger(2);
 *    $b = new \phpseclib3\Math\BigInteger(3);
 *
 *    $c = $a->add($b);
 *
 *    echo $c->toString(); // outputs 5
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 */

namespace phpseclib3\Math;

use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Math\BigInteger\Engines\Engine;

/**
 * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
 * numbers.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class BigInteger implements \JsonSerializable
{
    /**
     * Main Engine
     *
     * @var class-string<Engine>
     */
    private static $mainEngine;

    /**
     * Selected Engines
     *
     * @var list<string>
     */
    private static $engines;

    /**
     * The actual BigInteger object
     *
     * @var object
     */
    private $value;

    /**
     * Mode independent value used for serialization.
     *
     * @see self::__sleep()
     * @see self::__wakeup()
     * @var string
     */
    private $hex;

    /**
     * Precision (used only for serialization)
     *
     * @see self::__sleep()
     * @see self::__wakeup()
     * @var int
     */
    private $precision;

    /**
     * Sets engine type.
     *
     * Throws an exception if the type is invalid
     *
     * @param string $main
     * @param list<string> $modexps optional
     * @return void
     */
    public static function setEngine($main, array $modexps = ['DefaultEngine'])
    {
        self::$engines = [];

        $fqmain = 'phpseclib3\\Math\\BigInteger\\Engines\\' . $main;
        if (!class_exists($fqmain) || !method_exists($fqmain, 'isValidEngine')) {
            throw new \InvalidArgumentException("$main is not a valid engine");
        }
        if (!$fqmain::isValidEngine()) {
            throw new BadConfigurationException("$main is not setup correctly on this system");
        }
        /** @var class-string<Engine> $fqmain */
        self::$mainEngine = $fqmain;

        $found = false;
        foreach ($modexps as $modexp) {
            try {
                $fqmain::setModExpEngine($modexp);
                $found = true;
                break;
            } catch (\Exception $e) {
            }
        }

        if (!$found) {
            throw new BadConfigurationException("No valid modular exponentiation engine found for $main");
        }

        self::$engines = [$main, $modexp];
    }

    /**
     * Returns the engine type
     *
     * @return string[]
     */
    public static function getEngine()
    {
        self::initialize_static_variables();

        return self::$engines;
    }

    /**
     * Initialize static variables
     */
    private static function initialize_static_variables()
    {
        if (!isset(self::$mainEngine)) {
            $engines = [
                ['GMP', ['DefaultEngine']],
                ['PHP64', ['OpenSSL']],
                ['BCMath', ['OpenSSL']],
                ['PHP32', ['OpenSSL']],
                ['PHP64', ['DefaultEngine']],
                ['PHP32', ['DefaultEngine']]
            ];
            // per https://phpseclib.com/docs/speed PHP 8.4.0+ _significantly_ sped up BCMath
            if (version_compare(PHP_VERSION, '8.4.0') >= 0) {
                $engines[1][0] = 'BCMath';
                $engines[2][0] = 'PHP64';
            }

            foreach ($engines as $engine) {
                try {
                    self::setEngine($engine[0], $engine[1]);
                    return;
                } catch (\Exception $e) {
                }
            }

            throw new \UnexpectedValueException('No valid BigInteger found. This is only possible when JIT is enabled on Windows and neither the GMP or BCMath extensions are available so either disable JIT or install GMP / BCMath');
        }
    }

    /**
     * Converts base-2, base-10, base-16, and binary strings (base-256) to BigIntegers.
     *
     * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
     * two's compliment.  The sole exception to this is -10, which is treated the same as 10 is.
     *
     * @param string|int|Engine $x Base-10 number or base-$base number if $base set.
     * @param int $base
     */
    public function __construct($x = 0, $base = 10)
    {
        self::initialize_static_variables();

        if ($x instanceof self::$mainEngine) {
            $this->value = clone $x;
        } elseif ($x instanceof Engine) {
            $this->value = new static("$x");
            $this->value->setPrecision($x->getPrecision());
        } else {
            $this->value = new self::$mainEngine($x, $base);
        }
    }

    /**
     * Converts a BigInteger to a base-10 number.
     *
     * @return string
     */
    public function toString()
    {
        return $this->value->toString();
    }

    /**
     *  __toString() magic method
     */
    public function __toString()
    {
        return (string)$this->value;
    }

    /**
     *  __debugInfo() magic method
     *
     * Will be called, automatically, when print_r() or var_dump() are called
     */
    public function __debugInfo()
    {
        return $this->value->__debugInfo();
    }

    /**
     * Converts a BigInteger to a byte string (eg. base-256).
     *
     * @param bool $twos_compliment
     * @return string
     */
    public function toBytes($twos_compliment = false)
    {
        return $this->value->toBytes($twos_compliment);
    }

    /**
     * Converts a BigInteger to a hex string (eg. base-16).
     *
     * @param bool $twos_compliment
     * @return string
     */
    public function toHex($twos_compliment = false)
    {
        return $this->value->toHex($twos_compliment);
    }

    /**
     * Converts a BigInteger to a bit string (eg. base-2).
     *
     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
     * saved as two's compliment.
     *
     * @param bool $twos_compliment
     * @return string
     */
    public function toBits($twos_compliment = false)
    {
        return $this->value->toBits($twos_compliment);
    }

    /**
     * Adds two BigIntegers.
     *
     * @param BigInteger $y
     * @return BigInteger
     */
    public function add(BigInteger $y)
    {
        return new static($this->value->add($y->value));
    }

    /**
     * Subtracts two BigIntegers.
     *
     * @param BigInteger $y
     * @return BigInteger
     */
    public function subtract(BigInteger $y)
    {
        return new static($this->value->subtract($y->value));
    }

    /**
     * Multiplies two BigIntegers
     *
     * @param BigInteger $x
     * @return BigInteger
     */
    public function multiply(BigInteger $x)
    {
        return new static($this->value->multiply($x->value));
    }

    /**
     * Divides two BigIntegers.
     *
     * Returns an array whose first element contains the quotient and whose second element contains the
     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
     * and the divisor (basically, the "common residue" is the first positive modulo).
     *
     * Here's an example:
     * <code>
     * <?php
     *    $a = new \phpseclib3\Math\BigInteger('10');
     *    $b = new \phpseclib3\Math\BigInteger('20');
     *
     *    list($quotient, $remainder) = $a->divide($b);
     *
     *    echo $quotient->toString(); // outputs 0
     *    echo "\r\n";
     *    echo $remainder->toString(); // outputs 10
     * ?>
     * </code>
     *
     * @param BigInteger $y
     * @return BigInteger[]
     */
    public function divide(BigInteger $y)
    {
        list($q, $r) = $this->value->divide($y->value);
        return [
            new static($q),
            new static($r)
        ];
    }

    /**
     * Calculates modular inverses.
     *
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
     *
     * @param BigInteger $n
     * @return BigInteger
     * @changed in phpseclib 4.0.0
     */
    public function modInverse(BigInteger $n)
    {
        return new static($this->value->modInverse($n->value));
    }

    /**
     * Calculates modular inverses.
     *
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
     *
     * @param BigInteger $n
     * @return BigInteger[]
     */
    public function extendedGCD(BigInteger $n)
    {
        $extended = $this->value->extendedGCD($n->value);
        $gcd = $extended['gcd'];
        $x = $extended['x'];
        $y = $extended['y'];
        return [
            'gcd' => new static($gcd),
            'x' => new static($x),
            'y' => new static($y)
        ];
    }

    /**
     * Calculates the greatest common divisor
     *
     * Say you have 693 and 609.  The GCD is 21.
     *
     * @param BigInteger $n
     * @return BigInteger
     */
    public function gcd(BigInteger $n)
    {
        return new static($this->value->gcd($n->value));
    }

    /**
     * Absolute value.
     *
     * @return BigInteger
     */
    public function abs()
    {
        return new static($this->value->abs());
    }

    /**
     * Set Precision
     *
     * Some bitwise operations give different results depending on the precision being used.  Examples include left
     * shift, not, and rotates.
     *
     * @param int $bits
     */
    public function setPrecision($bits)
    {
        $this->value->setPrecision($bits);
    }

    /**
     * Get Precision
     *
     * Returns the precision if it exists, false if it doesn't
     *
     * @return int|bool
     */
    public function getPrecision()
    {
        return $this->value->getPrecision();
    }

    /**
     * Serialize
     *
     * Will be called, automatically, when serialize() is called on a BigInteger object.
     *
     * __sleep() / __wakeup() have been around since PHP 4.0 but were deprecated in PHP 8.5
     *
     * \Serializable was introduced in PHP 5.1 and deprecated in PHP 8.1:
     * https://wiki.php.net/rfc/phase_out_serializable
     *
     * __serialize() / __unserialize() were introduced in PHP 7.4:
     * https://wiki.php.net/rfc/custom_object_serialization
     *
     * @return array
     */
    public function __sleep()
    {
        $this->hex = $this->toHex(true);
        $vars = ['hex'];
        if ($this->getPrecision() > 0) {
            $vars[] = 'precision';
        }
        return $vars;
    }

    /**
     * Serialize
     *
     * Will be called, automatically, when unserialize() is called on a BigInteger object.
     */
    public function __wakeup()
    {
        $temp = new static($this->hex, -16);
        $this->value = $temp->value;
        if ($this->precision > 0) {
            // recalculate $this->bitmask
            $this->setPrecision($this->precision);
        }
    }

    /**
     *  __serialize() magic method
     *
     * @see self::__unserialize()
     * @return array
     * @access public
     */
    public function __serialize()
    {
        $result = ['hex' => $this->toHex(true)];
        if ($this->getPrecision() > 0) {
            $result['precision'] = $this->getPrecision();
        }
        return $result;
    }

    /**
     *  __unserialize() magic method
     *
     * @see self::__serialize()
     * @access public
     */
    public function __unserialize(array $data)
    {
        $temp = new static($data['hex'], -16);
        $this->value = $temp->value;
        if (isset($data['precision']) && $data['precision'] > 0) {
            // recalculate $this->bitmask
            $this->setPrecision($data['precision']);
        }
    }

    /**
     * JSON Serialize
     *
     * Will be called, automatically, when json_encode() is called on a BigInteger object.
     *
     * @return array{hex: string, precision?: int]
     */
    #[\ReturnTypeWillChange]
    public function jsonSerialize()
    {
        $result = ['hex' => $this->toHex(true)];
        if ($this->precision > 0) {
            $result['precision'] = $this->getPrecision();
        }
        return $result;
    }

    /**
     * Performs modular exponentiation.
     *
     * @param BigInteger $e
     * @param BigInteger $n
     * @return BigInteger
     */
    public function powMod(BigInteger $e, BigInteger $n)
    {
        return new static($this->value->powMod($e->value, $n->value));
    }

    /**
     * Performs modular exponentiation.
     *
     * @param BigInteger $e
     * @param BigInteger $n
     * @return BigInteger
     */
    public function modPow(BigInteger $e, BigInteger $n)
    {
        return new static($this->value->modPow($e->value, $n->value));
    }

    /**
     * Compares two numbers.
     *
     * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite.  The reason for this
     * is demonstrated thusly:
     *
     * $x  > $y: $x->compare($y)  > 0
     * $x  < $y: $x->compare($y)  < 0
     * $x == $y: $x->compare($y) == 0
     *
     * Note how the same comparison operator is used.  If you want to test for equality, use $x->equals($y).
     *
     * {@internal Could return $this->subtract($x), but that's not as fast as what we do do.}
     *
     * @param BigInteger $y
     * @return int in case < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
     * @see self::equals()
     */
    public function compare(BigInteger $y)
    {
        return $this->value->compare($y->value);
    }

    /**
     * Tests the equality of two numbers.
     *
     * If you need to see if one number is greater than or less than another number, use BigInteger::compare()
     *
     * @param BigInteger $x
     * @return bool
     */
    public function equals(BigInteger $x)
    {
        return $this->value->equals($x->value);
    }

    /**
     * Logical Not
     *
     * @return BigInteger
     */
    public function bitwise_not()
    {
        return new static($this->value->bitwise_not());
    }

    /**
     * Logical And
     *
     * @param BigInteger $x
     * @return BigInteger
     */
    public function bitwise_and(BigInteger $x)
    {
        return new static($this->value->bitwise_and($x->value));
    }

    /**
     * Logical Or
     *
     * @param BigInteger $x
     * @return BigInteger
     */
    public function bitwise_or(BigInteger $x)
    {
        return new static($this->value->bitwise_or($x->value));
    }

    /**
     * Logical Exclusive Or
     *
     * @param BigInteger $x
     * @return BigInteger
     */
    public function bitwise_xor(BigInteger $x)
    {
        return new static($this->value->bitwise_xor($x->value));
    }

    /**
     * Logical Right Shift
     *
     * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
     *
     * @param int $shift
     * @return BigInteger
     */
    public function bitwise_rightShift($shift)
    {
        return new static($this->value->bitwise_rightShift($shift));
    }

    /**
     * Logical Left Shift
     *
     * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
     *
     * @param int $shift
     * @return BigInteger
     */
    public function bitwise_leftShift($shift)
    {
        return new static($this->value->bitwise_leftShift($shift));
    }

    /**
     * Logical Left Rotate
     *
     * Instead of the top x bits being dropped they're appended to the shifted bit string.
     *
     * @param int $shift
     * @return BigInteger
     */
    public function bitwise_leftRotate($shift)
    {
        return new static($this->value->bitwise_leftRotate($shift));
    }

    /**
     * Logical Right Rotate
     *
     * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
     *
     * @param int $shift
     * @return BigInteger
     */
    public function bitwise_rightRotate($shift)
    {
        return new static($this->value->bitwise_rightRotate($shift));
    }

    /**
     * Returns the smallest and largest n-bit number
     *
     * @param int $bits
     * @return BigInteger[]
     */
    public static function minMaxBits($bits)
    {
        self::initialize_static_variables();

        $class = self::$mainEngine;
        $minMax = $class::minMaxBits($bits);
        $min = $minMax['min'];
        $max = $minMax['max'];
        return [
            'min' => new static($min),
            'max' => new static($max)
        ];
    }

    /**
     * Return the size of a BigInteger in bits
     *
     * @return int
     */
    public function getLength()
    {
        return $this->value->getLength();
    }

    /**
     * Return the size of a BigInteger in bytes
     *
     * @return int
     */
    public function getLengthInBytes()
    {
        return $this->value->getLengthInBytes();
    }

    /**
     * Generates a random number of a certain size
     *
     * Bit length is equal to $size
     *
     * @param int $size
     * @return BigInteger
     */
    public static function random($size)
    {
        self::initialize_static_variables();

        $class = self::$mainEngine;
        return new static($class::random($size));
    }

    /**
     * Generates a random prime number of a certain size
     *
     * Bit length is equal to $size
     *
     * @param int $size
     * @return BigInteger
     */
    public static function randomPrime($size)
    {
        self::initialize_static_variables();

        $class = self::$mainEngine;
        return new static($class::randomPrime($size));
    }

    /**
     * Generate a random prime number between a range
     *
     * If there's not a prime within the given range, false will be returned.
     *
     * @param BigInteger $min
     * @param BigInteger $max
     * @return false|BigInteger
     */
    public static function randomRangePrime(BigInteger $min, BigInteger $max)
    {
        $class = self::$mainEngine;
        return new static($class::randomRangePrime($min->value, $max->value));
    }

    /**
     * Generate a random number between a range
     *
     * Returns a random number between $min and $max where $min and $max
     * can be defined using one of the two methods:
     *
     * BigInteger::randomRange($min, $max)
     * BigInteger::randomRange($max, $min)
     *
     * @param BigInteger $min
     * @param BigInteger $max
     * @return BigInteger
     */
    public static function randomRange(BigInteger $min, BigInteger $max)
    {
        $class = self::$mainEngine;
        return new static($class::randomRange($min->value, $max->value));
    }

    /**
     * Checks a numer to see if it's prime
     *
     * Assuming the $t parameter is not set, this function has an error rate of 2**-80.  The main motivation for the
     * $t parameter is distributability.  BigInteger::randomPrime() can be distributed across multiple pageloads
     * on a website instead of just one.
     *
     * @param int|bool $t
     * @return bool
     */
    public function isPrime($t = false)
    {
        return $this->value->isPrime($t);
    }

    /**
     * Calculates the nth root of a biginteger.
     *
     * Returns the nth root of a positive biginteger, where n defaults to 2
     *
     * @param int $n optional
     * @return BigInteger
     */
    public function root($n = 2)
    {
        return new static($this->value->root($n));
    }

    /**
     * Performs exponentiation.
     *
     * @param BigInteger $n
     * @return BigInteger
     */
    public function pow(BigInteger $n)
    {
        return new static($this->value->pow($n->value));
    }

    /**
     * Return the minimum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param BigInteger ...$nums
     * @return BigInteger
     */
    public static function min(BigInteger ...$nums)
    {
        $class = self::$mainEngine;
        $nums = array_map(function ($num) {
            return $num->value;
        }, $nums);
        return new static($class::min(...$nums));
    }

    /**
     * Return the maximum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param BigInteger ...$nums
     * @return BigInteger
     */
    public static function max(BigInteger ...$nums)
    {
        $class = self::$mainEngine;
        $nums = array_map(function ($num) {
            return $num->value;
        }, $nums);
        return new static($class::max(...$nums));
    }

    /**
     * Tests BigInteger to see if it is between two integers, inclusive
     *
     * @param BigInteger $min
     * @param BigInteger $max
     * @return bool
     */
    public function between(BigInteger $min, BigInteger $max)
    {
        return $this->value->between($min->value, $max->value);
    }

    /**
     * Clone
     */
    public function __clone()
    {
        $this->value = clone $this->value;
    }

    /**
     * Is Odd?
     *
     * @return bool
     */
    public function isOdd()
    {
        return $this->value->isOdd();
    }

    /**
     * Tests if a bit is set
     *
     * @param int $x
     * @return bool
     */
    public function testBit($x)
    {
        return $this->value->testBit($x);
    }

    /**
     * Is Negative?
     *
     * @return bool
     */
    public function isNegative()
    {
        return $this->value->isNegative();
    }

    /**
     * Negate
     *
     * Given $k, returns -$k
     *
     * @return BigInteger
     */
    public function negate()
    {
        return new static($this->value->negate());
    }

    /**
     * Scan for 1 and right shift by that amount
     *
     * ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
     *
     * @param BigInteger $r
     * @return int
     */
    public static function scan1divide(BigInteger $r)
    {
        $class = self::$mainEngine;
        return $class::scan1divide($r->value);
    }

    /**
     * Create Recurring Modulo Function
     *
     * Sometimes it may be desirable to do repeated modulos with the same number outside of
     * modular exponentiation
     *
     * @return callable
     */
    public function createRecurringModuloFunction()
    {
        $func = $this->value->createRecurringModuloFunction();
        return function (BigInteger $x) use ($func) {
            return new static($func($x->value));
        };
    }

    /**
     * Bitwise Split
     *
     * Splits BigInteger's into chunks of $split bits
     *
     * @param int $split
     * @return BigInteger[]
     */
    public function bitwise_split($split)
    {
        return array_map(function ($val) {
            return new static($val);
        }, $this->value->bitwise_split($split));
    }
}
<?php

/**
 * Prime Finite Fields
 *
 * Utilizes the factory design pattern
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math;

use phpseclib3\Math\Common\FiniteField;
use phpseclib3\Math\PrimeField\Integer;

/**
 * Prime Finite Fields
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class PrimeField extends FiniteField
{
    /**
     * Instance Counter
     *
     * @var int
     */
    private static $instanceCounter = 0;

    /**
     * Keeps track of current instance
     *
     * @var int
     */
    protected $instanceID;

    /**
     * Default constructor
     */
    public function __construct(BigInteger $modulo)
    {
        if (!$modulo->isPrime()) {
            throw new \UnexpectedValueException('PrimeField requires a prime number be passed to the constructor');
        }

        $this->instanceID = self::$instanceCounter++;
        Integer::setModulo($this->instanceID, $modulo);
        Integer::setRecurringModuloFunction($this->instanceID, $modulo->createRecurringModuloFunction());
    }

    /**
     * Use a custom defined modular reduction function
     *
     * @return void
     */
    public function setReduction(\Closure $func)
    {
        $this->reduce = $func->bindTo($this, $this);
    }

    /**
     * Returns an instance of a dynamically generated PrimeFieldInteger class
     *
     * @return Integer
     */
    public function newInteger(BigInteger $num)
    {
        return new Integer($this->instanceID, $num);
    }

    /**
     * Returns an integer on the finite field between one and the prime modulo
     *
     * @return Integer
     */
    public function randomInteger()
    {
        static $one;
        if (!isset($one)) {
            $one = new BigInteger(1);
        }

        return new Integer($this->instanceID, BigInteger::randomRange($one, Integer::getModulo($this->instanceID)));
    }

    /**
     * Returns the length of the modulo in bytes
     *
     * @return int
     */
    public function getLengthInBytes()
    {
        return Integer::getModulo($this->instanceID)->getLengthInBytes();
    }

    /**
     * Returns the length of the modulo in bits
     *
     * @return int
     */
    public function getLength()
    {
        return Integer::getModulo($this->instanceID)->getLength();
    }

    /**
     *  Destructor
     */
    public function __destruct()
    {
        Integer::cleanupCache($this->instanceID);
    }
}
<?php

/**
 * Finite Field Integer Base Class
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 */

namespace phpseclib3\Math\Common\FiniteField;

/**
 * Finite Field Integer
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Integer implements \JsonSerializable
{
    /**
     * JSON Serialize
     *
     * Will be called, automatically, when json_encode() is called on a BigInteger object.
     *
     * PHP Serialize isn't supported because unserializing would require the factory be
     * serialized as well and that just sounds like too much
     *
     * @return array{hex: string}
     */
    #[\ReturnTypeWillChange]
    public function jsonSerialize()
    {
        return ['hex' => $this->toHex(true)];
    }

    /**
     * Converts an Integer to a hex string (eg. base-16).
     *
     * @return string
     */
    abstract public function toHex();
}
<?php

/**
 * Finite Fields Base Class
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 */

namespace phpseclib3\Math\Common;

/**
 * Finite Fields
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class FiniteField
{
}
<?php

/**
 * Binary Finite Fields
 *
 * In a binary finite field numbers are actually polynomial equations. If you
 * represent the number as a sequence of bits you get a sequence of 1's or 0's.
 * These 1's or 0's represent the coefficients of the x**n, where n is the
 * location of the given bit. When you add numbers over a binary finite field
 * the result should have a coefficient of 1 or 0 as well. Hence addition
 * and subtraction become the same operation as XOR.
 * eg. 1 + 1 + 1 == 3 % 2 == 1 or 0 - 1 == -1 % 2 == 1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 */

namespace phpseclib3\Math\BinaryField;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Math\BigInteger;
use phpseclib3\Math\BinaryField;
use phpseclib3\Math\Common\FiniteField\Integer as Base;

/**
 * Binary Finite Fields
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Integer extends Base
{
    /**
     * Holds the BinaryField's value
     *
     * @var string
     */
    protected $value;

    /**
     * Keeps track of current instance
     *
     * @var int
     */
    protected $instanceID;

    /**
     * Holds the PrimeField's modulo
     *
     * @var array<int, string>
     */
    protected static $modulo;

    /**
     * Holds a pre-generated function to perform modulo reductions
     *
     * @var callable[]
     */
    protected static $reduce;

    /**
     * Default constructor
     */
    public function __construct($instanceID, $num = '')
    {
        $this->instanceID = $instanceID;
        if (!strlen($num)) {
            $this->value = '';
        } else {
            $reduce = static::$reduce[$instanceID];
            $this->value = $reduce($num);
        }
    }

    /**
     * Set the modulo for a given instance
     * @param int $instanceID
     * @param string $modulo
     */
    public static function setModulo($instanceID, $modulo)
    {
        static::$modulo[$instanceID] = $modulo;
    }

    /**
     * Set the modulo for a given instance
     */
    public static function setRecurringModuloFunction($instanceID, callable $function)
    {
        static::$reduce[$instanceID] = $function;
    }

    /**
     * Tests a parameter to see if it's of the right instance
     *
     * Throws an exception if the incorrect class is being utilized
     */
    private static function checkInstance(self $x, self $y)
    {
        if ($x->instanceID != $y->instanceID) {
            throw new \UnexpectedValueException('The instances of the two BinaryField\Integer objects do not match');
        }
    }

    /**
     * Tests the equality of two numbers.
     *
     * @return bool
     */
    public function equals(self $x)
    {
        static::checkInstance($this, $x);

        return $this->value == $x->value;
    }

    /**
     * Compares two numbers.
     *
     * @return int
     */
    public function compare(self $x)
    {
        static::checkInstance($this, $x);

        $a = $this->value;
        $b = $x->value;

        $length = max(strlen($a), strlen($b));

        $a = str_pad($a, $length, "\0", STR_PAD_LEFT);
        $b = str_pad($b, $length, "\0", STR_PAD_LEFT);

        return strcmp($a, $b);
    }

    /**
     * Returns the degree of the polynomial
     *
     * @param string $x
     * @return int
     */
    private static function deg($x)
    {
        $x = ltrim($x, "\0");
        $xbit = decbin(ord($x[0]));
        $xlen = $xbit == '0' ? 0 : strlen($xbit);
        $len = strlen($x);
        if (!$len) {
            return -1;
        }
        return 8 * strlen($x) - 9 + $xlen;
    }

    /**
     * Perform polynomial division
     *
     * @return string[]
     * @link https://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor#Euclidean_division
     */
    private static function polynomialDivide($x, $y)
    {
        // in wikipedia's description of the algorithm, lc() is the leading coefficient. over a binary field that's
        // always going to be 1.

        $q = chr(0);
        $d = static::deg($y);
        $r = $x;
        while (($degr = static::deg($r)) >= $d) {
            $s = '1' . str_repeat('0', $degr - $d);
            $s = BinaryField::base2ToBase256($s);
            $length = max(strlen($s), strlen($q));
            $q = !isset($q) ? $s :
                str_pad($q, $length, "\0", STR_PAD_LEFT) ^
                str_pad($s, $length, "\0", STR_PAD_LEFT);
            $s = static::polynomialMultiply($s, $y);
            $length = max(strlen($r), strlen($s));
            $r = str_pad($r, $length, "\0", STR_PAD_LEFT) ^
                 str_pad($s, $length, "\0", STR_PAD_LEFT);
        }

        return [ltrim($q, "\0"), ltrim($r, "\0")];
    }

    /**
     * Perform polynomial multiplation in the traditional way
     *
     * @return string
     * @link https://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplication
     */
    private static function regularPolynomialMultiply($x, $y)
    {
        $precomputed = [ltrim($x, "\0")];
        $x = strrev(BinaryField::base256ToBase2($x));
        $y = strrev(BinaryField::base256ToBase2($y));
        if (strlen($x) == strlen($y)) {
            $length = strlen($x);
        } else {
            $length = max(strlen($x), strlen($y));
            $x = str_pad($x, $length, '0');
            $y = str_pad($y, $length, '0');
        }
        $result = str_repeat('0', 2 * $length - 1);
        $result = BinaryField::base2ToBase256($result);
        $size = strlen($result);
        $x = strrev($x);

        // precompute left shift 1 through 7
        for ($i = 1; $i < 8; $i++) {
            $precomputed[$i] = BinaryField::base2ToBase256($x . str_repeat('0', $i));
        }
        for ($i = 0; $i < strlen($y); $i++) {
            if ($y[$i] == '1') {
                $temp = $precomputed[$i & 7] . str_repeat("\0", $i >> 3);
                $result ^= str_pad($temp, $size, "\0", STR_PAD_LEFT);
            }
        }

        return $result;
    }

    /**
     * Perform polynomial multiplation
     *
     * Uses karatsuba multiplication to reduce x-bit multiplications to a series of 32-bit multiplications
     *
     * @return string
     * @link https://en.wikipedia.org/wiki/Karatsuba_algorithm
     */
    private static function polynomialMultiply($x, $y)
    {
        if (strlen($x) == strlen($y)) {
            $length = strlen($x);
        } else {
            $length = max(strlen($x), strlen($y));
            $x = str_pad($x, $length, "\0", STR_PAD_LEFT);
            $y = str_pad($y, $length, "\0", STR_PAD_LEFT);
        }

        switch (true) {
            case PHP_INT_SIZE == 8 && $length <= 4:
                return $length != 4 ?
                    self::subMultiply(str_pad($x, 4, "\0", STR_PAD_LEFT), str_pad($y, 4, "\0", STR_PAD_LEFT)) :
                    self::subMultiply($x, $y);
            case PHP_INT_SIZE == 4 || $length > 32:
                return self::regularPolynomialMultiply($x, $y);
        }

        $m = $length >> 1;

        $x1 = substr($x, 0, -$m);
        $x0 = substr($x, -$m);
        $y1 = substr($y, 0, -$m);
        $y0 = substr($y, -$m);

        $z2 = self::polynomialMultiply($x1, $y1);
        $z0 = self::polynomialMultiply($x0, $y0);
        $z1 = self::polynomialMultiply(
            self::subAdd2($x1, $x0),
            self::subAdd2($y1, $y0)
        );

        $z1 = self::subAdd3($z1, $z2, $z0);

        $xy = self::subAdd3(
            $z2 . str_repeat("\0", 2 * $m),
            $z1 . str_repeat("\0", $m),
            $z0
        );

        return ltrim($xy, "\0");
    }

    /**
     * Perform polynomial multiplication on 2x 32-bit numbers, returning
     * a 64-bit number
     *
     * @param string $x
     * @param string $y
     * @return string
     * @link https://www.bearssl.org/constanttime.html#ghash-for-gcm
     */
    private static function subMultiply($x, $y)
    {
        $x = unpack('N', $x)[1];
        $y = unpack('N', $y)[1];

        $x0 = $x & 0x11111111;
        $x1 = $x & 0x22222222;
        $x2 = $x & 0x44444444;
        $x3 = $x & 0x88888888;

        $y0 = $y & 0x11111111;
        $y1 = $y & 0x22222222;
        $y2 = $y & 0x44444444;
        $y3 = $y & 0x88888888;

        $z0 = ($x0 * $y0) ^ ($x1 * $y3) ^ ($x2 * $y2) ^ ($x3 * $y1);
        $z1 = ($x0 * $y1) ^ ($x1 * $y0) ^ ($x2 * $y3) ^ ($x3 * $y2);
        $z2 = ($x0 * $y2) ^ ($x1 * $y1) ^ ($x2 * $y0) ^ ($x3 * $y3);
        $z3 = ($x0 * $y3) ^ ($x1 * $y2) ^ ($x2 * $y1) ^ ($x3 * $y0);

        $z0 &= 0x1111111111111111;
        $z1 &= 0x2222222222222222;
        $z2 &= 0x4444444444444444;
        $z3 &= -8608480567731124088; // 0x8888888888888888 gets interpreted as a float

        $z = $z0 | $z1 | $z2 | $z3;

        return pack('J', $z);
    }

    /**
     * Adds two numbers
     *
     * @param string $x
     * @param string $y
     * @return string
     */
    private static function subAdd2($x, $y)
    {
        $length = max(strlen($x), strlen($y));
        $x = str_pad($x, $length, "\0", STR_PAD_LEFT);
        $y = str_pad($y, $length, "\0", STR_PAD_LEFT);
        return $x ^ $y;
    }

    /**
     * Adds three numbers
     *
     * @param string $x
     * @param string $y
     * @return string
     */
    private static function subAdd3($x, $y, $z)
    {
        $length = max(strlen($x), strlen($y), strlen($z));
        $x = str_pad($x, $length, "\0", STR_PAD_LEFT);
        $y = str_pad($y, $length, "\0", STR_PAD_LEFT);
        $z = str_pad($z, $length, "\0", STR_PAD_LEFT);
        return $x ^ $y ^ $z;
    }

    /**
     * Adds two BinaryFieldIntegers.
     *
     * @return static
     */
    public function add(self $y)
    {
        static::checkInstance($this, $y);

        $length = strlen(static::$modulo[$this->instanceID]);

        $x = str_pad($this->value, $length, "\0", STR_PAD_LEFT);
        $y = str_pad($y->value, $length, "\0", STR_PAD_LEFT);

        return new static($this->instanceID, $x ^ $y);
    }

    /**
     * Subtracts two BinaryFieldIntegers.
     *
     * @return static
     */
    public function subtract(self $x)
    {
        return $this->add($x);
    }

    /**
     * Multiplies two BinaryFieldIntegers.
     *
     * @return static
     */
    public function multiply(self $y)
    {
        static::checkInstance($this, $y);

        return new static($this->instanceID, static::polynomialMultiply($this->value, $y->value));
    }

    /**
     * Returns the modular inverse of a BinaryFieldInteger
     *
     * @return static
     */
    public function modInverse()
    {
        $remainder0 = static::$modulo[$this->instanceID];
        $remainder1 = $this->value;

        if ($remainder1 == '') {
            return new static($this->instanceID);
        }

        $aux0 = "\0";
        $aux1 = "\1";
        while ($remainder1 != "\1") {
            list($q, $r) = static::polynomialDivide($remainder0, $remainder1);
            $remainder0 = $remainder1;
            $remainder1 = $r;
            // the auxiliary in row n is given by the sum of the auxiliary in
            // row n-2 and the product of the quotient and the auxiliary in row
            // n-1
            $temp = static::polynomialMultiply($aux1, $q);
            $aux = str_pad($aux0, strlen($temp), "\0", STR_PAD_LEFT) ^
                   str_pad($temp, strlen($aux0), "\0", STR_PAD_LEFT);
            $aux0 = $aux1;
            $aux1 = $aux;
        }

        $temp = new static($this->instanceID);
        $temp->value = ltrim($aux1, "\0");
        return $temp;
    }

    /**
     * Divides two PrimeFieldIntegers.
     *
     * @return static
     */
    public function divide(self $x)
    {
        static::checkInstance($this, $x);

        $x = $x->modInverse();
        return $this->multiply($x);
    }

    /**
     * Negate
     *
     * A negative number can be written as 0-12. With modulos, 0 is the same thing as the modulo
     * so 0-12 is the same thing as modulo-12
     *
     * @return object
     */
    public function negate()
    {
        $x = str_pad($this->value, strlen(static::$modulo[$this->instanceID]), "\0", STR_PAD_LEFT);

        return new static($this->instanceID, $x ^ static::$modulo[$this->instanceID]);
    }

    /**
     * Returns the modulo
     *
     * @return string
     */
    public static function getModulo($instanceID)
    {
        return static::$modulo[$instanceID];
    }

    /**
     * Converts an Integer to a byte string (eg. base-256).
     *
     * @return string
     */
    public function toBytes()
    {
        return str_pad($this->value, strlen(static::$modulo[$this->instanceID]), "\0", STR_PAD_LEFT);
    }

    /**
     * Converts an Integer to a hex string (eg. base-16).
     *
     * @return string
     */
    public function toHex()
    {
        return Strings::bin2hex($this->toBytes());
    }

    /**
     * Converts an Integer to a bit string (eg. base-2).
     *
     * @return string
     */
    public function toBits()
    {
        //return str_pad(BinaryField::base256ToBase2($this->value), strlen(static::$modulo[$this->instanceID]), '0', STR_PAD_LEFT);
        return BinaryField::base256ToBase2($this->value);
    }

    /**
     * Converts an Integer to a BigInteger
     *
     * @return string
     */
    public function toBigInteger()
    {
        return new BigInteger($this->value, 256);
    }

    /**
     *  __toString() magic method
     *
     */
    public function __toString()
    {
        return (string) $this->toBigInteger();
    }

    /**
     *  __debugInfo() magic method
     *
     */
    public function __debugInfo()
    {
        return ['value' => $this->toHex()];
    }
}
<?php

/**
 * PHP Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\PHP;

use phpseclib3\Math\BigInteger\Engines\PHP;

/**
 * PHP Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Base extends PHP
{
    /**
     * Cache constants
     *
     * $cache[self::VARIABLE] tells us whether or not the cached data is still valid.
     *
     */
    const VARIABLE = 0;
    /**
     * $cache[self::DATA] contains the cached data.
     *
     */
    const DATA = 1;

    /**
     * Test for engine validity
     *
     * @return bool
     */
    public static function isValidEngine()
    {
        return static::class != __CLASS__;
    }

    /**
     * Performs modular exponentiation.
     *
     * The most naive approach to modular exponentiation has very unreasonable requirements, and
     * and although the approach involving repeated squaring does vastly better, it, too, is impractical
     * for our purposes.  The reason being that division - by far the most complicated and time-consuming
     * of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
     *
     * Modular reductions resolve this issue.  Although an individual modular reduction takes more time
     * then an individual division, when performed in succession (with the same modulo), they're a lot faster.
     *
     * The two most commonly used modular reductions are Barrett and Montgomery reduction.  Montgomery reduction,
     * although faster, only works when the gcd of the modulo and of the base being used is 1.  In RSA, when the
     * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
     * the product of two odd numbers is odd), but what about when RSA isn't used?
     *
     * In contrast, Barrett reduction has no such constraint.  As such, some bigint implementations perform a
     * Barrett reduction after every operation in the modpow function.  Others perform Barrett reductions when the
     * modulo is even and Montgomery reductions when the modulo is odd.  BigInteger.java's modPow method, however,
     * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
     * the other, a power of two - and recombine them, later.  This is the method that this modPow function uses.
     * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
     *
     * @param PHP $x
     * @param PHP $e
     * @param PHP $n
     * @param string $class
     * @return PHP
     */
    protected static function powModHelper(PHP $x, PHP $e, PHP $n, $class)
    {
        if (empty($e->value)) {
            $temp = new $class();
            $temp->value = [1];
            return $x->normalize($temp);
        }

        if ($e->value == [1]) {
            list(, $temp) = $x->divide($n);
            return $x->normalize($temp);
        }

        if ($e->value == [2]) {
            $temp = new $class();
            $temp->value = $class::square($x->value);
            list(, $temp) = $temp->divide($n);
            return $x->normalize($temp);
        }

        return $x->normalize(static::slidingWindow($x, $e, $n, $class));
    }

    /**
     * Modular reduction preparation
     *
     * @param array $x
     * @param array $n
     * @param string $class
     * @see self::slidingWindow()
     * @return array
     */
    protected static function prepareReduce(array $x, array $n, $class)
    {
        return static::reduce($x, $n, $class);
    }

    /**
     * Modular multiply
     *
     * @param array $x
     * @param array $y
     * @param array $n
     * @param string $class
     * @see self::slidingWindow()
     * @return array
     */
    protected static function multiplyReduce(array $x, array $y, array $n, $class)
    {
        $temp = $class::multiplyHelper($x, false, $y, false);
        return static::reduce($temp[self::VALUE], $n, $class);
    }

    /**
     * Modular square
     *
     * @param array $x
     * @param array $n
     * @param string $class
     * @see self::slidingWindow()
     * @return array
     */
    protected static function squareReduce(array $x, array $n, $class)
    {
        return static::reduce($class::square($x), $n, $class);
    }
}
<?php

/**
 * PHP Montgomery Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\PHP;

use phpseclib3\Math\BigInteger\Engines\Engine;
use phpseclib3\Math\BigInteger\Engines\PHP;
use phpseclib3\Math\BigInteger\Engines\PHP\Reductions\PowerOfTwo;

/**
 * PHP Montgomery Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Montgomery extends Base
{
    /**
     * Test for engine validity
     *
     * @return bool
     */
    public static function isValidEngine()
    {
        return static::class != __CLASS__;
    }

    /**
     * Performs modular exponentiation.
     *
     * @template T of Engine
     * @param Engine $x
     * @param Engine $e
     * @param Engine $n
     * @param class-string<T> $class
     * @return T
     */
    protected static function slidingWindow(Engine $x, Engine $e, Engine $n, $class)
    {
        // is the modulo odd?
        if ($n->value[0] & 1) {
            return parent::slidingWindow($x, $e, $n, $class);
        }
        // if it's not, it's even

        // find the lowest set bit (eg. the max pow of 2 that divides $n)
        for ($i = 0; $i < count($n->value); ++$i) {
            if ($n->value[$i]) {
                $temp = decbin($n->value[$i]);
                $j = strlen($temp) - strrpos($temp, '1') - 1;
                $j += $class::BASE * $i;
                break;
            }
        }
        // at this point, 2^$j * $n/(2^$j) == $n

        $mod1 = clone $n;
        $mod1->rshift($j);
        $mod2 = new $class();
        $mod2->value = [1];
        $mod2->lshift($j);

        $part1 = $mod1->value != [1] ? parent::slidingWindow($x, $e, $mod1, $class) : new $class();
        $part2 = PowerOfTwo::slidingWindow($x, $e, $mod2, $class);

        $y1 = $mod2->modInverse($mod1);
        $y2 = $mod1->modInverse($mod2);

        $result = $part1->multiply($mod2);
        $result = $result->multiply($y1);

        $temp = $part2->multiply($mod1);
        $temp = $temp->multiply($y2);

        $result = $result->add($temp);
        list(, $result) = $result->divide($n);

        return $result;
    }
}
<?php

/**
 * PHP Classic Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;

use phpseclib3\Math\BigInteger\Engines\PHP\Base;

/**
 * PHP Classic Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Classic extends Base
{
    /**
     * Regular Division
     *
     * @param array $x
     * @param array $n
     * @param string $class
     * @return array
     */
    protected static function reduce(array $x, array $n, $class)
    {
        $lhs = new $class();
        $lhs->value = $x;
        $rhs = new $class();
        $rhs->value = $n;
        list(, $temp) = $lhs->divide($rhs);
        return $temp->value;
    }
}
<?php

/**
 * PHP Montgomery Modular Exponentiation Engine with interleaved multiplication
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;

use phpseclib3\Math\BigInteger\Engines\PHP;

/**
 * PHP Montgomery Modular Exponentiation Engine with interleaved multiplication
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class MontgomeryMult extends Montgomery
{
    /**
     * Montgomery Multiply
     *
     * Interleaves the montgomery reduction and long multiplication algorithms together as described in
     * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
     *
     * @see self::_prepMontgomery()
     * @see self::_montgomery()
     * @param array $x
     * @param array $y
     * @param array $m
     * @param class-string<PHP> $class
     * @return array
     */
    public static function multiplyReduce(array $x, array $y, array $m, $class)
    {
        // the following code, although not callable, can be run independently of the above code
        // although the above code performed better in my benchmarks the following could might
        // perform better under different circumstances. in lieu of deleting it it's just been
        // made uncallable

        static $cache = [
            self::VARIABLE => [],
            self::DATA => []
        ];

        if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
            $key = count($cache[self::VARIABLE]);
            $cache[self::VARIABLE][] = $m;
            $cache[self::DATA][] = self::modInverse67108864($m, $class);
        }

        $n = max(count($x), count($y), count($m));
        $x = array_pad($x, $n, 0);
        $y = array_pad($y, $n, 0);
        $m = array_pad($m, $n, 0);
        $a = [self::VALUE => self::array_repeat(0, $n + 1)];
        for ($i = 0; $i < $n; ++$i) {
            $temp = $a[self::VALUE][0] + $x[$i] * $y[0];
            $temp = $temp - $class::BASE_FULL * ($class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
            $temp = $temp * $cache[self::DATA][$key];
            $temp = $temp - $class::BASE_FULL * ($class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
            $temp = $class::addHelper($class::regularMultiply([$x[$i]], $y), false, $class::regularMultiply([$temp], $m), false);
            $a = $class::addHelper($a[self::VALUE], false, $temp[self::VALUE], false);
            $a[self::VALUE] = array_slice($a[self::VALUE], 1);
        }
        if (self::compareHelper($a[self::VALUE], false, $m, false) >= 0) {
            $a = $class::subtractHelper($a[self::VALUE], false, $m, false);
        }
        return $a[self::VALUE];
    }
}
<?php

/**
 * PHP Power of Two Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;

use phpseclib3\Math\BigInteger\Engines\PHP\Base;

/**
 * PHP Power Of Two Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PowerOfTwo extends Base
{
    /**
     * Prepare a number for use in Montgomery Modular Reductions
     *
     * @param array $x
     * @param array $n
     * @param string $class
     * @return array
     */
    protected static function prepareReduce(array $x, array $n, $class)
    {
        return self::reduce($x, $n, $class);
    }

    /**
     * Power Of Two Reduction
     *
     * @param array $x
     * @param array $n
     * @param string $class
     * @return array
     */
    protected static function reduce(array $x, array $n, $class)
    {
        $lhs = new $class();
        $lhs->value = $x;
        $rhs = new $class();
        $rhs->value = $n;

        $temp = new $class();
        $temp->value = [1];

        $result = $lhs->bitwise_and($rhs->subtract($temp));
        return $result->value;
    }
}
<?php

/**
 * PHP Montgomery Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;

use phpseclib3\Math\BigInteger\Engines\PHP\Montgomery as Progenitor;

/**
 * PHP Montgomery Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Montgomery extends Progenitor
{
    /**
     * Prepare a number for use in Montgomery Modular Reductions
     *
     * @param array $x
     * @param array $n
     * @param string $class
     * @return array
     */
    protected static function prepareReduce(array $x, array $n, $class)
    {
        $lhs = new $class();
        $lhs->value = array_merge(self::array_repeat(0, count($n)), $x);
        $rhs = new $class();
        $rhs->value = $n;

        list(, $temp) = $lhs->divide($rhs);
        return $temp->value;
    }

    /**
     * Montgomery Multiply
     *
     * Interleaves the montgomery reduction and long multiplication algorithms together as described in
     * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
     *
     * @param array $x
     * @param array $n
     * @param string $class
     * @return array
     */
    protected static function reduce(array $x, array $n, $class)
    {
        static $cache = [
            self::VARIABLE => [],
            self::DATA => []
        ];

        if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
            $key = count($cache[self::VARIABLE]);
            $cache[self::VARIABLE][] = $x;
            $cache[self::DATA][] = self::modInverse67108864($n, $class);
        }

        $k = count($n);

        $result = [self::VALUE => $x];

        for ($i = 0; $i < $k; ++$i) {
            $temp = $result[self::VALUE][$i] * $cache[self::DATA][$key];
            $temp = $temp - $class::BASE_FULL * ($class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31));
            $temp = $class::regularMultiply([$temp], $n);
            $temp = array_merge(self::array_repeat(0, $i), $temp);
            $result = $class::addHelper($result[self::VALUE], false, $temp, false);
        }

        $result[self::VALUE] = array_slice($result[self::VALUE], $k);

        if (self::compareHelper($result, false, $n, false) >= 0) {
            $result = $class::subtractHelper($result[self::VALUE], false, $n, false);
        }

        return $result[self::VALUE];
    }

    /**
     * Modular Inverse of a number mod 2**26 (eg. 67108864)
     *
     * Based off of the bnpInvDigit function implemented and justified in the following URL:
     *
     * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
     *
     * The following URL provides more info:
     *
     * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
     *
     * As for why we do all the bitmasking...  strange things can happen when converting from floats to ints. For
     * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
     * int(-2147483648).  To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
     * auto-converted to floats.  The outermost bitmask is present because without it, there's no guarantee that
     * the "residue" returned would be the so-called "common residue".  We use fmod, in the last step, because the
     * maximum possible $x is 26 bits and the maximum $result is 16 bits.  Thus, we have to be able to handle up to
     * 40 bits, which only 64-bit floating points will support.
     *
     * Thanks to Pedro Gimeno Fortea for input!
     *
     * @param array $x
     * @param string $class
     * @return int
     */
    protected static function modInverse67108864(array $x, $class) // 2**26 == 67,108,864
    {
        $x = -$x[0];
        $result = $x & 0x3; // x**-1 mod 2**2
        $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
        $result = ($result * (2 - ($x & 0xFF) * $result))  & 0xFF; // x**-1 mod 2**8
        $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
        $result = $class::BASE == 26 ?
            fmod($result * (2 - fmod($x * $result, $class::BASE_FULL)), $class::BASE_FULL) : // x**-1 mod 2**26
            ($result * (2 - ($x * $result) % $class::BASE_FULL)) % $class::BASE_FULL;
        return $result & $class::MAX_DIGIT;
    }
}
<?php

/**
 * PHP Dynamic Barrett Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;

use phpseclib3\Math\BigInteger\Engines\PHP;
use phpseclib3\Math\BigInteger\Engines\PHP\Base;

/**
 * PHP Dynamic Barrett Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class EvalBarrett extends Base
{
    /**
     * Custom Reduction Function
     *
     * @see self::generateCustomReduction
     */
    private static $custom_reduction;

    /**
     * Barrett Modular Reduction
     *
     * This calls a dynamically generated loop unrolled function that's specific to a given modulo.
     * Array lookups are avoided as are if statements testing for how many bits the host OS supports, etc.
     *
     * @param array $n
     * @param array $m
     * @param string $class
     * @return array
     */
    protected static function reduce(array $n, array $m, $class)
    {
        $inline = self::$custom_reduction;
        return $inline($n);
    }

    /**
     * Generate Custom Reduction
     *
     * @param PHP $m
     * @param string $class
     * @return callable
     */
    protected static function generateCustomReduction(PHP $m, $class)
    {
        $m_length = count($m->value);

        if ($m_length < 5) {
            $code = '
                $lhs = new ' . $class . '();
                $lhs->value = $x;
                $rhs = new ' . $class . '();
                $rhs->value = [' .
                implode(',', array_map(self::class . '::float2string', $m->value)) . '];
                list(, $temp) = $lhs->divide($rhs);
                return $temp->value;
            ';
            eval('$func = function ($x) { ' . $code . '};');
            self::$custom_reduction = $func;
            //self::$custom_reduction = \Closure::bind($func, $m, $class);
            return $func;
        }

        $correctionNeeded = false;
        if ($m_length & 1) {
            $correctionNeeded = true;
            $m = clone $m;
            array_unshift($m->value, 0);
            $m_length++;
        }

        $lhs = new $class();
        $lhs_value = &$lhs->value;

        $lhs_value = self::array_repeat(0, $m_length + ($m_length >> 1));
        $lhs_value[] = 1;
        $rhs = new $class();

        list($u, $m1) = $lhs->divide($m);

        if ($class::BASE != 26) {
            $u = $u->value;
        } else {
            $lhs_value = self::array_repeat(0, 2 * $m_length);
            $lhs_value[] = 1;
            $rhs = new $class();

            list($u) = $lhs->divide($m);
            $u = $u->value;
        }

        $m = $m->value;
        $m1 = $m1->value;

        $cutoff = count($m) + (count($m) >> 1);

        $code = $correctionNeeded ?
            'array_unshift($n, 0);' :
            '';

        $code .= '
            if (count($n) > ' . (2 * count($m)) . ') {
                $lhs = new ' . $class . '();
                $rhs = new ' . $class . '();
                $lhs->value = $n;
                $rhs->value = [' .
                implode(',', array_map(self::class . '::float2string', $m)) . '];
                list(, $temp) = $lhs->divide($rhs);
                return $temp->value;
            }

            $lsd = array_slice($n, 0, ' . $cutoff . ');
            $msd = array_slice($n, ' . $cutoff . ');';

        $code .= self::generateInlineTrim('msd');
        $code .= self::generateInlineMultiply('msd', $m1, 'temp', $class);
        $code .= self::generateInlineAdd('lsd', 'temp', 'n', $class);

        $code .= '$temp = array_slice($n, ' . (count($m) - 1) . ');';
        $code .= self::generateInlineMultiply('temp', $u, 'temp2', $class);
        $code .= self::generateInlineTrim('temp2');

        $code .= $class::BASE == 26 ?
            '$temp = array_slice($temp2, ' . (count($m) + 1) . ');' :
            '$temp = array_slice($temp2, ' . ((count($m) >> 1) + 1) . ');';
        $code .= self::generateInlineMultiply('temp', $m, 'temp2', $class);
        $code .= self::generateInlineTrim('temp2');

        /*
        if ($class::BASE == 26) {
            $code.= '$n = array_slice($n, 0, ' . (count($m) + 1) . ');
                     $temp2 = array_slice($temp2, 0, ' . (count($m) + 1) . ');';
        }
        */

        $code .= self::generateInlineSubtract2('n', 'temp2', 'temp', $class);

        $subcode = self::generateInlineSubtract1('temp', $m, 'temp2', $class);
        $subcode .= '$temp = $temp2;';

        $code .= self::generateInlineCompare($m, 'temp', $subcode);

        if ($correctionNeeded) {
            $code .= 'array_shift($temp);';
        }

        $code .= 'return $temp;';

        eval('$func = function ($n) { ' . $code . '};');

        self::$custom_reduction = $func;

        return $func;

        //self::$custom_reduction = \Closure::bind($func, $m, $class);
    }

    /**
     * Inline Trim
     *
     * Removes leading zeros
     *
     * @param string $name
     * @return string
     */
    private static function generateInlineTrim($name)
    {
        return '
            for ($i = count($' . $name . ') - 1; $i >= 0; --$i) {
                if ($' . $name . '[$i]) {
                    break;
                }
                unset($' . $name . '[$i]);
            }';
    }

    /**
     * Inline Multiply (unknown, known)
     *
     * @param string $input
     * @param array $arr
     * @param string $output
     * @param string $class
     * @return string
     */
    private static function generateInlineMultiply($input, array $arr, $output, $class)
    {
        if (!count($arr)) {
            return 'return [];';
        }

        $regular = '
            $length = count($' . $input . ');
            if (!$length) {
                $' . $output . ' = [];
            }else{
            $' . $output . ' = array_fill(0, $length + ' . count($arr) . ', 0);
            $carry = 0;';

        for ($i = 0; $i < count($arr); $i++) {
            $regular .= '
                $subtemp = $' . $input . '[0] * ' . $arr[$i];
            $regular .= $i ? ' + $carry;' : ';';

            $regular .= '$carry = ';
            $regular .= $class::BASE === 26 ?
            'intval($subtemp / 0x4000000);' :
            '$subtemp >> 31;';
            $regular .=
            '$' . $output . '[' . $i . '] = ';
            if ($class::BASE === 26) {
                $regular .= '(int) (';
            }
            $regular .= '$subtemp - ' . $class::BASE_FULL . ' * $carry';
            $regular .= $class::BASE === 26 ? ');' : ';';
        }

        $regular .= '$' . $output . '[' . count($arr) . '] = $carry;';

        $regular .= '
            for ($i = 1; $i < $length; ++$i) {';

        for ($j = 0; $j < count($arr); $j++) {
            $regular .= $j ? '$k++;' : '$k = $i;';
            $regular .= '
                $subtemp = $' . $output . '[$k] + $' . $input . '[$i] * ' . $arr[$j];
            $regular .= $j ? ' + $carry;' : ';';

            $regular .= '$carry = ';
            $regular .= $class::BASE === 26 ?
                'intval($subtemp / 0x4000000);' :
                '$subtemp >> 31;';
            $regular .=
                '$' . $output . '[$k] = ';
            if ($class::BASE === 26) {
                $regular .= '(int) (';
            }
            $regular .= '$subtemp - ' . $class::BASE_FULL . ' * $carry';
            $regular .= $class::BASE === 26 ? ');' : ';';
        }

        $regular .= '$' . $output . '[++$k] = $carry; $carry = 0;';

        $regular .= '}}';

        //if (count($arr) < 2 * self::KARATSUBA_CUTOFF) {
        //}

        return $regular;
    }

    /**
     * Inline Addition
     *
     * @param string $x
     * @param string $y
     * @param string $result
     * @param string $class
     * @return string
     */
    private static function generateInlineAdd($x, $y, $result, $class)
    {
        $code = '
            $length = max(count($' . $x . '), count($' . $y . '));
            $' . $result . ' = array_pad($' . $x . ', $length + 1, 0);
            $_' . $y . ' = array_pad($' . $y . ', $length, 0);
            $carry = 0;
            for ($i = 0, $j = 1; $j < $length; $i+=2, $j+=2) {
                $sum = ($' . $result . '[$j] + $_' . $y . '[$j]) * ' . $class::BASE_FULL . '
                           + $' . $result . '[$i] + $_' . $y . '[$i] +
                           $carry;
                $carry = $sum >= ' . self::float2string($class::MAX_DIGIT2) . ';
                $sum = $carry ? $sum - ' . self::float2string($class::MAX_DIGIT2) . ' : $sum;';

            $code .= $class::BASE === 26 ?
                '$upper = intval($sum / 0x4000000); $' . $result . '[$i] = (int) ($sum - ' . $class::BASE_FULL . ' * $upper);' :
                '$upper = $sum >> 31; $' . $result . '[$i] = $sum - ' . $class::BASE_FULL . ' * $upper;';
            $code .= '
                $' . $result . '[$j] = $upper;
            }
            if ($j == $length) {
                $sum = $' . $result . '[$i] + $_' . $y . '[$i] + $carry;
                $carry = $sum >= ' . self::float2string($class::BASE_FULL) . ';
                $' . $result . '[$i] = $carry ? $sum - ' . self::float2string($class::BASE_FULL) . ' : $sum;
                ++$i;
            }
            if ($carry) {
                for (; $' . $result . '[$i] == ' . $class::MAX_DIGIT . '; ++$i) {
                    $' . $result . '[$i] = 0;
                }
                ++$' . $result . '[$i];
            }';
            $code .= self::generateInlineTrim($result);

            return $code;
    }

    /**
     * Inline Subtraction 2
     *
     * For when $known is more digits than $unknown. This is the harder use case to optimize for.
     *
     * @param string $known
     * @param string $unknown
     * @param string $result
     * @param string $class
     * @return string
     */
    private static function generateInlineSubtract2($known, $unknown, $result, $class)
    {
        $code = '
            $' . $result . ' = $' . $known . ';
            $carry = 0;
            $size = count($' . $unknown . ');
            for ($i = 0, $j = 1; $j < $size; $i+= 2, $j+= 2) {
                $sum = ($' . $known . '[$j] - $' . $unknown . '[$j]) * ' . $class::BASE_FULL . ' + $' . $known . '[$i]
                    - $' . $unknown . '[$i]
                    - $carry;
                $carry = $sum < 0;
                if ($carry) {
                    $sum+= ' . self::float2string($class::MAX_DIGIT2) . ';
                }
                $subtemp = ';
        $code .= $class::BASE === 26 ?
            'intval($sum / 0x4000000);' :
            '$sum >> 31;';
        $code .= '$' . $result . '[$i] = ';
        if ($class::BASE === 26) {
            $code .= '(int) (';
        }
        $code .= '$sum - ' . $class::BASE_FULL . ' * $subtemp';
        if ($class::BASE === 26) {
            $code .= ')';
        }
        $code .= ';
                $' . $result . '[$j] = $subtemp;
            }
            if ($j == $size) {
                $sum = $' . $known . '[$i] - $' . $unknown . '[$i] - $carry;
                $carry = $sum < 0;
                $' . $result . '[$i] = $carry ? $sum + ' . $class::BASE_FULL . ' : $sum;
                ++$i;
            }

            if ($carry) {
                for (; !$' . $result . '[$i]; ++$i) {
                    $' . $result . '[$i] = ' . $class::MAX_DIGIT . ';
                }
                --$' . $result . '[$i];
            }';

        $code .= self::generateInlineTrim($result);

        return $code;
    }

    /**
     * Inline Subtraction 1
     *
     * For when $unknown is more digits than $known. This is the easier use case to optimize for.
     *
     * @param string $unknown
     * @param array $known
     * @param string $result
     * @param string $class
     * @return string
     */
    private static function generateInlineSubtract1($unknown, array $known, $result, $class)
    {
        $code = '$' . $result . ' = $' . $unknown . ';';
        for ($i = 0, $j = 1; $j < count($known); $i += 2, $j += 2) {
            $code .= '$sum = $' . $unknown . '[' . $j . '] * ' . $class::BASE_FULL . ' + $' . $unknown . '[' . $i . '] - ';
            $code .= self::float2string($known[$j] * $class::BASE_FULL + $known[$i]);
            if ($i != 0) {
                $code .= ' - $carry';
            }

            $code .= ';
                if ($carry = $sum < 0) {
                    $sum+= ' . self::float2string($class::MAX_DIGIT2) . ';
                }
                $subtemp = ';
            $code .= $class::BASE === 26 ?
                'intval($sum / 0x4000000);' :
                '$sum >> 31;';
            $code .= '
                $' . $result . '[' . $i . '] = ';
            if ($class::BASE === 26) {
                $code .= ' (int) (';
            }
            $code .= '$sum - ' . $class::BASE_FULL . ' * $subtemp';
            if ($class::BASE === 26) {
                $code .= ')';
            }
            $code .= ';
                $' . $result . '[' . $j . '] = $subtemp;';
        }

        $code .= '$i = ' . $i . ';';

        if ($j == count($known)) {
            $code .= '
                $sum = $' . $unknown . '[' . $i . '] - ' . $known[$i] . ' - $carry;
                $carry = $sum < 0;
                $' . $result . '[' . $i . '] = $carry ? $sum + ' . $class::BASE_FULL . ' : $sum;
                ++$i;';
        }

        $code .= '
            if ($carry) {
                for (; !$' . $result . '[$i]; ++$i) {
                    $' . $result . '[$i] = ' . $class::MAX_DIGIT . ';
                }
                --$' . $result . '[$i];
            }';
        $code .= self::generateInlineTrim($result);

        return $code;
    }

    /**
     * Inline Comparison
     *
     * If $unknown >= $known then loop
     *
     * @param array $known
     * @param string $unknown
     * @param string $subcode
     * @return string
     */
    private static function generateInlineCompare(array $known, $unknown, $subcode)
    {
        $uniqid = uniqid();
        $code = 'loop_' . $uniqid . ':
            $clength = count($' . $unknown . ');
            switch (true) {
                case $clength < ' . count($known) . ':
                    goto end_' . $uniqid . ';
                case $clength > ' . count($known) . ':';
        for ($i = count($known) - 1; $i >= 0; $i--) {
            $code .= '
                case $' . $unknown . '[' . $i . '] > ' . $known[$i] . ':
                    goto subcode_' . $uniqid . ';
                case $' . $unknown . '[' . $i . '] < ' . $known[$i] . ':
                    goto end_' . $uniqid . ';';
        }
        $code .= '
                default:
                    // do subcode
            }

            subcode_' . $uniqid . ':' . $subcode . '
            goto loop_' . $uniqid . ';

            end_' . $uniqid . ':';

        return $code;
    }

    /**
     * Convert a float to a string
     *
     * If you do echo floatval(pow(2, 52)) you'll get 4.6116860184274E+18. It /can/ be displayed without a loss of
     * precision but displayed in this way there will be precision loss, hence the need for this method.
     *
     * @param int|float $num
     * @return string
     */
    private static function float2string($num)
    {
        if (!is_float($num)) {
            return (string) $num;
        }

        if ($num < 0) {
            return '-' . self::float2string(abs($num));
        }

        $temp = '';
        while ($num) {
            $temp = fmod($num, 10) . $temp;
            $num = floor($num / 10);
        }

        return $temp;
    }
}
<?php

/**
 * PHP Barrett Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\PHP\Reductions;

use phpseclib3\Math\BigInteger\Engines\PHP;
use phpseclib3\Math\BigInteger\Engines\PHP\Base;

/**
 * PHP Barrett Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Barrett extends Base
{
    /**
     * Barrett Modular Reduction
     *
     * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information.  Modified slightly,
     * so as not to require negative numbers (initially, this script didn't support negative numbers).
     *
     * Employs "folding", as described at
     * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}.  To quote from
     * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
     *
     * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
     * usable on account of (1) its not using reasonable radix points as discussed in
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
     * radix points, it only works when there are an even number of digits in the denominator.  The reason for (2) is that
     * (x >> 1) + (x >> 1) != x / 2 + x / 2.  If x is even, they're the same, but if x is odd, they're not.  See the in-line
     * comments for details.
     *
     * @param array $n
     * @param array $m
     * @param class-string<PHP> $class
     * @return array
     */
    protected static function reduce(array $n, array $m, $class)
    {
        static $cache = [
            self::VARIABLE => [],
            self::DATA => []
        ];

        $m_length = count($m);

        // if (self::compareHelper($n, $static::square($m)) >= 0) {
        if (count($n) > 2 * $m_length) {
            $lhs = new $class();
            $rhs = new $class();
            $lhs->value = $n;
            $rhs->value = $m;
            list(, $temp) = $lhs->divide($rhs);
            return $temp->value;
        }

        // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
        if ($m_length < 5) {
            return self::regularBarrett($n, $m, $class);
        }
        // n = 2 * m.length
        $correctionNeeded = false;
        if ($m_length & 1) {
            $correctionNeeded = true;
            array_unshift($n, 0);
            array_unshift($m, 0);
            $m_length++;
        }

        if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
            $key = count($cache[self::VARIABLE]);
            $cache[self::VARIABLE][] = $m;

            $lhs = new $class();
            $lhs_value = &$lhs->value;
            $lhs_value = self::array_repeat(0, $m_length + ($m_length >> 1));
            $lhs_value[] = 1;
            $rhs = new $class();
            $rhs->value = $m;

            list($u, $m1) = $lhs->divide($rhs);
            $u = $u->value;
            $m1 = $m1->value;

            $cache[self::DATA][] = [
                'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
                'm1' => $m1 // m.length
            ];
        } else {
            $cacheValues = $cache[self::DATA][$key];
            $u = $cacheValues['u'];
            $m1 = $cacheValues['m1'];
        }

        $cutoff = $m_length + ($m_length >> 1);
        $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
        $msd = array_slice($n, $cutoff);    // m.length >> 1

        $lsd = self::trim($lsd);
        $temp = $class::multiplyHelper($msd, false, $m1, false); // m.length + (m.length >> 1)
        $n = $class::addHelper($lsd, false, $temp[self::VALUE], false); // m.length + (m.length >> 1) + 1 (so basically we're adding two same length numbers)
        //if ($m_length & 1) {
        //    return self::regularBarrett($n[self::VALUE], $m, $class);
        //}

        // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
        $temp = array_slice($n[self::VALUE], $m_length - 1);
        // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
        // if odd:  ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
        // note that these are upper bounds. let's say m.length is 2. then you'd be multiplying a
        // 3 digit number by a 1 digit number. if you're doing 999 * 9 (in base 10) the result will
        // be a 4 digit number. but if you're multiplying 111 * 1 then the result will be a 3 digit
        // number.
        $temp = $class::multiplyHelper($temp, false, $u, false);
        // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
        // if odd:  (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
        $temp = array_slice($temp[self::VALUE], ($m_length >> 1) + 1);
        // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
        // if odd:  (m.length - (m.length >> 1)) + m.length     = 2 * m.length - (m.length >> 1)
        $temp = $class::multiplyHelper($temp, false, $m, false);
        // at this point, if m had an odd number of digits, we'd (probably) be subtracting a 2 * m.length - (m.length >> 1)
        // digit number from a m.length + (m.length >> 1) + 1 digit number.  ie. there'd be an extra digit and the while loop
        // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
        $result = $class::subtractHelper($n[self::VALUE], false, $temp[self::VALUE], false);

        while (self::compareHelper($result[self::VALUE], $result[self::SIGN], $m, false) >= 0) {
            $result = $class::subtractHelper($result[self::VALUE], $result[self::SIGN], $m, false);
        }

        if ($correctionNeeded) {
            array_shift($result[self::VALUE]);
        }

        return $result[self::VALUE];
    }

    /**
     * (Regular) Barrett Modular Reduction
     *
     * For numbers with more than four digits BigInteger::_barrett() is faster.  The difference between that and this
     * is that this function does not fold the denominator into a smaller form.
     *
     * @param array $x
     * @param array $n
     * @param string $class
     * @return array
     */
    private static function regularBarrett(array $x, array $n, $class)
    {
        static $cache = [
            self::VARIABLE => [],
            self::DATA => []
        ];

        $n_length = count($n);

        if (count($x) > 2 * $n_length) {
            $lhs = new $class();
            $rhs = new $class();
            $lhs->value = $x;
            $rhs->value = $n;
            list(, $temp) = $lhs->divide($rhs);
            return $temp->value;
        }

        if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
            $key = count($cache[self::VARIABLE]);
            $cache[self::VARIABLE][] = $n;
            $lhs = new $class();
            $lhs_value = &$lhs->value;
            $lhs_value = self::array_repeat(0, 2 * $n_length);
            $lhs_value[] = 1;
            $rhs = new $class();
            $rhs->value = $n;
            list($temp, ) = $lhs->divide($rhs); // m.length
            $cache[self::DATA][] = $temp->value;
        }

        // 2 * m.length - (m.length - 1) = m.length + 1
        $temp = array_slice($x, $n_length - 1);
        // (m.length + 1) + m.length = 2 * m.length + 1
        $temp = $class::multiplyHelper($temp, false, $cache[self::DATA][$key], false);
        // (2 * m.length + 1) - (m.length - 1) = m.length + 2
        $temp = array_slice($temp[self::VALUE], $n_length + 1);

        // m.length + 1
        $result = array_slice($x, 0, $n_length + 1);
        // m.length + 1
        $temp = self::multiplyLower($temp, false, $n, false, $n_length + 1, $class);
        // $temp == array_slice($class::regularMultiply($temp, false, $n, false)->value, 0, $n_length + 1)

        if (self::compareHelper($result, false, $temp[self::VALUE], $temp[self::SIGN]) < 0) {
            $corrector_value = self::array_repeat(0, $n_length + 1);
            $corrector_value[count($corrector_value)] = 1;
            $result = $class::addHelper($result, false, $corrector_value, false);
            $result = $result[self::VALUE];
        }

        // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
        $result = $class::subtractHelper($result, false, $temp[self::VALUE], $temp[self::SIGN]);
        while (self::compareHelper($result[self::VALUE], $result[self::SIGN], $n, false) > 0) {
            $result = $class::subtractHelper($result[self::VALUE], $result[self::SIGN], $n, false);
        }

        return $result[self::VALUE];
    }

    /**
     * Performs long multiplication up to $stop digits
     *
     * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
     *
     * @see self::regularBarrett()
     * @param array $x_value
     * @param bool $x_negative
     * @param array $y_value
     * @param bool $y_negative
     * @param int $stop
     * @param string $class
     * @return array
     */
    private static function multiplyLower(array $x_value, $x_negative, array $y_value, $y_negative, $stop, $class)
    {
        $x_length = count($x_value);
        $y_length = count($y_value);

        if (!$x_length || !$y_length) { // a 0 is being multiplied
            return [
                self::VALUE => [],
                self::SIGN => false
            ];
        }

        if ($x_length < $y_length) {
            $temp = $x_value;
            $x_value = $y_value;
            $y_value = $temp;

            $x_length = count($x_value);
            $y_length = count($y_value);
        }

        $product_value = self::array_repeat(0, $x_length + $y_length);

        // the following for loop could be removed if the for loop following it
        // (the one with nested for loops) initially set $i to 0, but
        // doing so would also make the result in one set of unnecessary adds,
        // since on the outermost loops first pass, $product->value[$k] is going
        // to always be 0

        $carry = 0;

        for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
            $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
            $carry = $class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
            $product_value[$j] = (int) ($temp - $class::BASE_FULL * $carry);
        }

        if ($j < $stop) {
            $product_value[$j] = $carry;
        }

        // the above for loop is what the previous comment was talking about.  the
        // following for loop is the "one with nested for loops"

        for ($i = 1; $i < $y_length; ++$i) {
            $carry = 0;

            for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
                $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
                $carry = $class::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
                $product_value[$k] = (int) ($temp - $class::BASE_FULL * $carry);
            }

            if ($k < $stop) {
                $product_value[$k] = $carry;
            }
        }

        return [
            self::VALUE => self::trim($product_value),
            self::SIGN => $x_negative != $y_negative
        ];
    }
}
<?php

/**
 * OpenSSL Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\PHP;

use phpseclib3\Math\BigInteger\Engines\OpenSSL as Progenitor;

/**
 * OpenSSL Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OpenSSL extends Progenitor
{
}
<?php

/**
 * PHP Default Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\PHP;

use phpseclib3\Math\BigInteger\Engines\PHP\Reductions\EvalBarrett;

/**
 * PHP Default Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DefaultEngine extends EvalBarrett
{
}
<?php

/**
 * GMP Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\GMP;

use phpseclib3\Math\BigInteger\Engines\GMP;

/**
 * GMP Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DefaultEngine extends GMP
{
    /**
     * Performs modular exponentiation.
     *
     * @param GMP $x
     * @param GMP $e
     * @param GMP $n
     * @return GMP
     */
    protected static function powModHelper(GMP $x, GMP $e, GMP $n)
    {
        $temp = new GMP();
        $temp->value = gmp_powm($x->value, $e->value, $n->value);

        return $x->normalize($temp);
    }
}
<?php

/**
 * OpenSSL Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines;

use phpseclib3\Crypt\RSA\Formats\Keys\PKCS8;
use phpseclib3\Math\BigInteger;

/**
 * OpenSSL Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OpenSSL
{
    /**
     * Test for engine validity
     *
     * @return bool
     */
    public static function isValidEngine()
    {
        return extension_loaded('openssl') && static::class != __CLASS__;
    }

    /**
     * Performs modular exponentiation.
     *
     * @param Engine $x
     * @param Engine $e
     * @param Engine $n
     * @return Engine
     */
    public static function powModHelper(Engine $x, Engine $e, Engine $n)
    {
        if ($n->getLengthInBytes() < 31 || $n->getLengthInBytes() > 16384) {
            throw new \OutOfRangeException('Only modulo between 31 and 16384 bits are accepted');
        }

        $key = PKCS8::savePublicKey(
            new BigInteger($n),
            new BigInteger($e)
        );

        $plaintext = str_pad($x->toBytes(), $n->getLengthInBytes(), "\0", STR_PAD_LEFT);

        // this is easily prone to failure. if the modulo is a multiple of 2 or 3 or whatever it
        // won't work and you'll get a "failure: error:0906D06C:PEM routines:PEM_read_bio:no start line"
        // error. i suppose, for even numbers, we could do what PHP\Montgomery.php does, but then what
        // about odd numbers divisible by 3, by 5, etc?
        if (!openssl_public_encrypt($plaintext, $result, $key, OPENSSL_NO_PADDING)) {
            throw new \UnexpectedValueException(openssl_error_string());
        }

        $class = get_class($x);
        return new $class($result, 256);
    }
}
<?php

/**
 * Pure-PHP 64-bit BigInteger Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines;

/**
 * Pure-PHP 64-bit Engine.
 *
 * Uses 64-bit integers if int size is 8 bits
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class PHP64 extends PHP
{
    // Constants used by PHP.php
    const BASE = 31;
    const BASE_FULL = 0x80000000;
    const MAX_DIGIT = 0x7FFFFFFF;
    const MSB = 0x40000000;

    /**
     * MAX10 in greatest MAX10LEN satisfying
     * MAX10 = 10**MAX10LEN <= 2**BASE.
     */
    const MAX10 = 1000000000;

    /**
     * MAX10LEN in greatest MAX10LEN satisfying
     * MAX10 = 10**MAX10LEN <= 2**BASE.
     */
    const MAX10LEN = 9;
    const MAX_DIGIT2 = 4611686018427387904;

    /**
     * Initialize a PHP64 BigInteger Engine instance
     *
     * @param int $base
     * @see parent::initialize()
     */
    protected function initialize($base)
    {
        if ($base != 256 && $base != -256) {
            return parent::initialize($base);
        }

        $val = $this->value;
        $this->value = [];
        $vals = &$this->value;
        $i = strlen($val);
        if (!$i) {
            return;
        }

        while (true) {
            $i -= 4;
            if ($i < 0) {
                if ($i == -4) {
                    break;
                }
                $val = substr($val, 0, 4 + $i);
                $val = str_pad($val, 4, "\0", STR_PAD_LEFT);
                if ($val == "\0\0\0\0") {
                    break;
                }
                $i = 0;
            }
            list(, $digit) = unpack('N', substr($val, $i, 4));
            $step = count($vals) & 7;
            if (!$step) {
                $digit &= static::MAX_DIGIT;
                $i++;
            } else {
                $shift = 8 - $step;
                $digit >>= $shift;
                $shift = 32 - $shift;
                $digit &= (1 << $shift) - 1;
                $temp = $i > 0 ? ord($val[$i - 1]) : 0;
                $digit |= ($temp << $shift) & 0x7F000000;
            }
            $vals[] = $digit;
        }
        while (end($vals) === 0) {
            array_pop($vals);
        }
        reset($vals);
    }

    /**
     * Test for engine validity
     *
     * @see parent::__construct()
     * @return bool
     */
    public static function isValidEngine()
    {
        return PHP_INT_SIZE >= 8 && !self::testJITOnWindows();
    }

    /**
     * Adds two BigIntegers.
     *
     * @param PHP64 $y
     * @return PHP64
     */
    public function add(PHP64 $y)
    {
        $temp = self::addHelper($this->value, $this->is_negative, $y->value, $y->is_negative);

        return $this->convertToObj($temp);
    }

    /**
     * Subtracts two BigIntegers.
     *
     * @param PHP64 $y
     * @return PHP64
     */
    public function subtract(PHP64 $y)
    {
        $temp = self::subtractHelper($this->value, $this->is_negative, $y->value, $y->is_negative);

        return $this->convertToObj($temp);
    }

    /**
     * Multiplies two BigIntegers.
     *
     * @param PHP64 $y
     * @return PHP64
     */
    public function multiply(PHP64 $y)
    {
        $temp = self::multiplyHelper($this->value, $this->is_negative, $y->value, $y->is_negative);

        return $this->convertToObj($temp);
    }

    /**
     * Divides two BigIntegers.
     *
     * Returns an array whose first element contains the quotient and whose second element contains the
     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
     * and the divisor (basically, the "common residue" is the first positive modulo).
     *
     * @param PHP64 $y
     * @return array{PHP64, PHP64}
     */
    public function divide(PHP64 $y)
    {
        return $this->divideHelper($y);
    }

    /**
     * Calculates modular inverses.
     *
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
     * @param PHP64 $n
     * @return false|PHP64
     */
    public function modInverse(PHP64 $n)
    {
        return $this->modInverseHelper($n);
    }

    /**
     * Calculates modular inverses.
     *
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
     * @param PHP64 $n
     * @return PHP64[]
     */
    public function extendedGCD(PHP64 $n)
    {
        return $this->extendedGCDHelper($n);
    }

    /**
     * Calculates the greatest common divisor
     *
     * Say you have 693 and 609.  The GCD is 21.
     *
     * @param PHP64 $n
     * @return PHP64
     */
    public function gcd(PHP64 $n)
    {
        return $this->extendedGCD($n)['gcd'];
    }

    /**
     * Logical And
     *
     * @param PHP64 $x
     * @return PHP64
     */
    public function bitwise_and(PHP64 $x)
    {
        return $this->bitwiseAndHelper($x);
    }

    /**
     * Logical Or
     *
     * @param PHP64 $x
     * @return PHP64
     */
    public function bitwise_or(PHP64 $x)
    {
        return $this->bitwiseOrHelper($x);
    }

    /**
     * Logical Exclusive Or
     *
     * @param PHP64 $x
     * @return PHP64
     */
    public function bitwise_xor(PHP64 $x)
    {
        return $this->bitwiseXorHelper($x);
    }

    /**
     * Compares two numbers.
     *
     * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite.  The reason for this is
     * demonstrated thusly:
     *
     * $x  > $y: $x->compare($y)  > 0
     * $x  < $y: $x->compare($y)  < 0
     * $x == $y: $x->compare($y) == 0
     *
     * Note how the same comparison operator is used.  If you want to test for equality, use $x->equals($y).
     *
     * {@internal Could return $this->subtract($x), but that's not as fast as what we do do.}
     *
     * @param PHP64 $y
     * @return int in case < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
     * @see self::equals()
     */
    public function compare(PHP64 $y)
    {
        return parent::compareHelper($this->value, $this->is_negative, $y->value, $y->is_negative);
    }

    /**
     * Tests the equality of two numbers.
     *
     * If you need to see if one number is greater than or less than another number, use BigInteger::compare()
     *
     * @param PHP64 $x
     * @return bool
     */
    public function equals(PHP64 $x)
    {
        return $this->value === $x->value && $this->is_negative == $x->is_negative;
    }

    /**
     * Performs modular exponentiation.
     *
     * @param PHP64 $e
     * @param PHP64 $n
     * @return PHP64
     */
    public function modPow(PHP64 $e, PHP64 $n)
    {
        return $this->powModOuter($e, $n);
    }

    /**
     * Performs modular exponentiation.
     *
     * Alias for modPow().
     *
     * @param PHP64 $e
     * @param PHP64 $n
     * @return PHP64|false
     */
    public function powMod(PHP64 $e, PHP64 $n)
    {
        return $this->powModOuter($e, $n);
    }

    /**
     * Generate a random prime number between a range
     *
     * If there's not a prime within the given range, false will be returned.
     *
     * @param PHP64 $min
     * @param PHP64 $max
     * @return false|PHP64
     */
    public static function randomRangePrime(PHP64 $min, PHP64 $max)
    {
        return self::randomRangePrimeOuter($min, $max);
    }

    /**
     * Generate a random number between a range
     *
     * Returns a random number between $min and $max where $min and $max
     * can be defined using one of the two methods:
     *
     * BigInteger::randomRange($min, $max)
     * BigInteger::randomRange($max, $min)
     *
     * @param PHP64 $min
     * @param PHP64 $max
     * @return PHP64
     */
    public static function randomRange(PHP64 $min, PHP64 $max)
    {
        return self::randomRangeHelper($min, $max);
    }

    /**
     * Performs exponentiation.
     *
     * @param PHP64 $n
     * @return PHP64
     */
    public function pow(PHP64 $n)
    {
        return $this->powHelper($n);
    }

    /**
     * Return the minimum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param PHP64 ...$nums
     * @return PHP64
     */
    public static function min(PHP64 ...$nums)
    {
        return self::minHelper($nums);
    }

    /**
     * Return the maximum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param PHP64 ...$nums
     * @return PHP64
     */
    public static function max(PHP64 ...$nums)
    {
        return self::maxHelper($nums);
    }

    /**
     * Tests BigInteger to see if it is between two integers, inclusive
     *
     * @param PHP64 $min
     * @param PHP64 $max
     * @return bool
     */
    public function between(PHP64 $min, PHP64 $max)
    {
        return $this->compare($min) >= 0 && $this->compare($max) <= 0;
    }
}
<?php

/**
 * Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\BCMath;

use phpseclib3\Math\BigInteger\Engines\BCMath;

/**
 * Sliding Window Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Base extends BCMath
{
    /**
     * Cache constants
     *
     * $cache[self::VARIABLE] tells us whether or not the cached data is still valid.
     *
     */
    const VARIABLE = 0;
    /**
     * $cache[self::DATA] contains the cached data.
     *
     */
    const DATA = 1;

    /**
     * Test for engine validity
     *
     * @return bool
     */
    public static function isValidEngine()
    {
        return static::class != __CLASS__;
    }

    /**
     * Performs modular exponentiation.
     *
     * @param BCMath $x
     * @param BCMath $e
     * @param BCMath $n
     * @param string $class
     * @return BCMath
     */
    protected static function powModHelper(BCMath $x, BCMath $e, BCMath $n, $class)
    {
        if (empty($e->value)) {
            $temp = new $class();
            $temp->value = '1';
            return $x->normalize($temp);
        }

        return $x->normalize(static::slidingWindow($x, $e, $n, $class));
    }

    /**
     * Modular reduction preparation
     *
     * @param string $x
     * @param string $n
     * @param string $class
     * @see self::slidingWindow()
     * @return string
     */
    protected static function prepareReduce($x, $n, $class)
    {
        return static::reduce($x, $n);
    }

    /**
     * Modular multiply
     *
     * @param string $x
     * @param string $y
     * @param string $n
     * @param string $class
     * @see self::slidingWindow()
     * @return string
     */
    protected static function multiplyReduce($x, $y, $n, $class)
    {
        return static::reduce(bcmul($x, $y, 0), $n);
    }

    /**
     * Modular square
     *
     * @param string $x
     * @param string $n
     * @param string $class
     * @see self::slidingWindow()
     * @return string
     */
    protected static function squareReduce($x, $n, $class)
    {
        return static::reduce(bcmul($x, $x, 0), $n);
    }
}
<?php

/**
 * Built-In BCMath Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\BCMath;

use phpseclib3\Math\BigInteger\Engines\BCMath;

/**
 * Built-In BCMath Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class BuiltIn extends BCMath
{
    /**
     * Performs modular exponentiation.
     *
     * @param BCMath $x
     * @param BCMath $e
     * @param BCMath $n
     * @return BCMath
     */
    protected static function powModHelper(BCMath $x, BCMath $e, BCMath $n)
    {
        $temp = new BCMath();
        $temp->value = bcpowmod($x->value, $e->value, $n->value, 0);

        return $x->normalize($temp);
    }
}
<?php

/**
 * BCMath Dynamic Barrett Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\BCMath\Reductions;

use phpseclib3\Math\BigInteger\Engines\BCMath;
use phpseclib3\Math\BigInteger\Engines\BCMath\Base;

/**
 * PHP Barrett Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class EvalBarrett extends Base
{
    /**
     * Custom Reduction Function
     *
     * @see self::generateCustomReduction
     */
    private static $custom_reduction;

    /**
     * Barrett Modular Reduction
     *
     * This calls a dynamically generated loop unrolled function that's specific to a given modulo.
     * Array lookups are avoided as are if statements testing for how many bits the host OS supports, etc.
     *
     * @param string $n
     * @param string $m
     * @return string
     */
    protected static function reduce($n, $m)
    {
        $inline = self::$custom_reduction;
        return $inline($n);
    }

    /**
     * Generate Custom Reduction
     *
     * @param BCMath $m
     * @param string $class
     * @return callable|void
     */
    protected static function generateCustomReduction(BCMath $m, $class)
    {
        $m_length = strlen($m);

        if ($m_length < 5) {
            $code = 'return self::BCMOD_THREE_PARAMS ? bcmod($x, $n, 0) : bcmod($x, $n);';
            eval('$func = function ($n) { ' . $code . '};');
            self::$custom_reduction = $func;
            return;
        }

        $lhs = '1' . str_repeat('0', $m_length + ($m_length >> 1));
        $u = bcdiv($lhs, $m, 0);
        $m1 = bcsub($lhs, bcmul($u, $m, 0), 0);

        $cutoff = $m_length + ($m_length >> 1);

        $m = "'$m'";
        $u = "'$u'";
        $m1 = "'$m1'";

        $code = '
            $lsd = substr($n, -' . $cutoff . ');
            $msd = substr($n, 0, -' . $cutoff . ');

            $temp = bcmul($msd, ' . $m1 . ', 0);
            $n = bcadd($lsd, $temp, 0);

            $temp = substr($n, 0, ' . (-$m_length + 1) . ');
            $temp = bcmul($temp, ' . $u . ', 0);
            $temp = substr($temp, 0, ' . (-($m_length >> 1) - 1) . ');
            $temp = bcmul($temp, ' . $m . ', 0);

            $result = bcsub($n, $temp, 0);

            if ($result[0] == \'-\') {
                $temp = \'1' . str_repeat('0', $m_length + 1) . '\';
                $result = bcadd($result, $temp, 0);
            }

            while (bccomp($result, ' . $m . ') >= 0) {
                $result = bcsub($result, ' . $m . ', 0);
            }

            return $result;';

        eval('$func = function ($n) { ' . $code . '};');

        self::$custom_reduction = $func;

        return $func;
    }
}
<?php

/**
 * BCMath Barrett Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\BCMath\Reductions;

use phpseclib3\Math\BigInteger\Engines\BCMath\Base;

/**
 * PHP Barrett Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Barrett extends Base
{
    /**
     * Cache constants
     *
     * $cache[self::VARIABLE] tells us whether or not the cached data is still valid.
     *
     */
    const VARIABLE = 0;
    /**
     * $cache[self::DATA] contains the cached data.
     *
     */
    const DATA = 1;

    /**
     * Barrett Modular Reduction
     *
     * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information.  Modified slightly,
     * so as not to require negative numbers (initially, this script didn't support negative numbers).
     *
     * Employs "folding", as described at
     * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}.  To quote from
     * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
     *
     * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
     * usable on account of (1) its not using reasonable radix points as discussed in
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
     * radix points, it only works when there are an even number of digits in the denominator.  The reason for (2) is that
     * (x >> 1) + (x >> 1) != x / 2 + x / 2.  If x is even, they're the same, but if x is odd, they're not.  See the in-line
     * comments for details.
     *
     * @param string $n
     * @param string $m
     * @return string
     */
    protected static function reduce($n, $m)
    {
        static $cache = [
            self::VARIABLE => [],
            self::DATA => []
        ];

        $m_length = strlen($m);

        if (strlen($n) > 2 * $m_length) {
            return self::BCMOD_THREE_PARAMS ? bcmod($n, $m, 0) : bcmod($n, $m);
        }

        // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
        if ($m_length < 5) {
            return self::regularBarrett($n, $m);
        }
        // n = 2 * m.length
        $correctionNeeded = false;
        if ($m_length & 1) {
            $correctionNeeded = true;
            $n .= '0';
            $m .= '0';
            $m_length++;
        }

        if (($key = array_search($m, $cache[self::VARIABLE])) === false) {
            $key = count($cache[self::VARIABLE]);
            $cache[self::VARIABLE][] = $m;

            $lhs = '1' . str_repeat('0', $m_length + ($m_length >> 1));
            $u = bcdiv($lhs, $m, 0);
            $m1 = bcsub($lhs, bcmul($u, $m, 0), 0);

            $cache[self::DATA][] = [
                'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
                'm1' => $m1 // m.length
            ];
        } else {
            $cacheValues = $cache[self::DATA][$key];
            $u = $cacheValues['u'];
            $m1 = $cacheValues['m1'];
        }

        $cutoff = $m_length + ($m_length >> 1);

        $lsd = substr($n, -$cutoff);
        $msd = substr($n, 0, -$cutoff);

        $temp = bcmul($msd, $m1, 0); // m.length + (m.length >> 1)
        $n = bcadd($lsd, $temp, 0); // m.length + (m.length >> 1) + 1 (so basically we're adding two same length numbers)
        //if ($m_length & 1) {
        //    return self::regularBarrett($n, $m);
        //}

        // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
        $temp = substr($n, 0, -$m_length + 1);
        // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
        // if odd:  ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
        $temp = bcmul($temp, $u, 0);
        // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
        // if odd:  (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
        $temp = substr($temp, 0, -($m_length >> 1) - 1);
        // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
        // if odd:  (m.length - (m.length >> 1)) + m.length     = 2 * m.length - (m.length >> 1)
        $temp = bcmul($temp, $m, 0);

        // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
        // number from a m.length + (m.length >> 1) + 1 digit number.  ie. there'd be an extra digit and the while loop
        // following this comment would loop a lot (hence our calling _regularBarrett() in that situation).

        $result = bcsub($n, $temp, 0);

        //if (bccomp($result, '0') < 0) {
        if ($result[0] == '-') {
            $temp = '1' . str_repeat('0', $m_length + 1);
            $result = bcadd($result, $temp, 0);
        }

        while (bccomp($result, $m, 0) >= 0) {
            $result = bcsub($result, $m, 0);
        }

        return $correctionNeeded && $result != '0' ? substr($result, 0, -1) : $result;
    }

    /**
     * (Regular) Barrett Modular Reduction
     *
     * For numbers with more than four digits BigInteger::_barrett() is faster.  The difference between that and this
     * is that this function does not fold the denominator into a smaller form.
     *
     * @param string $x
     * @param string $n
     * @return string
     */
    private static function regularBarrett($x, $n)
    {
        static $cache = [
            self::VARIABLE => [],
            self::DATA => []
        ];

        $n_length = strlen($n);

        if (strlen($x) > 2 * $n_length) {
            return self::BCMOD_THREE_PARAMS ? bcmod($x, $n, 0) : bcmod($x, $n);
        }

        if (($key = array_search($n, $cache[self::VARIABLE])) === false) {
            $key = count($cache[self::VARIABLE]);
            $cache[self::VARIABLE][] = $n;
            $lhs = '1' . str_repeat('0', 2 * $n_length);
            $cache[self::DATA][] = bcdiv($lhs, $n, 0);
        }

        $temp = substr($x, 0, -$n_length + 1);
        $temp = bcmul($temp, $cache[self::DATA][$key], 0);
        $temp = substr($temp, 0, -$n_length - 1);

        $r1 = substr($x, -$n_length - 1);
        $r2 = substr(bcmul($temp, $n, 0), -$n_length - 1);
        $result = bcsub($r1, $r2);

        //if (bccomp($result, '0') < 0) {
        if ($result[0] == '-') {
            $q = '1' . str_repeat('0', $n_length + 1);
            $result = bcadd($result, $q, 0);
        }

        while (bccomp($result, $n, 0) >= 0) {
            $result = bcsub($result, $n, 0);
        }

        return $result;
    }
}
<?php

/**
 * OpenSSL Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\BCMath;

use phpseclib3\Math\BigInteger\Engines\OpenSSL as Progenitor;

/**
 * OpenSSL Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OpenSSL extends Progenitor
{
}
<?php

/**
 * BCMath Default Modular Exponentiation Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines\BCMath;

use phpseclib3\Math\BigInteger\Engines\BCMath\Reductions\Barrett;

/**
 * PHP Default Modular Exponentiation Engine
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DefaultEngine extends Barrett
{
}
<?php

/**
 * Pure-PHP 32-bit BigInteger Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines;

/**
 * Pure-PHP 32-bit Engine.
 *
 * Uses 64-bit floats if int size is 4 bits
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class PHP32 extends PHP
{
    // Constants used by PHP.php
    const BASE = 26;
    const BASE_FULL = 0x4000000;
    const MAX_DIGIT = 0x3FFFFFF;
    const MSB = 0x2000000;

    /**
     * MAX10 in greatest MAX10LEN satisfying
     * MAX10 = 10**MAX10LEN <= 2**BASE.
     */
    const MAX10 = 10000000;

    /**
     * MAX10LEN in greatest MAX10LEN satisfying
     * MAX10 = 10**MAX10LEN <= 2**BASE.
     */
    const MAX10LEN = 7;
    const MAX_DIGIT2 = 4503599627370496;

    /**
     * Initialize a PHP32 BigInteger Engine instance
     *
     * @param int $base
     * @see parent::initialize()
     */
    protected function initialize($base)
    {
        if ($base != 256 && $base != -256) {
            return parent::initialize($base);
        }

        $val = $this->value;
        $this->value = [];
        $vals = &$this->value;
        $i = strlen($val);
        if (!$i) {
            return;
        }

        while (true) {
            $i -= 4;
            if ($i < 0) {
                if ($i == -4) {
                    break;
                }
                $val = substr($val, 0, 4 + $i);
                $val = str_pad($val, 4, "\0", STR_PAD_LEFT);
                if ($val == "\0\0\0\0") {
                    break;
                }
                $i = 0;
            }
            list(, $digit) = unpack('N', substr($val, $i, 4));
            if ($digit < 0) {
                $digit += 0xFFFFFFFF + 1;
            }
            $step = count($vals) & 3;
            if ($step) {
                $digit = (int) floor($digit / pow(2, 2 * $step));
            }
            if ($step != 3) {
                $digit = (int) fmod($digit, static::BASE_FULL);
                $i++;
            }
            $vals[] = $digit;
        }
        while (end($vals) === 0) {
            array_pop($vals);
        }
        reset($vals);
    }

    /**
     * Test for engine validity
     *
     * @see parent::__construct()
     * @return bool
     */
    public static function isValidEngine()
    {
        return PHP_INT_SIZE >= 4 && !self::testJITOnWindows();
    }

    /**
     * Adds two BigIntegers.
     *
     * @param PHP32 $y
     * @return PHP32
     */
    public function add(PHP32 $y)
    {
        $temp = self::addHelper($this->value, $this->is_negative, $y->value, $y->is_negative);

        return $this->convertToObj($temp);
    }

    /**
     * Subtracts two BigIntegers.
     *
     * @param PHP32 $y
     * @return PHP32
     */
    public function subtract(PHP32 $y)
    {
        $temp = self::subtractHelper($this->value, $this->is_negative, $y->value, $y->is_negative);

        return $this->convertToObj($temp);
    }

    /**
     * Multiplies two BigIntegers.
     *
     * @param PHP32 $y
     * @return PHP32
     */
    public function multiply(PHP32 $y)
    {
        $temp = self::multiplyHelper($this->value, $this->is_negative, $y->value, $y->is_negative);

        return $this->convertToObj($temp);
    }

    /**
     * Divides two BigIntegers.
     *
     * Returns an array whose first element contains the quotient and whose second element contains the
     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
     * and the divisor (basically, the "common residue" is the first positive modulo).
     *
     * @param PHP32 $y
     * @return array{PHP32, PHP32}
     */
    public function divide(PHP32 $y)
    {
        return $this->divideHelper($y);
    }

    /**
     * Calculates modular inverses.
     *
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
     * @param PHP32 $n
     * @return false|PHP32
     */
    public function modInverse(PHP32 $n)
    {
        return $this->modInverseHelper($n);
    }

    /**
     * Calculates modular inverses.
     *
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
     * @param PHP32 $n
     * @return PHP32[]
     */
    public function extendedGCD(PHP32 $n)
    {
        return $this->extendedGCDHelper($n);
    }

    /**
     * Calculates the greatest common divisor
     *
     * Say you have 693 and 609.  The GCD is 21.
     *
     * @param PHP32 $n
     * @return PHP32
     */
    public function gcd(PHP32 $n)
    {
        return $this->extendedGCD($n)['gcd'];
    }

    /**
     * Logical And
     *
     * @param PHP32 $x
     * @return PHP32
     */
    public function bitwise_and(PHP32 $x)
    {
        return $this->bitwiseAndHelper($x);
    }

    /**
     * Logical Or
     *
     * @param PHP32 $x
     * @return PHP32
     */
    public function bitwise_or(PHP32 $x)
    {
        return $this->bitwiseOrHelper($x);
    }

    /**
     * Logical Exclusive Or
     *
     * @param PHP32 $x
     * @return PHP32
     */
    public function bitwise_xor(PHP32 $x)
    {
        return $this->bitwiseXorHelper($x);
    }

    /**
     * Compares two numbers.
     *
     * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite.  The reason for this is
     * demonstrated thusly:
     *
     * $x  > $y: $x->compare($y)  > 0
     * $x  < $y: $x->compare($y)  < 0
     * $x == $y: $x->compare($y) == 0
     *
     * Note how the same comparison operator is used.  If you want to test for equality, use $x->equals($y).
     *
     * {@internal Could return $this->subtract($x), but that's not as fast as what we do do.}
     *
     * @param PHP32 $y
     * @return int in case < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
     * @see self::equals()
     */
    public function compare(PHP32 $y)
    {
        return $this->compareHelper($this->value, $this->is_negative, $y->value, $y->is_negative);
    }

    /**
     * Tests the equality of two numbers.
     *
     * If you need to see if one number is greater than or less than another number, use BigInteger::compare()
     *
     * @param PHP32 $x
     * @return bool
     */
    public function equals(PHP32 $x)
    {
        return $this->value === $x->value && $this->is_negative == $x->is_negative;
    }

    /**
     * Performs modular exponentiation.
     *
     * @param PHP32 $e
     * @param PHP32 $n
     * @return PHP32
     */
    public function modPow(PHP32 $e, PHP32 $n)
    {
        return $this->powModOuter($e, $n);
    }

    /**
     * Performs modular exponentiation.
     *
     * Alias for modPow().
     *
     * @param PHP32 $e
     * @param PHP32 $n
     * @return PHP32
     */
    public function powMod(PHP32 $e, PHP32 $n)
    {
        return $this->powModOuter($e, $n);
    }

    /**
     * Generate a random prime number between a range
     *
     * If there's not a prime within the given range, false will be returned.
     *
     * @param PHP32 $min
     * @param PHP32 $max
     * @return false|PHP32
     */
    public static function randomRangePrime(PHP32 $min, PHP32 $max)
    {
        return self::randomRangePrimeOuter($min, $max);
    }

    /**
     * Generate a random number between a range
     *
     * Returns a random number between $min and $max where $min and $max
     * can be defined using one of the two methods:
     *
     * BigInteger::randomRange($min, $max)
     * BigInteger::randomRange($max, $min)
     *
     * @param PHP32 $min
     * @param PHP32 $max
     * @return PHP32
     */
    public static function randomRange(PHP32 $min, PHP32 $max)
    {
        return self::randomRangeHelper($min, $max);
    }

    /**
     * Performs exponentiation.
     *
     * @param PHP32 $n
     * @return PHP32
     */
    public function pow(PHP32 $n)
    {
        return $this->powHelper($n);
    }

    /**
     * Return the minimum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param PHP32 ...$nums
     * @return PHP32
     */
    public static function min(PHP32 ...$nums)
    {
        return self::minHelper($nums);
    }

    /**
     * Return the maximum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param PHP32 ...$nums
     * @return PHP32
     */
    public static function max(PHP32 ...$nums)
    {
        return self::maxHelper($nums);
    }

    /**
     * Tests BigInteger to see if it is between two integers, inclusive
     *
     * @param PHP32 $min
     * @param PHP32 $max
     * @return bool
     */
    public function between(PHP32 $min, PHP32 $max)
    {
        return $this->compare($min) >= 0 && $this->compare($max) <= 0;
    }
}
<?php

/**
 * BCMath BigInteger Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Exception\BadConfigurationException;

/**
 * BCMath Engine.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class BCMath extends Engine
{
    /**
     * Can Bitwise operations be done fast?
     *
     * @see parent::bitwise_leftRotate()
     * @see parent::bitwise_rightRotate()
     */
    const FAST_BITWISE = false;

    /**
     * Engine Directory
     *
     * @see parent::setModExpEngine
     */
    const ENGINE_DIR = 'BCMath';

    /**
     * Test to see if bcmod() accepts 2 or 3 parameters
     */
    const BCMOD_THREE_PARAMS = PHP_VERSION_ID >= 72000;

    /**
     * Test for engine validity
     *
     * @return bool
     * @see parent::__construct()
     */
    public static function isValidEngine()
    {
        return extension_loaded('bcmath');
    }

    /**
     * Default constructor
     *
     * @param mixed $x integer Base-10 number or base-$base number if $base set.
     * @param int $base
     * @see parent::__construct()
     */
    public function __construct($x = 0, $base = 10)
    {
        if (!isset(static::$isValidEngine[static::class])) {
            static::$isValidEngine[static::class] = self::isValidEngine();
        }
        if (!static::$isValidEngine[static::class]) {
            throw new BadConfigurationException('BCMath is not setup correctly on this system');
        }

        $this->value = '0';

        parent::__construct($x, $base);
    }

    /**
     * Initialize a BCMath BigInteger Engine instance
     *
     * @param int $base
     * @see parent::__construct()
     */
    protected function initialize($base)
    {
        switch (abs($base)) {
            case 256:
                // round $len to the nearest 4
                $len = (strlen($this->value) + 3) & ~3;

                $x = str_pad($this->value, $len, chr(0), STR_PAD_LEFT);

                $this->value = '0';
                for ($i = 0; $i < $len; $i += 4) {
                    $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
                    $this->value = bcadd(
                        $this->value,
                        0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord(
                            $x[$i + 2]
                        ) << 8) | ord($x[$i + 3])),
                        0
                    );
                }

                if ($this->is_negative) {
                    $this->value = '-' . $this->value;
                }
                break;
            case 16:
                $x = (strlen($this->value) & 1) ? '0' . $this->value : $this->value;
                $temp = new self(Strings::hex2bin($x), 256);
                $this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
                $this->is_negative = false;
                break;
            case 10:
                // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
                // results then doing it on '-1' does (modInverse does $x[0])
                $this->value = $this->value === '-' ? '0' : (string)$this->value;
        }
    }

    /**
     * Converts a BigInteger to a base-10 number.
     *
     * @return string
     */
    public function toString()
    {
        if ($this->value === '0') {
            return '0';
        }

        return ltrim($this->value, '0');
    }

    /**
     * Converts a BigInteger to a byte string (eg. base-256).
     *
     * @param bool $twos_compliment
     * @return string
     */
    public function toBytes($twos_compliment = false)
    {
        if ($twos_compliment) {
            return $this->toBytesHelper();
        }

        $value = '';
        $current = $this->value;

        if ($current[0] == '-') {
            $current = substr($current, 1);
        }

        while (bccomp($current, '0', 0) > 0) {
            $temp = self::BCMOD_THREE_PARAMS ? bcmod($current, '16777216', 0) : bcmod($current, '16777216');
            $value = chr($temp >> 16) . chr(($temp >> 8) & 0xFF) . chr($temp & 0xFF) . $value;
            $current = bcdiv($current, '16777216', 0);
        }

        return $this->precision > 0 ?
            substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
            ltrim($value, chr(0));
    }

    /**
     * Adds two BigIntegers.
     *
     * @param BCMath $y
     * @return BCMath
     */
    public function add(BCMath $y)
    {
        $temp = new self();
        $temp->value = bcadd($this->value, $y->value, 0);

        return $this->normalize($temp);
    }

    /**
     * Subtracts two BigIntegers.
     *
     * @param BCMath $y
     * @return BCMath
     */
    public function subtract(BCMath $y)
    {
        $temp = new self();
        $temp->value = bcsub($this->value, $y->value, 0);

        return $this->normalize($temp);
    }

    /**
     * Multiplies two BigIntegers.
     *
     * @param BCMath $x
     * @return BCMath
     */
    public function multiply(BCMath $x)
    {
        $temp = new self();
        $temp->value = bcmul($this->value, $x->value, 0);

        return $this->normalize($temp);
    }

    /**
     * Divides two BigIntegers.
     *
     * Returns an array whose first element contains the quotient and whose second element contains the
     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
     * and the divisor (basically, the "common residue" is the first positive modulo).
     *
     * @param BCMath $y
     * @return array{static, static}
     */
    public function divide(BCMath $y)
    {
        $quotient = new self();
        $remainder = new self();

        $quotient->value = bcdiv($this->value, $y->value, 0);
        $remainder->value = self::BCMOD_THREE_PARAMS ? bcmod($this->value, $y->value, 0) : bcmod($this->value, $y->value);

        if ($remainder->value[0] == '-') {
            $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
        }

        return [$this->normalize($quotient), $this->normalize($remainder)];
    }

    /**
     * Calculates modular inverses.
     *
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
     *
     * @param BCMath $n
     * @return false|BCMath
     */
    public function modInverse(BCMath $n)
    {
        return $this->modInverseHelper($n);
    }

    /**
     * Calculates the greatest common divisor and Bezout's identity.
     *
     * Say you have 693 and 609.  The GCD is 21.  Bezout's identity states that there exist integers x and y such that
     * 693*x + 609*y == 21.  In point of fact, there are actually an infinite number of x and y combinations and which
     * combination is returned is dependent upon which mode is in use.  See
     * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
     *
     * @param BCMath $n
     * @return array{gcd: static, x: static, y: static}
     */
    public function extendedGCD(BCMath $n)
    {
        // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
        // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway.  as is,
        // the basic extended euclidean algorithim is what we're using.

        $u = $this->value;
        $v = $n->value;

        $a = '1';
        $b = '0';
        $c = '0';
        $d = '1';

        while (bccomp($v, '0', 0) != 0) {
            $q = bcdiv($u, $v, 0);

            $temp = $u;
            $u = $v;
            $v = bcsub($temp, bcmul($v, $q, 0), 0);

            $temp = $a;
            $a = $c;
            $c = bcsub($temp, bcmul($a, $q, 0), 0);

            $temp = $b;
            $b = $d;
            $d = bcsub($temp, bcmul($b, $q, 0), 0);
        }

        return [
            'gcd' => $this->normalize(new static($u)),
            'x' => $this->normalize(new static($a)),
            'y' => $this->normalize(new static($b))
        ];
    }

    /**
     * Calculates the greatest common divisor
     *
     * Say you have 693 and 609.  The GCD is 21.
     *
     * @param BCMath $n
     * @return BCMath
     */
    public function gcd(BCMath $n)
    {
        $gcd = $this->extendedGCD($n)['gcd'];
        return $gcd;
    }

    /**
     * Absolute value.
     *
     * @return BCMath
     */
    public function abs()
    {
        $temp = new static();
        $temp->value = strlen($this->value) && $this->value[0] == '-' ?
            substr($this->value, 1) :
            $this->value;

        return $temp;
    }

    /**
     * Logical And
     *
     * @param BCMath $x
     * @return BCMath
     */
    public function bitwise_and(BCMath $x)
    {
        return $this->bitwiseAndHelper($x);
    }

    /**
     * Logical Or
     *
     * @param BCMath $x
     * @return BCMath
     */
    public function bitwise_or(BCMath $x)
    {
        return $this->bitwiseOrHelper($x);
    }

    /**
     * Logical Exclusive Or
     *
     * @param BCMath $x
     * @return BCMath
     */
    public function bitwise_xor(BCMath $x)
    {
        return $this->bitwiseXorHelper($x);
    }

    /**
     * Logical Right Shift
     *
     * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
     *
     * @param int $shift
     * @return BCMath
     */
    public function bitwise_rightShift($shift)
    {
        $temp = new static();
        $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);

        return $this->normalize($temp);
    }

    /**
     * Logical Left Shift
     *
     * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
     *
     * @param int $shift
     * @return BCMath
     */
    public function bitwise_leftShift($shift)
    {
        $temp = new static();
        $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);

        return $this->normalize($temp);
    }

    /**
     * Compares two numbers.
     *
     * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite.  The reason for this
     * is demonstrated thusly:
     *
     * $x  > $y: $x->compare($y)  > 0
     * $x  < $y: $x->compare($y)  < 0
     * $x == $y: $x->compare($y) == 0
     *
     * Note how the same comparison operator is used.  If you want to test for equality, use $x->equals($y).
     *
     * {@internal Could return $this->subtract($x), but that's not as fast as what we do do.}
     *
     * @param BCMath $y
     * @return int in case < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
     * @see self::equals()
     */
    public function compare(BCMath $y)
    {
        return bccomp($this->value, $y->value, 0);
    }

    /**
     * Tests the equality of two numbers.
     *
     * If you need to see if one number is greater than or less than another number, use BigInteger::compare()
     *
     * @param BCMath $x
     * @return bool
     */
    public function equals(BCMath $x)
    {
        return $this->value == $x->value;
    }

    /**
     * Performs modular exponentiation.
     *
     * @param BCMath $e
     * @param BCMath $n
     * @return BCMath
     */
    public function modPow(BCMath $e, BCMath $n)
    {
        return $this->powModOuter($e, $n);
    }

    /**
     * Performs modular exponentiation.
     *
     * Alias for modPow().
     *
     * @param BCMath $e
     * @param BCMath $n
     * @return BCMath
     */
    public function powMod(BCMath $e, BCMath $n)
    {
        return $this->powModOuter($e, $n);
    }

    /**
     * Performs modular exponentiation.
     *
     * @param BCMath $e
     * @param BCMath $n
     * @return BCMath
     */
    protected function powModInner(BCMath $e, BCMath $n)
    {
        try {
            $class = static::$modexpEngine[static::class];
            return $class::powModHelper($this, $e, $n, static::class);
        } catch (\Exception $err) {
            return BCMath\DefaultEngine::powModHelper($this, $e, $n, static::class);
        }
    }

    /**
     * Normalize
     *
     * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
     *
     * @param BCMath $result
     * @return BCMath
     */
    protected function normalize(BCMath $result)
    {
        $result->precision = $this->precision;
        $result->bitmask = $this->bitmask;

        if ($result->bitmask !== false) {
            $result->value = self::BCMOD_THREE_PARAMS ? bcmod($result->value, $result->bitmask->value, 0) : bcmod($result->value, $result->bitmask->value);
        }

        return $result;
    }

    /**
     * Generate a random prime number between a range
     *
     * If there's not a prime within the given range, false will be returned.
     *
     * @param BCMath $min
     * @param BCMath $max
     * @return false|BCMath
     */
    public static function randomRangePrime(BCMath $min, BCMath $max)
    {
        return self::randomRangePrimeOuter($min, $max);
    }

    /**
     * Generate a random number between a range
     *
     * Returns a random number between $min and $max where $min and $max
     * can be defined using one of the two methods:
     *
     * BigInteger::randomRange($min, $max)
     * BigInteger::randomRange($max, $min)
     *
     * @param BCMath $min
     * @param BCMath $max
     * @return BCMath
     */
    public static function randomRange(BCMath $min, BCMath $max)
    {
        return self::randomRangeHelper($min, $max);
    }

    /**
     * Make the current number odd
     *
     * If the current number is odd it'll be unchanged.  If it's even, one will be added to it.
     *
     * @see self::randomPrime()
     */
    protected function make_odd()
    {
        if (!$this->isOdd()) {
            $this->value = bcadd($this->value, '1', 0);
        }
    }

    /**
     * Test the number against small primes.
     *
     * @see self::isPrime()
     */
    protected function testSmallPrimes()
    {
        if ($this->value === '1') {
            return false;
        }
        if ($this->value === '2') {
            return true;
        }
        if ($this->value[strlen($this->value) - 1] % 2 == 0) {
            return false;
        }

        $value = $this->value;

        foreach (self::PRIMES as $prime) {
            $r = self::BCMOD_THREE_PARAMS ? bcmod($this->value, $prime, 0) : bcmod($this->value, $prime);
            if ($r == '0') {
                return $this->value == $prime;
            }
        }

        return true;
    }

    /**
     * Scan for 1 and right shift by that amount
     *
     * ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
     *
     * @param BCMath $r
     * @return int
     * @see self::isPrime()
     */
    public static function scan1divide(BCMath $r)
    {
        $r_value = &$r->value;
        $s = 0;
        // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals(static::$one[static::class]) check earlier
        while ($r_value[strlen($r_value) - 1] % 2 == 0) {
            $r_value = bcdiv($r_value, '2', 0);
            ++$s;
        }

        return $s;
    }

    /**
     * Performs exponentiation.
     *
     * @param BCMath $n
     * @return BCMath
     */
    public function pow(BCMath $n)
    {
        $temp = new self();
        $temp->value = bcpow($this->value, $n->value, 0);

        return $this->normalize($temp);
    }

    /**
     * Return the minimum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param BCMath ...$nums
     * @return BCMath
     */
    public static function min(BCMath ...$nums)
    {
        return self::minHelper($nums);
    }

    /**
     * Return the maximum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param BCMath ...$nums
     * @return BCMath
     */
    public static function max(BCMath ...$nums)
    {
        return self::maxHelper($nums);
    }

    /**
     * Tests BigInteger to see if it is between two integers, inclusive
     *
     * @param BCMath $min
     * @param BCMath $max
     * @return bool
     */
    public function between(BCMath $min, BCMath $max)
    {
        return $this->compare($min) >= 0 && $this->compare($max) <= 0;
    }

    /**
     * Set Bitmask
     *
     * @param int $bits
     * @return Engine
     * @see self::setPrecision()
     */
    protected static function setBitmask($bits)
    {
        $temp = parent::setBitmask($bits);
        return $temp->add(static::$one[static::class]);
    }

    /**
     * Is Odd?
     *
     * @return bool
     */
    public function isOdd()
    {
        return $this->value[strlen($this->value) - 1] % 2 == 1;
    }

    /**
     * Tests if a bit is set
     *
     * @return bool
     */
    public function testBit($x)
    {
        $divisor = bcpow('2', $x + 1, 0);
        return bccomp(
            self::BCMOD_THREE_PARAMS ? bcmod($this->value, $divisor, 0) : bcmod($this->value, $divisor),
            bcpow('2', $x, 0),
            0
        ) >= 0;
    }

    /**
     * Is Negative?
     *
     * @return bool
     */
    public function isNegative()
    {
        return strlen($this->value) && $this->value[0] == '-';
    }

    /**
     * Negate
     *
     * Given $k, returns -$k
     *
     * @return BCMath
     */
    public function negate()
    {
        $temp = clone $this;

        if (!strlen($temp->value)) {
            return $temp;
        }

        $temp->value = $temp->value[0] == '-' ?
            substr($this->value, 1) :
            '-' . $this->value;

        return $temp;
    }
}
<?php

/**
 * Base BigInteger Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Random;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Math\BigInteger;

/**
 * Base Engine.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Engine implements \JsonSerializable
{
    /* final protected */ const PRIMES = [
        3,   5,   7,   11,  13,  17,  19,  23,  29,  31,  37,  41,  43,  47,  53,  59,
        61,  67,  71,  73,  79,  83,  89,  97,  101, 103, 107, 109, 113, 127, 131, 137,
        139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
        229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
        317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
        421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
        521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
        619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
        733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
        839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
        953, 967, 971, 977, 983, 991, 997,
    ];

    /**
     * BigInteger(0)
     *
     * @var array<class-string<static>, static>
     */
    protected static $zero = [];

    /**
     * BigInteger(1)
     *
     * @var array<class-string<static>, static>
     */
    protected static $one  = [];

    /**
     * BigInteger(2)
     *
     * @var array<class-string<static>, static>
     */
    protected static $two = [];

    /**
     * Modular Exponentiation Engine
     *
     * @var array<class-string<static>, class-string<static>>
     */
    protected static $modexpEngine;

    /**
     * Engine Validity Flag
     *
     * @var array<class-string<static>, bool>
     */
    protected static $isValidEngine;

    /**
     * Holds the BigInteger's value
     *
     * @var \GMP|string|array|int
     */
    protected $value;

    /**
     * Holds the BigInteger's sign
     *
     * @var bool
     */
    protected $is_negative;

    /**
     * Precision
     *
     * @see static::setPrecision()
     * @var int
     */
    protected $precision = -1;

    /**
     * Precision Bitmask
     *
     * @see static::setPrecision()
     * @var static|false
     */
    protected $bitmask = false;

    /**
     * Recurring Modulo Function
     *
     * @var callable
     */
    protected $reduce;

    /**
     * Mode independent value used for serialization.
     *
     * @see self::__sleep()
     * @see self::__wakeup()
     * @var string
     */
    protected $hex;

    /**
     * Default constructor
     *
     * @param int|numeric-string $x integer Base-10 number or base-$base number if $base set.
     * @param int $base
     */
    public function __construct($x = 0, $base = 10)
    {
        if (!array_key_exists(static::class, static::$zero)) {
            static::$zero[static::class] = null; // Placeholder to prevent infinite loop.
            static::$zero[static::class] = new static(0);
            static::$one[static::class] = new static(1);
            static::$two[static::class] = new static(2);
        }

        // '0' counts as empty() but when the base is 256 '0' is equal to ord('0') or 48
        // '0' is the only value like this per http://php.net/empty
        if (empty($x) && (abs($base) != 256 || $x !== '0')) {
            return;
        }

        switch ($base) {
            case -256:
            case 256:
                if ($base == -256 && (ord($x[0]) & 0x80)) {
                    $this->value = ~$x;
                    $this->is_negative = true;
                } else {
                    $this->value = $x;
                    $this->is_negative = false;
                }

                $this->initialize($base);

                if ($this->is_negative) {
                    $temp = $this->add(new static('-1'));
                    $this->value = $temp->value;
                }
                break;
            case -16:
            case 16:
                if ($base > 0 && $x[0] == '-') {
                    $this->is_negative = true;
                    $x = substr($x, 1);
                }

                $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#s', '$1', $x);

                $is_negative = false;
                if ($base < 0 && hexdec($x[0]) >= 8) {
                    $this->is_negative = $is_negative = true;
                    $x = Strings::bin2hex(~Strings::hex2bin($x));
                }

                $this->value = $x;
                $this->initialize($base);

                if ($is_negative) {
                    $temp = $this->add(new static('-1'));
                    $this->value = $temp->value;
                }
                break;
            case -10:
            case 10:
                // (?<!^)(?:-).*: find any -'s that aren't at the beginning and then any characters that follow that
                // (?<=^|-)0*: find any 0's that are preceded by the start of the string or by a - (ie. octals)
                // [^-0-9].*: find any non-numeric characters and then any characters that follow that
                $this->value = preg_replace('#(?<!^)(?:-).*|(?<=^|-)0*|[^-0-9].*#s', '', $x);
                if (!strlen($this->value) || $this->value == '-') {
                    $this->value = '0';
                }
                $this->initialize($base);
                break;
            case -2:
            case 2:
                if ($base > 0 && $x[0] == '-') {
                    $this->is_negative = true;
                    $x = substr($x, 1);
                }

                $x = preg_replace('#^([01]*).*#s', '$1', $x);

                $temp = new static(Strings::bits2bin($x), 128 * $base); // ie. either -16 or +16
                $this->value = $temp->value;
                if ($temp->is_negative) {
                    $this->is_negative = true;
                }

                break;
            default:
                // base not supported, so we'll let $this == 0
        }
    }

    /**
     * Sets engine type.
     *
     * Throws an exception if the type is invalid
     *
     * @param class-string<Engine> $engine
     */
    public static function setModExpEngine($engine)
    {
        $fqengine = '\\phpseclib3\\Math\\BigInteger\\Engines\\' . static::ENGINE_DIR . '\\' . $engine;
        if (!class_exists($fqengine) || !method_exists($fqengine, 'isValidEngine')) {
            throw new \InvalidArgumentException("$engine is not a valid engine");
        }
        if (!$fqengine::isValidEngine()) {
            throw new BadConfigurationException("$engine is not setup correctly on this system");
        }
        static::$modexpEngine[static::class] = $fqengine;
    }

    /**
     * Converts a BigInteger to a byte string (eg. base-256).
     *
     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
     * saved as two's compliment.
     * @return string
     */
    protected function toBytesHelper()
    {
        $comparison = $this->compare(new static());
        if ($comparison == 0) {
            return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
        }

        $temp = $comparison < 0 ? $this->add(new static(1)) : $this;
        $bytes = $temp->toBytes();

        if (!strlen($bytes)) { // eg. if the number we're trying to convert is -1
            $bytes = chr(0);
        }

        if (ord($bytes[0]) & 0x80) {
            $bytes = chr(0) . $bytes;
        }

        return $comparison < 0 ? ~$bytes : $bytes;
    }

    /**
     * Converts a BigInteger to a hex string (eg. base-16).
     *
     * @param bool $twos_compliment
     * @return string
     */
    public function toHex($twos_compliment = false)
    {
        return Strings::bin2hex($this->toBytes($twos_compliment));
    }

    /**
     * Converts a BigInteger to a bit string (eg. base-2).
     *
     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
     * saved as two's compliment.
     *
     * @param bool $twos_compliment
     * @return string
     */
    public function toBits($twos_compliment = false)
    {
        $hex = $this->toBytes($twos_compliment);
        $bits = Strings::bin2bits($hex);

        $result = $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');

        if ($twos_compliment && $this->compare(new static()) > 0 && $this->precision <= 0) {
            return '0' . $result;
        }

        return $result;
    }

    /**
     * Calculates modular inverses.
     *
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
     *
     * {@internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.}
     *
     * @param Engine $n
     * @return static|false
     */
    protected function modInverseHelper(Engine $n)
    {
        // $x mod -$n == $x mod $n.
        $n = $n->abs();

        if ($this->compare(static::$zero[static::class]) < 0) {
            $temp = $this->abs();
            $temp = $temp->modInverse($n);
            return $this->normalize($n->subtract($temp));
        }

        $extended = $this->extendedGCD($n);
        $gcd = $extended['gcd'];
        $x = $extended['x'];

        if (!$gcd->equals(static::$one[static::class])) {
            return false;
        }

        $x = $x->compare(static::$zero[static::class]) < 0 ? $x->add($n) : $x;

        return $this->compare(static::$zero[static::class]) < 0 ? $this->normalize($n->subtract($x)) : $this->normalize($x);
    }

    /**
     * Serialize
     *
     * Will be called, automatically, when serialize() is called on a BigInteger object.
     *
     * @return array
     */
    public function __sleep()
    {
        $this->hex = $this->toHex(true);
        $vars = ['hex'];
        if ($this->precision > 0) {
            $vars[] = 'precision';
        }
        return $vars;
    }

    /**
     * Serialize
     *
     * Will be called, automatically, when unserialize() is called on a BigInteger object.
     *
     * @return void
     */
    public function __wakeup()
    {
        $temp = new static($this->hex, -16);
        $this->value = $temp->value;
        $this->is_negative = $temp->is_negative;
        if ($this->precision > 0) {
            // recalculate $this->bitmask
            $this->setPrecision($this->precision);
        }
    }

    /**
     *  __serialize() magic method
     *
     * __sleep / __wakeup were depreciated in PHP 8.5
     * Will be called, automatically, when serialize() is called on a Math_BigInteger object.
     *
     * @see self::__unserialize()
     * @access public
     */
    public function __serialize()
    {
        $result = ['hex' => $this->toHex(true)];
        if ($this->precision > 0) {
            $result['precision'] = $this->precision;
        }
        return $result;
    }

    /**
     *  __unserialize() magic method
     *
     * __sleep / __wakeup were depreciated in PHP 8.5
     * Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
     *
     * @see self::__serialize()
     * @access public
     */
    public function __unserialize(array $data)
    {
        $temp = new static($data['hex'], -16);
        $this->value = $temp->value;
        $this->is_negative = $temp->is_negative;
        if (isset($data['precision']) && $data['precision'] > 0) {
            // recalculate $this->bitmask
            $this->setPrecision($data['precision']);
        }
    }

    /**
     * JSON Serialize
     *
     * Will be called, automatically, when json_encode() is called on a BigInteger object.
     *
     * @return array{hex: string, precision?: int]
     */
    #[\ReturnTypeWillChange]
    public function jsonSerialize()
    {
        $result = ['hex' => $this->toHex(true)];
        if ($this->precision > 0) {
            $result['precision'] = $this->precision;
        }
        return $result;
    }

    /**
     * Converts a BigInteger to a base-10 number.
     *
     * @return string
     */
    public function __toString()
    {
        return $this->toString();
    }

    /**
     *  __debugInfo() magic method
     *
     * Will be called, automatically, when print_r() or var_dump() are called
     *
     * @return array
     */
    public function __debugInfo()
    {
        $result = [
            'value' => '0x' . $this->toHex(true),
            'engine' => basename(static::class)
        ];
        return $this->precision > 0 ? $result + ['precision' => $this->precision] : $result;
    }

    /**
     * Set Precision
     *
     * Some bitwise operations give different results depending on the precision being used.  Examples include left
     * shift, not, and rotates.
     *
     * @param int $bits
     */
    public function setPrecision($bits)
    {
        if ($bits < 1) {
            $this->precision = -1;
            $this->bitmask = false;

            return;
        }
        $this->precision = $bits;
        $this->bitmask = static::setBitmask($bits);

        $temp = $this->normalize($this);
        $this->value = $temp->value;
    }

    /**
     * Get Precision
     *
     * Returns the precision if it exists, -1 if it doesn't
     *
     * @return int
     */
    public function getPrecision()
    {
        return $this->precision;
    }

    /**
     * Set Bitmask
     * @return static
     * @param int $bits
     * @see self::setPrecision()
     */
    protected static function setBitmask($bits)
    {
        return new static(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
    }

    /**
     * Logical Not
     *
     * @return Engine|string
     */
    public function bitwise_not()
    {
        // calculuate "not" without regard to $this->precision
        // (will always result in a smaller number.  ie. ~1 isn't 1111 1110 - it's 0)
        $temp = $this->toBytes();
        if ($temp == '') {
            return $this->normalize(static::$zero[static::class]);
        }
        $pre_msb = decbin(ord($temp[0]));
        $temp = ~$temp;
        $msb = decbin(ord($temp[0]));
        if (strlen($msb) == 8) {
            $msb = substr($msb, strpos($msb, '0'));
        }
        $temp[0] = chr(bindec($msb));

        // see if we need to add extra leading 1's
        $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
        $new_bits = $this->precision - $current_bits;
        if ($new_bits <= 0) {
            return $this->normalize(new static($temp, 256));
        }

        // generate as many leading 1's as we need to.
        $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);

        self::base256_lshift($leading_ones, $current_bits);

        $temp = str_pad($temp, strlen($leading_ones), chr(0), STR_PAD_LEFT);

        return $this->normalize(new static($leading_ones | $temp, 256));
    }

    /**
     * Logical Left Shift
     *
     * Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
     *
     * @param string $x
     * @param int $shift
     * @return void
     */
    protected static function base256_lshift(&$x, $shift)
    {
        if ($shift == 0) {
            return;
        }

        $num_bytes = $shift >> 3; // eg. floor($shift/8)
        $shift &= 7; // eg. $shift % 8

        $carry = 0;
        for ($i = strlen($x) - 1; $i >= 0; --$i) {
            $temp = (ord($x[$i]) << $shift) | $carry;
            $x[$i] = chr($temp & 0xFF);
            $carry = $temp >> 8;
        }
        $carry = ($carry != 0) ? chr($carry) : '';
        $x = $carry . $x . str_repeat(chr(0), $num_bytes);
    }

    /**
     * Logical Left Rotate
     *
     * Instead of the top x bits being dropped they're appended to the shifted bit string.
     *
     * @param int $shift
     * @return Engine
     */
    public function bitwise_leftRotate($shift)
    {
        $bits = $this->toBytes();

        if ($this->precision > 0) {
            $precision = $this->precision;
            if (static::FAST_BITWISE) {
                $mask = $this->bitmask->toBytes();
            } else {
                $mask = $this->bitmask->subtract(new static(1));
                $mask = $mask->toBytes();
            }
        } else {
            $temp = ord($bits[0]);
            for ($i = 0; $temp >> $i; ++$i) {
            }
            $precision = 8 * strlen($bits) - 8 + $i;
            $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
        }

        if ($shift < 0) {
            $shift += $precision;
        }
        $shift %= $precision;

        if (!$shift) {
            return clone $this;
        }

        $left = $this->bitwise_leftShift($shift);
        $left = $left->bitwise_and(new static($mask, 256));
        $right = $this->bitwise_rightShift($precision - $shift);
        $result = static::FAST_BITWISE ? $left->bitwise_or($right) : $left->add($right);
        return $this->normalize($result);
    }

    /**
     * Logical Right Rotate
     *
     * Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
     *
     * @param int $shift
     * @return Engine
     */
    public function bitwise_rightRotate($shift)
    {
        return $this->bitwise_leftRotate(-$shift);
    }

    /**
     * Returns the smallest and largest n-bit number
     *
     * @param int $bits
     * @return array{min: static, max: static}
     */
    public static function minMaxBits($bits)
    {
        $bytes = $bits >> 3;
        $min = str_repeat(chr(0), $bytes);
        $max = str_repeat(chr(0xFF), $bytes);
        $msb = $bits & 7;
        if ($msb) {
            $min = chr(1 << ($msb - 1)) . $min;
            $max = chr((1 << $msb) - 1) . $max;
        } else {
            $min[0] = chr(0x80);
        }
        return [
            'min' => new static($min, 256),
            'max' => new static($max, 256)
        ];
    }

    /**
     * Return the size of a BigInteger in bits
     *
     * @return int
     */
    public function getLength()
    {
        return strlen($this->toBits());
    }

    /**
     * Return the size of a BigInteger in bytes
     *
     * @return int
     */
    public function getLengthInBytes()
    {
        return (int) ceil($this->getLength() / 8);
    }

    /**
     * Performs some pre-processing for powMod
     *
     * @param Engine $e
     * @param Engine $n
     * @return static|false
     */
    protected function powModOuter(Engine $e, Engine $n)
    {
        $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();

        if ($e->compare(new static()) < 0) {
            $e = $e->abs();

            $temp = $this->modInverse($n);
            if ($temp === false) {
                return false;
            }

            return $this->normalize($temp->powModInner($e, $n));
        }

        if ($this->compare($n) > 0 || $this->isNegative()) {
            list(, $temp) = $this->divide($n);
            return $temp->powModInner($e, $n);
        }

        return $this->powModInner($e, $n);
    }

    /**
     * Sliding Window k-ary Modular Exponentiation
     *
     * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}.  In a departure from those algorithims,
     * however, this function performs a modular reduction after every multiplication and squaring operation.
     * As such, this function has the same preconditions that the reductions being used do.
     *
     * @template T of Engine
     * @param Engine $x
     * @param Engine $e
     * @param Engine $n
     * @param class-string<T> $class
     * @return T
     */
    protected static function slidingWindow(Engine $x, Engine $e, Engine $n, $class)
    {
        static $window_ranges = [7, 25, 81, 241, 673, 1793]; // from BigInteger.java's oddModPow function
        //static $window_ranges = [0, 7, 36, 140, 450, 1303, 3529]; // from MPM 7.3.1

        $e_bits = $e->toBits();
        $e_length = strlen($e_bits);

        // calculate the appropriate window size.
        // $window_size == 3 if $window_ranges is between 25 and 81, for example.
        for ($i = 0, $window_size = 1; $i < count($window_ranges) && $e_length > $window_ranges[$i]; ++$window_size, ++$i) {
        }

        $n_value = $n->value;

        if (method_exists(static::class, 'generateCustomReduction')) {
            static::generateCustomReduction($n, $class);
        }

        // precompute $this^0 through $this^$window_size
        $powers = [];
        $powers[1] = static::prepareReduce($x->value, $n_value, $class);
        $powers[2] = static::squareReduce($powers[1], $n_value, $class);

        // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
        // in a 1.  ie. it's supposed to be odd.
        $temp = 1 << ($window_size - 1);
        for ($i = 1; $i < $temp; ++$i) {
            $i2 = $i << 1;
            $powers[$i2 + 1] = static::multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $class);
        }

        $result = new $class(1);
        $result = static::prepareReduce($result->value, $n_value, $class);

        for ($i = 0; $i < $e_length;) {
            if (!$e_bits[$i]) {
                $result = static::squareReduce($result, $n_value, $class);
                ++$i;
            } else {
                for ($j = $window_size - 1; $j > 0; --$j) {
                    if (!empty($e_bits[$i + $j])) {
                        break;
                    }
                }

                // eg. the length of substr($e_bits, $i, $j + 1)
                for ($k = 0; $k <= $j; ++$k) {
                    $result = static::squareReduce($result, $n_value, $class);
                }

                $result = static::multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $class);

                $i += $j + 1;
            }
        }

        $temp = new $class();
        $temp->value = static::reduce($result, $n_value, $class);

        return $temp;
    }

    /**
     * Generates a random number of a certain size
     *
     * Bit length is equal to $size
     *
     * @param int $size
     * @return Engine
     */
    public static function random($size)
    {
        $minMax = static::minMaxBits($size);
        $min = $minMax['min'];
        $max = $minMax['max'];
        return static::randomRange($min, $max);
    }

    /**
     * Generates a random prime number of a certain size
     *
     * Bit length is equal to $size
     *
     * @param int $size
     * @return Engine
     */
    public static function randomPrime($size)
    {
        $minMax = static::minMaxBits($size);
        $min = $minMax['min'];
        $max = $minMax['max'];
        return static::randomRangePrime($min, $max);
    }

    /**
     * Performs some pre-processing for randomRangePrime
     *
     * @param Engine $min
     * @param Engine $max
     * @return static|false
     */
    protected static function randomRangePrimeOuter(Engine $min, Engine $max)
    {
        $compare = $max->compare($min);

        if (!$compare) {
            return $min->isPrime() ? $min : false;
        } elseif ($compare < 0) {
            // if $min is bigger then $max, swap $min and $max
            $temp = $max;
            $max = $min;
            $min = $temp;
        }

        $length = $max->getLength();
        if ($length > 8196) {
            throw new \RuntimeException("Generation of random prime numbers larger than 8196 has been disabled ($length)");
        }

        $x = static::randomRange($min, $max);

        return static::randomRangePrimeInner($x, $min, $max);
    }

    /**
     * Generate a random number between a range
     *
     * Returns a random number between $min and $max where $min and $max
     * can be defined using one of the two methods:
     *
     * BigInteger::randomRange($min, $max)
     * BigInteger::randomRange($max, $min)
     *
     * @param Engine $min
     * @param Engine $max
     * @return Engine
     */
    protected static function randomRangeHelper(Engine $min, Engine $max)
    {
        $compare = $max->compare($min);

        if (!$compare) {
            return $min;
        } elseif ($compare < 0) {
            // if $min is bigger then $max, swap $min and $max
            $temp = $max;
            $max = $min;
            $min = $temp;
        }

        if (!isset(static::$one[static::class])) {
            static::$one[static::class] = new static(1);
        }

        $max = $max->subtract($min->subtract(static::$one[static::class]));

        $size = strlen(ltrim($max->toBytes(), chr(0)));

        /*
            doing $random % $max doesn't work because some numbers will be more likely to occur than others.
            eg. if $max is 140 and $random's max is 255 then that'd mean both $random = 5 and $random = 145
            would produce 5 whereas the only value of random that could produce 139 would be 139. ie.
            not all numbers would be equally likely. some would be more likely than others.

            creating a whole new random number until you find one that is within the range doesn't work
            because, for sufficiently small ranges, the likelihood that you'd get a number within that range
            would be pretty small. eg. with $random's max being 255 and if your $max being 1 the probability
            would be pretty high that $random would be greater than $max.

            phpseclib works around this using the technique described here:

            http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
        */
        $random_max = new static(chr(1) . str_repeat("\0", $size), 256);
        $random = new static(Random::string($size), 256);

        list($max_multiple) = $random_max->divide($max);
        $max_multiple = $max_multiple->multiply($max);

        while ($random->compare($max_multiple) >= 0) {
            $random = $random->subtract($max_multiple);
            $random_max = $random_max->subtract($max_multiple);
            $random = $random->bitwise_leftShift(8);
            $random = $random->add(new static(Random::string(1), 256));
            $random_max = $random_max->bitwise_leftShift(8);
            list($max_multiple) = $random_max->divide($max);
            $max_multiple = $max_multiple->multiply($max);
        }
        list(, $random) = $random->divide($max);

        return $random->add($min);
    }

    /**
     * Performs some post-processing for randomRangePrime
     *
     * @param Engine $x
     * @param Engine $min
     * @param Engine $max
     * @return static|false
     */
    protected static function randomRangePrimeInner(Engine $x, Engine $min, Engine $max)
    {
        if (!isset(static::$two[static::class])) {
            static::$two[static::class] = new static('2');
        }

        $x->make_odd();
        if ($x->compare($max) > 0) {
            // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
            if ($min->equals($max)) {
                return false;
            }
            $x = clone $min;
            $x->make_odd();
        }

        $initial_x = clone $x;

        while (true) {
            if ($x->isPrime()) {
                return $x;
            }

            $x = $x->add(static::$two[static::class]);

            if ($x->compare($max) > 0) {
                $x = clone $min;
                if ($x->equals(static::$two[static::class])) {
                    return $x;
                }
                $x->make_odd();
            }

            if ($x->equals($initial_x)) {
                return false;
            }
        }
    }

    /**
     * Sets the $t parameter for primality testing
     *
     * @return int
     */
    protected function setupIsPrime()
    {
        $length = $this->getLengthInBytes();

        // see HAC 4.49 "Note (controlling the error probability)"
        // @codingStandardsIgnoreStart
             if ($length >= 163) { $t =  2; } // floor(1300 / 8)
        else if ($length >= 106) { $t =  3; } // floor( 850 / 8)
        else if ($length >= 81 ) { $t =  4; } // floor( 650 / 8)
        else if ($length >= 68 ) { $t =  5; } // floor( 550 / 8)
        else if ($length >= 56 ) { $t =  6; } // floor( 450 / 8)
        else if ($length >= 50 ) { $t =  7; } // floor( 400 / 8)
        else if ($length >= 43 ) { $t =  8; } // floor( 350 / 8)
        else if ($length >= 37 ) { $t =  9; } // floor( 300 / 8)
        else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
        else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
        else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
        else                     { $t = 27; }
        // @codingStandardsIgnoreEnd

        return $t;
    }

    /**
     * Tests Primality
     *
     * Uses the {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}.
     * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24} for more info.
     *
     * @param int $t
     * @return bool
     */
    protected function testPrimality($t)
    {
        if (!$this->testSmallPrimes()) {
            return false;
        }

        $n   = clone $this;
        $n_1 = $n->subtract(static::$one[static::class]);
        $n_2 = $n->subtract(static::$two[static::class]);

        $r = clone $n_1;
        $s = static::scan1divide($r);

        for ($i = 0; $i < $t; ++$i) {
            $a = static::randomRange(static::$two[static::class], $n_2);
            $y = $a->modPow($r, $n);

            if (!$y->equals(static::$one[static::class]) && !$y->equals($n_1)) {
                for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
                    $y = $y->modPow(static::$two[static::class], $n);
                    if ($y->equals(static::$one[static::class])) {
                        return false;
                    }
                }

                if (!$y->equals($n_1)) {
                    return false;
                }
            }
        }

        return true;
    }

    /**
     * Checks a numer to see if it's prime
     *
     * Assuming the $t parameter is not set, this function has an error rate of 2**-80.  The main motivation for the
     * $t parameter is distributability.  BigInteger::randomPrime() can be distributed across multiple pageloads
     * on a website instead of just one.
     *
     * @param int|bool $t
     * @return bool
     */
    public function isPrime($t = false)
    {
        // OpenSSL limits RSA keys to 16384 bits. The length of an RSA key is equal to the length of the modulo, which is
        // produced by multiplying the primes p and q by one another. The largest number two 8196 bit primes can produce is
        // a 16384 bit number so, basically, 8196 bit primes are the largest OpenSSL will generate and if that's the largest
        // that it'll generate it also stands to reason that that's the largest you'll be able to test primality on
        $length = $this->getLength();
        if ($length > 8196) {
            throw new \RuntimeException("Primality testing is not supported for numbers larger than 8196 bits ($length)");
        }

        if (!$t) {
            $t = $this->setupIsPrime();
        }
        return $this->testPrimality($t);
    }

    /**
     * Performs a few preliminary checks on root
     *
     * @param int $n
     * @return Engine
     */
    protected function rootHelper($n)
    {
        if ($n < 1) {
            return clone static::$zero[static::class];
        } // we want positive exponents
        if ($this->compare(static::$one[static::class]) < 0) {
            return clone static::$zero[static::class];
        } // we want positive numbers
        if ($this->compare(static::$two[static::class]) < 0) {
            return clone static::$one[static::class];
        } // n-th root of 1 or 2 is 1

        return $this->rootInner($n);
    }

    /**
     * Calculates the nth root of a biginteger.
     *
     * Returns the nth root of a positive biginteger, where n defaults to 2
     *
     * {@internal This function is based off of {@link http://mathforum.org/library/drmath/view/52605.html this page} and {@link http://stackoverflow.com/questions/11242920/calculating-nth-root-with-bcmath-in-php this stackoverflow question}.}
     *
     * @param int $n
     * @return Engine
     */
    protected function rootInner($n)
    {
        $n = new static($n);

        // g is our guess number
        $g = static::$two[static::class];
        // while (g^n < num) g=g*2
        while ($g->pow($n)->compare($this) < 0) {
            $g = $g->multiply(static::$two[static::class]);
        }
        // if (g^n==num) num is a power of 2, we're lucky, end of job
        // == 0 bccomp(bcpow($g, $n), $n->value)==0
        if ($g->pow($n)->equals($this) > 0) {
            $root = $g;
            return $this->normalize($root);
        }

        // if we're here num wasn't a power of 2 :(
        $og = $g; // og means original guess and here is our upper bound
        $g = $g->divide(static::$two[static::class])[0]; // g is set to be our lower bound
        $step = $og->subtract($g)->divide(static::$two[static::class])[0]; // step is the half of upper bound - lower bound
        $g = $g->add($step); // we start at lower bound + step , basically in the middle of our interval

        // while step>1

        while ($step->compare(static::$one[static::class]) == 1) {
            $guess = $g->pow($n);
            $step = $step->divide(static::$two[static::class])[0];
            $comp = $guess->compare($this); // compare our guess with real number
            switch ($comp) {
                case -1: // if guess is lower we add the new step
                    $g = $g->add($step);
                    break;
                case 1: // if guess is higher we sub the new step
                    $g = $g->subtract($step);
                    break;
                case 0: // if guess is exactly the num we're done, we return the value
                    $root = $g;
                    break 2;
            }
        }

        if ($comp == 1) {
            $g = $g->subtract($step);
        }

        // whatever happened, g is the closest guess we can make so return it
        $root = $g;

        return $this->normalize($root);
    }

    /**
     * Calculates the nth root of a biginteger.
     *
     * @param int $n
     * @return Engine
     */
    public function root($n = 2)
    {
        return $this->rootHelper($n);
    }

    /**
     * Return the minimum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param array $nums
     * @return Engine
     */
    protected static function minHelper(array $nums)
    {
        if (count($nums) == 1) {
            return $nums[0];
        }
        $min = $nums[0];
        for ($i = 1; $i < count($nums); $i++) {
            $min = $min->compare($nums[$i]) > 0 ? $nums[$i] : $min;
        }
        return $min;
    }

    /**
     * Return the minimum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param array $nums
     * @return Engine
     */
    protected static function maxHelper(array $nums)
    {
        if (count($nums) == 1) {
            return $nums[0];
        }
        $max = $nums[0];
        for ($i = 1; $i < count($nums); $i++) {
            $max = $max->compare($nums[$i]) < 0 ? $nums[$i] : $max;
        }
        return $max;
    }

    /**
     * Create Recurring Modulo Function
     *
     * Sometimes it may be desirable to do repeated modulos with the same number outside of
     * modular exponentiation
     *
     * @return callable
     */
    public function createRecurringModuloFunction()
    {
        $class = static::class;

        $fqengine = !method_exists(static::$modexpEngine[static::class], 'reduce') ?
            '\\phpseclib3\\Math\\BigInteger\\Engines\\' . static::ENGINE_DIR . '\\DefaultEngine' :
            static::$modexpEngine[static::class];
        if (method_exists($fqengine, 'generateCustomReduction')) {
            $func = $fqengine::generateCustomReduction($this, static::class);
            return eval('return function(' . static::class . ' $x) use ($func, $class) {
                $r = new $class();
                $r->value = $func($x->value);
                return $r;
            };');
        }
        $n = $this->value;
        return eval('return function(' . static::class . ' $x) use ($n, $fqengine, $class) {
            $r = new $class();
            $r->value = $fqengine::reduce($x->value, $n, $class);
            return $r;
        };');
    }

    /**
     * Calculates the greatest common divisor and Bezout's identity.
     *
     * @param Engine $n
     * @return array{gcd: Engine, x: Engine, y: Engine}
     */
    protected function extendedGCDHelper(Engine $n)
    {
        $u = clone $this;
        $v = clone $n;

        $one = new static(1);
        $zero = new static();

        $a = clone $one;
        $b = clone $zero;
        $c = clone $zero;
        $d = clone $one;

        while (!$v->equals($zero)) {
            list($q) = $u->divide($v);

            $temp = $u;
            $u = $v;
            $v = $temp->subtract($v->multiply($q));

            $temp = $a;
            $a = $c;
            $c = $temp->subtract($a->multiply($q));

            $temp = $b;
            $b = $d;
            $d = $temp->subtract($b->multiply($q));
        }

        return [
            'gcd' => $u,
            'x' => $a,
            'y' => $b
        ];
    }

    /**
     * Bitwise Split
     *
     * Splits BigInteger's into chunks of $split bits
     *
     * @param int $split
     * @return Engine[]
     */
    public function bitwise_split($split)
    {
        if ($split < 1) {
            throw new \RuntimeException('Offset must be greater than 1');
        }

        $mask = static::$one[static::class]->bitwise_leftShift($split)->subtract(static::$one[static::class]);

        $num = clone $this;

        $vals = [];
        while (!$num->equals(static::$zero[static::class])) {
            $vals[] = $num->bitwise_and($mask);
            $num = $num->bitwise_rightShift($split);
        }

        return array_reverse($vals);
    }

    /**
     * Logical And
     *
     * @param Engine $x
     * @return Engine
     */
    protected function bitwiseAndHelper(Engine $x)
    {
        $left = $this->toBytes(true);
        $right = $x->toBytes(true);

        $length = max(strlen($left), strlen($right));

        $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
        $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);

        return $this->normalize(new static($left & $right, -256));
    }

    /**
     * Logical Or
     *
     * @param Engine $x
     * @return Engine
     */
    protected function bitwiseOrHelper(Engine $x)
    {
        $left = $this->toBytes(true);
        $right = $x->toBytes(true);

        $length = max(strlen($left), strlen($right));

        $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
        $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);

        return $this->normalize(new static($left | $right, -256));
    }

    /**
     * Logical Exclusive Or
     *
     * @param Engine $x
     * @return Engine
     */
    protected function bitwiseXorHelper(Engine $x)
    {
        $left = $this->toBytes(true);
        $right = $x->toBytes(true);

        $length = max(strlen($left), strlen($right));


        $left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
        $right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
        return $this->normalize(new static($left ^ $right, -256));
    }
}
<?php

/**
 * GMP BigInteger Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines;

use phpseclib3\Exception\BadConfigurationException;

/**
 * GMP Engine.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class GMP extends Engine
{
    /**
     * Can Bitwise operations be done fast?
     *
     * @see parent::bitwise_leftRotate()
     * @see parent::bitwise_rightRotate()
     */
    const FAST_BITWISE = true;

    /**
     * Engine Directory
     *
     * @see parent::setModExpEngine
     */
    const ENGINE_DIR = 'GMP';

    /**
     * Test for engine validity
     *
     * @return bool
     * @see parent::__construct()
     */
    public static function isValidEngine()
    {
        return extension_loaded('gmp');
    }

    /**
     * Default constructor
     *
     * @param mixed $x integer Base-10 number or base-$base number if $base set.
     * @param int $base
     * @see parent::__construct()
     */
    public function __construct($x = 0, $base = 10)
    {
        if (!isset(static::$isValidEngine[static::class])) {
            static::$isValidEngine[static::class] = self::isValidEngine();
        }
        if (!static::$isValidEngine[static::class]) {
            throw new BadConfigurationException('GMP is not setup correctly on this system');
        }

        if ($x instanceof \GMP) {
            $this->value = $x;
            return;
        }

        $this->value = gmp_init(0);

        parent::__construct($x, $base);
    }

    /**
     * Initialize a GMP BigInteger Engine instance
     *
     * @param int $base
     * @see parent::__construct()
     */
    protected function initialize($base)
    {
        switch (abs($base)) {
            case 256:
                $this->value = gmp_import($this->value);
                if ($this->is_negative) {
                    $this->value = -$this->value;
                }
                break;
            case 16:
                $temp = $this->is_negative ? '-0x' . $this->value : '0x' . $this->value;
                $this->value = gmp_init($temp);
                break;
            case 10:
                $this->value = gmp_init(isset($this->value) ? $this->value : '0');
        }
    }

    /**
     * Converts a BigInteger to a base-10 number.
     *
     * @return string
     */
    public function toString()
    {
        return (string)$this->value;
    }

    /**
     * Converts a BigInteger to a bit string (eg. base-2).
     *
     * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
     * saved as two's compliment.
     *
     * @param bool $twos_compliment
     * @return string
     */
    public function toBits($twos_compliment = false)
    {
        $hex = $this->toHex($twos_compliment);
        $bits = strlen($hex) ? gmp_strval(gmp_init($hex, 16), 2) : '';

        if ($this->precision > 0) {
            $bits = substr($bits, -$this->precision);
        }

        if ($twos_compliment && $this->compare(new static()) > 0 && $this->precision <= 0) {
            return '0' . $bits;
        }

        return $bits;
    }

    /**
     * Converts a BigInteger to a byte string (eg. base-256).
     *
     * @param bool $twos_compliment
     * @return string
     */
    public function toBytes($twos_compliment = false)
    {
        if ($twos_compliment) {
            return $this->toBytesHelper();
        }

        if (gmp_cmp($this->value, gmp_init(0)) == 0) {
            return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
        }

        $temp = gmp_export($this->value);

        return $this->precision > 0 ?
            substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
            ltrim($temp, chr(0));
    }

    /**
     * Adds two BigIntegers.
     *
     * @param GMP $y
     * @return GMP
     */
    public function add(GMP $y)
    {
        $temp = new self();
        $temp->value = $this->value + $y->value;

        return $this->normalize($temp);
    }

    /**
     * Subtracts two BigIntegers.
     *
     * @param GMP $y
     * @return GMP
     */
    public function subtract(GMP $y)
    {
        $temp = new self();
        $temp->value = $this->value - $y->value;

        return $this->normalize($temp);
    }

    /**
     * Multiplies two BigIntegers.
     *
     * @param GMP $x
     * @return GMP
     */
    public function multiply(GMP $x)
    {
        $temp = new self();
        $temp->value = $this->value * $x->value;

        return $this->normalize($temp);
    }

    /**
     * Divides two BigIntegers.
     *
     * Returns an array whose first element contains the quotient and whose second element contains the
     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
     * and the divisor (basically, the "common residue" is the first positive modulo).
     *
     * @param GMP $y
     * @return array{GMP, GMP}
     */
    public function divide(GMP $y)
    {
        $quotient = new self();
        $remainder = new self();

        list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);

        if (gmp_sign($remainder->value) < 0) {
            $remainder->value = $remainder->value + gmp_abs($y->value);
        }

        return [$this->normalize($quotient), $this->normalize($remainder)];
    }

    /**
     * Compares two numbers.
     *
     * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite.  The reason for this
     * is demonstrated thusly:
     *
     * $x  > $y: $x->compare($y)  > 0
     * $x  < $y: $x->compare($y)  < 0
     * $x == $y: $x->compare($y) == 0
     *
     * Note how the same comparison operator is used.  If you want to test for equality, use $x->equals($y).
     *
     * {@internal Could return $this->subtract($x), but that's not as fast as what we do do.}
     *
     * @param GMP $y
     * @return int in case < 0 if $this is less than $y; > 0 if $this is greater than $y, and 0 if they are equal.
     * @see self::equals()
     */
    public function compare(GMP $y)
    {
        $r = gmp_cmp($this->value, $y->value);
        if ($r < -1) {
            $r = -1;
        }
        if ($r > 1) {
            $r = 1;
        }
        return $r;
    }

    /**
     * Tests the equality of two numbers.
     *
     * If you need to see if one number is greater than or less than another number, use BigInteger::compare()
     *
     * @param GMP $x
     * @return bool
     */
    public function equals(GMP $x)
    {
        return $this->value == $x->value;
    }

    /**
     * Calculates modular inverses.
     *
     * Say you have (30 mod 17 * x mod 17) mod 17 == 1.  x can be found using modular inverses.
     *
     * @param GMP $n
     * @return false|GMP
     */
    public function modInverse(GMP $n)
    {
        $temp = new self();
        $temp->value = gmp_invert($this->value, $n->value);

        return $temp->value === false ? false : $this->normalize($temp);
    }

    /**
     * Calculates the greatest common divisor and Bezout's identity.
     *
     * Say you have 693 and 609.  The GCD is 21.  Bezout's identity states that there exist integers x and y such that
     * 693*x + 609*y == 21.  In point of fact, there are actually an infinite number of x and y combinations and which
     * combination is returned is dependent upon which mode is in use.  See
     * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bezout's identity - Wikipedia} for more information.
     *
     * @param GMP $n
     * @return GMP[]
     */
    public function extendedGCD(GMP $n)
    {
        $extended = gmp_gcdext($this->value, $n->value);
        $g = $extended['g'];
        $s = $extended['s'];
        $t = $extended['t'];

        return [
            'gcd' => $this->normalize(new self($g)),
            'x' => $this->normalize(new self($s)),
            'y' => $this->normalize(new self($t))
        ];
    }

    /**
     * Calculates the greatest common divisor
     *
     * Say you have 693 and 609.  The GCD is 21.
     *
     * @param GMP $n
     * @return GMP
     */
    public function gcd(GMP $n)
    {
        $r = gmp_gcd($this->value, $n->value);
        return $this->normalize(new self($r));
    }

    /**
     * Absolute value.
     *
     * @return GMP
     */
    public function abs()
    {
        $temp = new self();
        $temp->value = gmp_abs($this->value);

        return $temp;
    }

    /**
     * Logical And
     *
     * @param GMP $x
     * @return GMP
     */
    public function bitwise_and(GMP $x)
    {
        $temp = new self();
        $temp->value = $this->value & $x->value;

        return $this->normalize($temp);
    }

    /**
     * Logical Or
     *
     * @param GMP $x
     * @return GMP
     */
    public function bitwise_or(GMP $x)
    {
        $temp = new self();
        $temp->value = $this->value | $x->value;

        return $this->normalize($temp);
    }

    /**
     * Logical Exclusive Or
     *
     * @param GMP $x
     * @return GMP
     */
    public function bitwise_xor(GMP $x)
    {
        $temp = new self();
        $temp->value = $this->value ^ $x->value;

        return $this->normalize($temp);
    }

    /**
     * Logical Right Shift
     *
     * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
     *
     * @param int $shift
     * @return GMP
     */
    public function bitwise_rightShift($shift)
    {
        // 0xFFFFFFFF >> 2 == -1 (on 32-bit systems)
        // gmp_init('0xFFFFFFFF') >> 2 == gmp_init('0x3FFFFFFF')

        $temp = new self();
        $temp->value = $this->value >> $shift;

        return $this->normalize($temp);
    }

    /**
     * Logical Left Shift
     *
     * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
     *
     * @param int $shift
     * @return GMP
     */
    public function bitwise_leftShift($shift)
    {
        $temp = new self();
        $temp->value = $this->value << $shift;

        return $this->normalize($temp);
    }

    /**
     * Performs modular exponentiation.
     *
     * @param GMP $e
     * @param GMP $n
     * @return GMP
     */
    public function modPow(GMP $e, GMP $n)
    {
        return $this->powModOuter($e, $n);
    }

    /**
     * Performs modular exponentiation.
     *
     * Alias for modPow().
     *
     * @param GMP $e
     * @param GMP $n
     * @return GMP
     */
    public function powMod(GMP $e, GMP $n)
    {
        return $this->powModOuter($e, $n);
    }

    /**
     * Performs modular exponentiation.
     *
     * @param GMP $e
     * @param GMP $n
     * @return GMP
     */
    protected function powModInner(GMP $e, GMP $n)
    {
        $class = static::$modexpEngine[static::class];
        return $class::powModHelper($this, $e, $n);
    }

    /**
     * Normalize
     *
     * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
     *
     * @param GMP $result
     * @return GMP
     */
    protected function normalize(GMP $result)
    {
        $result->precision = $this->precision;
        $result->bitmask = $this->bitmask;

        if ($result->bitmask !== false) {
            $flip = $result->value < 0;
            if ($flip) {
                $result->value = -$result->value;
            }
            $result->value = $result->value & $result->bitmask->value;
            if ($flip) {
                $result->value = -$result->value;
            }
        }

        return $result;
    }

    /**
     * Performs some post-processing for randomRangePrime
     *
     * @param Engine $x
     * @param Engine $min
     * @param Engine $max
     * @return GMP
     */
    protected static function randomRangePrimeInner(Engine $x, Engine $min, Engine $max)
    {
        $p = gmp_nextprime($x->value);

        if ($p <= $max->value) {
            return new self($p);
        }

        if ($min->value != $x->value) {
            $x = new self($x->value - 1);
        }

        return self::randomRangePrime($min, $x);
    }

    /**
     * Generate a random prime number between a range
     *
     * If there's not a prime within the given range, false will be returned.
     *
     * @param GMP $min
     * @param GMP $max
     * @return false|GMP
     */
    public static function randomRangePrime(GMP $min, GMP $max)
    {
        return self::randomRangePrimeOuter($min, $max);
    }

    /**
     * Generate a random number between a range
     *
     * Returns a random number between $min and $max where $min and $max
     * can be defined using one of the two methods:
     *
     * BigInteger::randomRange($min, $max)
     * BigInteger::randomRange($max, $min)
     *
     * @param GMP $min
     * @param GMP $max
     * @return GMP
     */
    public static function randomRange(GMP $min, GMP $max)
    {
        return self::randomRangeHelper($min, $max);
    }

    /**
     * Make the current number odd
     *
     * If the current number is odd it'll be unchanged.  If it's even, one will be added to it.
     *
     * @see self::randomPrime()
     */
    protected function make_odd()
    {
        gmp_setbit($this->value, 0);
    }

    /**
     * Tests Primality
     *
     * @param int $t
     * @return bool
     */
    protected function testPrimality($t)
    {
        return gmp_prob_prime($this->value, $t) != 0;
    }

    /**
     * Calculates the nth root of a biginteger.
     *
     * Returns the nth root of a positive biginteger, where n defaults to 2
     *
     * @param int $n
     * @return GMP
     */
    protected function rootInner($n)
    {
        $root = new self();
        $root->value = gmp_root($this->value, $n);
        return $this->normalize($root);
    }

    /**
     * Performs exponentiation.
     *
     * @param GMP $n
     * @return GMP
     */
    public function pow(GMP $n)
    {
        $temp = new self();
        $temp->value = $this->value ** $n->value;

        return $this->normalize($temp);
    }

    /**
     * Return the minimum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param GMP ...$nums
     * @return GMP
     */
    public static function min(GMP ...$nums)
    {
        return self::minHelper($nums);
    }

    /**
     * Return the maximum BigInteger between an arbitrary number of BigIntegers.
     *
     * @param GMP ...$nums
     * @return GMP
     */
    public static function max(GMP ...$nums)
    {
        return self::maxHelper($nums);
    }

    /**
     * Tests BigInteger to see if it is between two integers, inclusive
     *
     * @param GMP $min
     * @param GMP $max
     * @return bool
     */
    public function between(GMP $min, GMP $max)
    {
        return $this->compare($min) >= 0 && $this->compare($max) <= 0;
    }

    /**
     * Create Recurring Modulo Function
     *
     * Sometimes it may be desirable to do repeated modulos with the same number outside of
     * modular exponentiation
     *
     * @return callable
     */
    public function createRecurringModuloFunction()
    {
        $temp = $this->value;
        return function (GMP $x) use ($temp) {
            return new GMP($x->value % $temp);
        };
    }

    /**
     * Scan for 1 and right shift by that amount
     *
     * ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
     *
     * @param GMP $r
     * @return int
     */
    public static function scan1divide(GMP $r)
    {
        $s = gmp_scan1($r->value, 0);
        $r->value >>= $s;
        return $s;
    }

    /**
     * Is Odd?
     *
     * @return bool
     */
    public function isOdd()
    {
        return gmp_testbit($this->value, 0);
    }

    /**
     * Tests if a bit is set
     *
     * @return bool
     */
    public function testBit($x)
    {
        return gmp_testbit($this->value, $x);
    }

    /**
     * Is Negative?
     *
     * @return bool
     */
    public function isNegative()
    {
        return gmp_sign($this->value) == -1;
    }

    /**
     * Negate
     *
     * Given $k, returns -$k
     *
     * @return GMP
     */
    public function negate()
    {
        $temp = clone $this;
        $temp->value = -$this->value;

        return $temp;
    }
}
<?php

/**
 * Pure-PHP BigInteger Engine
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Math\BigInteger\Engines;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Exception\BadConfigurationException;

/**
 * Pure-PHP Engine.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PHP extends Engine
{
    /**#@+
     * Array constants
     *
     * Rather than create a thousands and thousands of new BigInteger objects in repeated function calls to add() and
     * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
     *
     */
    /**
     * $result[self::VALUE] contains the value.
     */
    const VALUE = 0;
    /**
     * $result[self::SIGN] contains the sign.
     */
    const SIGN = 1;
    /**#@-*/

    /**
     * Karatsuba Cutoff
     *
     * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
     *
     */
    const KARATSUBA_CUTOFF = 25;

    /**
     * Can Bitwise operations be done fast?
     *
     * @see parent::bitwise_leftRotate()
     * @see parent::bitwise_rightRotate()
     */
    const FAST_BITWISE = true;

    /**
     * Engine Directory
     *
     * @see parent::setModExpEngine
     */
    const ENGINE_DIR = 'PHP';

    /**
     * Default constructor
     *
     * @param mixed $x integer Base-10 number or base-$base number if $base set.
     * @param int $base
     * @return PHP
     * @see parent::__construct()
     */
    public function __construct($x = 0, $base = 10)
    {
        if (!isset(static::$isValidEngine[static::class])) {
            static::$isValidEngine[static::class] = static::isValidEngine();
        }
        if (!static::$isValidEngine[static::class]) {
            throw new BadConfigurationException(static::class . ' is not setup correctly on this system');
        }

        $this->value = [];
        parent::__construct($x, $base);
    }

    /**
     * Initialize a PHP BigInteger Engine instance
     *
     * @param int $base
     * @see parent::__construct()
     */
    protected function initialize($base)
    {
        switch (abs($base)) {
            case 16:
                $x = (strlen($this->value) & 1) ? '0' . $this->value : $this->value;
                $temp = new static(Strings::hex2bin($x), 256);
                $this->value = $temp->value;
                break;
            case 10:
                $temp = new static();

                $multiplier = new static();
                $multiplier->value = [static::MAX10];

                $x = $this->value;

                if ($x[0] == '-') {
                    $this->is_negative = true;
                    $x = substr($x, 1);
                }

                $x = str_pad(
                    $x,
                    strlen($x) + ((static::MAX10LEN - 1) * strlen($x)) % static::MAX10LEN,
                    0,
                    STR_PAD_LEFT
                );
                while (strlen($x)) {
                    $temp = $temp->multiply($multiplier);
                    $temp = $temp->add(new static($this->int2bytes(substr($x, 0, static::MAX10LEN)), 256));
                    $x = substr($x, static::MAX10LEN);
                }

                $this->value = $temp->value;
        }
    }

    /**
     * Pads strings so that unpack may be used on them
     *
     * @param string $str
     * @return string
     */
    protected function pad($str)
    {
        $length = strlen($str);

        $pad = 4 - (strlen($str) % 4);

        return str_pad($str, $length + $pad, "\0", STR_PAD_LEFT);
    }

    /**
     * Converts a BigInteger to a base-10 number.
     *
     * @return string
     */
    public function toString()
    {
        if (!count($this->value)) {
            return '0';
        }

        $temp = clone $this;
        $temp->bitmask = false;
        $temp->is_negative = false;

        $divisor = new static();
        $divisor->value = [static::MAX10];
        $result = '';
        while (count($temp->value)) {
            list($temp, $mod) = $temp->divide($divisor);
            $result = str_pad(
                isset($mod->value[0]) ? $mod->value[0] : '',
                static::MAX10LEN,
                '0',
                STR_PAD_LEFT
            ) . $result;
        }
        $result = ltrim($result, '0');
        if (empty($result)) {
            $result = '0';
        }

        if ($this->is_negative) {
            $result = '-' . $result;
        }

        return $result;
    }

    /**
     * Converts a BigInteger to a byte string (eg. base-256).
     *
     * @param bool $twos_compliment
     * @return string
     */
    public function toBytes($twos_compliment = false)
    {
        if ($twos_compliment) {
            return $this->toBytesHelper();
        }

        if (!count($this->value)) {
            return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
        }

        $result = $this->bitwise_small_split(8);
        $result = implode('', array_map('chr', $result));

        return $this->precision > 0 ?
            str_pad(
                substr($result, -(($this->precision + 7) >> 3)),
                ($this->precision + 7) >> 3,
                chr(0),
                STR_PAD_LEFT
            ) :
            $result;
    }

    /**
     * Performs addition.
     *
     * @param array $x_value
     * @param bool $x_negative
     * @param array $y_value
     * @param bool $y_negative
     * @return array
     */
    protected static function addHelper(array $x_value, $x_negative, array $y_value, $y_negative)
    {
        $x_size = count($x_value);
        $y_size = count($y_value);

        if ($x_size == 0) {
            return [
                self::VALUE => $y_value,
                self::SIGN => $y_negative
            ];
        } elseif ($y_size == 0) {
            return [
                self::VALUE => $x_value,
                self::SIGN => $x_negative
            ];
        }

        // subtract, if appropriate
        if ($x_negative != $y_negative) {
            if ($x_value == $y_value) {
                return [
                    self::VALUE => [],
                    self::SIGN => false
                ];
            }

            $temp = self::subtractHelper($x_value, false, $y_value, false);
            $temp[self::SIGN] = self::compareHelper($x_value, false, $y_value, false) > 0 ?
                $x_negative : $y_negative;

            return $temp;
        }

        if ($x_size < $y_size) {
            $size = $x_size;
            $value = $y_value;
        } else {
            $size = $y_size;
            $value = $x_value;
        }

        $value[count($value)] = 0; // just in case the carry adds an extra digit

        $carry = 0;
        for ($i = 0, $j = 1; $j < $size; $i += 2, $j += 2) {
            //$sum = $x_value[$j] * static::BASE_FULL + $x_value[$i] + $y_value[$j] * static::BASE_FULL + $y_value[$i] + $carry;
            $sum = ($x_value[$j] + $y_value[$j]) * static::BASE_FULL + $x_value[$i] + $y_value[$i] + $carry;
            $carry = $sum >= static::MAX_DIGIT2; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
            $sum = $carry ? $sum - static::MAX_DIGIT2 : $sum;

            $temp = static::BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);

            $value[$i] = (int)($sum - static::BASE_FULL * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
            $value[$j] = $temp;
        }

        if ($j == $size) { // ie. if $y_size is odd
            $sum = $x_value[$i] + $y_value[$i] + $carry;
            $carry = $sum >= static::BASE_FULL;
            $value[$i] = $carry ? $sum - static::BASE_FULL : $sum;
            ++$i; // ie. let $i = $j since we've just done $value[$i]
        }

        if ($carry) {
            for (; $value[$i] == static::MAX_DIGIT; ++$i) {
                $value[$i] = 0;
            }
            ++$value[$i];
        }

        return [
            self::VALUE => self::trim($value),
            self::SIGN => $x_negative
        ];
    }

    /**
     * Performs subtraction.
     *
     * @param array $x_value
     * @param bool $x_negative
     * @param array $y_value
     * @param bool $y_negative
     * @return array
     */
    public static function subtractHelper(array $x_value, $x_negative, array $y_value, $y_negative)
    {
        $x_size = count($x_value);
        $y_size = count($y_value);

        if ($x_size == 0) {
            return [
                self::VALUE => $y_value,
                self::SIGN => !$y_negative
            ];
        } elseif ($y_size == 0) {
            return [
                self::VALUE => $x_value,
                self::SIGN => $x_negative
            ];
        }

        // add, if appropriate (ie. -$x - +$y or +$x - -$y)
        if ($x_negative != $y_negative) {
            $temp = self::addHelper($x_value, false, $y_value, false);
            $temp[self::SIGN] = $x_negative;

            return $temp;
        }

        $diff = self::compareHelper($x_value, $x_negative, $y_value, $y_negative);

        if (!$diff) {
            return [
                self::VALUE => [],
                self::SIGN => false
            ];
        }

        // switch $x and $y around, if appropriate.
        if ((!$x_negative && $diff < 0) || ($x_negative && $diff > 0)) {
            $temp = $x_value;
            $x_value = $y_value;
            $y_value = $temp;

            $x_negative = !$x_negative;

            $x_size = count($x_value);
            $y_size = count($y_value);
        }

        // at this point, $x_value should be at least as big as - if not bigger than - $y_value

        $carry = 0;
        for ($i = 0, $j = 1; $j < $y_size; $i += 2, $j += 2) {
            $sum = ($x_value[$j] - $y_value[$j]) * static::BASE_FULL + $x_value[$i] - $y_value[$i] - $carry;

            $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
            $sum = $carry ? $sum + static::MAX_DIGIT2 : $sum;

            $temp = static::BASE === 26 ? intval($sum / 0x4000000) : ($sum >> 31);

            $x_value[$i] = (int)($sum - static::BASE_FULL * $temp);
            $x_value[$j] = $temp;
        }

        if ($j == $y_size) { // ie. if $y_size is odd
            $sum = $x_value[$i] - $y_value[$i] - $carry;
            $carry = $sum < 0;
            $x_value[$i] = $carry ? $sum + static::BASE_FULL : $sum;
            ++$i;
        }

        if ($carry) {
            for (; !$x_value[$i]; ++$i) {
                $x_value[$i] = static::MAX_DIGIT;
            }
            --$x_value[$i];
        }

        return [
            self::VALUE => self::trim($x_value),
            self::SIGN => $x_negative
        ];
    }

    /**
     * Performs multiplication.
     *
     * @param array $x_value
     * @param bool $x_negative
     * @param array $y_value
     * @param bool $y_negative
     * @return array
     */
    protected static function multiplyHelper(array $x_value, $x_negative, array $y_value, $y_negative)
    {
        //if ( $x_value == $y_value ) {
        //    return [
        //        self::VALUE => self::square($x_value),
        //        self::SIGN => $x_sign != $y_value
        //    ];
        //}

        $x_length = count($x_value);
        $y_length = count($y_value);

        if (!$x_length || !$y_length) { // a 0 is being multiplied
            return [
                self::VALUE => [],
                self::SIGN => false
            ];
        }

        return [
            self::VALUE => min($x_length, $y_length) < 2 * self::KARATSUBA_CUTOFF ?
                self::trim(self::regularMultiply($x_value, $y_value)) :
                self::trim(self::karatsuba($x_value, $y_value)),
            self::SIGN => $x_negative != $y_negative
        ];
    }

    /**
     * Performs Karatsuba multiplication on two BigIntegers
     *
     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
     *
     * @param array $x_value
     * @param array $y_value
     * @return array
     */
    private static function karatsuba(array $x_value, array $y_value)
    {
        $m = min(count($x_value) >> 1, count($y_value) >> 1);

        if ($m < self::KARATSUBA_CUTOFF) {
            return self::regularMultiply($x_value, $y_value);
        }

        $x1 = array_slice($x_value, $m);
        $x0 = array_slice($x_value, 0, $m);
        $y1 = array_slice($y_value, $m);
        $y0 = array_slice($y_value, 0, $m);

        $z2 = self::karatsuba($x1, $y1);
        $z0 = self::karatsuba($x0, $y0);

        $z1 = self::addHelper($x1, false, $x0, false);
        $temp = self::addHelper($y1, false, $y0, false);
        $z1 = self::karatsuba($z1[self::VALUE], $temp[self::VALUE]);
        $temp = self::addHelper($z2, false, $z0, false);
        $z1 = self::subtractHelper($z1, false, $temp[self::VALUE], false);

        $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
        $z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]);

        $xy = self::addHelper($z2, false, $z1[self::VALUE], $z1[self::SIGN]);
        $xy = self::addHelper($xy[self::VALUE], $xy[self::SIGN], $z0, false);

        return $xy[self::VALUE];
    }

    /**
     * Performs long multiplication on two BigIntegers
     *
     * Modeled after 'multiply' in MutableBigInteger.java.
     *
     * @param array $x_value
     * @param array $y_value
     * @return array
     */
    protected static function regularMultiply(array $x_value, array $y_value)
    {
        $x_length = count($x_value);
        $y_length = count($y_value);

        if (!$x_length || !$y_length) { // a 0 is being multiplied
            return [];
        }

        $product_value = self::array_repeat(0, $x_length + $y_length);

        // the following for loop could be removed if the for loop following it
        // (the one with nested for loops) initially set $i to 0, but
        // doing so would also make the result in one set of unnecessary adds,
        // since on the outermost loops first pass, $product->value[$k] is going
        // to always be 0

        $carry = 0;
        for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
            $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
            $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
            $product_value[$j] = (int)($temp - static::BASE_FULL * $carry);
        }

        $product_value[$j] = $carry;

        // the above for loop is what the previous comment was talking about.  the
        // following for loop is the "one with nested for loops"
        for ($i = 1; $i < $y_length; ++$i) {
            $carry = 0;

            for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
                $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
                $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
                $product_value[$k] = (int)($temp - static::BASE_FULL * $carry);
            }

            $product_value[$k] = $carry;
        }

        return $product_value;
    }

    /**
     * Divides two BigIntegers.
     *
     * Returns an array whose first element contains the quotient and whose second element contains the
     * "common residue".  If the remainder would be positive, the "common residue" and the remainder are the
     * same.  If the remainder would be negative, the "common residue" is equal to the sum of the remainder
     * and the divisor (basically, the "common residue" is the first positive modulo).
     *
     * @return array{static, static}
     * @internal This function is based off of
     *     {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
     */
    protected function divideHelper(PHP $y)
    {
        if (count($y->value) == 1) {
            list($q, $r) = $this->divide_digit($this->value, $y->value[0]);
            $quotient = new static();
            $remainder = new static();
            $quotient->value = $q;
            if ($this->is_negative) {
                $r = $y->value[0] - $r;
            }
            $remainder->value = [$r];
            $quotient->is_negative = $this->is_negative != $y->is_negative;
            return [$this->normalize($quotient), $this->normalize($remainder)];
        }

        $x = clone $this;
        $y = clone $y;

        $x_sign = $x->is_negative;
        $y_sign = $y->is_negative;

        $x->is_negative = $y->is_negative = false;

        $diff = $x->compare($y);

        if (!$diff) {
            $temp = new static();
            $temp->value = [1];
            $temp->is_negative = $x_sign != $y_sign;
            return [$this->normalize($temp), $this->normalize(static::$zero[static::class])];
        }

        if ($diff < 0) {
            // if $x is negative, "add" $y.
            if ($x_sign) {
                $x = $y->subtract($x);
            }
            return [$this->normalize(static::$zero[static::class]), $this->normalize($x)];
        }

        // normalize $x and $y as described in HAC 14.23 / 14.24
        $msb = $y->value[count($y->value) - 1];
        for ($shift = 0; !($msb & static::MSB); ++$shift) {
            $msb <<= 1;
        }
        $x->lshift($shift);
        $y->lshift($shift);
        $y_value = &$y->value;

        $x_max = count($x->value) - 1;
        $y_max = count($y->value) - 1;

        $quotient = new static();
        $quotient_value = &$quotient->value;
        $quotient_value = self::array_repeat(0, $x_max - $y_max + 1);

        static $temp, $lhs, $rhs;
        if (!isset($temp)) {
            $temp = new static();
            $lhs = new static();
            $rhs = new static();
        }
        if (static::class != get_class($temp)) {
            $temp = new static();
            $lhs = new static();
            $rhs = new static();
        }
        $temp_value = &$temp->value;
        $rhs_value =  &$rhs->value;

        // $temp = $y << ($x_max - $y_max-1) in base 2**26
        $temp_value = array_merge(self::array_repeat(0, $x_max - $y_max), $y_value);

        while ($x->compare($temp) >= 0) {
            // calculate the "common residue"
            ++$quotient_value[$x_max - $y_max];
            $x = $x->subtract($temp);
            $x_max = count($x->value) - 1;
        }

        for ($i = $x_max; $i >= $y_max + 1; --$i) {
            $x_value = &$x->value;
            $x_window = [
                isset($x_value[$i]) ? $x_value[$i] : 0,
                isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
                isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
            ];
            $y_window = [
                $y_value[$y_max],
                ($y_max > 0) ? $y_value[$y_max - 1] : 0
            ];

            $q_index = $i - $y_max - 1;
            if ($x_window[0] == $y_window[0]) {
                $quotient_value[$q_index] = static::MAX_DIGIT;
            } else {
                $quotient_value[$q_index] = self::safe_divide(
                    $x_window[0] * static::BASE_FULL + $x_window[1],
                    $y_window[0]
                );
            }

            $temp_value = [$y_window[1], $y_window[0]];

            $lhs->value = [$quotient_value[$q_index]];
            $lhs = $lhs->multiply($temp);

            $rhs_value = [$x_window[2], $x_window[1], $x_window[0]];

            while ($lhs->compare($rhs) > 0) {
                --$quotient_value[$q_index];

                $lhs->value = [$quotient_value[$q_index]];
                $lhs = $lhs->multiply($temp);
            }

            $adjust = self::array_repeat(0, $q_index);
            $temp_value = [$quotient_value[$q_index]];
            $temp = $temp->multiply($y);
            $temp_value = &$temp->value;
            if (count($temp_value)) {
                $temp_value = array_merge($adjust, $temp_value);
            }

            $x = $x->subtract($temp);

            if ($x->compare(static::$zero[static::class]) < 0) {
                $temp_value = array_merge($adjust, $y_value);
                $x = $x->add($temp);

                --$quotient_value[$q_index];
            }

            $x_max = count($x_value) - 1;
        }

        // unnormalize the remainder
        $x->rshift($shift);

        $quotient->is_negative = $x_sign != $y_sign;

        // calculate the "common residue", if appropriate
        if ($x_sign) {
            $y->rshift($shift);
            $x = $y->subtract($x);
        }

        return [$this->normalize($quotient), $this->normalize($x)];
    }

    /**
     * Divides a BigInteger by a regular integer
     *
     * abc / x = a00 / x + b0 / x + c / x
     *
     * @param array $dividend
     * @param int $divisor
     * @return array
     */
    private static function divide_digit(array $dividend, $divisor)
    {
        $carry = 0;
        $result = [];

        for ($i = count($dividend) - 1; $i >= 0; --$i) {
            $temp = static::BASE_FULL * $carry + $dividend[$i];
            $result[$i] = self::safe_divide($temp, $divisor);
            $carry = (int)($temp - $divisor * $result[$i]);
        }

        return [$result, $carry];
    }

    /**
     * Single digit division
     *
     * Even if int64 is being used the division operator will return a float64 value
     * if the dividend is not evenly divisible by the divisor. Since a float64 doesn't
     * have the precision of int64 this is a problem so, when int64 is being used,
     * we'll guarantee that the dividend is divisible by first subtracting the remainder.
     *
     * @param int $x
     * @param int $y
     * @return int
     */
    private static function safe_divide($x, $y)
    {
        if (static::BASE === 26) {
            return (int)($x / $y);
        }

        // static::BASE === 31
        /** @var int */
        return ($x - ($x % $y)) / $y;
    }

    /**
     * Convert an array / boolean to a PHP BigInteger object
     *
     * @param array $arr
     * @return static
     */
    protected function convertToObj(array $arr)
    {
        $result = new static();
        $result->value = $arr[self::VALUE];
        $result->is_negative = $arr[self::SIGN];

        return $this->normalize($result);
    }

    /**
     * Normalize
     *
     * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
     *
     * @param PHP $result
     * @return static
     */
    protected function normalize(PHP $result)
    {
        $result->precision = $this->precision;
        $result->bitmask = $this->bitmask;

        $value = &$result->value;

        if (!count($value)) {
            $result->is_negative = false;
            return $result;
        }

        $value = static::trim($value);

        if (!empty($result->bitmask->value)) {
            $length = min(count($value), count($result->bitmask->value));
            $value = array_slice($value, 0, $length);

            for ($i = 0; $i < $length; ++$i) {
                $value[$i] = $value[$i] & $result->bitmask->value[$i];
            }

            $value = static::trim($value);
        }

        return $result;
    }

    /**
     * Compares two numbers.
     *
     * @param array $x_value
     * @param bool $x_negative
     * @param array $y_value
     * @param bool $y_negative
     * @return int
     * @see static::compare()
     */
    protected static function compareHelper(array $x_value, $x_negative, array $y_value, $y_negative)
    {
        if ($x_negative != $y_negative) {
            return (!$x_negative && $y_negative) ? 1 : -1;
        }

        $result = $x_negative ? -1 : 1;

        if (count($x_value) != count($y_value)) {
            return (count($x_value) > count($y_value)) ? $result : -$result;
        }
        $size = max(count($x_value), count($y_value));

        $x_value = array_pad($x_value, $size, 0);
        $y_value = array_pad($y_value, $size, 0);

        for ($i = count($x_value) - 1; $i >= 0; --$i) {
            if ($x_value[$i] != $y_value[$i]) {
                return ($x_value[$i] > $y_value[$i]) ? $result : -$result;
            }
        }

        return 0;
    }

    /**
     * Absolute value.
     *
     * @return PHP
     */
    public function abs()
    {
        $temp = new static();
        $temp->value = $this->value;

        return $temp;
    }

    /**
     * Trim
     *
     * Removes leading zeros
     *
     * @param list<static> $value
     * @return list<static>
     */
    protected static function trim(array $value)
    {
        for ($i = count($value) - 1; $i >= 0; --$i) {
            if ($value[$i]) {
                break;
            }
            unset($value[$i]);
        }

        return $value;
    }

    /**
     * Logical Right Shift
     *
     * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
     *
     * @param int $shift
     * @return PHP
     */
    public function bitwise_rightShift($shift)
    {
        $temp = new static();

        // could just replace lshift with this, but then all lshift() calls would need to be rewritten
        // and I don't want to do that...
        $temp->value = $this->value;
        $temp->rshift($shift);

        return $this->normalize($temp);
    }

    /**
     * Logical Left Shift
     *
     * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
     *
     * @param int $shift
     * @return PHP
     */
    public function bitwise_leftShift($shift)
    {
        $temp = new static();
        // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
        // and I don't want to do that...
        $temp->value = $this->value;
        $temp->lshift($shift);

        return $this->normalize($temp);
    }

    /**
     * Converts 32-bit integers to bytes.
     *
     * @param int $x
     * @return string
     */
    private static function int2bytes($x)
    {
        return ltrim(pack('N', $x), chr(0));
    }

    /**
     * Array Repeat
     *
     * @param int $input
     * @param int $multiplier
     * @return array
     */
    protected static function array_repeat($input, $multiplier)
    {
        return $multiplier ? array_fill(0, $multiplier, $input) : [];
    }

    /**
     * Logical Left Shift
     *
     * Shifts BigInteger's by $shift bits.
     *
     * @param int $shift
     */
    protected function lshift($shift)
    {
        if ($shift == 0) {
            return;
        }

        $num_digits = (int)($shift / static::BASE);
        $shift %= static::BASE;
        $shift = 1 << $shift;

        $carry = 0;

        for ($i = 0; $i < count($this->value); ++$i) {
            $temp = $this->value[$i] * $shift + $carry;
            $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
            $this->value[$i] = (int)($temp - $carry * static::BASE_FULL);
        }

        if ($carry) {
            $this->value[count($this->value)] = $carry;
        }

        while ($num_digits--) {
            array_unshift($this->value, 0);
        }
    }

    /**
     * Logical Right Shift
     *
     * Shifts BigInteger's by $shift bits.
     *
     * @param int $shift
     */
    protected function rshift($shift)
    {
        if ($shift == 0) {
            return;
        }

        $num_digits = (int)($shift / static::BASE);
        $shift %= static::BASE;
        $carry_shift = static::BASE - $shift;
        $carry_mask = (1 << $shift) - 1;

        if ($num_digits) {
            $this->value = array_slice($this->value, $num_digits);
        }

        $carry = 0;

        for ($i = count($this->value) - 1; $i >= 0; --$i) {
            $temp = $this->value[$i] >> $shift | $carry;
            $carry = ($this->value[$i] & $carry_mask) << $carry_shift;
            $this->value[$i] = $temp;
        }

        $this->value = static::trim($this->value);
    }

    /**
     * Performs modular exponentiation.
     *
     * @param PHP $e
     * @param PHP $n
     * @return PHP
     */
    protected function powModInner(PHP $e, PHP $n)
    {
        try {
            $class = static::$modexpEngine[static::class];
            return $class::powModHelper($this, $e, $n, static::class);
        } catch (\Exception $err) {
            return PHP\DefaultEngine::powModHelper($this, $e, $n, static::class);
        }
    }

    /**
     * Performs squaring
     *
     * @param list<static> $x
     * @return list<static>
     */
    protected static function square(array $x)
    {
        return count($x) < 2 * self::KARATSUBA_CUTOFF ?
            self::trim(self::baseSquare($x)) :
            self::trim(self::karatsubaSquare($x));
    }

    /**
     * Performs traditional squaring on two BigIntegers
     *
     * Squaring can be done faster than multiplying a number by itself can be.  See
     * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
     *
     * @param array $value
     * @return array
     */
    protected static function baseSquare(array $value)
    {
        if (empty($value)) {
            return [];
        }
        $square_value = self::array_repeat(0, 2 * count($value));

        for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
            $i2 = $i << 1;

            $temp = $square_value[$i2] + $value[$i] * $value[$i];
            $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
            $square_value[$i2] = (int)($temp - static::BASE_FULL * $carry);

            // note how we start from $i+1 instead of 0 as we do in multiplication.
            for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
                $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
                $carry = static::BASE === 26 ? intval($temp / 0x4000000) : ($temp >> 31);
                $square_value[$k] = (int)($temp - static::BASE_FULL * $carry);
            }

            // the following line can yield values larger 2**15.  at this point, PHP should switch
            // over to floats.
            $square_value[$i + $max_index + 1] = $carry;
        }

        return $square_value;
    }

    /**
     * Performs Karatsuba "squaring" on two BigIntegers
     *
     * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
     * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
     *
     * @param array $value
     * @return array
     */
    protected static function karatsubaSquare(array $value)
    {
        $m = count($value) >> 1;

        if ($m < self::KARATSUBA_CUTOFF) {
            return self::baseSquare($value);
        }

        $x1 = array_slice($value, $m);
        $x0 = array_slice($value, 0, $m);

        $z2 = self::karatsubaSquare($x1);
        $z0 = self::karatsubaSquare($x0);

        $z1 = self::addHelper($x1, false, $x0, false);
        $z1 = self::karatsubaSquare($z1[self::VALUE]);
        $temp = self::addHelper($z2, false, $z0, false);
        $z1 = self::subtractHelper($z1, false, $temp[self::VALUE], false);

        $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
        $z1[self::VALUE] = array_merge(array_fill(0, $m, 0), $z1[self::VALUE]);

        $xx = self::addHelper($z2, false, $z1[self::VALUE], $z1[self::SIGN]);
        $xx = self::addHelper($xx[self::VALUE], $xx[self::SIGN], $z0, false);

        return $xx[self::VALUE];
    }

    /**
     * Make the current number odd
     *
     * If the current number is odd it'll be unchanged.  If it's even, one will be added to it.
     *
     * @see self::randomPrime()
     */
    protected function make_odd()
    {
        $this->value[0] |= 1;
    }

    /**
     * Test the number against small primes.
     *
     * @see self::isPrime()
     */
    protected function testSmallPrimes()
    {
        if ($this->value == [1]) {
            return false;
        }
        if ($this->value == [2]) {
            return true;
        }
        if (~$this->value[0] & 1) {
            return false;
        }

        $value = $this->value;
        foreach (static::PRIMES as $prime) {
            list(, $r) = self::divide_digit($value, $prime);
            if (!$r) {
                return count($value) == 1 && $value[0] == $prime;
            }
        }

        return true;
    }

    /**
     * Scan for 1 and right shift by that amount
     *
     * ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
     *
     * @param PHP $r
     * @return int
     * @see self::isPrime()
     */
    public static function scan1divide(PHP $r)
    {
        $r_value = &$r->value;
        for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
            $temp = ~$r_value[$i] & static::MAX_DIGIT;
            for ($j = 1; ($temp >> $j) & 1; ++$j) {
            }
            if ($j <= static::BASE) {
                break;
            }
        }
        $s = static::BASE * $i + $j;
        $r->rshift($s);
        return $s;
    }

    /**
     * Performs exponentiation.
     *
     * @param PHP $n
     * @return PHP
     */
    protected function powHelper(PHP $n)
    {
        if ($n->compare(static::$zero[static::class]) == 0) {
            return new static(1);
        } // n^0 = 1

        $temp = clone $this;
        while (!$n->equals(static::$one[static::class])) {
            $temp = $temp->multiply($this);
            $n = $n->subtract(static::$one[static::class]);
        }

        return $temp;
    }

    /**
     * Is Odd?
     *
     * @return bool
     */
    public function isOdd()
    {
        return (bool)($this->value[0] & 1);
    }

    /**
     * Tests if a bit is set
     *
     * @return bool
     */
    public function testBit($x)
    {
        $digit = (int) floor($x / static::BASE);
        $bit = $x % static::BASE;

        if (!isset($this->value[$digit])) {
            return false;
        }

        return (bool)($this->value[$digit] & (1 << $bit));
    }

    /**
     * Is Negative?
     *
     * @return bool
     */
    public function isNegative()
    {
        return $this->is_negative;
    }

    /**
     * Negate
     *
     * Given $k, returns -$k
     *
     * @return static
     */
    public function negate()
    {
        $temp = clone $this;
        $temp->is_negative = !$temp->is_negative;

        return $temp;
    }

    /**
     * Bitwise Split
     *
     * Splits BigInteger's into chunks of $split bits
     *
     * @param int $split
     * @return list<static>
     */
    public function bitwise_split($split)
    {
        if ($split < 1) {
            throw new \RuntimeException('Offset must be greater than 1');
        }

        $width = (int)($split / static::BASE);
        if (!$width) {
            $arr = $this->bitwise_small_split($split);
            return array_map(function ($digit) {
                $temp = new static();
                $temp->value = $digit != 0 ? [$digit] : [];
                return $temp;
            }, $arr);
        }

        $vals = [];
        $val = $this->value;

        $i = $overflow = 0;
        $len = count($val);
        while ($i < $len) {
            $digit = [];
            if (!$overflow) {
                $digit = array_slice($val, $i, $width);
                $i += $width;
                $overflow = $split % static::BASE;
                if ($overflow) {
                    $mask = (1 << $overflow) - 1;
                    $temp = isset($val[$i]) ? $val[$i] : 0;
                    $digit[] = $temp & $mask;
                }
            } else {
                $remaining = static::BASE - $overflow;
                $tempsplit = $split - $remaining;
                $tempwidth = (int)($tempsplit / static::BASE + 1);
                $digit = array_slice($val, $i, $tempwidth);
                $i += $tempwidth;
                $tempoverflow = $tempsplit % static::BASE;
                if ($tempoverflow) {
                    $tempmask = (1 << $tempoverflow) - 1;
                    $temp = isset($val[$i]) ? $val[$i] : 0;
                    $digit[] = $temp & $tempmask;
                }
                $newbits = 0;
                for ($j = count($digit) - 1; $j >= 0; $j--) {
                    $temp = $digit[$j] & $mask;
                    $digit[$j] = ($digit[$j] >> $overflow) | ($newbits << $remaining);
                    $newbits = $temp;
                }
                $overflow = $tempoverflow;
                $mask = $tempmask;
            }
            $temp = new static();
            $temp->value = static::trim($digit);
            $vals[] = $temp;
        }

        return array_reverse($vals);
    }

    /**
     * Bitwise Split where $split < static::BASE
     *
     * @param int $split
     * @return list<int>
     */
    private function bitwise_small_split($split)
    {
        $vals = [];
        $val = $this->value;

        $mask = (1 << $split) - 1;

        $i = $overflow = 0;
        $len = count($val);
        $val[] = 0;
        $remaining = static::BASE;
        while ($i != $len) {
            $digit = $val[$i] & $mask;
            $val[$i] >>= $split;
            if (!$overflow) {
                $remaining -= $split;
                $overflow = $split <= $remaining ? 0 : $split - $remaining;

                if (!$remaining) {
                    $i++;
                    $remaining = static::BASE;
                    $overflow = 0;
                }
            } elseif (++$i != $len) {
                $tempmask = (1 << $overflow) - 1;
                $digit |= ($val[$i] & $tempmask) << $remaining;
                $val[$i] >>= $overflow;
                $remaining = static::BASE - $overflow;
                $overflow = $split <= $remaining ? 0 : $split - $remaining;
            }

            $vals[] = $digit;
        }

        while ($vals[count($vals) - 1] == 0) {
            unset($vals[count($vals) - 1]);
        }

        return array_reverse($vals);
    }

    /**
     * @return bool
     */
    protected static function testJITOnWindows()
    {
        // see https://github.com/php/php-src/issues/11917
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && function_exists('opcache_get_status') && PHP_VERSION_ID < 80213 && !defined('PHPSECLIB_ALLOW_JIT')) {
            $status = opcache_get_status();
            if ($status && isset($status['jit']) && $status['jit']['enabled'] && $status['jit']['on']) {
                return true;
            }
        }
        return false;
    }

    /**
     * Return the size of a BigInteger in bits
     *
     * @return int
     */
    public function getLength()
    {
        $max = count($this->value) - 1;
        return $max != -1 ?
            $max * static::BASE + intval(ceil(log($this->value[$max] + 1, 2))) :
            0;
    }
}
<?php

/**
 * Prime Finite Fields
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 */

namespace phpseclib3\Math\PrimeField;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Math\BigInteger;
use phpseclib3\Math\Common\FiniteField\Integer as Base;

/**
 * Prime Finite Fields
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Integer extends Base
{
    /**
     * Holds the PrimeField's value
     *
     * @var BigInteger
     */
    protected $value;

    /**
     * Keeps track of current instance
     *
     * @var int
     */
    protected $instanceID;

    /**
     * Holds the PrimeField's modulo
     *
     * @var array<int, BigInteger>
     */
    protected static $modulo;

    /**
     * Holds a pre-generated function to perform modulo reductions
     *
     * @var array<int, callable(BigInteger):BigInteger>
     */
    protected static $reduce;

    /**
     * Zero
     *
     * @var BigInteger[]
     */
    protected static $zero;

    /**
     * One
     *
     * @var BigInteger[]
     */
    protected static $one;

    /**
     * Two
     *
     * @var BigInteger[]
     */
    protected static $two;

    /**
     * Default constructor
     *
     * @param int $instanceID
     * @param BigInteger $num
     */
    public function __construct($instanceID, $num = null)
    {
        $this->instanceID = $instanceID;
        if (!isset($num)) {
            $this->value = clone static::$zero[$instanceID];
        } else {
            $reduce = static::$reduce[$instanceID];
            $this->value = $reduce($num);
        }
    }

    /**
     * Set the modulo for a given instance
     *
     * @param int $instanceID
     * @return void
     */
    public static function setModulo($instanceID, BigInteger $modulo)
    {
        static::$modulo[$instanceID] = $modulo;
    }

    /**
     * Set the modulo for a given instance
     *
     * @param int $instanceID
     * @return void
     */
    public static function setRecurringModuloFunction($instanceID, callable $function)
    {
        static::$reduce[$instanceID] = $function;
        if (!isset(static::$zero[$instanceID])) {
            static::$zero[$instanceID] = new BigInteger();
        }
    }

    /**
     * Delete the modulo for a given instance
     */
    public static function cleanupCache($instanceID)
    {
        unset(static::$modulo[$instanceID]);
        unset(static::$reduce[$instanceID]);
        unset(static::$zero[$instanceID]);
        unset(static::$one[$instanceID]);
        unset(static::$two[$instanceID]);
    }

    /**
     * Returns the modulo
     *
     * @param int $instanceID
     * @return BigInteger
     */
    public static function getModulo($instanceID)
    {
        return static::$modulo[$instanceID];
    }

    /**
     * Tests a parameter to see if it's of the right instance
     *
     * Throws an exception if the incorrect class is being utilized
     *
     * @return void
     */
    public static function checkInstance(self $x, self $y)
    {
        if ($x->instanceID != $y->instanceID) {
            throw new \UnexpectedValueException('The instances of the two PrimeField\Integer objects do not match');
        }
    }

    /**
     * Tests the equality of two numbers.
     *
     * @return bool
     */
    public function equals(self $x)
    {
        static::checkInstance($this, $x);

        return $this->value->equals($x->value);
    }

    /**
     * Compares two numbers.
     *
     * @return int
     */
    public function compare(self $x)
    {
        static::checkInstance($this, $x);

        return $this->value->compare($x->value);
    }

    /**
     * Adds two PrimeFieldIntegers.
     *
     * @return static
     */
    public function add(self $x)
    {
        static::checkInstance($this, $x);

        $temp = new static($this->instanceID);
        $temp->value = $this->value->add($x->value);
        if ($temp->value->compare(static::$modulo[$this->instanceID]) >= 0) {
            $temp->value = $temp->value->subtract(static::$modulo[$this->instanceID]);
        }

        return $temp;
    }

    /**
     * Subtracts two PrimeFieldIntegers.
     *
     * @return static
     */
    public function subtract(self $x)
    {
        static::checkInstance($this, $x);

        $temp = new static($this->instanceID);
        $temp->value = $this->value->subtract($x->value);
        if ($temp->value->isNegative()) {
            $temp->value = $temp->value->add(static::$modulo[$this->instanceID]);
        }

        return $temp;
    }

    /**
     * Multiplies two PrimeFieldIntegers.
     *
     * @return static
     */
    public function multiply(self $x)
    {
        static::checkInstance($this, $x);

        return new static($this->instanceID, $this->value->multiply($x->value));
    }

    /**
     * Divides two PrimeFieldIntegers.
     *
     * @return static
     */
    public function divide(self $x)
    {
        static::checkInstance($this, $x);

        $denominator = $x->value->modInverse(static::$modulo[$this->instanceID]);
        return new static($this->instanceID, $this->value->multiply($denominator));
    }

    /**
     * Performs power operation on a PrimeFieldInteger.
     *
     * @return static
     */
    public function pow(BigInteger $x)
    {
        $temp = new static($this->instanceID);
        $temp->value = $this->value->powMod($x, static::$modulo[$this->instanceID]);

        return $temp;
    }

    /**
     * Calculates the square root
     *
     * @link https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm
     * @return static|false
     */
    public function squareRoot()
    {
        if (!isset(static::$one[$this->instanceID])) {
            static::$one[$this->instanceID] = new BigInteger(1);
            static::$two[$this->instanceID] = new BigInteger(2);
        }
        $one = &static::$one[$this->instanceID];
        $two = &static::$two[$this->instanceID];
        $modulo = &static::$modulo[$this->instanceID];
        $reduce = &static::$reduce[$this->instanceID];

        $p_1 = $modulo->subtract($one);
        $q = clone $p_1;
        $s = BigInteger::scan1divide($q);
        list($pow) = $p_1->divide($two);
        for ($z = $one; !$z->equals($modulo); $z = $z->add($one)) {
            $temp = $z->powMod($pow, $modulo);
            if ($temp->equals($p_1)) {
                break;
            }
        }

        $m = new BigInteger($s);
        $c = $z->powMod($q, $modulo);
        $t = $this->value->powMod($q, $modulo);
        list($temp) = $q->add($one)->divide($two);
        $r = $this->value->powMod($temp, $modulo);

        while (!$t->equals($one)) {
            for ($i = clone $one; $i->compare($m) < 0; $i = $i->add($one)) {
                if ($t->powMod($two->pow($i), $modulo)->equals($one)) {
                    break;
                }
            }

            if ($i->compare($m) == 0) {
                return false;
            }
            $b = $c->powMod($two->pow($m->subtract($i)->subtract($one)), $modulo);
            $m = $i;
            $c = $reduce($b->multiply($b));
            $t = $reduce($t->multiply($c));
            $r = $reduce($r->multiply($b));
        }

        return new static($this->instanceID, $r);
    }

    /**
     * Is Odd?
     *
     * @return bool
     */
    public function isOdd()
    {
        return $this->value->isOdd();
    }

    /**
     * Negate
     *
     * A negative number can be written as 0-12. With modulos, 0 is the same thing as the modulo
     * so 0-12 is the same thing as modulo-12
     *
     * @return static
     */
    public function negate()
    {
        return new static($this->instanceID, static::$modulo[$this->instanceID]->subtract($this->value));
    }

    /**
     * Converts an Integer to a byte string (eg. base-256).
     *
     * @return string
     */
    public function toBytes()
    {
        if (isset(static::$modulo[$this->instanceID])) {
            $length = static::$modulo[$this->instanceID]->getLengthInBytes();
            return str_pad($this->value->toBytes(), $length, "\0", STR_PAD_LEFT);
        }
        return $this->value->toBytes();
    }

    /**
     * Converts an Integer to a hex string (eg. base-16).
     *
     * @return string
     */
    public function toHex()
    {
        return Strings::bin2hex($this->toBytes());
    }

    /**
     * Converts an Integer to a bit string (eg. base-2).
     *
     * @return string
     */
    public function toBits()
    {
        // return $this->value->toBits();
        static $length;
        if (!isset($length)) {
            $length = static::$modulo[$this->instanceID]->getLength();
        }

        return str_pad($this->value->toBits(), $length, '0', STR_PAD_LEFT);
    }

    /**
     * Returns the w-ary non-adjacent form (wNAF)
     *
     * @param int $w optional
     * @return array<int, int>
     */
    public function getNAF($w = 1)
    {
        $w++;

        $zero = &static::$zero[$this->instanceID];

        $mask = new BigInteger((1 << $w) - 1);
        $sub = new BigInteger(1 << $w);
        //$sub = new BigInteger(1 << ($w - 1));
        $d = $this->toBigInteger();
        $d_i = [];

        $i = 0;
        while ($d->compare($zero) > 0) {
            if ($d->isOdd()) {
                // start mods

                $bigInteger = $d->testBit($w - 1) ?
                    $d->bitwise_and($mask)->subtract($sub) :
                    //$sub->subtract($d->bitwise_and($mask)) :
                    $d->bitwise_and($mask);
                // end mods
                $d = $d->subtract($bigInteger);
                $d_i[$i] = (int) $bigInteger->toString();
            } else {
                $d_i[$i] = 0;
            }
            $shift = !$d->equals($zero) && $d->bitwise_and($mask)->equals($zero) ? $w : 1; // $w or $w + 1?
            $d = $d->bitwise_rightShift($shift);
            while (--$shift > 0) {
                $d_i[++$i] = 0;
            }
            $i++;
        }

        return $d_i;
    }

    /**
     * Converts an Integer to a BigInteger
     *
     * @return BigInteger
     */
    public function toBigInteger()
    {
        return clone $this->value;
    }

    /**
     *  __toString() magic method
     *
     * @return string
     */
    public function __toString()
    {
        return (string) $this->value;
    }

    /**
     *  __debugInfo() magic method
     *
     * @return array
     */
    public function __debugInfo()
    {
        return ['value' => $this->toHex()];
    }
}
<?php

/**
 * Binary Finite Fields
 *
 * Utilizes the factory design pattern
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 */

namespace phpseclib3\Math;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Math\BinaryField\Integer;
use phpseclib3\Math\Common\FiniteField;

/**
 * Binary Finite Fields
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class BinaryField extends FiniteField
{
    /**
     * Instance Counter
     *
     * @var int
     */
    private static $instanceCounter = 0;

    /**
     * Keeps track of current instance
     *
     * @var int
     */
    protected $instanceID;

    /** @var BigInteger */
    private $randomMax;

    /**
     * Default constructor
     */
    public function __construct(...$indices)
    {
        $m = array_shift($indices);
        if ($m > 571) {
            /* sect571r1 and sect571k1 are the largest binary curves that https://www.secg.org/sec2-v2.pdf defines
               altho theoretically there may be legit reasons to use binary finite fields with larger degrees
               imposing a limit on the maximum size is both reasonable and precedented. in particular,
               http://tools.ietf.org/html/rfc4253#section-6.1 (The Secure Shell (SSH) Transport Layer Protocol) says
               "implementations SHOULD check that the packet length is reasonable in order for the implementation to
                avoid denial of service and/or buffer overflow attacks" */
            throw new \OutOfBoundsException('Degrees larger than 571 are not supported');
        }
        $val = str_repeat('0', $m) . '1';
        foreach ($indices as $index) {
            $val[$index] = '1';
        }
        $modulo = static::base2ToBase256(strrev($val));

        $mStart = 2 * $m - 2;
        $t = ceil($m / 8);
        $finalMask = chr((1 << ($m % 8)) - 1);
        if ($finalMask == "\0") {
            $finalMask = "\xFF";
        }
        $bitLen = $mStart + 1;
        $pad = ceil($bitLen / 8);
        $h = $bitLen & 7;
        $h = $h ? 8 - $h : 0;

        $r = rtrim(substr($val, 0, -1), '0');
        $u = [static::base2ToBase256(strrev($r))];
        for ($i = 1; $i < 8; $i++) {
            $u[] = static::base2ToBase256(strrev(str_repeat('0', $i) . $r));
        }

        // implements algorithm 2.40 (in section 2.3.5) in "Guide to Elliptic Curve Cryptography"
        // with W = 8
        $reduce = function ($c) use ($u, $mStart, $m, $t, $finalMask, $pad, $h) {
            $c = str_pad($c, $pad, "\0", STR_PAD_LEFT);
            for ($i = $mStart; $i >= $m;) {
                $g = $h >> 3;
                $mask = $h & 7;
                $mask = $mask ? 1 << (7 - $mask) : 0x80;
                for (; $mask > 0; $mask >>= 1, $i--, $h++) {
                    if (ord($c[$g]) & $mask) {
                        $temp = $i - $m;
                        $j = $temp >> 3;
                        $k = $temp & 7;
                        $t1 = $j ? substr($c, 0, -$j) : $c;
                        $length = strlen($t1);
                        if ($length) {
                            $t2 = str_pad($u[$k], $length, "\0", STR_PAD_LEFT);
                            $temp = $t1 ^ $t2;
                            $c = $j ? substr_replace($c, $temp, 0, $length) : $temp;
                        }
                    }
                }
            }
            $c = substr($c, -$t);
            if (strlen($c) == $t) {
                $c[0] = $c[0] & $finalMask;
            }
            return ltrim($c, "\0");
        };

        $this->instanceID = self::$instanceCounter++;
        Integer::setModulo($this->instanceID, $modulo);
        Integer::setRecurringModuloFunction($this->instanceID, $reduce);

        $this->randomMax = new BigInteger($modulo, 2);
    }

    /**
     * Returns an instance of a dynamically generated PrimeFieldInteger class
     *
     * @param string $num
     * @return Integer
     */
    public function newInteger($num)
    {
        return new Integer($this->instanceID, $num instanceof BigInteger ? $num->toBytes() : $num);
    }

    /**
     * Returns an integer on the finite field between one and the prime modulo
     *
     * @return Integer
     */
    public function randomInteger()
    {
        static $one;
        if (!isset($one)) {
            $one = new BigInteger(1);
        }

        return new Integer($this->instanceID, BigInteger::randomRange($one, $this->randomMax)->toBytes());
    }

    /**
     * Returns the length of the modulo in bytes
     *
     * @return int
     */
    public function getLengthInBytes()
    {
        return strlen(Integer::getModulo($this->instanceID));
    }

    /**
     * Returns the length of the modulo in bits
     *
     * @return int
     */
    public function getLength()
    {
        return strlen(Integer::getModulo($this->instanceID)) << 3;
    }

    /**
     * Converts a base-2 string to a base-256 string
     *
     * @param string $x
     * @param int|null $size
     * @return string
     */
    public static function base2ToBase256($x, $size = null)
    {
        $str = Strings::bits2bin($x);

        $pad = strlen($x) >> 3;
        if (strlen($x) & 3) {
            $pad++;
        }
        $str = str_pad($str, $pad, "\0", STR_PAD_LEFT);
        if (isset($size)) {
            $str = str_pad($str, $size, "\0", STR_PAD_LEFT);
        }

        return $str;
    }

    /**
     * Converts a base-256 string to a base-2 string
     *
     * @param string $x
     * @return string
     */
    public static function base256ToBase2($x)
    {
        if (function_exists('gmp_import')) {
            return gmp_strval(gmp_import($x), 2);
        }

        return Strings::bin2bits($x);
    }
}
<?php

/**
 * UnsupportedFormatException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * UnsupportedFormatException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class UnsupportedFormatException extends \RuntimeException
{
}
<?php

/**
 * InsufficientSetupException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * InsufficientSetupException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class InsufficientSetupException extends \RuntimeException
{
}
<?php

/**
 * BadModeException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * BadModeException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class BadModeException extends \RuntimeException
{
}
<?php

namespace phpseclib3\Exception;

/**
 * Indicates an absent or malformed packet length header
 */
class InvalidPacketLengthException extends ConnectionClosedException
{
}
<?php

namespace phpseclib3\Exception;

/**
 * Indicates a timeout awaiting server response
 */
class TimeoutException extends \RuntimeException
{
}
<?php

/**
 * UnableToConnectException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * UnableToConnectException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class UnableToConnectException extends \RuntimeException
{
}
<?php

/**
 * FileNotFoundException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * FileNotFoundException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class FileNotFoundException extends \RuntimeException
{
}
<?php

/**
 * ConnectionClosedException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * ConnectionClosedException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class ConnectionClosedException extends \RuntimeException
{
}
<?php

/**
 * NoSupportedAlgorithmsException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * NoSupportedAlgorithmsException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class NoSupportedAlgorithmsException extends \RuntimeException
{
}
<?php

/**
 * NoKeyLoadedException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * NoKeyLoadedException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class NoKeyLoadedException extends \RuntimeException
{
}
<?php

/**
 * BadConfigurationException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * BadConfigurationException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class BadConfigurationException extends \RuntimeException
{
}
<?php

/**
 * UnsupportedAlgorithmException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * UnsupportedAlgorithmException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class UnsupportedAlgorithmException extends \RuntimeException
{
}
<?php

/**
 * InconsistentSetupException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * InconsistentSetupException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class InconsistentSetupException extends \RuntimeException
{
}
<?php

/**
 * BadDecryptionException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * BadDecryptionException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class BadDecryptionException extends \RuntimeException
{
}
<?php

/**
 * UnsupportedCurveException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * UnsupportedCurveException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class UnsupportedCurveException extends \RuntimeException
{
}
<?php

/**
 * UnsupportedOperationException
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Exception;

/**
 * UnsupportedOperationException
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class UnsupportedOperationException extends \RuntimeException
{
}
<?php

/**
 * ASN1 Signature Handler
 *
 * PHP version 5
 *
 * Handles signatures in the format described in
 * https://tools.ietf.org/html/rfc3279#section-2.2.2
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA\Formats\Signature;

use phpseclib3\File\ASN1 as Encoder;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * ASN1 Signature Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class ASN1
{
    /**
     * Loads a signature
     *
     * @param string $sig
     * @return array|bool
     */
    public static function load($sig)
    {
        if (!is_string($sig)) {
            return false;
        }

        $decoded = Encoder::decodeBER($sig);
        if (empty($decoded)) {
            return false;
        }
        $components = Encoder::asn1map($decoded[0], Maps\DssSigValue::MAP);

        return $components;
    }

    /**
     * Returns a signature in the appropriate format
     *
     * @param BigInteger $r
     * @param BigInteger $s
     * @return string
     */
    public static function save(BigInteger $r, BigInteger $s)
    {
        return Encoder::encodeDER(compact('r', 's'), Maps\DssSigValue::MAP);
    }
}
<?php

/**
 * Raw DSA Signature Handler
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA\Formats\Signature;

use phpseclib3\Crypt\Common\Formats\Signature\Raw as Progenitor;

/**
 * Raw DSA Signature Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Raw extends Progenitor
{
}
<?php

/**
 * SSH2 Signature Handler
 *
 * PHP version 5
 *
 * Handles signatures in the format used by SSH2
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA\Formats\Signature;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Math\BigInteger;

/**
 * SSH2 Signature Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class SSH2
{
    /**
     * Loads a signature
     *
     * @param string $sig
     * @return mixed
     */
    public static function load($sig)
    {
        if (!is_string($sig)) {
            return false;
        }

        $result = Strings::unpackSSH2('ss', $sig);
        if ($result === false) {
            return false;
        }
        list($type, $blob) = $result;
        if ($type != 'ssh-dss' || strlen($blob) != 40) {
            return false;
        }

        return [
            'r' => new BigInteger(substr($blob, 0, 20), 256),
            's' => new BigInteger(substr($blob, 20), 256)
        ];
    }

    /**
     * Returns a signature in the appropriate format
     *
     * @param BigInteger $r
     * @param BigInteger $s
     * @return string
     */
    public static function save(BigInteger $r, BigInteger $s)
    {
        if ($r->getLength() > 160 || $s->getLength() > 160) {
            return false;
        }
        return Strings::packSSH2(
            'ss',
            'ssh-dss',
            str_pad($r->toBytes(), 20, "\0", STR_PAD_LEFT) .
            str_pad($s->toBytes(), 20, "\0", STR_PAD_LEFT)
        );
    }
}
<?php

/**
 * Raw DSA Key Handler
 *
 * PHP version 5
 *
 * Reads and creates arrays as DSA keys
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA\Formats\Keys;

use phpseclib3\Math\BigInteger;

/**
 * Raw DSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Raw
{
    /**
     * Break a public or private key down into its constituent components
     *
     * @param array $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        if (!is_array($key)) {
            throw new \UnexpectedValueException('Key should be a array - not a ' . gettype($key));
        }

        switch (true) {
            case !isset($key['p']) || !isset($key['q']) || !isset($key['g']):
            case !$key['p'] instanceof BigInteger:
            case !$key['q'] instanceof BigInteger:
            case !$key['g'] instanceof BigInteger:
            case !isset($key['x']) && !isset($key['y']):
            case isset($key['x']) && !$key['x'] instanceof BigInteger:
            case isset($key['y']) && !$key['y'] instanceof BigInteger:
                throw new \UnexpectedValueException('Key appears to be malformed');
        }

        $options = ['p' => 1, 'q' => 1, 'g' => 1, 'x' => 1, 'y' => 1];

        return array_intersect_key($key, $options);
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @param BigInteger $y
     * @param BigInteger $x
     * @param string $password optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '')
    {
        return compact('p', 'q', 'g', 'y', 'x');
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @param BigInteger $y
     * @return string
     */
    public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
    {
        return compact('p', 'q', 'g', 'y');
    }
}
<?php

/**
 * OpenSSH Formatted DSA Key Handler
 *
 * PHP version 5
 *
 * Place in $HOME/.ssh/authorized_keys
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\OpenSSH as Progenitor;
use phpseclib3\Math\BigInteger;

/**
 * OpenSSH Formatted DSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OpenSSH extends Progenitor
{
    /**
     * Supported Key Types
     *
     * @var array
     */
    protected static $types = ['ssh-dss'];

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        $parsed = parent::load($key, $password);

        if (isset($parsed['paddedKey'])) {
            list($type) = Strings::unpackSSH2('s', $parsed['paddedKey']);
            if ($type != $parsed['type']) {
                throw new \RuntimeException("The public and private keys are not of the same type ($type vs $parsed[type])");
            }

            list($p, $q, $g, $y, $x, $comment) = Strings::unpackSSH2('i5s', $parsed['paddedKey']);

            return compact('p', 'q', 'g', 'y', 'x', 'comment');
        }

        list($p, $q, $g, $y) = Strings::unpackSSH2('iiii', $parsed['publicKey']);

        $comment = $parsed['comment'];

        return compact('p', 'q', 'g', 'y', 'comment');
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @param BigInteger $y
     * @param array $options optional
     * @return string
     */
    public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, array $options = [])
    {
        if ($q->getLength() != 160) {
            throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
        }

        // from <http://tools.ietf.org/html/rfc4253#page-15>:
        // string    "ssh-dss"
        // mpint     p
        // mpint     q
        // mpint     g
        // mpint     y
        $DSAPublicKey = Strings::packSSH2('siiii', 'ssh-dss', $p, $q, $g, $y);

        if (isset($options['binary']) ? $options['binary'] : self::$binary) {
            return $DSAPublicKey;
        }

        $comment = isset($options['comment']) ? $options['comment'] : self::$comment;
        $DSAPublicKey = 'ssh-dss ' . base64_encode($DSAPublicKey) . ' ' . $comment;

        return $DSAPublicKey;
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @param BigInteger $y
     * @param BigInteger $x
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = [])
    {
        $publicKey = self::savePublicKey($p, $q, $g, $y, ['binary' => true]);
        $privateKey = Strings::packSSH2('si5', 'ssh-dss', $p, $q, $g, $y, $x);

        return self::wrapPrivateKey($publicKey, $privateKey, $password, $options);
    }
}
<?php

/**
 * XML Formatted DSA Key Handler
 *
 * While XKMS defines a private key format for RSA it does not do so for DSA. Quoting that standard:
 *
 * "[XKMS] does not specify private key parameters for the DSA signature algorithm since the algorithm only
 *  supports signature modes and so the application of server generated keys and key recovery is of limited
 *  value"
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Math\BigInteger;

/**
 * XML Formatted DSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class XML
{
    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        if (!class_exists('DOMDocument')) {
            throw new BadConfigurationException('The dom extension is not setup correctly on this system');
        }

        $use_errors = libxml_use_internal_errors(true);

        $dom = new \DOMDocument();
        if (substr($key, 0, 5) != '<?xml') {
            $key = '<xml>' . $key . '</xml>';
        }
        if (!$dom->loadXML($key)) {
            libxml_use_internal_errors($use_errors);
            throw new \UnexpectedValueException('Key does not appear to contain XML');
        }
        $xpath = new \DOMXPath($dom);
        $keys = ['p', 'q', 'g', 'y', 'j', 'seed', 'pgencounter'];
        foreach ($keys as $key) {
            // $dom->getElementsByTagName($key) is case-sensitive
            $temp = $xpath->query("//*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$key']");
            if (!$temp->length) {
                continue;
            }
            $value = new BigInteger(Strings::base64_decode($temp->item(0)->nodeValue), 256);
            switch ($key) {
                case 'p': // a prime modulus meeting the [DSS] requirements
                    // Parameters P, Q, and G can be public and common to a group of users. They might be known
                    // from application context. As such, they are optional but P and Q must either both appear
                    // or both be absent
                    $components['p'] = $value;
                    break;
                case 'q': // an integer in the range 2**159 < Q < 2**160 which is a prime divisor of P-1
                    $components['q'] = $value;
                    break;
                case 'g': // an integer with certain properties with respect to P and Q
                    $components['g'] = $value;
                    break;
                case 'y': // G**X mod P (where X is part of the private key and not made public)
                    $components['y'] = $value;
                    // the remaining options do not do anything
                case 'j': // (P - 1) / Q
                    // Parameter J is available for inclusion solely for efficiency as it is calculatable from
                    // P and Q
                case 'seed': // a DSA prime generation seed
                    // Parameters seed and pgenCounter are used in the DSA prime number generation algorithm
                    // specified in [DSS]. As such, they are optional but must either both be present or both
                    // be absent
                case 'pgencounter': // a DSA prime generation counter
            }
        }

        libxml_use_internal_errors($use_errors);

        if (!isset($components['y'])) {
            throw new \UnexpectedValueException('Key is missing y component');
        }

        switch (true) {
            case !isset($components['p']):
            case !isset($components['q']):
            case !isset($components['g']):
                return ['y' => $components['y']];
        }

        return $components;
    }

    /**
     * Convert a public key to the appropriate format
     *
     * See https://www.w3.org/TR/xmldsig-core/#sec-DSAKeyValue
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @param BigInteger $y
     * @return string
     */
    public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
    {
        return "<DSAKeyValue>\r\n" .
               '  <P>' . Strings::base64_encode($p->toBytes()) . "</P>\r\n" .
               '  <Q>' . Strings::base64_encode($q->toBytes()) . "</Q>\r\n" .
               '  <G>' . Strings::base64_encode($g->toBytes()) . "</G>\r\n" .
               '  <Y>' . Strings::base64_encode($y->toBytes()) . "</Y>\r\n" .
               '</DSAKeyValue>';
    }
}
<?php

/**
 * PuTTY Formatted DSA Key Handler
 *
 * puttygen does not generate DSA keys with an N of anything other than 160, however,
 * it can still load them and convert them. PuTTY will load them, too, but SSH servers
 * won't accept them. Since PuTTY formatted keys are primarily used with SSH this makes
 * keys with N > 160 kinda useless, hence this handlers not supporting such keys.
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\PuTTY as Progenitor;
use phpseclib3\Math\BigInteger;

/**
 * PuTTY Formatted DSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PuTTY extends Progenitor
{
    /**
     * Public Handler
     *
     * @var string
     */
    const PUBLIC_HANDLER = 'phpseclib3\Crypt\DSA\Formats\Keys\OpenSSH';

    /**
     * Algorithm Identifier
     *
     * @var array
     */
    protected static $types = ['ssh-dss'];

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        $components = parent::load($key, $password);
        if (!isset($components['private'])) {
            return $components;
        }
        $type = $components['type'];
        $comment = $components['comment'];
        $public = $components['public'];
        $private = $components['private'];
        unset($components['public'], $components['private']);

        list($p, $q, $g, $y) = Strings::unpackSSH2('iiii', $public);
        list($x) = Strings::unpackSSH2('i', $private);

        return compact('p', 'q', 'g', 'y', 'x', 'comment');
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @param BigInteger $y
     * @param BigInteger $x
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = false, array $options = [])
    {
        if ($q->getLength() != 160) {
            throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
        }

        $public = Strings::packSSH2('iiii', $p, $q, $g, $y);
        $private = Strings::packSSH2('i', $x);

        return self::wrapPrivateKey($public, $private, 'ssh-dss', $password, $options);
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @param BigInteger $y
     * @return string
     */
    public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
    {
        if ($q->getLength() != 160) {
            throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
        }

        return self::wrapPublicKey(Strings::packSSH2('iiii', $p, $q, $g, $y), 'ssh-dss');
    }
}
<?php

/**
 * PKCS#1 Formatted DSA Key Handler
 *
 * PHP version 5
 *
 * Used by File/X509.php
 *
 * Processes keys with the following headers:
 *
 * -----BEGIN DSA PRIVATE KEY-----
 * -----BEGIN DSA PUBLIC KEY-----
 * -----BEGIN DSA PARAMETERS-----
 *
 * Analogous to ssh-keygen's pem format (as specified by -m)
 *
 * Also, technically, PKCS1 decribes RSA but I am not aware of a formal specification for DSA.
 * The DSA private key format seems to have been adapted from the RSA private key format so
 * we're just re-using that as the name.
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * PKCS#1 Formatted DSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS1 extends Progenitor
{
    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        $key = parent::load($key, $password);

        $decoded = ASN1::decodeBER($key);
        if (!$decoded) {
            throw new \RuntimeException('Unable to decode BER');
        }

        $key = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP);
        if (is_array($key)) {
            return $key;
        }

        $key = ASN1::asn1map($decoded[0], Maps\DSAPrivateKey::MAP);
        if (is_array($key)) {
            if ($key['version']->toString() !== '0') {
                throw new \UnexpectedValueException('Version number is not valid');
            }
            return $key;
        }

        // PKCS1 DSA public keys are not supported by phpseclib since they can't be used to do
        // anything on their own. in order to verify a signature with DSA you need p, q, g and y.
        // a PKCS1 DSA public key only has y. to verify a signature with a PKCS1 DSA public key
        // you'd also need to load a PKCS1 DSA parameters file separately. like you'd need to
        // load two files instead of just one. there's no other key format that phpseclib supports
        // that has that requirement so building it in for PKCS1 DSA public keys seems excessive.
        //
        // the whole thing would be rather like an RSA public key having the modulo live in
        // a separate file than the exponent.
        //
        // this isn't an issue for PKCS8 DSA public keys because those keys have the parameters
        // included. eg. \phpseclib3\File\ASN1\Maps\SubjectPublicKeyInfo has "algorithm" and
        // "subjectPublicKey" and "algorithm", in turn, has "algorithm" and "parameters". y
        // is saved as "subjectPublicKey" and p, q and g are saved as "parameters".

        //$key = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);

        throw new \RuntimeException('Unable to perform ASN1 mapping');
    }

    /**
     * Convert DSA parameters to the appropriate format
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @return string
     */
    public static function saveParameters(BigInteger $p, BigInteger $q, BigInteger $g)
    {
        $key = [
            'p' => $p,
            'q' => $q,
            'g' => $g
        ];

        $key = ASN1::encodeDER($key, Maps\DSAParams::MAP);

        return "-----BEGIN DSA PARAMETERS-----\r\n" .
               chunk_split(Strings::base64_encode($key), 64) .
               "-----END DSA PARAMETERS-----\r\n";
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @param BigInteger $y
     * @param BigInteger $x
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = [])
    {
        $key = [
            'version' => 0,
            'p' => $p,
            'q' => $q,
            'g' => $g,
            'y' => $y,
            'x' => $x
        ];

        $key = ASN1::encodeDER($key, Maps\DSAPrivateKey::MAP);

        return self::wrapPrivateKey($key, 'DSA', $password, $options);
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @param BigInteger $y
     * @return string
     */
    public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
    {
        $key = ASN1::encodeDER($y, Maps\DSAPublicKey::MAP);

        return self::wrapPublicKey($key, 'DSA');
    }
}
<?php

/**
 * PKCS#8 Formatted DSA Key Handler
 *
 * PHP version 5
 *
 * Processes keys with the following headers:
 *
 * -----BEGIN ENCRYPTED PRIVATE KEY-----
 * -----BEGIN PRIVATE KEY-----
 * -----BEGIN PUBLIC KEY-----
 *
 * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
 * is specific to private keys it's basically creating a DER-encoded wrapper
 * for keys. This just extends that same concept to public keys (much like ssh-keygen)
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA\Formats\Keys;

use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * PKCS#8 Formatted DSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS8 extends Progenitor
{
    /**
     * OID Name
     *
     * @var string
     */
    const OID_NAME = 'id-dsa';

    /**
     * OID Value
     *
     * @var string
     */
    const OID_VALUE = '1.2.840.10040.4.1';

    /**
     * Child OIDs loaded
     *
     * @var bool
     */
    protected static $childOIDsLoaded = false;

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        $key = parent::load($key, $password);

        $type = isset($key['privateKey']) ? 'privateKey' : 'publicKey';

        $decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element);
        if (!$decoded) {
            throw new \RuntimeException('Unable to decode BER of parameters');
        }
        $components = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP);
        if (!is_array($components)) {
            throw new \RuntimeException('Unable to perform ASN1 mapping on parameters');
        }

        $decoded = ASN1::decodeBER($key[$type]);
        if (empty($decoded)) {
            throw new \RuntimeException('Unable to decode BER');
        }

        $var = $type == 'privateKey' ? 'x' : 'y';
        $components[$var] = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);
        if (!$components[$var] instanceof BigInteger) {
            throw new \RuntimeException('Unable to perform ASN1 mapping');
        }

        if (isset($key['meta'])) {
            $components['meta'] = $key['meta'];
        }

        return $components;
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @param BigInteger $y
     * @param BigInteger $x
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = [])
    {
        $params = [
            'p' => $p,
            'q' => $q,
            'g' => $g
        ];
        $params = ASN1::encodeDER($params, Maps\DSAParams::MAP);
        $params = new ASN1\Element($params);
        $key = ASN1::encodeDER($x, Maps\DSAPublicKey::MAP);
        return self::wrapPrivateKey($key, [], $params, $password, null, '', $options);
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $p
     * @param BigInteger $q
     * @param BigInteger $g
     * @param BigInteger $y
     * @param array $options optional
     * @return string
     */
    public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, array $options = [])
    {
        $params = [
            'p' => $p,
            'q' => $q,
            'g' => $g
        ];
        $params = ASN1::encodeDER($params, Maps\DSAParams::MAP);
        $params = new ASN1\Element($params);
        $key = ASN1::encodeDER($y, Maps\DSAPublicKey::MAP);
        return self::wrapPublicKey($key, $params, null, $options);
    }
}
<?php

/**
 * DSA Private Key
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA;

use phpseclib3\Crypt\Common;
use phpseclib3\Crypt\DSA;
use phpseclib3\Crypt\DSA\Formats\Signature\ASN1 as ASN1Signature;
use phpseclib3\Math\BigInteger;
use phpseclib3\Exception\BadConfigurationException;

/**
 * DSA Private Key
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
final class PrivateKey extends DSA implements Common\PrivateKey
{
    use Common\Traits\PasswordProtected;

    /**
     * DSA secret exponent x
     *
     * @var BigInteger
     */
    protected $x;

    /**
     * Returns the public key
     *
     * If you do "openssl rsa -in private.rsa -pubout -outform PEM" you get a PKCS8 formatted key
     * that contains a publicKeyAlgorithm AlgorithmIdentifier and a publicKey BIT STRING.
     * An AlgorithmIdentifier contains an OID and a parameters field. With RSA public keys this
     * parameters field is NULL. With DSA PKCS8 public keys it is not - it contains the p, q and g
     * variables. The publicKey BIT STRING contains, simply, the y variable. This can be verified
     * by getting a DSA PKCS8 public key:
     *
     * "openssl dsa -in private.dsa -pubout -outform PEM"
     *
     * ie. just swap out rsa with dsa in the rsa command above.
     *
     * A PKCS1 public key corresponds to the publicKey portion of the PKCS8 key. In the case of RSA
     * the publicKey portion /is/ the key. In the case of DSA it is not. You cannot verify a signature
     * without the parameters and the PKCS1 DSA public key format does not include the parameters.
     *
     * @see self::getPrivateKey()
     * @return mixed
     */
    public function getPublicKey()
    {
        $type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey');

        if (!isset($this->y)) {
            $this->y = $this->g->powMod($this->x, $this->p);
        }

        $key = $type::savePublicKey($this->p, $this->q, $this->g, $this->y);

        return DSA::loadFormat('PKCS8', $key)
            ->withHash($this->hash->getHash())
            ->withSignatureFormat($this->shortFormat);
    }

    /**
     * Create a signature
     *
     * @see self::verify()
     * @param string $message
     * @return mixed
     */
    public function sign($message)
    {
        $format = $this->sigFormat;

        if (self::$forcedEngine === 'libsodium') {
            throw new BadConfigurationException('Engine libsodium is forced but unsupported for DSA');
        }

        if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) {
            throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA');
        }

        if (function_exists('openssl_get_md_methods') && self::$forcedEngine !== 'PHP') {
            if (in_array($this->hash->getHash(), openssl_get_md_methods())) {
                $signature = '';
                $result = openssl_sign($message, $signature, $this->withPassword()->toString('PKCS8'), $this->hash->getHash());

                if ($result) {
                    if ($this->shortFormat == 'ASN1') {
                        return $signature;
                    }

                    $loaded = ASN1Signature::load($signature);
                    $r = $loaded['r'];
                    $s = $loaded['s'];

                    return $format::save($r, $s);
                } elseif (self::$forcedEngine === 'OpenSSL') {
                    throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
                }
            } elseif (self::$forcedEngine === 'OpenSSL') {
                throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA / ' . $this->hash->getHash());
            }
        }

        $h = $this->hash->hash($message);
        $h = $this->bits2int($h);

        while (true) {
            $k = BigInteger::randomRange(self::$one, $this->q->subtract(self::$one));
            $r = $this->g->powMod($k, $this->p);
            list(, $r) = $r->divide($this->q);
            if ($r->equals(self::$zero)) {
                continue;
            }
            $kinv = $k->modInverse($this->q);
            $temp = $h->add($this->x->multiply($r));
            $temp = $kinv->multiply($temp);
            list(, $s) = $temp->divide($this->q);
            if (!$s->equals(self::$zero)) {
                break;
            }
        }

        // the following is an RFC6979 compliant implementation of deterministic DSA
        // it's unused because it's mainly intended for use when a good CSPRNG isn't
        // available. if phpseclib's CSPRNG isn't good then even key generation is
        // suspect
        /*
        $h1 = $this->hash->hash($message);
        $k = $this->computek($h1);
        $r = $this->g->powMod($k, $this->p);
        list(, $r) = $r->divide($this->q);
        $kinv = $k->modInverse($this->q);
        $h1 = $this->bits2int($h1);
        $temp = $h1->add($this->x->multiply($r));
        $temp = $kinv->multiply($temp);
        list(, $s) = $temp->divide($this->q);
        */

        return $format::save($r, $s);
    }

    /**
     * Returns the private key
     *
     * @param string $type
     * @param array $options optional
     * @return string
     */
    public function toString($type, array $options = [])
    {
        $type = self::validatePlugin('Keys', $type, 'savePrivateKey');

        if (!isset($this->y)) {
            $this->y = $this->g->powMod($this->x, $this->p);
        }

        return $type::savePrivateKey($this->p, $this->q, $this->g, $this->y, $this->x, $this->password, $options);
    }
}
<?php

/**
 * DSA Public Key
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA;

use phpseclib3\Crypt\Common;
use phpseclib3\Crypt\DSA;
use phpseclib3\Crypt\DSA\Formats\Signature\ASN1 as ASN1Signature;
use phpseclib3\Exception\BadConfigurationException;

/**
 * DSA Public Key
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
final class PublicKey extends DSA implements Common\PublicKey
{
    use Common\Traits\Fingerprint;

    /**
     * Verify a signature
     *
     * @see self::verify()
     * @param string $message
     * @param string $signature
     * @return mixed
     */
    public function verify($message, $signature)
    {
        if (self::$forcedEngine === 'libsodium') {
            throw new BadConfigurationException('Engine libsodium is forced but unsupported for DSA');
        }

        if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) {
            throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA');
        }

        $format = $this->sigFormat;

        $params = $format::load($signature);
        if ($params === false || count($params) != 2) {
            return false;
        }
        $r = $params['r'];
        $s = $params['s'];

        if (function_exists('openssl_get_md_methods') && self::$forcedEngine !== 'PHP') {
            if (in_array($this->hash->getHash(), openssl_get_md_methods())) {
                $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;

                $result = openssl_verify($message, $sig, $this->toString('PKCS8'), $this->hash->getHash());

                if ($result != -1) {
                    return (bool) $result;
                }
            } elseif (self::$forcedEngine === 'OpenSSL') {
                throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA / ' . $this->hash->getHash());
            }
        }

        $q_1 = $this->q->subtract(self::$one);
        if (!$r->between(self::$one, $q_1) || !$s->between(self::$one, $q_1)) {
            return false;
        }

        $w = $s->modInverse($this->q);
        $h = $this->hash->hash($message);
        $h = $this->bits2int($h);
        list(, $u1) = $h->multiply($w)->divide($this->q);
        list(, $u2) = $r->multiply($w)->divide($this->q);
        $v1 = $this->g->powMod($u1, $this->p);
        $v2 = $this->y->powMod($u2, $this->p);
        list(, $v) = $v1->multiply($v2)->divide($this->p);
        list(, $v) = $v->divide($this->q);

        return $v->equals($r);
    }

    /**
     * Returns the public key
     *
     * @param string $type
     * @param array $options optional
     * @return string
     */
    public function toString($type, array $options = [])
    {
        $type = self::validatePlugin('Keys', $type, 'savePublicKey');

        return $type::savePublicKey($this->p, $this->q, $this->g, $this->y, $options);
    }
}
<?php

/**
 * DSA Parameters
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DSA;

use phpseclib3\Crypt\DSA;

/**
 * DSA Parameters
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
final class Parameters extends DSA
{
    /**
     * Returns the parameters
     *
     * @param string $type
     * @param array $options optional
     * @return string
     */
    public function toString($type = 'PKCS1', array $options = [])
    {
        $type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');

        return $type::saveParameters($this->p, $this->q, $this->g, $options);
    }
}
<?php

/**
 * Pure-PHP implementation of Blowfish.
 *
 * Uses mcrypt, if available, and an internal implementation, otherwise.
 *
 * PHP version 5
 *
 * Useful resources are as follows:
 *
 *  - {@link http://en.wikipedia.org/wiki/Blowfish_(cipher) Wikipedia description of Blowfish}
 *
 * # An overview of bcrypt vs Blowfish
 *
 * OpenSSH private keys use a customized version of bcrypt. Specifically, instead of
 * encrypting OrpheanBeholderScryDoubt 64 times OpenSSH's bcrypt variant encrypts
 * OxychromaticBlowfishSwatDynamite 64 times. so we can't use crypt().
 *
 * bcrypt is basically Blowfish but instead of performing the key expansion once it performs
 * the expansion 129 times for each round, with the first key expansion interleaving the salt
 * and password. This renders OpenSSL unusable and forces us to use a pure-PHP implementation
 * of blowfish.
 *
 * # phpseclib's four different _encryptBlock() implementations
 *
 * When using Blowfish as an encryption algorithm, _encryptBlock() is called 9 + 512 +
 * (the number of blocks in the plaintext) times.
 *
 * Each of the first 9 calls to _encryptBlock() modify the P-array. Each of the next 512
 * calls modify the S-boxes. The remaining _encryptBlock() calls operate on the plaintext to
 * produce the ciphertext. In the pure-PHP implementation of Blowfish these remaining
 * _encryptBlock() calls are highly optimized through the use of eval(). Among other things,
 * P-array lookups are eliminated by hard-coding the key-dependent P-array values, and thus we
 * have explained 2 of the 4 different _encryptBlock() implementations.
 *
 * With bcrypt things are a bit different. _encryptBlock() is called 1,079,296 times,
 * assuming 16 rounds (which is what OpenSSH's bcrypt defaults to). The eval()-optimized
 * _encryptBlock() isn't as beneficial because the P-array values are not constant. Well, they
 * are constant, but only for, at most, 777 _encryptBlock() calls, which is equivalent to ~6KB
 * of data. The average length of back to back _encryptBlock() calls with a fixed P-array is
 * 514.12, which is ~4KB of data. Creating an eval()-optimized _encryptBlock() has an upfront
 * cost, which is CPU dependent and is probably not going to be worth it for just ~4KB of
 * data. Conseqeuently, bcrypt does not benefit from the eval()-optimized _encryptBlock().
 *
 * The regular _encryptBlock() does unpack() and pack() on every call, as well, and that can
 * begin to add up after one million function calls.
 *
 * In theory, one might think that it might be beneficial to rewrite all block ciphers so
 * that, instead of passing strings to _encryptBlock(), you convert the string to an array of
 * integers and then pass successive subarrays of that array to _encryptBlock. This, however,
 * kills PHP's memory use. Like let's say you have a 1MB long string. After doing
 * $in = str_repeat('a', 1024 * 1024); PHP's memory utilization jumps up by ~1MB. After doing
 * $blocks = str_split($in, 4); it jumps up by an additional ~16MB. After
 * $blocks = array_map(fn($x) => unpack('N*', $x), $blocks); it jumps up by an additional
 * ~90MB, yielding a 106x increase in memory usage. Consequently, it bcrypt calls a different
 * _encryptBlock() then the regular Blowfish does. That said, the Blowfish _encryptBlock() is
 * basically just a thin wrapper around the bcrypt _encryptBlock(), so there's that.
 *
 * This explains 3 of the 4 _encryptBlock() implementations. the last _encryptBlock()
 * implementation can best be understood by doing Ctrl + F and searching for where
 * self::$use_reg_intval is defined.
 *
 * # phpseclib's three different _setupKey() implementations
 *
 * Every bcrypt round is the equivalent of encrypting 512KB of data. Since OpenSSH uses 16
 * rounds by default that's ~8MB of data that's essentially being encrypted whenever
 * you use bcrypt. That's a lot of data, however, bcrypt operates within tighter constraints
 * than regular Blowfish, so we can use that to our advantage. In particular, whereas Blowfish
 * supports variable length keys, in bcrypt, the initial "key" is the sha512 hash of the
 * password. sha512 hashes are 512 bits or 64 bytes long and thus the bcrypt keys are of a
 * fixed length whereas Blowfish keys are not of a fixed length.
 *
 * bcrypt actually has two different key expansion steps. The first one (expandstate) is
 * constantly XOR'ing every _encryptBlock() parameter against the salt prior _encryptBlock()'s
 * being called. The second one (expand0state) is more similar to Blowfish's _setupKey()
 * but it can still use the fixed length key optimization discussed above and can do away with
 * the pack() / unpack() calls.
 *
 * I suppose _setupKey() could be made to be a thin wrapper around expandstate() but idk it's
 * just a lot of work for very marginal benefits as _setupKey() is only called once for
 * regular Blowfish vs the 128 times it's called --per round-- with bcrypt.
 *
 * # blowfish + bcrypt in the same class
 *
 * Altho there's a lot of Blowfish code that bcrypt doesn't re-use, bcrypt does re-use the
 * initial S-boxes, the initial P-array and the int-only _encryptBlock() implementation.
 *
 * # Credit
 *
 * phpseclib's bcrypt implementation is based losely off of OpenSSH's implementation:
 *
 * https://github.com/openssh/openssh-portable/blob/master/openbsd-compat/bcrypt_pbkdf.c
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $blowfish = new \phpseclib3\Crypt\Blowfish('ctr');
 *
 *    $blowfish->setKey('12345678901234567890123456789012');
 *
 *    $plaintext = str_repeat('a', 1024);
 *
 *    echo $blowfish->decrypt($blowfish->encrypt($plaintext));
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Crypt\Common\BlockCipher;

/**
 * Pure-PHP implementation of Blowfish.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 * @author  Hans-Juergen Petrich <petrich@tronic-media.com>
 */
class Blowfish extends BlockCipher
{
    /**
     * Block Length of the cipher
     *
     * @see Common\SymmetricKey::block_size
     * @var int
     */
    protected $block_size = 8;

    /**
     * The mcrypt specific name of the cipher
     *
     * @see Common\SymmetricKey::cipher_name_mcrypt
     * @var string
     */
    protected $cipher_name_mcrypt = 'blowfish';

    /**
     * Optimizing value while CFB-encrypting
     *
     * @see Common\SymmetricKey::cfb_init_len
     * @var int
     */
    protected $cfb_init_len = 500;

    /**
     * The fixed subkeys boxes
     *
     * S-Box
     *
     * @var    array
     */
    private static $sbox = [
        0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
        0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
        0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
        0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
        0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
        0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
        0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
        0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
        0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
        0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
        0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
        0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
        0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
        0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
        0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
        0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
        0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
        0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
        0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
        0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
        0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
        0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
        0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
        0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
        0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
        0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
        0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
        0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
        0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
        0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
        0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
        0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,

        0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
        0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
        0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
        0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
        0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
        0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
        0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
        0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
        0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
        0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
        0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
        0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
        0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
        0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
        0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
        0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
        0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
        0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
        0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
        0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
        0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
        0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
        0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
        0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
        0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
        0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
        0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
        0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
        0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
        0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
        0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
        0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,

        0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
        0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
        0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
        0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
        0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
        0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
        0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
        0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
        0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
        0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
        0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
        0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
        0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
        0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
        0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
        0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
        0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
        0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
        0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
        0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
        0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
        0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
        0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
        0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
        0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
        0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
        0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
        0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
        0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
        0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
        0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
        0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,

        0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
        0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
        0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
        0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
        0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
        0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
        0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
        0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
        0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
        0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
        0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
        0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
        0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
        0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
        0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
        0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
        0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
        0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
        0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
        0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
        0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
        0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
        0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
        0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
        0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
        0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
        0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
        0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
        0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
        0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
        0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
        0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
    ];

    /**
     * P-Array consists of 18 32-bit subkeys
     *
     * @var array
     */
    private static $parray = [
        0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
        0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
        0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
    ];

    /**
     * The BCTX-working Array
     *
     * Holds the expanded key [p] and the key-depended s-boxes [sb]
     *
     * @var array
     */
    private $bctx;

    /**
     * Holds the last used key
     *
     * @var array
     */
    private $kl;

    /**
     * The Key Length (in bytes)
     * {@internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16.  Exists in conjunction with $Nk
     *    because the encryption / decryption / key schedule creation requires this number and not $key_length.  We could
     *    derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
     *    of that, we'll just precompute it once.}
     *
     * @see Common\SymmetricKey::setKeyLength()
     * @var int
     */
    protected $key_length = 16;

    /**
     * Default Constructor.
     *
     * @param string $mode
     * @throws \InvalidArgumentException if an invalid / unsupported mode is provided
     */
    public function __construct($mode)
    {
        parent::__construct($mode);

        if ($this->mode == self::MODE_STREAM) {
            throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
        }
    }

    /**
     * Sets the key length.
     *
     * Key lengths can be between 32 and 448 bits.
     *
     * @param int $length
     */
    public function setKeyLength($length)
    {
        if ($length < 32 || $length > 448) {
                throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes between 32 and 448 bits are supported');
        }

        $this->key_length = $length >> 3;

        parent::setKeyLength($length);
    }

    /**
     * Test for engine validity
     *
     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
     *
     * @see Common\SymmetricKey::isValidEngine()
     * @param int $engine
     * @return bool
     */
    protected function isValidEngineHelper($engine)
    {
        if ($engine == self::ENGINE_OPENSSL) {
            if ($this->key_length < 16) {
                return false;
            }
            // quoting https://www.openssl.org/news/openssl-3.0-notes.html, OpenSSL 3.0.1
            // "Moved all variations of the EVP ciphers CAST5, BF, IDEA, SEED, RC2, RC4, RC5, and DES to the legacy provider"
            // in theory openssl_get_cipher_methods() should catch this but, on GitHub Actions, at least, it does not
            if (defined('OPENSSL_VERSION_TEXT') && version_compare(preg_replace('#OpenSSL (\d+\.\d+\.\d+) .*#', '$1', OPENSSL_VERSION_TEXT), '3.0.1', '>=')) {
                return false;
            }
            $this->cipher_name_openssl_ecb = 'bf-ecb';
            $this->cipher_name_openssl = 'bf-' . $this->openssl_translate_mode();
        }

        return parent::isValidEngineHelper($engine);
    }

    /**
     * Setup the key (expansion)
     *
     * @see Common\SymmetricKey::_setupKey()
     */
    protected function setupKey()
    {
        if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
            // already expanded
            return;
        }
        $this->kl = ['key' => $this->key];

        /* key-expanding p[] and S-Box building sb[] */
        $this->bctx = [
            'p'  => [],
            'sb' => self::$sbox
        ];

        // unpack binary string in unsigned chars
        $key  = array_values(unpack('C*', $this->key));
        $keyl = count($key);
        // with bcrypt $keyl will always be 16 (because the key is the sha512 of the key you provide)
        for ($j = 0, $i = 0; $i < 18; ++$i) {
            // xor P1 with the first 32-bits of the key, xor P2 with the second 32-bits ...
            for ($data = 0, $k = 0; $k < 4; ++$k) {
                $data = ($data << 8) | $key[$j];
                if (++$j >= $keyl) {
                    $j = 0;
                }
            }
            $this->bctx['p'][] = self::$parray[$i] ^ intval($data);
        }

        // encrypt the zero-string, replace P1 and P2 with the encrypted data,
        // encrypt P3 and P4 with the new P1 and P2, do it with all P-array and subkeys
        $data = "\0\0\0\0\0\0\0\0";
        for ($i = 0; $i < 18; $i += 2) {
            list($l, $r) = array_values(unpack('N*', $data = $this->encryptBlock($data)));
            $this->bctx['p'][$i    ] = $l;
            $this->bctx['p'][$i + 1] = $r;
        }
        for ($i = 0; $i < 0x400; $i += 0x100) {
            for ($j = 0; $j < 256; $j += 2) {
                list($l, $r) = array_values(unpack('N*', $data = $this->encryptBlock($data)));
                $this->bctx['sb'][$i | $j] = $l;
                $this->bctx['sb'][$i | ($j + 1)] = $r;
            }
        }
    }

    /**
     * Initialize Static Variables
     */
    protected static function initialize_static_variables()
    {
        if (is_float(self::$sbox[0x200])) {
            self::$sbox = array_map([self::class, 'safe_intval'], self::$sbox);
            self::$parray = array_map([self::class, 'safe_intval'], self::$parray);
        }

        parent::initialize_static_variables();
    }

    /**
     * bcrypt
     *
     * @param string $sha2pass
     * @param string $sha2salt
     * @access private
     * @return string
     */
    private static function bcrypt_hash($sha2pass, $sha2salt)
    {
        $p = self::$parray;
        $sbox = self::$sbox;

        $cdata = array_values(unpack('N*', 'OxychromaticBlowfishSwatDynamite'));
        $sha2pass = array_values(unpack('N*', $sha2pass));
        $sha2salt = array_values(unpack('N*', $sha2salt));

        self::expandstate($sha2salt, $sha2pass, $sbox, $p);
        for ($i = 0; $i < 64; $i++) {
            self::expand0state($sha2salt, $sbox, $p);
            self::expand0state($sha2pass, $sbox, $p);
        }

        for ($i = 0; $i < 64; $i++) {
            for ($j = 0; $j < 8; $j += 2) { // count($cdata) == 8
                list($cdata[$j], $cdata[$j + 1]) = self::encryptBlockHelperFast($cdata[$j], $cdata[$j + 1], $sbox, $p);
            }
        }

        return pack('V*', ...$cdata);
    }

    /**
     * Performs OpenSSH-style bcrypt
     *
     * @param string $pass
     * @param string $salt
     * @param int $keylen
     * @param int $rounds
     * @access public
     * @return string
     */
    public static function bcrypt_pbkdf($pass, $salt, $keylen, $rounds)
    {
        self::initialize_static_variables();

        if (PHP_INT_SIZE == 4) {
            throw new \RuntimeException('bcrypt is far too slow to be practical on 32-bit versions of PHP');
        }

        $sha2pass = hash('sha512', $pass, true);
        $results = [];
        $count = 1;
        while (32 * count($results) < $keylen) {
            $countsalt = $salt . pack('N', $count++);
            $sha2salt = hash('sha512', $countsalt, true);
            $out = $tmpout = self::bcrypt_hash($sha2pass, $sha2salt);
            for ($i = 1; $i < $rounds; $i++) {
                $sha2salt = hash('sha512', $tmpout, true);
                $tmpout = self::bcrypt_hash($sha2pass, $sha2salt);
                $out ^= $tmpout;
            }
            $results[] = $out;
        }
        $output = '';
        for ($i = 0; $i < 32; $i++) {
            foreach ($results as $result) {
                $output .= $result[$i];
            }
        }
        return substr($output, 0, $keylen);
    }

    /**
     * Key expansion without salt
     *
     * @access private
     * @param int[] $key
     * @param int[] $sbox
     * @param int[] $p
     * @see self::_bcrypt_hash()
     */
    private static function expand0state(array $key, array &$sbox, array &$p)
    {
        // expand0state is basically the same thing as this:
        //return self::expandstate(array_fill(0, 16, 0), $key);
        // but this separate function eliminates a bunch of XORs and array lookups

        $p = [
            $p[0] ^ $key[0],
            $p[1] ^ $key[1],
            $p[2] ^ $key[2],
            $p[3] ^ $key[3],
            $p[4] ^ $key[4],
            $p[5] ^ $key[5],
            $p[6] ^ $key[6],
            $p[7] ^ $key[7],
            $p[8] ^ $key[8],
            $p[9] ^ $key[9],
            $p[10] ^ $key[10],
            $p[11] ^ $key[11],
            $p[12] ^ $key[12],
            $p[13] ^ $key[13],
            $p[14] ^ $key[14],
            $p[15] ^ $key[15],
            $p[16] ^ $key[0],
            $p[17] ^ $key[1]
        ];

        // @codingStandardsIgnoreStart
        list( $p[0],  $p[1]) = self::encryptBlockHelperFast(     0,      0, $sbox, $p);
        list( $p[2],  $p[3]) = self::encryptBlockHelperFast($p[ 0], $p[ 1], $sbox, $p);
        list( $p[4],  $p[5]) = self::encryptBlockHelperFast($p[ 2], $p[ 3], $sbox, $p);
        list( $p[6],  $p[7]) = self::encryptBlockHelperFast($p[ 4], $p[ 5], $sbox, $p);
        list( $p[8],  $p[9]) = self::encryptBlockHelperFast($p[ 6], $p[ 7], $sbox, $p);
        list($p[10], $p[11]) = self::encryptBlockHelperFast($p[ 8], $p[ 9], $sbox, $p);
        list($p[12], $p[13]) = self::encryptBlockHelperFast($p[10], $p[11], $sbox, $p);
        list($p[14], $p[15]) = self::encryptBlockHelperFast($p[12], $p[13], $sbox, $p);
        list($p[16], $p[17]) = self::encryptBlockHelperFast($p[14], $p[15], $sbox, $p);
        // @codingStandardsIgnoreEnd

        list($sbox[0], $sbox[1]) = self::encryptBlockHelperFast($p[16], $p[17], $sbox, $p);
        for ($i = 2; $i < 1024; $i += 2) {
            list($sbox[$i], $sbox[$i + 1]) = self::encryptBlockHelperFast($sbox[$i - 2], $sbox[$i - 1], $sbox, $p);
        }
    }

    /**
     * Key expansion with salt
     *
     * @access private
     * @param int[] $data
     * @param int[] $key
     * @param int[] $sbox
     * @param int[] $p
     * @see self::_bcrypt_hash()
     */
    private static function expandstate(array $data, array $key, array &$sbox, array &$p)
    {
        $p = [
            $p[0] ^ $key[0],
            $p[1] ^ $key[1],
            $p[2] ^ $key[2],
            $p[3] ^ $key[3],
            $p[4] ^ $key[4],
            $p[5] ^ $key[5],
            $p[6] ^ $key[6],
            $p[7] ^ $key[7],
            $p[8] ^ $key[8],
            $p[9] ^ $key[9],
            $p[10] ^ $key[10],
            $p[11] ^ $key[11],
            $p[12] ^ $key[12],
            $p[13] ^ $key[13],
            $p[14] ^ $key[14],
            $p[15] ^ $key[15],
            $p[16] ^ $key[0],
            $p[17] ^ $key[1]
        ];

        // @codingStandardsIgnoreStart
        list( $p[0],  $p[1]) = self::encryptBlockHelperFast($data[ 0]         , $data[ 1]         , $sbox, $p);
        list( $p[2],  $p[3]) = self::encryptBlockHelperFast($data[ 2] ^ $p[ 0], $data[ 3] ^ $p[ 1], $sbox, $p);
        list( $p[4],  $p[5]) = self::encryptBlockHelperFast($data[ 4] ^ $p[ 2], $data[ 5] ^ $p[ 3], $sbox, $p);
        list( $p[6],  $p[7]) = self::encryptBlockHelperFast($data[ 6] ^ $p[ 4], $data[ 7] ^ $p[ 5], $sbox, $p);
        list( $p[8],  $p[9]) = self::encryptBlockHelperFast($data[ 8] ^ $p[ 6], $data[ 9] ^ $p[ 7], $sbox, $p);
        list($p[10], $p[11]) = self::encryptBlockHelperFast($data[10] ^ $p[ 8], $data[11] ^ $p[ 9], $sbox, $p);
        list($p[12], $p[13]) = self::encryptBlockHelperFast($data[12] ^ $p[10], $data[13] ^ $p[11], $sbox, $p);
        list($p[14], $p[15]) = self::encryptBlockHelperFast($data[14] ^ $p[12], $data[15] ^ $p[13], $sbox, $p);
        list($p[16], $p[17]) = self::encryptBlockHelperFast($data[ 0] ^ $p[14], $data[ 1] ^ $p[15], $sbox, $p);
        // @codingStandardsIgnoreEnd

        list($sbox[0], $sbox[1]) = self::encryptBlockHelperFast($data[2] ^ $p[16], $data[3] ^ $p[17], $sbox, $p);
        for ($i = 2, $j = 4; $i < 1024; $i += 2, $j = ($j + 2) % 16) { // instead of 16 maybe count($data) would be better?
            list($sbox[$i], $sbox[$i + 1]) = self::encryptBlockHelperFast($data[$j] ^ $sbox[$i - 2], $data[$j + 1] ^ $sbox[$i - 1], $sbox, $p);
        }
    }

    /**
     * Encrypts a block
     *
     * @param string $in
     * @return string
     */
    protected function encryptBlock($in)
    {
        $p = $this->bctx['p'];
        // extract($this->bctx['sb'], EXTR_PREFIX_ALL, 'sb'); // slower
        $sb = $this->bctx['sb'];

        $in = unpack('N*', $in);
        $l = $in[1];
        $r = $in[2];

        list($r, $l) = PHP_INT_SIZE == 4 ?
            self::encryptBlockHelperSlow($l, $r, $sb, $p) :
            self::encryptBlockHelperFast($l, $r, $sb, $p);

        return pack("N*", $r, $l);
    }

    /**
     * Fast helper function for block encryption
     *
     * @access private
     * @param int $x0
     * @param int $x1
     * @param int[] $sbox
     * @param int[] $p
     * @return int[]
     */
    private static function encryptBlockHelperFast($x0, $x1, array $sbox, array $p)
    {
        $x0 ^= $p[0];
        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[1];
        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[2];
        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[3];
        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[4];
        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[5];
        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[6];
        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[7];
        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[8];
        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[9];
        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[10];
        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[11];
        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[12];
        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[13];
        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[14];
        $x1 ^= ((($sbox[($x0 & 0xFF000000) >> 24] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[15];
        $x0 ^= ((($sbox[($x1 & 0xFF000000) >> 24] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[16];

        return [$x1 & 0xFFFFFFFF ^ $p[17], $x0 & 0xFFFFFFFF];
    }

    /**
     * Slow helper function for block encryption
     *
     * @access private
     * @param int $x0
     * @param int $x1
     * @param int[] $sbox
     * @param int[] $p
     * @return int[]
     */
    private static function encryptBlockHelperSlow($x0, $x1, array $sbox, array $p)
    {
        // -16777216 == intval(0xFF000000) on 32-bit PHP installs
        $x0 ^= $p[0];
        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[1];
        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[2];
        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[3];
        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[4];
        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[5];
        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[6];
        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[7];
        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[8];
        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[9];
        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[10];
        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[11];
        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[12];
        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[13];
        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[14];
        $x1 ^= self::safe_intval((self::safe_intval($sbox[(($x0 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x0 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x0 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x0 & 0xFF)]) ^ $p[15];
        $x0 ^= self::safe_intval((self::safe_intval($sbox[(($x1 & -16777216) >> 24) & 0xFF] + $sbox[0x100 | (($x1 & 0xFF0000) >> 16)]) ^ $sbox[0x200 | (($x1 & 0xFF00) >> 8)]) + $sbox[0x300 | ($x1 & 0xFF)]) ^ $p[16];

        return [$x1 ^ $p[17], $x0];
    }

    /**
     * Decrypts a block
     *
     * @param string $in
     * @return string
     */
    protected function decryptBlock($in)
    {
        $p = $this->bctx['p'];
        $sb = $this->bctx['sb'];

        $in = unpack('N*', $in);
        $l = $in[1];
        $r = $in[2];

        for ($i = 17; $i > 2; $i -= 2) {
            $l ^= $p[$i];
            $r ^= self::safe_intval((self::safe_intval($sb[$l >> 24 & 0xff] + $sb[0x100 + ($l >> 16 & 0xff)]) ^
                  $sb[0x200 + ($l >>  8 & 0xff)]) +
                  $sb[0x300 + ($l       & 0xff)]);

            $r ^= $p[$i - 1];
            $l ^= self::safe_intval((self::safe_intval($sb[$r >> 24 & 0xff] + $sb[0x100 + ($r >> 16 & 0xff)]) ^
                  $sb[0x200 + ($r >>  8 & 0xff)]) +
                  $sb[0x300 + ($r       & 0xff)]);
        }
        return pack('N*', $r ^ $p[0], $l ^ $p[1]);
    }

    /**
     * Setup the performance-optimized function for de/encrypt()
     *
     * @see Common\SymmetricKey::_setupInlineCrypt()
     */
    protected function setupInlineCrypt()
    {
        $p = $this->bctx['p'];
        $init_crypt = '
            static $sb;
            if (!$sb) {
                $sb = $this->bctx["sb"];
            }
        ';

        $safeint = self::safe_intval_inline();

        // Generating encrypt code:
        $encrypt_block = '
            $in = unpack("N*", $in);
            $l = $in[1];
            $r = $in[2];
        ';
        for ($i = 0; $i < 16; $i += 2) {
            $encrypt_block .= '
                $l^= ' . $p[$i] . ';
                $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb[$l >> 24 & 0xff] + $sb[0x100 + ($l >> 16 & 0xff)]') . ' ^
                      $sb[0x200 + ($l >>  8 & 0xff)]) +
                      $sb[0x300 + ($l       & 0xff)]') . ';

                $r^= ' . $p[$i + 1] . ';
                $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb[$r >> 24 & 0xff] + $sb[0x100 + ($r >> 16 & 0xff)]') . '  ^
                      $sb[0x200 + ($r >>  8 & 0xff)]) +
                      $sb[0x300 + ($r       & 0xff)]') . ';
            ';
        }
        $encrypt_block .= '
            $in = pack("N*",
                $r ^ ' . $p[17] . ',
                $l ^ ' . $p[16] . '
            );
        ';
         // Generating decrypt code:
        $decrypt_block = '
            $in = unpack("N*", $in);
            $l = $in[1];
            $r = $in[2];
        ';

        for ($i = 17; $i > 2; $i -= 2) {
            $decrypt_block .= '
                $l^= ' . $p[$i] . ';
                $r^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb[$l >> 24 & 0xff] + $sb[0x100 + ($l >> 16 & 0xff)]') . ' ^
                      $sb[0x200 + ($l >>  8 & 0xff)]) +
                      $sb[0x300 + ($l       & 0xff)]') . ';

                $r^= ' . $p[$i - 1] . ';
                $l^= ' . sprintf($safeint, '(' . sprintf($safeint, '$sb[$r >> 24 & 0xff] + $sb[0x100 + ($r >> 16 & 0xff)]') . ' ^
                      $sb[0x200 + ($r >>  8 & 0xff)]) +
                      $sb[0x300 + ($r       & 0xff)]') . ';
            ';
        }

        $decrypt_block .= '
            $in = pack("N*",
                $r ^ ' . $p[0] . ',
                $l ^ ' . $p[1] . '
            );
        ';

        $this->inline_crypt = $this->createInlineCryptFunction(
            [
               'init_crypt'    => $init_crypt,
               'init_encrypt'  => '',
               'init_decrypt'  => '',
               'encrypt_block' => $encrypt_block,
               'decrypt_block' => $decrypt_block
            ]
        );
    }
}
<?php

/**
 * Base Class for all stream ciphers
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common;

/**
 * Base Class for all stream cipher classes
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class StreamCipher extends SymmetricKey
{
    /**
     * Block Length of the cipher
     *
     * Stream ciphers do not have a block size
     *
     * @see SymmetricKey::block_size
     * @var int
     */
    protected $block_size = 0;

    /**
     * Default Constructor.
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
     * @return StreamCipher
     */
    public function __construct()
    {
        parent::__construct('stream');
    }

    /**
     * Stream ciphers not use an IV
     *
     * @return bool
     */
    public function usesIV()
    {
        return false;
    }
}
<?php

/**
 * Base Class for all asymmetric key ciphers
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common;

use phpseclib3\Crypt\DSA;
use phpseclib3\Crypt\Hash;
use phpseclib3\Crypt\RSA;
use phpseclib3\Exception\NoKeyLoadedException;
use phpseclib3\Exception\UnsupportedFormatException;
use phpseclib3\Math\BigInteger;

/**
 * Base Class for all asymmetric cipher classes
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class AsymmetricKey
{
    /**
     * Precomputed Zero
     *
     * @var BigInteger
     */
    protected static $zero;

    /**
     * Precomputed One
     *
     * @var BigInteger
     */
    protected static $one;

    /**
     * Format of the loaded key
     *
     * @var string
     */
    protected $format;

    /**
     * Hash function
     *
     * @var Hash
     */
    protected $hash;

    /**
     * HMAC function
     *
     * @var Hash
     */
    private $hmac;

    /**
     * Supported plugins (lower case)
     *
     * @see self::initialize_static_variables()
     * @var array
     */
    private static $plugins = [];

    /**
     * Invisible plugins
     *
     * @see self::initialize_static_variables()
     * @var array
     */
    private static $invisiblePlugins = [];

    /**
     * Key Comment
     *
     * @var null|string
     */
    private $comment;

    /**
     * OpenSSL configuration file name.
     *
     * @see self::createKey()
     * @var ?string
     */
    protected static $configFile;

    /**
     * @param string $type
     * @return array|string
     */
    abstract public function toString($type, array $options = []);

    /**
     * The constructor
     */
    protected function __construct()
    {
        self::initialize_static_variables();

        $this->hash = new Hash('sha256');
        $this->hmac = new Hash('sha256');
    }

    /**
     * Initialize static variables
     */
    protected static function initialize_static_variables()
    {
        if (!isset(self::$zero)) {
            self::$zero = new BigInteger(0);
            self::$one = new BigInteger(1);
        }

        if (!isset(self::$configFile)) {
            self::$configFile = dirname(__FILE__) . '/../../openssl.cnf';
        }

        self::loadPlugins('Keys');
        if (static::ALGORITHM != 'RSA' && static::ALGORITHM != 'DH') {
            self::loadPlugins('Signature');
        }
    }

    /**
     * Load the key
     *
     * @param string $key
     * @param string $password optional
     * @return PublicKey|PrivateKey
     */
    public static function load($key, $password = false)
    {
        self::initialize_static_variables();

        $class = new \ReflectionClass(static::class);
        if ($class->isFinal()) {
            throw new \RuntimeException('load() should not be called from final classes (' . static::class . ')');
        }

        $components = false;
        foreach (self::$plugins[static::ALGORITHM]['Keys'] as $format) {
            if (isset(self::$invisiblePlugins[static::ALGORITHM]) && in_array($format, self::$invisiblePlugins[static::ALGORITHM])) {
                continue;
            }
            try {
                $components = $format::load($key, $password);
            } catch (\Exception $e) {
                $components = false;
            }
            if ($components !== false) {
                break;
            }
        }

        if ($components === false) {
            throw new NoKeyLoadedException('Unable to read key');
        }

        $components['format'] = $format;
        $components['secret'] = isset($components['secret']) ? $components['secret'] : '';
        $comment = isset($components['comment']) ? $components['comment'] : null;
        $new = static::onLoad($components);
        $new->format = $format;
        $new->comment = $comment;
        return $new instanceof PrivateKey ?
            $new->withPassword($password) :
            $new;
    }

    /**
     * Loads a private key
     *
     * @return PrivateKey
     * @param string|array $key
     * @param string $password optional
     */
    public static function loadPrivateKey($key, $password = '')
    {
        $key = self::load($key, $password);
        if (!$key instanceof PrivateKey) {
            throw new NoKeyLoadedException('The key that was loaded was not a private key');
        }
        return $key;
    }

    /**
     * Loads a public key
     *
     * @return PublicKey
     * @param string|array $key
     */
    public static function loadPublicKey($key)
    {
        $key = self::load($key);
        if (!$key instanceof PublicKey) {
            throw new NoKeyLoadedException('The key that was loaded was not a public key');
        }
        return $key;
    }

    /**
     * Loads parameters
     *
     * @return AsymmetricKey
     * @param string|array $key
     */
    public static function loadParameters($key)
    {
        $key = self::load($key);
        if (!$key instanceof PrivateKey && !$key instanceof PublicKey) {
            throw new NoKeyLoadedException('The key that was loaded was not a parameter');
        }
        return $key;
    }

    /**
     * Load the key, assuming a specific format
     *
     * @param string $type
     * @param string $key
     * @param string $password optional
     * @return static
     */
    public static function loadFormat($type, $key, $password = false)
    {
        self::initialize_static_variables();

        $components = false;
        $format = strtolower($type);
        if (isset(self::$plugins[static::ALGORITHM]['Keys'][$format])) {
            $format = self::$plugins[static::ALGORITHM]['Keys'][$format];
            $components = $format::load($key, $password);
        }

        if ($components === false) {
            throw new NoKeyLoadedException('Unable to read key');
        }

        $components['format'] = $format;
        $components['secret'] = isset($components['secret']) ? $components['secret'] : '';

        $new = static::onLoad($components);
        $new->format = $format;
        return $new instanceof PrivateKey ?
            $new->withPassword($password) :
            $new;
    }

    /**
     * Loads a private key
     *
     * @return PrivateKey
     * @param string $type
     * @param string $key
     * @param string $password optional
     */
    public static function loadPrivateKeyFormat($type, $key, $password = false)
    {
        $key = self::loadFormat($type, $key, $password);
        if (!$key instanceof PrivateKey) {
            throw new NoKeyLoadedException('The key that was loaded was not a private key');
        }
        return $key;
    }

    /**
     * Loads a public key
     *
     * @return PublicKey
     * @param string $type
     * @param string $key
     */
    public static function loadPublicKeyFormat($type, $key)
    {
        $key = self::loadFormat($type, $key);
        if (!$key instanceof PublicKey) {
            throw new NoKeyLoadedException('The key that was loaded was not a public key');
        }
        return $key;
    }

    /**
     * Loads parameters
     *
     * @return AsymmetricKey
     * @param string $type
     * @param string|array $key
     */
    public static function loadParametersFormat($type, $key)
    {
        $key = self::loadFormat($type, $key);
        if (!$key instanceof PrivateKey && !$key instanceof PublicKey) {
            throw new NoKeyLoadedException('The key that was loaded was not a parameter');
        }
        return $key;
    }

    /**
     * Validate Plugin
     *
     * @param string $format
     * @param string $type
     * @param string $method optional
     * @return mixed
     */
    protected static function validatePlugin($format, $type, $method = null)
    {
        $type = strtolower($type);
        if (!isset(self::$plugins[static::ALGORITHM][$format][$type])) {
            throw new UnsupportedFormatException("$type is not a supported format");
        }
        $type = self::$plugins[static::ALGORITHM][$format][$type];
        if (isset($method) && !method_exists($type, $method)) {
            throw new UnsupportedFormatException("$type does not implement $method");
        }

        return $type;
    }

    /**
     * Load Plugins
     *
     * @param string $format
     */
    private static function loadPlugins($format)
    {
        if (!isset(self::$plugins[static::ALGORITHM][$format])) {
            self::$plugins[static::ALGORITHM][$format] = [];
            foreach (new \DirectoryIterator(__DIR__ . '/../' . static::ALGORITHM . '/Formats/' . $format . '/') as $file) {
                if ($file->getExtension() != 'php') {
                    continue;
                }
                $name = $file->getBasename('.php');
                if ($name[0] == '.') {
                    continue;
                }
                $type = 'phpseclib3\Crypt\\' . static::ALGORITHM . '\\Formats\\' . $format . '\\' . $name;
                $reflect = new \ReflectionClass($type);
                if ($reflect->isTrait()) {
                    continue;
                }
                self::$plugins[static::ALGORITHM][$format][strtolower($name)] = $type;
                if ($reflect->hasConstant('IS_INVISIBLE')) {
                    self::$invisiblePlugins[static::ALGORITHM][] = $type;
                }
            }
        }
    }

    /**
     * Returns a list of supported formats.
     *
     * @return array
     */
    public static function getSupportedKeyFormats()
    {
        self::initialize_static_variables();

        return self::$plugins[static::ALGORITHM]['Keys'];
    }

    /**
     * Sets the OpenSSL config file path
     *
     * Set to the empty string to use the default config file
     *
     * @param string $val
     */
    public static function setOpenSSLConfigPath($val)
    {
        self::$configFile = $val;
    }

    /**
     * Add a fileformat plugin
     *
     * The plugin needs to either already be loaded or be auto-loadable.
     * Loading a plugin whose shortname overwrite an existing shortname will overwrite the old plugin.
     *
     * @see self::load()
     * @param string $fullname
     * @return bool
     */
    public static function addFileFormat($fullname)
    {
        self::initialize_static_variables();

        if (class_exists($fullname)) {
            $meta = new \ReflectionClass($fullname);
            $shortname = $meta->getShortName();
            self::$plugins[static::ALGORITHM]['Keys'][strtolower($shortname)] = $fullname;
            if ($meta->hasConstant('IS_INVISIBLE')) {
                self::$invisiblePlugins[static::ALGORITHM][] = strtolower($shortname);
            }
        }
    }

    /**
     * Returns the format of the loaded key.
     *
     * If the key that was loaded wasn't in a valid or if the key was auto-generated
     * with RSA::createKey() then this will throw an exception.
     *
     * @see self::load()
     * @return mixed
     */
    public function getLoadedFormat()
    {
        if (empty($this->format)) {
            throw new NoKeyLoadedException('This key was created with createKey - it was not loaded with load. Therefore there is no "loaded format"');
        }

        $meta = new \ReflectionClass($this->format);
        return $meta->getShortName();
    }

    /**
     * Returns the key's comment
     *
     * Not all key formats support comments. If you want to set a comment use toString()
     *
     * @return null|string
     */
    public function getComment()
    {
        return $this->comment;
    }

    /**
     * Force engine (useful for unit testing)
     */
    public static function forceEngine($engine = null)
    {
        if (!isset($engine)) {
            static::$forcedEngine = null;
            return;
        }
        switch ($engine) {
            case 'PHP':
            case 'OpenSSL':
            case 'libsodium':
                static::$forcedEngine = $engine;
                break;
            default:
                throw new \InvalidArgumentException('Valid engines are null, PHP, OpenSSL or libsodium');
        }
    }

    public static function getForcedEngine()
    {
        return static::$forcedEngine;
    }

    /**
     * __toString() magic method
     *
     * @return string
     */
    public function __toString()
    {
        return $this->toString('PKCS8');
    }

    /**
     * Determines which hashing function should be used
     *
     * @param string $hash
     */
    public function withHash($hash)
    {
        $new = clone $this;

        $new->hash = new Hash($hash);
        $new->hmac = new Hash($hash);

        return $new;
    }

    /**
     * Returns the hash algorithm currently being used
     *
     */
    public function getHash()
    {
        return clone $this->hash;
    }

    /**
     * Compute the pseudorandom k for signature generation,
     * using the process specified for deterministic DSA.
     *
     * @param string $h1
     * @return string
     */
    protected function computek($h1)
    {
        $v = str_repeat("\1", strlen($h1));

        $k = str_repeat("\0", strlen($h1));

        $x = $this->int2octets($this->x);
        $h1 = $this->bits2octets($h1);

        $this->hmac->setKey($k);
        $k = $this->hmac->hash($v . "\0" . $x . $h1);
        $this->hmac->setKey($k);
        $v = $this->hmac->hash($v);
        $k = $this->hmac->hash($v . "\1" . $x . $h1);
        $this->hmac->setKey($k);
        $v = $this->hmac->hash($v);

        $qlen = $this->q->getLengthInBytes();

        while (true) {
            $t = '';
            while (strlen($t) < $qlen) {
                $v = $this->hmac->hash($v);
                $t = $t . $v;
            }
            $k = $this->bits2int($t);

            if (!$k->equals(self::$zero) && $k->compare($this->q) < 0) {
                break;
            }
            $k = $this->hmac->hash($v . "\0");
            $this->hmac->setKey($k);
            $v = $this->hmac->hash($v);
        }

        return $k;
    }

    /**
     * Integer to Octet String
     *
     * @param BigInteger $v
     * @return string
     */
    private function int2octets($v)
    {
        $out = $v->toBytes();
        $rolen = $this->q->getLengthInBytes();
        if (strlen($out) < $rolen) {
            return str_pad($out, $rolen, "\0", STR_PAD_LEFT);
        } elseif (strlen($out) > $rolen) {
            return substr($out, -$rolen);
        } else {
            return $out;
        }
    }

    /**
     * Bit String to Integer
     *
     * @param string $in
     * @return BigInteger
     */
    protected function bits2int($in)
    {
        $v = new BigInteger($in, 256);
        $vlen = strlen($in) << 3;
        $qlen = $this->q->getLength();
        if ($vlen > $qlen) {
            return $v->bitwise_rightShift($vlen - $qlen);
        }
        return $v;
    }

    /**
     * Bit String to Octet String
     *
     * @param string $in
     * @return string
     */
    private function bits2octets($in)
    {
        $z1 = $this->bits2int($in);
        $z2 = $z1->subtract($this->q);
        return $z2->compare(self::$zero) < 0 ?
            $this->int2octets($z1) :
            $this->int2octets($z2);
    }
}
<?php

/**
 * Raw Signature Handler
 *
 * PHP version 5
 *
 * Handles signatures as arrays
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common\Formats\Signature;

use phpseclib3\Math\BigInteger;

/**
 * Raw Signature Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Raw
{
    /**
     * Loads a signature
     *
     * @param array $sig
     * @return array|bool
     */
    public static function load($sig)
    {
        switch (true) {
            case !is_array($sig):
            case !isset($sig['r']) || !isset($sig['s']):
            case !$sig['r'] instanceof BigInteger:
            case !$sig['s'] instanceof BigInteger:
                return false;
        }

        return [
            'r' => $sig['r'],
            's' => $sig['s']
        ];
    }

    /**
     * Returns a signature in the appropriate format
     *
     * @param BigInteger $r
     * @param BigInteger $s
     * @return string
     */
    public static function save(BigInteger $r, BigInteger $s)
    {
        return compact('r', 's');
    }
}
<?php

/**
 * OpenSSH Key Handler
 *
 * PHP version 5
 *
 * Place in $HOME/.ssh/authorized_keys
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\AES;
use phpseclib3\Crypt\Random;
use phpseclib3\Exception\BadDecryptionException;

/**
 * OpenSSH Formatted RSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OpenSSH
{
    /**
     * Default comment
     *
     * @var string
     */
    protected static $comment = 'phpseclib-generated-key';

    /**
     * Binary key flag
     *
     * @var bool
     */
    protected static $binary = false;

    /**
     * Sets the default comment
     *
     * @param string $comment
     */
    public static function setComment($comment)
    {
        self::$comment = str_replace(["\r", "\n"], '', $comment);
    }

    /**
     * Break a public or private key down into its constituent components
     *
     * $type can be either ssh-dss or ssh-rsa
     *
     * @param string $key
     * @param string $password
     * @return array
     */
    public static function load($key, $password = '')
    {
        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        // key format is described here:
        // https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD

        if (strpos($key, 'BEGIN OPENSSH PRIVATE KEY') !== false) {
            $key = preg_replace('#(?:^-.*?-[\r\n]*$)|\s#ms', '', $key);
            $key = Strings::base64_decode($key);
            $magic = Strings::shift($key, 15);
            if ($magic != "openssh-key-v1\0") {
                throw new \RuntimeException('Expected openssh-key-v1');
            }
            list($ciphername, $kdfname, $kdfoptions, $numKeys) = Strings::unpackSSH2('sssN', $key);
            if ($numKeys != 1) {
                // if we wanted to support multiple keys we could update PublicKeyLoader to preview what the # of keys
                // would be; it'd then call Common\Keys\OpenSSH.php::load() and get the paddedKey. it'd then pass
                // that to the appropriate key loading parser $numKey times or something
                throw new \RuntimeException('Although the OpenSSH private key format supports multiple keys phpseclib does not');
            }
            switch ($ciphername) {
                case 'none':
                    break;
                case 'aes256-ctr':
                    if ($kdfname != 'bcrypt') {
                        throw new \RuntimeException('Only the bcrypt kdf is supported (' . $kdfname . ' encountered)');
                    }
                    list($salt, $rounds) = Strings::unpackSSH2('sN', $kdfoptions);
                    $crypto = new AES('ctr');
                    //$crypto->setKeyLength(256);
                    //$crypto->disablePadding();
                    $crypto->setPassword($password, 'bcrypt', $salt, $rounds, 32);
                    break;
                default:
                    throw new \RuntimeException('The only supported ciphers are: none, aes256-ctr (' . $ciphername . ' is being used)');
            }

            list($publicKey, $paddedKey) = Strings::unpackSSH2('ss', $key);
            list($type) = Strings::unpackSSH2('s', $publicKey);
            if (isset($crypto)) {
                $paddedKey = $crypto->decrypt($paddedKey);
            }
            list($checkint1, $checkint2) = Strings::unpackSSH2('NN', $paddedKey);
            // any leftover bytes in $paddedKey are for padding? but they should be sequential bytes. eg. 1, 2, 3, etc.
            if ($checkint1 != $checkint2) {
                if (isset($crypto)) {
                    throw new BadDecryptionException('Unable to decrypt key - please verify the password you are using');
                }
                throw new \RuntimeException("The two checkints do not match ($checkint1 vs. $checkint2)");
            }
            self::checkType($type);

            return compact('type', 'publicKey', 'paddedKey');
        }

        $parts = preg_split("#[\t ]+#", $key, 3);

        if (!isset($parts[1])) {
            $key = base64_decode($parts[0]);
            $comment = false;
        } else {
            $asciiType = $parts[0];
            self::checkType($parts[0]);
            $key = base64_decode($parts[1]);
            $comment = isset($parts[2]) ? $parts[2] : false;
        }
        if ($key === false) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        list($type) = Strings::unpackSSH2('s', $key);
        self::checkType($type);
        if (isset($asciiType) && $asciiType != $type) {
            throw new \RuntimeException('Two different types of keys are claimed: ' . $asciiType . ' and ' . $type);
        }
        if (strlen($key) <= 4) {
            throw new \UnexpectedValueException('Key appears to be malformed');
        }

        $publicKey = $key;

        return compact('type', 'publicKey', 'comment');
    }

    /**
     * Toggle between binary and printable keys
     *
     * Printable keys are what are generated by default. These are the ones that go in
     * $HOME/.ssh/authorized_key.
     *
     * @param bool $enabled
     */
    public static function setBinaryOutput($enabled)
    {
        self::$binary = $enabled;
    }

    /**
     * Checks to see if the type is valid
     *
     * @param string $candidate
     */
    private static function checkType($candidate)
    {
        if (!in_array($candidate, static::$types)) {
            throw new \RuntimeException("The key type ($candidate) is not equal to: " . implode(',', static::$types));
        }
    }

    /**
     * Wrap a private key appropriately
     *
     * @param string $publicKey
     * @param string $privateKey
     * @param string $password
     * @param array $options
     * @return string
     */
    protected static function wrapPrivateKey($publicKey, $privateKey, $password, $options)
    {
        list(, $checkint) = unpack('N', Random::string(4));

        $comment = isset($options['comment']) ? $options['comment'] : self::$comment;
        $paddedKey = Strings::packSSH2('NN', $checkint, $checkint) .
                     $privateKey .
                     Strings::packSSH2('s', $comment);

        $usesEncryption = !empty($password) && is_string($password);

        /*
           from http://tools.ietf.org/html/rfc4253#section-6 :

           Note that the length of the concatenation of 'packet_length',
           'padding_length', 'payload', and 'random padding' MUST be a multiple
           of the cipher block size or 8, whichever is larger.
         */
        $blockSize = $usesEncryption ? 16 : 8;
        $paddingLength = (($blockSize - 1) * strlen($paddedKey)) % $blockSize;
        for ($i = 1; $i <= $paddingLength; $i++) {
            $paddedKey .= chr($i);
        }
        if (!$usesEncryption) {
            $key = Strings::packSSH2('sssNss', 'none', 'none', '', 1, $publicKey, $paddedKey);
        } else {
            $rounds = isset($options['rounds']) ? $options['rounds'] : 16;
            $salt = Random::string(16);
            $kdfoptions = Strings::packSSH2('sN', $salt, $rounds);
            $crypto = new AES('ctr');
            $crypto->setPassword($password, 'bcrypt', $salt, $rounds, 32);
            $paddedKey = $crypto->encrypt($paddedKey);
            $key = Strings::packSSH2('sssNss', 'aes256-ctr', 'bcrypt', $kdfoptions, 1, $publicKey, $paddedKey);
        }
        $key = "openssh-key-v1\0$key";

        return "-----BEGIN OPENSSH PRIVATE KEY-----\n" .
               chunk_split(Strings::base64_encode($key), 70, "\n") .
               "-----END OPENSSH PRIVATE KEY-----\n";
    }
}
<?php

/**
 * PuTTY Formatted Key Handler
 *
 * See PuTTY's SSHPUBK.C and https://tartarus.org/~simon/putty-snapshots/htmldoc/AppendixC.html
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\AES;
use phpseclib3\Crypt\Hash;
use phpseclib3\Crypt\Random;
use phpseclib3\Exception\UnsupportedAlgorithmException;

/**
 * PuTTY Formatted Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PuTTY
{
    /**
     * Default comment
     *
     * @var string
     */
    private static $comment = 'phpseclib-generated-key';

    /**
     * Default version
     *
     * @var int
     */
    private static $version = 2;

    /**
     * Sets the default comment
     *
     * @param string $comment
     */
    public static function setComment($comment)
    {
        self::$comment = str_replace(["\r", "\n"], '', $comment);
    }

    /**
     * Sets the default version
     *
     * @param int $version
     */
    public static function setVersion($version)
    {
        if ($version != 2 && $version != 3) {
            throw new \RuntimeException('Only supported versions are 2 and 3');
        }
        self::$version = $version;
    }

    /**
     * Generate a symmetric key for PuTTY v2 keys
     *
     * @param string $password
     * @param int $length
     * @return string
     */
    private static function generateV2Key($password, $length)
    {
        $symkey = '';
        $sequence = 0;
        while (strlen($symkey) < $length) {
            $temp = pack('Na*', $sequence++, $password);
            $symkey .= Strings::hex2bin(sha1($temp));
        }
        return substr($symkey, 0, $length);
    }

    /**
     * Generate a symmetric key for PuTTY v3 keys
     *
     * @param string $password
     * @param string $flavour
     * @param int $memory
     * @param int $passes
     * @param string $salt
     * @return array
     */
    private static function generateV3Key($password, $flavour, $memory, $passes, $salt)
    {
        if (!function_exists('sodium_crypto_pwhash')) {
            throw new \RuntimeException('sodium_crypto_pwhash needs to exist for Argon2 password hasing');
        }

        switch ($flavour) {
            case 'Argon2i':
                $flavour = SODIUM_CRYPTO_PWHASH_ALG_ARGON2I13;
                break;
            case 'Argon2id':
                $flavour = SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13;
                break;
            default:
                throw new UnsupportedAlgorithmException('Only Argon2i and Argon2id are supported');
        }

        $length = 80; // keylen + ivlen + mac_keylen
        $temp = sodium_crypto_pwhash($length, $password, $salt, $passes, $memory << 10, $flavour);

        $symkey = substr($temp, 0, 32);
        $symiv = substr($temp, 32, 16);
        $hashkey = substr($temp, -32);

        return compact('symkey', 'symiv', 'hashkey');
    }

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password
     * @return array
     */
    public static function load($key, $password)
    {
        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        if (strpos($key, 'BEGIN SSH2 PUBLIC KEY') !== false) {
            $lines = preg_split('#[\r\n]+#', $key);
            switch (true) {
                case $lines[0] != '---- BEGIN SSH2 PUBLIC KEY ----':
                    throw new \UnexpectedValueException('Key doesn\'t start with ---- BEGIN SSH2 PUBLIC KEY ----');
                case $lines[count($lines) - 1] != '---- END SSH2 PUBLIC KEY ----':
                    throw new \UnexpectedValueException('Key doesn\'t end with ---- END SSH2 PUBLIC KEY ----');
            }
            $lines = array_splice($lines, 1, -1);
            $lines = array_map(function ($line) {
                return rtrim($line, "\r\n");
            }, $lines);
            $data = $current = '';
            $values = [];
            $in_value = false;
            foreach ($lines as $line) {
                switch (true) {
                    case preg_match('#^(.*?): (.*)#', $line, $match):
                        $in_value = $line[strlen($line) - 1] == '\\';
                        $current = strtolower($match[1]);
                        $values[$current] = $in_value ? substr($match[2], 0, -1) : $match[2];
                        break;
                    case $in_value:
                        $in_value = $line[strlen($line) - 1] == '\\';
                        $values[$current] .= $in_value ? substr($line, 0, -1) : $line;
                        break;
                    default:
                        $data .= $line;
                }
            }

            $components = call_user_func([static::PUBLIC_HANDLER, 'load'], $data);
            if ($components === false) {
                throw new \UnexpectedValueException('Unable to decode public key');
            }
            $components += $values;
            $components['comment'] = str_replace(['\\\\', '\"'], ['\\', '"'], $values['comment']);

            return $components;
        }

        $components = [];

        $key = preg_split('#\r\n|\r|\n#', trim($key));
        if (Strings::shift($key[0], strlen('PuTTY-User-Key-File-')) != 'PuTTY-User-Key-File-') {
            return false;
        }
        $version = (int) Strings::shift($key[0], 3); // should be either "2: " or "3: 0" prior to int casting
        if ($version != 2 && $version != 3) {
            throw new \RuntimeException('Only v2 and v3 PuTTY private keys are supported');
        }
        $components['type'] = $type = rtrim($key[0]);
        if (!in_array($type, static::$types)) {
            $error = count(static::$types) == 1 ?
                'Only ' . static::$types[0] . ' keys are supported. ' :
                '';
            throw new UnsupportedAlgorithmException($error . 'This is an unsupported ' . $type . ' key');
        }
        $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
        $components['comment'] = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));

        $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
        $public = Strings::base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));

        $source = Strings::packSSH2('ssss', $type, $encryption, $components['comment'], $public);

        $length = unpack('Nlength', Strings::shift($public, 4))['length'];
        $newtype = Strings::shift($public, $length);
        if ($newtype != $type) {
            throw new \RuntimeException('The binary type does not match the human readable type field');
        }

        $components['public'] = $public;

        switch ($version) {
            case 3:
                $hashkey = '';
                break;
            case 2:
                $hashkey = 'putty-private-key-file-mac-key';
        }

        $offset = $publicLength + 4;
        switch ($encryption) {
            case 'aes256-cbc':
                $crypto = new AES('cbc');
                switch ($version) {
                    case 3:
                        $flavour = trim(preg_replace('#Key-Derivation: (.*)#', '$1', $key[$offset++]));
                        $memory = trim(preg_replace('#Argon2-Memory: (\d+)#', '$1', $key[$offset++]));
                        $passes = trim(preg_replace('#Argon2-Passes: (\d+)#', '$1', $key[$offset++]));
                        $parallelism = trim(preg_replace('#Argon2-Parallelism: (\d+)#', '$1', $key[$offset++]));
                        $salt = Strings::hex2bin(trim(preg_replace('#Argon2-Salt: ([0-9a-f]+)#', '$1', $key[$offset++])));

                        $v3key = self::generateV3Key($password, $flavour, $memory, $passes, $salt);
                        $symkey = $v3key['symkey'];
                        $symiv = $v3key['symiv'];
                        $hashkey = $v3key['hashkey'];

                        break;
                    case 2:
                        $symkey = self::generateV2Key($password, 32);
                        $symiv = str_repeat("\0", $crypto->getBlockLength() >> 3);
                        $hashkey .= $password;
                }
        }

        switch ($version) {
            case 3:
                $hash = new Hash('sha256');
                $hash->setKey($hashkey);
                break;
            case 2:
                $hash = new Hash('sha1');
                $hash->setKey(sha1($hashkey, true));
        }

        $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$offset++]));
        $private = Strings::base64_decode(implode('', array_map('trim', array_slice($key, $offset, $privateLength))));

        if ($encryption != 'none') {
            $crypto->setKey($symkey);
            $crypto->setIV($symiv);
            $crypto->disablePadding();
            $private = $crypto->decrypt($private);
        }

        $source .= Strings::packSSH2('s', $private);

        $hmac = trim(preg_replace('#Private-MAC: (.+)#', '$1', $key[$offset + $privateLength]));
        $hmac = Strings::hex2bin($hmac);

        if (!hash_equals($hash->hash($source), $hmac)) {
            throw new \UnexpectedValueException('MAC validation error');
        }

        $components['private'] = $private;

        return $components;
    }

    /**
     * Wrap a private key appropriately
     *
     * @param string $public
     * @param string $private
     * @param string $type
     * @param string $password
     * @param array $options optional
     * @return string
     */
    protected static function wrapPrivateKey($public, $private, $type, $password, array $options = [])
    {
        $encryption = (!empty($password) || is_string($password)) ? 'aes256-cbc' : 'none';
        $comment = isset($options['comment']) ? $options['comment'] : self::$comment;
        $version = isset($options['version']) ? $options['version'] : self::$version;

        $key = "PuTTY-User-Key-File-$version: $type\r\n";
        $key .= "Encryption: $encryption\r\n";
        $key .= "Comment: $comment\r\n";

        $public = Strings::packSSH2('s', $type) . $public;

        $source = Strings::packSSH2('ssss', $type, $encryption, $comment, $public);

        $public = Strings::base64_encode($public);
        $key .= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
        $key .= chunk_split($public, 64);

        if (empty($password) && !is_string($password)) {
            $source .= Strings::packSSH2('s', $private);
            switch ($version) {
                case 3:
                    $hash = new Hash('sha256');
                    $hash->setKey('');
                    break;
                case 2:
                    $hash = new Hash('sha1');
                    $hash->setKey(sha1('putty-private-key-file-mac-key', true));
            }
        } else {
            $private .= Random::string(16 - (strlen($private) & 15));
            $source .= Strings::packSSH2('s', $private);
            $crypto = new AES('cbc');

            switch ($version) {
                case 3:
                    $salt = Random::string(16);
                    $key .= "Key-Derivation: Argon2id\r\n";
                    $key .= "Argon2-Memory: 8192\r\n";
                    $key .= "Argon2-Passes: 13\r\n";
                    $key .= "Argon2-Parallelism: 1\r\n";
                    $key .= "Argon2-Salt: " . Strings::bin2hex($salt) . "\r\n";
                    $v3key = self::generateV3Key($password, 'Argon2id', 8192, 13, $salt);
                    $symkey = $v3key['symkey'];
                    $symiv = $v3key['symiv'];
                    $hashkey = $v3key['hashkey'];

                    $hash = new Hash('sha256');
                    $hash->setKey($hashkey);

                    break;
                case 2:
                    $symkey = self::generateV2Key($password, 32);
                    $symiv = str_repeat("\0", $crypto->getBlockLength() >> 3);
                    $hashkey = 'putty-private-key-file-mac-key' . $password;

                    $hash = new Hash('sha1');
                    $hash->setKey(sha1($hashkey, true));
            }

            $crypto->setKey($symkey);
            $crypto->setIV($symiv);
            $crypto->disablePadding();
            $private = $crypto->encrypt($private);
            $mac = $hash->hash($source);
        }

        $private = Strings::base64_encode($private);
        $key .= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
        $key .= chunk_split($private, 64);
        $key .= 'Private-MAC: ' . Strings::bin2hex($hash->hash($source)) . "\r\n";

        return $key;
    }

    /**
     * Wrap a public key appropriately
     *
     * This is basically the format described in RFC 4716 (https://tools.ietf.org/html/rfc4716)
     *
     * @param string $key
     * @param string $type
     * @return string
     */
    protected static function wrapPublicKey($key, $type)
    {
        $key = pack('Na*a*', strlen($type), $type, $key);
        $key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" .
               'Comment: "' . str_replace(['\\', '"'], ['\\\\', '\"'], self::$comment) . "\"\r\n" .
               chunk_split(Strings::base64_encode($key), 64) .
               '---- END SSH2 PUBLIC KEY ----';
        return $key;
    }
}
<?php

/**
 * PKCS1 Formatted Key Handler
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\AES;
use phpseclib3\Crypt\DES;
use phpseclib3\Crypt\Random;
use phpseclib3\Crypt\TripleDES;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\File\ASN1;

/**
 * PKCS1 Formatted Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS1 extends PKCS
{
    /**
     * Default encryption algorithm
     *
     * @var string
     */
    private static $defaultEncryptionAlgorithm = 'AES-128-CBC';

    /**
     * Sets the default encryption algorithm
     *
     * @param string $algo
     */
    public static function setEncryptionAlgorithm($algo)
    {
        self::$defaultEncryptionAlgorithm = $algo;
    }

    /**
     * Returns the mode constant corresponding to the mode string
     *
     * @param string $mode
     * @return int
     * @throws \UnexpectedValueException if the block cipher mode is unsupported
     */
    private static function getEncryptionMode($mode)
    {
        switch ($mode) {
            case 'CBC':
            case 'ECB':
            case 'CFB':
            case 'OFB':
            case 'CTR':
                return $mode;
        }
        throw new \UnexpectedValueException('Unsupported block cipher mode of operation');
    }

    /**
     * Returns a cipher object corresponding to a string
     *
     * @param string $algo
     * @return string
     * @throws \UnexpectedValueException if the encryption algorithm is unsupported
     */
    private static function getEncryptionObject($algo)
    {
        $modes = '(CBC|ECB|CFB|OFB|CTR)';
        switch (true) {
            case preg_match("#^AES-(128|192|256)-$modes$#", $algo, $matches):
                $cipher = new AES(self::getEncryptionMode($matches[2]));
                $cipher->setKeyLength($matches[1]);
                return $cipher;
            case preg_match("#^DES-EDE3-$modes$#", $algo, $matches):
                return new TripleDES(self::getEncryptionMode($matches[1]));
            case preg_match("#^DES-$modes$#", $algo, $matches):
                return new DES(self::getEncryptionMode($matches[1]));
            default:
                throw new UnsupportedAlgorithmException($algo . ' is not a supported algorithm');
        }
    }

    /**
     * Generate a symmetric key for PKCS#1 keys
     *
     * @param string $password
     * @param string $iv
     * @param int $length
     * @return string
     */
    private static function generateSymmetricKey($password, $iv, $length)
    {
        $symkey = '';
        $iv = substr($iv, 0, 8);
        while (strlen($symkey) < $length) {
            $symkey .= md5($symkey . $password . $iv, true);
        }
        return substr($symkey, 0, $length);
    }

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    protected static function load($key, $password)
    {
        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
           "outside the scope" of PKCS#1.  PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
           protect private keys, however, that's not what OpenSSL* does.  OpenSSL protects private keys by adding
           two new "fields" to the key - DEK-Info and Proc-Type.  These fields are discussed here:

           http://tools.ietf.org/html/rfc1421#section-4.6.1.1
           http://tools.ietf.org/html/rfc1421#section-4.6.1.3

           DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
           DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
           function.  As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
           own implementation.  ie. the implementation *is* the standard and any bugs that may exist in that
           implementation are part of the standard, as well.

           * OpenSSL is the de facto standard.  It's utilized by OpenSSH and other projects */
        if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
            $iv = Strings::hex2bin(trim($matches[2]));
            // remove the Proc-Type / DEK-Info sections as they're no longer needed
            $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
            $ciphertext = ASN1::extractBER($key);
            if ($ciphertext === false) {
                $ciphertext = $key;
            }
            $crypto = self::getEncryptionObject($matches[1]);
            $crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3));
            $crypto->setIV($iv);
            $key = $crypto->decrypt($ciphertext);
        } else {
            if (self::$format != self::MODE_DER) {
                $decoded = ASN1::extractBER($key);
                if ($decoded !== false) {
                    $key = $decoded;
                } elseif (self::$format == self::MODE_PEM) {
                    throw new \UnexpectedValueException('Expected base64-encoded PEM format but was unable to decode base64 text');
                }
            }
        }

        return $key;
    }

    /**
     * Wrap a private key appropriately
     *
     * @param string $key
     * @param string $type
     * @param string $password
     * @param array $options optional
     * @return string
     */
    protected static function wrapPrivateKey($key, $type, $password, array $options = [])
    {
        if (empty($password) || !is_string($password)) {
            return "-----BEGIN $type PRIVATE KEY-----\r\n" .
                   chunk_split(Strings::base64_encode($key), 64) .
                   "-----END $type PRIVATE KEY-----";
        }

        $encryptionAlgorithm = isset($options['encryptionAlgorithm']) ? $options['encryptionAlgorithm'] : self::$defaultEncryptionAlgorithm;

        $cipher = self::getEncryptionObject($encryptionAlgorithm);
        $iv = Random::string($cipher->getBlockLength() >> 3);
        $cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3));
        $cipher->setIV($iv);
        $iv = strtoupper(Strings::bin2hex($iv));
        return "-----BEGIN $type PRIVATE KEY-----\r\n" .
               "Proc-Type: 4,ENCRYPTED\r\n" .
               "DEK-Info: " . $encryptionAlgorithm . ",$iv\r\n" .
               "\r\n" .
               chunk_split(Strings::base64_encode($cipher->encrypt($key)), 64) .
               "-----END $type PRIVATE KEY-----";
    }

    /**
     * Wrap a public key appropriately
     *
     * @param string $key
     * @param string $type
     * @return string
     */
    protected static function wrapPublicKey($key, $type)
    {
        return "-----BEGIN $type PUBLIC KEY-----\r\n" .
               chunk_split(Strings::base64_encode($key), 64) .
               "-----END $type PUBLIC KEY-----";
    }
}
<?php

/**
 * PKCS Formatted Key Handler
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common\Formats\Keys;

/**
 * PKCS1 Formatted Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS
{
    /**
     * Auto-detect the format
     */
    const MODE_ANY = 0;
    /**
     * Require base64-encoded PEM's be supplied
     */
    const MODE_PEM = 1;
    /**
     * Require raw DER's be supplied
     */
    const MODE_DER = 2;
    /**#@-*/

    /**
     * Is the key a base-64 encoded PEM, DER or should it be auto-detected?
     *
     * @var int
     */
    protected static $format = self::MODE_ANY;

    /**
     * Require base64-encoded PEM's be supplied
     *
     */
    public static function requirePEM()
    {
        self::$format = self::MODE_PEM;
    }

    /**
     * Require raw DER's be supplied
     *
     */
    public static function requireDER()
    {
        self::$format = self::MODE_DER;
    }

    /**
     * Accept any format and auto detect the format
     *
     * This is the default setting
     *
     */
    public static function requireAny()
    {
        self::$format = self::MODE_ANY;
    }
}
<?php

/**
 * PKCS#8 Formatted Key Handler
 *
 * PHP version 5
 *
 * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
 *
 * Processes keys with the following headers:
 *
 * -----BEGIN ENCRYPTED PRIVATE KEY-----
 * -----BEGIN PRIVATE KEY-----
 * -----BEGIN PUBLIC KEY-----
 *
 * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
 * is specific to private keys it's basically creating a DER-encoded wrapper
 * for keys. This just extends that same concept to public keys (much like ssh-keygen)
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\AES;
use phpseclib3\Crypt\DES;
use phpseclib3\Crypt\Random;
use phpseclib3\Crypt\RC2;
use phpseclib3\Crypt\RC4;
use phpseclib3\Crypt\TripleDES;
use phpseclib3\Exception\InsufficientSetupException;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;

/**
 * PKCS#8 Formatted Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS8 extends PKCS
{
    /**
     * Default encryption algorithm
     *
     * @var string
     */
    private static $defaultEncryptionAlgorithm = 'id-PBES2';

    /**
     * Default encryption scheme
     *
     * Only used when defaultEncryptionAlgorithm is id-PBES2
     *
     * @var string
     */
    private static $defaultEncryptionScheme = 'aes128-CBC-PAD';

    /**
     * Default PRF
     *
     * Only used when defaultEncryptionAlgorithm is id-PBES2
     *
     * @var string
     */
    private static $defaultPRF = 'id-hmacWithSHA256';

    /**
     * Default Iteration Count
     *
     * @var int
     */
    private static $defaultIterationCount = 2048;

    /**
     * OIDs loaded
     *
     * @var bool
     */
    private static $oidsLoaded = false;

    /**
     * Binary key flag
     *
     * @var bool
     */
    private static $binary = false;

    /**
     * Sets the default encryption algorithm
     *
     * @param string $algo
     */
    public static function setEncryptionAlgorithm($algo)
    {
        self::$defaultEncryptionAlgorithm = $algo;
    }

    /**
     * Sets the default encryption algorithm for PBES2
     *
     * @param string $algo
     */
    public static function setEncryptionScheme($algo)
    {
        self::$defaultEncryptionScheme = $algo;
    }

    /**
     * Sets the iteration count
     *
     * @param int $count
     */
    public static function setIterationCount($count)
    {
        self::$defaultIterationCount = $count;
    }

    /**
     * Sets the PRF for PBES2
     *
     * @param string $algo
     */
    public static function setPRF($algo)
    {
        self::$defaultPRF = $algo;
    }

    /**
     * Returns a SymmetricKey object based on a PBES1 $algo
     *
     * @return \phpseclib3\Crypt\Common\SymmetricKey
     * @param string $algo
     */
    private static function getPBES1EncryptionObject($algo)
    {
        $algo = preg_match('#^pbeWith(?:MD2|MD5|SHA1|SHA)And(.*?)-CBC$#', $algo, $matches) ?
            $matches[1] :
            substr($algo, 13); // strlen('pbeWithSHAAnd') == 13

        switch ($algo) {
            case 'DES':
                $cipher = new DES('cbc');
                break;
            case 'RC2':
                $cipher = new RC2('cbc');
                $cipher->setKeyLength(64);
                break;
            case '3-KeyTripleDES':
                $cipher = new TripleDES('cbc');
                break;
            case '2-KeyTripleDES':
                $cipher = new TripleDES('cbc');
                $cipher->setKeyLength(128);
                break;
            case '128BitRC2':
                $cipher = new RC2('cbc');
                $cipher->setKeyLength(128);
                break;
            case '40BitRC2':
                $cipher = new RC2('cbc');
                $cipher->setKeyLength(40);
                break;
            case '128BitRC4':
                $cipher = new RC4();
                $cipher->setKeyLength(128);
                break;
            case '40BitRC4':
                $cipher = new RC4();
                $cipher->setKeyLength(40);
                break;
            default:
                throw new UnsupportedAlgorithmException("$algo is not a supported algorithm");
        }

        return $cipher;
    }

    /**
     * Returns a hash based on a PBES1 $algo
     *
     * @return string
     * @param string $algo
     */
    private static function getPBES1Hash($algo)
    {
        if (preg_match('#^pbeWith(MD2|MD5|SHA1|SHA)And.*?-CBC$#', $algo, $matches)) {
            return $matches[1] == 'SHA' ? 'sha1' : $matches[1];
        }

        return 'sha1';
    }

    /**
     * Returns a KDF baesd on a PBES1 $algo
     *
     * @return string
     * @param string $algo
     */
    private static function getPBES1KDF($algo)
    {
        switch ($algo) {
            case 'pbeWithMD2AndDES-CBC':
            case 'pbeWithMD2AndRC2-CBC':
            case 'pbeWithMD5AndDES-CBC':
            case 'pbeWithMD5AndRC2-CBC':
            case 'pbeWithSHA1AndDES-CBC':
            case 'pbeWithSHA1AndRC2-CBC':
                return 'pbkdf1';
        }

        return 'pkcs12';
    }

    /**
     * Returns a SymmetricKey object baesd on a PBES2 $algo
     *
     * @return SymmetricKey
     * @param string $algo
     */
    private static function getPBES2EncryptionObject($algo)
    {
        switch ($algo) {
            case 'desCBC':
                $cipher = new DES('cbc');
                break;
            case 'des-EDE3-CBC':
                $cipher = new TripleDES('cbc');
                break;
            case 'rc2CBC':
                $cipher = new RC2('cbc');
                // in theory this can be changed
                $cipher->setKeyLength(128);
                break;
            case 'rc5-CBC-PAD':
                throw new UnsupportedAlgorithmException('rc5-CBC-PAD is not supported for PBES2 PKCS#8 keys');
            case 'aes128-CBC-PAD':
            case 'aes192-CBC-PAD':
            case 'aes256-CBC-PAD':
                $cipher = new AES('cbc');
                $cipher->setKeyLength(substr($algo, 3, 3));
                break;
            default:
                throw new UnsupportedAlgorithmException("$algo is not supported");
        }

        return $cipher;
    }

    /**
     * Initialize static variables
     *
     */
    private static function initialize_static_variables()
    {
        if (!isset(static::$childOIDsLoaded)) {
            throw new InsufficientSetupException('This class should not be called directly');
        }

        if (!static::$childOIDsLoaded) {
            ASN1::loadOIDs(is_array(static::OID_NAME) ?
                array_combine(static::OID_NAME, static::OID_VALUE) :
                [static::OID_NAME => static::OID_VALUE]);
            static::$childOIDsLoaded = true;
        }
        if (!self::$oidsLoaded) {
            // from https://tools.ietf.org/html/rfc2898
            ASN1::loadOIDs([
               // PBES1 encryption schemes
               'pbeWithMD2AndDES-CBC' => '1.2.840.113549.1.5.1',
               'pbeWithMD2AndRC2-CBC' => '1.2.840.113549.1.5.4',
               'pbeWithMD5AndDES-CBC' => '1.2.840.113549.1.5.3',
               'pbeWithMD5AndRC2-CBC' => '1.2.840.113549.1.5.6',
               'pbeWithSHA1AndDES-CBC' => '1.2.840.113549.1.5.10',
               'pbeWithSHA1AndRC2-CBC' => '1.2.840.113549.1.5.11',

               // from PKCS#12:
               // https://tools.ietf.org/html/rfc7292
               'pbeWithSHAAnd128BitRC4' => '1.2.840.113549.1.12.1.1',
               'pbeWithSHAAnd40BitRC4' => '1.2.840.113549.1.12.1.2',
               'pbeWithSHAAnd3-KeyTripleDES-CBC' => '1.2.840.113549.1.12.1.3',
               'pbeWithSHAAnd2-KeyTripleDES-CBC' => '1.2.840.113549.1.12.1.4',
               'pbeWithSHAAnd128BitRC2-CBC' => '1.2.840.113549.1.12.1.5',
               'pbeWithSHAAnd40BitRC2-CBC' => '1.2.840.113549.1.12.1.6',

               'id-PBKDF2' => '1.2.840.113549.1.5.12',
               'id-PBES2' => '1.2.840.113549.1.5.13',
               'id-PBMAC1' => '1.2.840.113549.1.5.14',

               // from PKCS#5 v2.1:
               // http://www.rsa.com/rsalabs/pkcs/files/h11302-wp-pkcs5v2-1-password-based-cryptography-standard.pdf
               'id-hmacWithSHA1' => '1.2.840.113549.2.7',
               'id-hmacWithSHA224' => '1.2.840.113549.2.8',
               'id-hmacWithSHA256' => '1.2.840.113549.2.9',
               'id-hmacWithSHA384' => '1.2.840.113549.2.10',
               'id-hmacWithSHA512' => '1.2.840.113549.2.11',
               'id-hmacWithSHA512-224' => '1.2.840.113549.2.12',
               'id-hmacWithSHA512-256' => '1.2.840.113549.2.13',

               'desCBC'       => '1.3.14.3.2.7',
               'des-EDE3-CBC' => '1.2.840.113549.3.7',
               'rc2CBC' => '1.2.840.113549.3.2',
               'rc5-CBC-PAD' => '1.2.840.113549.3.9',

               'aes128-CBC-PAD' => '2.16.840.1.101.3.4.1.2',
               'aes192-CBC-PAD' => '2.16.840.1.101.3.4.1.22',
               'aes256-CBC-PAD' => '2.16.840.1.101.3.4.1.42'
            ]);
            self::$oidsLoaded = true;
        }
    }

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    protected static function load($key, $password = '')
    {
        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        $isPublic = strpos($key, 'PUBLIC') !== false;
        $isPrivate = strpos($key, 'PRIVATE') !== false;

        $decoded = self::preParse($key);

        $meta = [];

        $decrypted = ASN1::asn1map($decoded[0], Maps\EncryptedPrivateKeyInfo::MAP);
        if (strlen($password) && is_array($decrypted)) {
            $algorithm = $decrypted['encryptionAlgorithm']['algorithm'];
            switch ($algorithm) {
                // PBES1
                case 'pbeWithMD2AndDES-CBC':
                case 'pbeWithMD2AndRC2-CBC':
                case 'pbeWithMD5AndDES-CBC':
                case 'pbeWithMD5AndRC2-CBC':
                case 'pbeWithSHA1AndDES-CBC':
                case 'pbeWithSHA1AndRC2-CBC':
                case 'pbeWithSHAAnd3-KeyTripleDES-CBC':
                case 'pbeWithSHAAnd2-KeyTripleDES-CBC':
                case 'pbeWithSHAAnd128BitRC2-CBC':
                case 'pbeWithSHAAnd40BitRC2-CBC':
                case 'pbeWithSHAAnd128BitRC4':
                case 'pbeWithSHAAnd40BitRC4':
                    $cipher = self::getPBES1EncryptionObject($algorithm);
                    $hash = self::getPBES1Hash($algorithm);
                    $kdf = self::getPBES1KDF($algorithm);

                    $meta['meta']['algorithm'] = $algorithm;

                    $temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
                    if (!$temp) {
                        throw new \RuntimeException('Unable to decode BER');
                    }
                    $map = ASN1::asn1map($temp[0], Maps\PBEParameter::MAP);
                    $salt = $map['salt'];
                    $iterationCount = $map['iterationCount'];
                    $iterationCount = (int) $iterationCount->toString();
                    $cipher->setPassword($password, $kdf, $hash, $salt, $iterationCount);
                    $key = $cipher->decrypt($decrypted['encryptedData']);
                    $decoded = ASN1::decodeBER($key);
                    if (!$decoded) {
                        throw new \RuntimeException('Unable to decode BER 2');
                    }

                    break;
                case 'id-PBES2':
                    $meta['meta']['algorithm'] = $algorithm;

                    $temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
                    if (!$temp) {
                        throw new \RuntimeException('Unable to decode BER');
                    }
                    $temp = ASN1::asn1map($temp[0], Maps\PBES2params::MAP);
                    $keyDerivationFunc = $temp['keyDerivationFunc'];
                    $encryptionScheme = $temp['encryptionScheme'];

                    $cipher = self::getPBES2EncryptionObject($encryptionScheme['algorithm']);
                    $meta['meta']['cipher'] = $encryptionScheme['algorithm'];

                    $temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
                    if (!$temp) {
                        throw new \RuntimeException('Unable to decode BER');
                    }
                    $temp = ASN1::asn1map($temp[0], Maps\PBES2params::MAP);
                    $keyDerivationFunc = $temp['keyDerivationFunc'];
                    $encryptionScheme = $temp['encryptionScheme'];

                    if (!$cipher instanceof RC2) {
                        $cipher->setIV($encryptionScheme['parameters']['octetString']);
                    } else {
                        $temp = ASN1::decodeBER($encryptionScheme['parameters']);
                        if (!$temp) {
                            throw new \RuntimeException('Unable to decode BER');
                        }
                        $map = ASN1::asn1map($temp[0], Maps\RC2CBCParameter::MAP);
                        $rc2ParametersVersion = $map['rc2ParametersVersion'];
                        $iv = $map['iv'];
                        $effectiveKeyLength = (int) $rc2ParametersVersion->toString();
                        switch ($effectiveKeyLength) {
                            case 160:
                                $effectiveKeyLength = 40;
                                break;
                            case 120:
                                $effectiveKeyLength = 64;
                                break;
                            case 58:
                                $effectiveKeyLength = 128;
                                break;
                            //default: // should be >= 256
                        }
                        $cipher->setIV($iv);
                        $cipher->setKeyLength($effectiveKeyLength);
                    }

                    $meta['meta']['keyDerivationFunc'] = $keyDerivationFunc['algorithm'];
                    switch ($keyDerivationFunc['algorithm']) {
                        case 'id-PBKDF2':
                            $temp = ASN1::decodeBER($keyDerivationFunc['parameters']);
                            if (!$temp) {
                                throw new \RuntimeException('Unable to decode BER');
                            }
                            $params = ASN1::asn1map($temp[0], Maps\PBKDF2params::MAP);
                            if (empty($params['prf'])) {
                                $params['prf'] = ['algorithm' => 'id-hmacWithSHA1'];
                            }
                            $salt = $params['salt'];
                            $iterationCount = $params['iterationCount'];
                            $prf = $params['prf'];
                            $meta['meta']['prf'] = $prf['algorithm'];
                            $hash = str_replace('-', '/', substr($prf['algorithm'], 11));
                            $params = [
                                $password,
                                'pbkdf2',
                                $hash,
                                $salt,
                                (int) $iterationCount->toString()
                            ];
                            if (isset($keyLength)) {
                                $params[] = (int) $keyLength->toString();
                            }
                            $cipher->setPassword(...$params);
                            $key = $cipher->decrypt($decrypted['encryptedData']);
                            $decoded = ASN1::decodeBER($key);
                            if (!$decoded) {
                                throw new \RuntimeException('Unable to decode BER 3');
                            }
                            break;
                        default:
                            throw new UnsupportedAlgorithmException('Only PBKDF2 is supported for PBES2 PKCS#8 keys');
                    }
                    break;
                case 'id-PBMAC1':
                    //$temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
                    //$value = ASN1::asn1map($temp[0], Maps\PBMAC1params::MAP);
                    // since i can't find any implementation that does PBMAC1 it is unsupported
                    throw new UnsupportedAlgorithmException('Only PBES1 and PBES2 PKCS#8 keys are supported.');
                // at this point we'll assume that the key conforms to PublicKeyInfo
            }
        }

        $private = ASN1::asn1map($decoded[0], Maps\OneAsymmetricKey::MAP);
        if (is_array($private)) {
            if ($isPublic) {
                throw new \UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key');
            }

            if (isset($private['privateKeyAlgorithm']['parameters']) && !$private['privateKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][1]['content'][1])) {
                $temp = $decoded[0]['content'][1]['content'][1];
                $private['privateKeyAlgorithm']['parameters'] = new ASN1\Element(substr($key, $temp['start'], $temp['length']));
            }
            if (is_array(static::OID_NAME)) {
                if (!in_array($private['privateKeyAlgorithm']['algorithm'], static::OID_NAME)) {
                    throw new UnsupportedAlgorithmException($private['privateKeyAlgorithm']['algorithm'] . ' is not a supported key type');
                }
            } else {
                if ($private['privateKeyAlgorithm']['algorithm'] != static::OID_NAME) {
                    throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $private['privateKeyAlgorithm']['algorithm'] . ' key');
                }
            }
            if (isset($private['publicKey'])) {
                if ($private['publicKey'][0] != "\0") {
                    throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($private['publicKey'][0]));
                }
                $private['publicKey'] = substr($private['publicKey'], 1);
            }
            return $private + $meta;
        }

        // EncryptedPrivateKeyInfo and PublicKeyInfo have largely identical "signatures". the only difference
        // is that the former has an octet string and the later has a bit string. the first byte of a bit
        // string represents the number of bits in the last byte that are to be ignored but, currently,
        // bit strings wanting a non-zero amount of bits trimmed are not supported
        $public = ASN1::asn1map($decoded[0], Maps\PublicKeyInfo::MAP);

        if (is_array($public)) {
            if ($isPrivate) {
                throw new \UnexpectedValueException('Human readable string claims private key but DER encoded string claims public key');
            }

            if ($public['publicKey'][0] != "\0") {
                throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($public['publicKey'][0]));
            }
            if (is_array(static::OID_NAME)) {
                if (!in_array($public['publicKeyAlgorithm']['algorithm'], static::OID_NAME)) {
                    throw new UnsupportedAlgorithmException($public['publicKeyAlgorithm']['algorithm'] . ' is not a supported key type');
                }
            } else {
                if ($public['publicKeyAlgorithm']['algorithm'] != static::OID_NAME) {
                    throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $public['publicKeyAlgorithm']['algorithm'] . ' key');
                }
            }
            if (isset($public['publicKeyAlgorithm']['parameters']) && !$public['publicKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][0]['content'][1])) {
                $temp = $decoded[0]['content'][0]['content'][1];
                $public['publicKeyAlgorithm']['parameters'] = new ASN1\Element(substr($key, $temp['start'], $temp['length']));
            }
            $public['publicKey'] = substr($public['publicKey'], 1);
            return $public;
        }

        throw new \RuntimeException('Unable to parse using either OneAsymmetricKey or PublicKeyInfo ASN1 maps');
    }

    /**
     * Toggle between binary (DER) and printable (PEM) keys
     *
     * Printable keys are what are generated by default.
     *
     * @param bool $enabled
     */
    public static function setBinaryOutput($enabled)
    {
        self::$binary = $enabled;
    }

    /**
     * Wrap a private key appropriately
     *
     * @param string $key
     * @param string $attr
     * @param mixed $params
     * @param string $password
     * @param string $oid optional
     * @param string $publicKey optional
     * @param array $options optional
     * @return string
     */
    protected static function wrapPrivateKey($key, $attr, $params, $password, $oid = null, $publicKey = '', array $options = [])
    {
        self::initialize_static_variables();

        $key = [
            'version' => 'v1',
            'privateKeyAlgorithm' => [
                'algorithm' => is_string(static::OID_NAME) ? static::OID_NAME : $oid
             ],
            'privateKey' => $key
        ];
        if ($oid != 'id-Ed25519' && $oid != 'id-Ed448' && $oid != 'id-X25519' && $oid != 'id-X448') {
            $key['privateKeyAlgorithm']['parameters'] = $params;
        }
        if (!empty($attr)) {
            $key['attributes'] = $attr;
        }
        if (!empty($publicKey)) {
            $key['version'] = 'v2';
            $key['publicKey'] = $publicKey;
        }
        $key = ASN1::encodeDER($key, Maps\OneAsymmetricKey::MAP);
        if (!empty($password) && is_string($password)) {
            $salt = Random::string(8);

            $iterationCount = isset($options['iterationCount']) ? $options['iterationCount'] : self::$defaultIterationCount;
            $encryptionAlgorithm = isset($options['encryptionAlgorithm']) ? $options['encryptionAlgorithm'] : self::$defaultEncryptionAlgorithm;
            $encryptionScheme = isset($options['encryptionScheme']) ? $options['encryptionScheme'] : self::$defaultEncryptionScheme;
            $prf = isset($options['PRF']) ? $options['PRF'] : self::$defaultPRF;

            if ($encryptionAlgorithm == 'id-PBES2') {
                $crypto = self::getPBES2EncryptionObject($encryptionScheme);
                $hash = str_replace('-', '/', substr($prf, 11));
                $kdf = 'pbkdf2';
                $iv = Random::string($crypto->getBlockLength() >> 3);

                $PBKDF2params = [
                    'salt' => $salt,
                    'iterationCount' => $iterationCount,
                    'prf' => ['algorithm' => $prf, 'parameters' => null]
                ];
                $PBKDF2params = ASN1::encodeDER($PBKDF2params, Maps\PBKDF2params::MAP);

                if (!$crypto instanceof RC2) {
                    $params = ['octetString' => $iv];
                } else {
                    $params = [
                        'rc2ParametersVersion' => 58,
                        'iv' => $iv
                    ];
                    $params = ASN1::encodeDER($params, Maps\RC2CBCParameter::MAP);
                    $params = new ASN1\Element($params);
                }

                $params = [
                    'keyDerivationFunc' => [
                        'algorithm' => 'id-PBKDF2',
                        'parameters' => new ASN1\Element($PBKDF2params)
                    ],
                    'encryptionScheme' => [
                        'algorithm' => $encryptionScheme,
                        'parameters' => $params
                    ]
                ];
                $params = ASN1::encodeDER($params, Maps\PBES2params::MAP);

                $crypto->setIV($iv);
            } else {
                $crypto = self::getPBES1EncryptionObject($encryptionAlgorithm);
                $hash = self::getPBES1Hash($encryptionAlgorithm);
                $kdf = self::getPBES1KDF($encryptionAlgorithm);

                $params = [
                    'salt' => $salt,
                    'iterationCount' => $iterationCount
                ];
                $params = ASN1::encodeDER($params, Maps\PBEParameter::MAP);
            }
            $crypto->setPassword($password, $kdf, $hash, $salt, $iterationCount);
            $key = $crypto->encrypt($key);

            $key = [
                'encryptionAlgorithm' => [
                    'algorithm' => $encryptionAlgorithm,
                    'parameters' => new ASN1\Element($params)
                ],
                'encryptedData' => $key
            ];

            $key = ASN1::encodeDER($key, Maps\EncryptedPrivateKeyInfo::MAP);

            if (isset($options['binary']) ? $options['binary'] : self::$binary) {
                return $key;
            }

            return "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
                   chunk_split(Strings::base64_encode($key), 64) .
                   "-----END ENCRYPTED PRIVATE KEY-----";
        }

        if (isset($options['binary']) ? $options['binary'] : self::$binary) {
            return $key;
        }

        return "-----BEGIN PRIVATE KEY-----\r\n" .
               chunk_split(Strings::base64_encode($key), 64) .
               "-----END PRIVATE KEY-----";
    }

    /**
     * Wrap a public key appropriately
     *
     * @param string $key
     * @param mixed $params
     * @param string $oid
     * @return string
     */
    protected static function wrapPublicKey($key, $params, $oid = null, array $options = [])
    {
        self::initialize_static_variables();

        $key = [
            'publicKeyAlgorithm' => [
                'algorithm' => is_string(static::OID_NAME) ? static::OID_NAME : $oid
            ],
            'publicKey' => "\0" . $key
        ];

        if ($oid != 'id-Ed25519' && $oid != 'id-Ed448' && $oid != 'id-X25519' && $oid != 'id-X448') {
            $key['publicKeyAlgorithm']['parameters'] = $params;
        }

        $key = ASN1::encodeDER($key, Maps\PublicKeyInfo::MAP);

        if (isset($options['binary']) ? $options['binary'] : self::$binary) {
            return $key;
        }

        return "-----BEGIN PUBLIC KEY-----\r\n" .
               chunk_split(Strings::base64_encode($key), 64) .
               "-----END PUBLIC KEY-----";
    }

    /**
     * Perform some preliminary parsing of the key
     *
     * @param string $key
     * @return array
     */
    private static function preParse(&$key)
    {
        self::initialize_static_variables();

        if (self::$format != self::MODE_DER) {
            $decoded = ASN1::extractBER($key);
            if ($decoded !== false) {
                $key = $decoded;
            } elseif (self::$format == self::MODE_PEM) {
                throw new \UnexpectedValueException('Expected base64-encoded PEM format but was unable to decode base64 text');
            }
        }

        $decoded = ASN1::decodeBER($key);
        if (!$decoded) {
            throw new \RuntimeException('Unable to decode BER');
        }

        return $decoded;
    }

    /**
     * Returns the encryption parameters used by the key
     *
     * @param string $key
     * @return array
     */
    public static function extractEncryptionAlgorithm($key)
    {
        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        $decoded = self::preParse($key);

        $r = ASN1::asn1map($decoded[0], Maps\EncryptedPrivateKeyInfo::MAP);
        if (!is_array($r)) {
            throw new \RuntimeException('Unable to parse using EncryptedPrivateKeyInfo map');
        }

        if ($r['encryptionAlgorithm']['algorithm'] == 'id-PBES2') {
            $decoded = ASN1::decodeBER($r['encryptionAlgorithm']['parameters']->element);
            if (!$decoded) {
                throw new \RuntimeException('Unable to decode BER');
            }
            $r['encryptionAlgorithm']['parameters'] = ASN1::asn1map($decoded[0], Maps\PBES2params::MAP);

            $kdf = &$r['encryptionAlgorithm']['parameters']['keyDerivationFunc'];
            switch ($kdf['algorithm']) {
                case 'id-PBKDF2':
                    $decoded = ASN1::decodeBER($kdf['parameters']->element);
                    if (!$decoded) {
                        throw new \RuntimeException('Unable to decode BER');
                    }
                    $kdf['parameters'] = ASN1::asn1map($decoded[0], Maps\PBKDF2params::MAP);
            }
        }

        return $r['encryptionAlgorithm'];
    }
}
<?php

/**
 * JSON Web Key (RFC7517) Handler
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common\Formats\Keys;

use phpseclib3\Common\Functions\Strings;

/**
 * JSON Web Key Formatted Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class JWK
{
    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password
     * @return array
     */
    public static function load($key, $password = '')
    {
        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        $key = preg_replace('#\s#', '', $key); // remove whitespace

        if (PHP_VERSION_ID >= 73000) {
            $key = json_decode($key, null, 512, JSON_THROW_ON_ERROR);
        } else {
            $key = json_decode($key);
            if (!$key) {
                throw new \RuntimeException('Unable to decode JSON');
            }
        }

        if (isset($key->kty)) {
            return $key;
        }

        if (!is_object($key)) {
            throw new \RuntimeException('invalid JWK: not an object');
        }

        if (!isset($key->keys)) {
            throw new \RuntimeException('invalid JWK: object has no property "keys"');
        }

        if (count($key->keys) != 1) {
            throw new \RuntimeException('Although the JWK key format supports multiple keys phpseclib does not');
        }

        return $key->keys[0];
    }

    /**
     * Wrap a key appropriately
     *
     * @return string
     */
    protected static function wrapKey(array $key, array $options)
    {
        return json_encode(['keys' => [$key + $options]]);
    }
}
<?php

/**
 * PrivateKey interface
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2009 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common;

/**
 * PrivateKey interface
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
interface PrivateKey
{
    public function sign($message);
    //public function decrypt($ciphertext);
    public function getPublicKey();
    public function toString($type, array $options = []);

    /**
     * @param string|false $password
     * @return mixed
     */
    public function withPassword($password = false);
}
<?php

/**
 * Base Class for all \phpseclib3\Crypt\* cipher classes
 *
 * PHP version 5
 *
 * Internally for phpseclib developers:
 *  If you plan to add a new cipher class, please note following rules:
 *
 *  - The new \phpseclib3\Crypt\* cipher class should extend \phpseclib3\Crypt\Common\SymmetricKey
 *
 *  - Following methods are then required to be overridden/overloaded:
 *
 *    - encryptBlock()
 *
 *    - decryptBlock()
 *
 *    - setupKey()
 *
 *  - All other methods are optional to be overridden/overloaded
 *
 *  - Look at the source code of the current ciphers how they extend \phpseclib3\Crypt\Common\SymmetricKey
 *    and take one of them as a start up for the new cipher class.
 *
 *  - Please read all the other comments/notes/hints here also for each class var/method
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Blowfish;
use phpseclib3\Crypt\Hash;
use phpseclib3\Exception\BadDecryptionException;
use phpseclib3\Exception\BadModeException;
use phpseclib3\Exception\InconsistentSetupException;
use phpseclib3\Exception\InsufficientSetupException;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\Math\BigInteger;
use phpseclib3\Math\BinaryField;
use phpseclib3\Math\PrimeField;

/**
 * Base Class for all \phpseclib3\Crypt\* cipher classes
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 * @author  Hans-Juergen Petrich <petrich@tronic-media.com>
 */
abstract class SymmetricKey
{
    /**
     * Encrypt / decrypt using the Counter mode.
     *
     * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
     *
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
     */
    const MODE_CTR = -1;
    /**
     * Encrypt / decrypt using the Electronic Code Book mode.
     *
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
     */
    const MODE_ECB = 1;
    /**
     * Encrypt / decrypt using the Code Book Chaining mode.
     *
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
     */
    const MODE_CBC = 2;
    /**
     * Encrypt / decrypt using the Cipher Feedback mode.
     *
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
     */
    const MODE_CFB = 3;
    /**
     * Encrypt / decrypt using the Cipher Feedback mode (8bit)
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
     */
    const MODE_CFB8 = 7;
    /**
     * Encrypt / decrypt using the Output Feedback mode (8bit)
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
     */
    const MODE_OFB8 = 8;
    /**
     * Encrypt / decrypt using the Output Feedback mode.
     *
     * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
     */
    const MODE_OFB = 4;
    /**
     * Encrypt / decrypt using Galois/Counter mode.
     *
     * @link https://en.wikipedia.org/wiki/Galois/Counter_Mode
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
     */
    const MODE_GCM = 5;
    /**
     * Encrypt / decrypt using streaming mode.
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
     */
    const MODE_STREAM = 6;

    /**
     * Mode Map
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
     */
    const MODE_MAP = [
        'ctr'    => self::MODE_CTR,
        'ecb'    => self::MODE_ECB,
        'cbc'    => self::MODE_CBC,
        'cfb'    => self::MODE_CFB,
        'cfb8'   => self::MODE_CFB8,
        'ofb'    => self::MODE_OFB,
        'ofb8'   => self::MODE_OFB8,
        'gcm'    => self::MODE_GCM,
        'stream' => self::MODE_STREAM
    ];

    /**
     * Base value for the internal implementation $engine switch
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
     */
    const ENGINE_INTERNAL = 1;
    /**
     * Base value for the eval() implementation $engine switch
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
     */
    const ENGINE_EVAL = 2;
    /**
     * Base value for the mcrypt implementation $engine switch
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
     */
    const ENGINE_MCRYPT = 3;
    /**
     * Base value for the openssl implementation $engine switch
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
     */
    const ENGINE_OPENSSL = 4;
    /**
     * Base value for the libsodium implementation $engine switch
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
     */
    const ENGINE_LIBSODIUM = 5;
    /**
     * Base value for the openssl / gcm implementation $engine switch
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
     */
    const ENGINE_OPENSSL_GCM = 6;

    /**
     * Engine Reverse Map
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::getEngine()
     */
    const ENGINE_MAP = [
        self::ENGINE_INTERNAL    => 'PHP',
        self::ENGINE_EVAL        => 'Eval',
        self::ENGINE_MCRYPT      => 'mcrypt',
        self::ENGINE_OPENSSL     => 'OpenSSL',
        self::ENGINE_LIBSODIUM   => 'libsodium',
        self::ENGINE_OPENSSL_GCM => 'OpenSSL (GCM)'
    ];

    /**
     * The Encryption Mode
     *
     * @see self::__construct()
     * @var int
     */
    protected $mode;

    /**
     * The Block Length of the block cipher
     *
     * @var int
     */
    protected $block_size = 16;

    /**
     * The Key
     *
     * @see self::setKey()
     * @var string
     */
    protected $key = false;

    /**
     * HMAC Key
     *
     * @see self::setupGCM()
     * @var ?string
     */
    protected $hKey = false;

    /**
     * The Initialization Vector
     *
     * @see self::setIV()
     * @var string
     */
    protected $iv = false;

    /**
     * A "sliding" Initialization Vector
     *
     * @see self::enableContinuousBuffer()
     * @see self::clearBuffers()
     * @var string
     */
    protected $encryptIV;

    /**
     * A "sliding" Initialization Vector
     *
     * @see self::enableContinuousBuffer()
     * @see self::clearBuffers()
     * @var string
     */
    protected $decryptIV;

    /**
     * Continuous Buffer status
     *
     * @see self::enableContinuousBuffer()
     * @var bool
     */
    protected $continuousBuffer = false;

    /**
     * Encryption buffer for CTR, OFB and CFB modes
     *
     * @see self::encrypt()
     * @see self::clearBuffers()
     * @var array
     */
    protected $enbuffer;

    /**
     * Decryption buffer for CTR, OFB and CFB modes
     *
     * @see self::decrypt()
     * @see self::clearBuffers()
     * @var array
     */
    protected $debuffer;

    /**
     * mcrypt resource for encryption
     *
     * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
     * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
     *
     * @see self::encrypt()
     * @var resource
     */
    private $enmcrypt;

    /**
     * mcrypt resource for decryption
     *
     * The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
     * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
     *
     * @see self::decrypt()
     * @var resource
     */
    private $demcrypt;

    /**
     * Does the enmcrypt resource need to be (re)initialized?
     *
     * @see \phpseclib3\Crypt\Twofish::setKey()
     * @see \phpseclib3\Crypt\Twofish::setIV()
     * @var bool
     */
    private $enchanged = true;

    /**
     * Does the demcrypt resource need to be (re)initialized?
     *
     * @see \phpseclib3\Crypt\Twofish::setKey()
     * @see \phpseclib3\Crypt\Twofish::setIV()
     * @var bool
     */
    private $dechanged = true;

    /**
     * mcrypt resource for CFB mode
     *
     * mcrypt's CFB mode, in (and only in) buffered context,
     * is broken, so phpseclib implements the CFB mode by it self,
     * even when the mcrypt php extension is available.
     *
     * In order to do the CFB-mode work (fast) phpseclib
     * use a separate ECB-mode mcrypt resource.
     *
     * @link http://phpseclib.sourceforge.net/cfb-demo.phps
     * @see self::encrypt()
     * @see self::decrypt()
     * @see self::setupMcrypt()
     * @var resource
     */
    private $ecb;

    /**
     * Optimizing value while CFB-encrypting
     *
     * Only relevant if $continuousBuffer enabled
     * and $engine == self::ENGINE_MCRYPT
     *
     * It's faster to re-init $enmcrypt if
     * $buffer bytes > $cfb_init_len than
     * using the $ecb resource furthermore.
     *
     * This value depends of the chosen cipher
     * and the time it would be needed for it's
     * initialization [by mcrypt_generic_init()]
     * which, typically, depends on the complexity
     * on its internaly Key-expanding algorithm.
     *
     * @see self::encrypt()
     * @var int
     */
    protected $cfb_init_len = 600;

    /**
     * Does internal cipher state need to be (re)initialized?
     *
     * @see self::setKey()
     * @see self::setIV()
     * @see self::disableContinuousBuffer()
     * @var bool
     */
    protected $changed = true;

    /**
     * Does Eval engie need to be (re)initialized?
     *
     * @see self::setup()
     * @var bool
     */
    protected $nonIVChanged = true;

    /**
     * Padding status
     *
     * @see self::enablePadding()
     * @var bool
     */
    private $padding = true;

    /**
     * Is the mode one that is paddable?
     *
     * @see self::__construct()
     * @var bool
     */
    private $paddable = false;

    /**
     * Holds which crypt engine internaly should be use,
     * which will be determined automatically on __construct()
     *
     * Currently available $engines are:
     * - self::ENGINE_LIBSODIUM   (very fast, php-extension: libsodium, extension_loaded('libsodium') required)
     * - self::ENGINE_OPENSSL_GCM (very fast, php-extension: openssl, extension_loaded('openssl') required)
     * - self::ENGINE_OPENSSL     (very fast, php-extension: openssl, extension_loaded('openssl') required)
     * - self::ENGINE_MCRYPT      (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
     * - self::ENGINE_EVAL        (medium, pure php-engine, no php-extension required)
     * - self::ENGINE_INTERNAL    (slower, pure php-engine, no php-extension required)
     *
     * @see self::setEngine()
     * @see self::encrypt()
     * @see self::decrypt()
     * @var int
     */
    protected $engine;

    /**
     * Holds the preferred crypt engine
     *
     * @see self::setEngine()
     * @see self::setPreferredEngine()
     * @var int
     */
    private $preferredEngine;

    /**
     * The mcrypt specific name of the cipher
     *
     * Only used if $engine == self::ENGINE_MCRYPT
     *
     * @link http://www.php.net/mcrypt_module_open
     * @link http://www.php.net/mcrypt_list_algorithms
     * @see self::setupMcrypt()
     * @var string
     */
    protected $cipher_name_mcrypt;

    /**
     * The openssl specific name of the cipher
     *
     * Only used if $engine == self::ENGINE_OPENSSL
     *
     * @link http://www.php.net/openssl-get-cipher-methods
     * @var string
     */
    protected $cipher_name_openssl;

    /**
     * The openssl specific name of the cipher in ECB mode
     *
     * If OpenSSL does not support the mode we're trying to use (CTR)
     * it can still be emulated with ECB mode.
     *
     * @link http://www.php.net/openssl-get-cipher-methods
     * @var string
     */
    protected $cipher_name_openssl_ecb;

    /**
     * The default salt used by setPassword()
     *
     * @see self::setPassword()
     * @var string
     */
    private $password_default_salt = 'phpseclib/salt';

    /**
     * The name of the performance-optimized callback function
     *
     * Used by encrypt() / decrypt()
     * only if $engine == self::ENGINE_INTERNAL
     *
     * @see self::encrypt()
     * @see self::decrypt()
     * @see self::setupInlineCrypt()
     * @var Callback
     */
    protected $inline_crypt;

    /**
     * If OpenSSL can be used in ECB but not in CTR we can emulate CTR
     *
     * @see self::openssl_ctr_process()
     * @var bool
     */
    private $openssl_emulate_ctr = false;

    /**
     * Don't truncate / null pad key
     *
     * @see self::clearBuffers()
     * @var bool
     */
    private $skip_key_adjustment = false;

    /**
     * Has the key length explicitly been set or should it be derived from the key, itself?
     *
     * @see self::setKeyLength()
     * @var bool
     */
    protected $explicit_key_length = false;

    /**
     * Hash subkey for GHASH
     *
     * @see self::setupGCM()
     * @see self::ghash()
     * @var BinaryField\Integer
     */
    private $h;

    /**
     * Additional authenticated data
     *
     * @var string
     */
    protected $aad = '';

    /**
     * Authentication Tag produced after a round of encryption
     *
     * @var string
     */
    protected $newtag = false;

    /**
     * Authentication Tag to be verified during decryption
     *
     * @var string
     */
    protected $oldtag = false;

    /**
     * GCM Binary Field
     *
     * @see self::__construct()
     * @see self::ghash()
     * @var BinaryField
     */
    private static $gcmField;

    /**
     * Poly1305 Prime Field
     *
     * @see self::enablePoly1305()
     * @see self::poly1305()
     * @var PrimeField
     */
    private static $poly1305Field;

    /**
     * Flag for using regular vs "safe" intval
     *
     * @see self::initialize_static_variables()
     * @var boolean
     */
    protected static $use_reg_intval;

    /**
     * Poly1305 Key
     *
     * @see self::setPoly1305Key()
     * @see self::poly1305()
     * @var string
     */
    protected $poly1305Key;

    /**
     * Poly1305 Flag
     *
     * @see self::setPoly1305Key()
     * @see self::enablePoly1305()
     * @var boolean
     */
    protected $usePoly1305 = false;

    /**
     * The Original Initialization Vector
     *
     * GCM uses the nonce to build the IV but we want to be able to distinguish between nonce-derived
     * IV's and user-set IV's
     *
     * @see self::setIV()
     * @var string
     */
    private $origIV = false;

    /**
     * Nonce
     *
     * Only used with GCM. We could re-use setIV() but nonce's can be of a different length and
     * toggling between GCM and other modes could be more complicated if we re-used setIV()
     *
     * @see self::setNonce()
     * @var string
     */
    protected $nonce = false;

    /**
     * Default Constructor.
     *
     * $mode could be:
     *
     * - ecb
     *
     * - cbc
     *
     * - ctr
     *
     * - cfb
     *
     * - cfb8
     *
     * - ofb
     *
     * - ofb8
     *
     * - gcm
     *
     * @param string $mode
     * @throws BadModeException if an invalid / unsupported mode is provided
     */
    public function __construct($mode)
    {
        $mode = strtolower($mode);
        // necessary because of 5.6 compatibility; we can't do isset(self::MODE_MAP[$mode]) in 5.6
        $map = self::MODE_MAP;
        if (!isset($map[$mode])) {
            throw new BadModeException('No valid mode has been specified');
        }

        $mode = self::MODE_MAP[$mode];

        // $mode dependent settings
        switch ($mode) {
            case self::MODE_ECB:
            case self::MODE_CBC:
                $this->paddable = true;
                break;
            case self::MODE_CTR:
            case self::MODE_CFB:
            case self::MODE_CFB8:
            case self::MODE_OFB:
            case self::MODE_OFB8:
            case self::MODE_STREAM:
                $this->paddable = false;
                break;
            case self::MODE_GCM:
                if ($this->block_size != 16) {
                    throw new BadModeException('GCM is only valid for block ciphers with a block size of 128 bits');
                }
                if (!isset(self::$gcmField)) {
                    self::$gcmField = new BinaryField(128, 7, 2, 1, 0);
                }
                $this->paddable = false;
                break;
            default:
                throw new BadModeException('No valid mode has been specified');
        }

        $this->mode = $mode;

        static::initialize_static_variables();
    }

    /**
     * Initialize static variables
     */
    protected static function initialize_static_variables()
    {
        if (!isset(self::$use_reg_intval)) {
            switch (true) {
                // PHP 8.5, per https://www.php.net/manual/en/migration85.incompatible.php, now emits a warning
                // "when casting floats (or strings that look like floats) to int if they cannot be represented as one"
                case PHP_VERSION_ID >= 80500 && PHP_INT_SIZE == 4:
                    self::$use_reg_intval = false;
                    break;
                // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
                case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
                case !function_exists('php_uname'):
                case !is_string(php_uname('m')):
                case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
                case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
                    self::$use_reg_intval = true;
                    break;
                case (php_uname('m') & "\xDF\xDF\xDF") == 'ARM':
                    switch (true) {
                        /* PHP 7.0.0 introduced a bug that affected 32-bit ARM processors:

                           https://github.com/php/php-src/commit/716da71446ebbd40fa6cf2cea8a4b70f504cc3cd

                           altho the changelogs make no mention of it, this bug was fixed with this commit:

                           https://github.com/php/php-src/commit/c1729272b17a1fe893d1a54e423d3b71470f3ee8

                           affected versions of PHP are: 7.0.x, 7.1.0 - 7.1.23 and 7.2.0 - 7.2.11 */
                        case PHP_VERSION_ID >= 70000 && PHP_VERSION_ID <= 70123:
                        case PHP_VERSION_ID >= 70200 && PHP_VERSION_ID <= 70211:
                            self::$use_reg_intval = false;
                            break;
                        default:
                            self::$use_reg_intval = true;
                    }
            }
        }
    }

    /**
     * Sets the initialization vector.
     *
     * setIV() is not required when ecb or gcm modes are being used.
     *
     * {@internal Can be overwritten by a sub class, but does not have to be}
     *
     * @param string $iv
     * @throws \LengthException if the IV length isn't equal to the block size
     * @throws \BadMethodCallException if an IV is provided when one shouldn't be
     */
    public function setIV($iv)
    {
        if ($this->mode == self::MODE_ECB) {
            throw new \BadMethodCallException('This mode does not require an IV.');
        }

        if ($this->mode == self::MODE_GCM) {
            throw new \BadMethodCallException('Use setNonce instead');
        }

        if (!$this->usesIV()) {
            throw new \BadMethodCallException('This algorithm does not use an IV.');
        }

        if (strlen($iv) != $this->block_size) {
            throw new \LengthException('Received initialization vector of size ' . strlen($iv) . ', but size ' . $this->block_size . ' is required');
        }

        $this->iv = $this->origIV = $iv;
        $this->changed = true;
    }

    /**
     * Enables Poly1305 mode.
     *
     * Once enabled Poly1305 cannot be disabled.
     *
     * @throws \BadMethodCallException if Poly1305 is enabled whilst in GCM mode
     */
    public function enablePoly1305()
    {
        if ($this->mode == self::MODE_GCM) {
            throw new \BadMethodCallException('Poly1305 cannot be used in GCM mode');
        }

        $this->usePoly1305 = true;
    }

    /**
     * Enables Poly1305 mode.
     *
     * Once enabled Poly1305 cannot be disabled. If $key is not passed then an attempt to call createPoly1305Key
     * will be made.
     *
     * @param string $key optional
     * @throws \LengthException if the key isn't long enough
     * @throws \BadMethodCallException if Poly1305 is enabled whilst in GCM mode
     */
    public function setPoly1305Key($key = null)
    {
        if ($this->mode == self::MODE_GCM) {
            throw new \BadMethodCallException('Poly1305 cannot be used in GCM mode');
        }

        if (!is_string($key) || strlen($key) != 32) {
            throw new \LengthException('The Poly1305 key must be 32 bytes long (256 bits)');
        }

        if (!isset(self::$poly1305Field)) {
            // 2^130-5
            self::$poly1305Field = new PrimeField(new BigInteger('3fffffffffffffffffffffffffffffffb', 16));
        }

        $this->poly1305Key = $key;
        $this->usePoly1305 = true;
    }

    /**
     * Sets the nonce.
     *
     * setNonce() is only required when gcm is used
     *
     * @param string $nonce
     * @throws \BadMethodCallException if an nonce is provided when one shouldn't be
     */
    public function setNonce($nonce)
    {
        if ($this->mode != self::MODE_GCM) {
            throw new \BadMethodCallException('Nonces are only used in GCM mode.');
        }

        $this->nonce = $nonce;
        $this->setEngine();
    }

    /**
     * Sets additional authenticated data
     *
     * setAAD() is only used by gcm or in poly1305 mode
     *
     * @param string $aad
     * @throws \BadMethodCallException if mode isn't GCM or if poly1305 isn't being utilized
     */
    public function setAAD($aad)
    {
        if ($this->mode != self::MODE_GCM && !$this->usePoly1305) {
            throw new \BadMethodCallException('Additional authenticated data is only utilized in GCM mode or with Poly1305');
        }

        $this->aad = $aad;
    }

    /**
     * Returns whether or not the algorithm uses an IV
     *
     * @return bool
     */
    public function usesIV()
    {
        return $this->mode != self::MODE_GCM && $this->mode != self::MODE_ECB;
    }

    /**
     * Returns whether or not the algorithm uses a nonce
     *
     * @return bool
     */
    public function usesNonce()
    {
        return $this->mode == self::MODE_GCM;
    }

    /**
     * Returns the current key length in bits
     *
     * @return int
     */
    public function getKeyLength()
    {
        return $this->key_length << 3;
    }

    /**
     * Returns the current block length in bits
     *
     * @return int
     */
    public function getBlockLength()
    {
        return $this->block_size << 3;
    }

    /**
     * Returns the current block length in bytes
     *
     * @return int
     */
    public function getBlockLengthInBytes()
    {
        return $this->block_size;
    }

    /**
     * Sets the key length.
     *
     * Keys with explicitly set lengths need to be treated accordingly
     *
     * @param int $length
     */
    public function setKeyLength($length)
    {
        $this->explicit_key_length = $length >> 3;

        if (is_string($this->key) && strlen($this->key) != $this->explicit_key_length) {
            $this->key = false;
            throw new InconsistentSetupException('Key has already been set and is not ' . $this->explicit_key_length . ' bytes long');
        }
    }

    /**
     * Sets the key.
     *
     * The min/max length(s) of the key depends on the cipher which is used.
     * If the key not fits the length(s) of the cipher it will paded with null bytes
     * up to the closest valid key length.  If the key is more than max length,
     * we trim the excess bits.
     *
     * If the key is not explicitly set, it'll be assumed to be all null bytes.
     *
     * {@internal Could, but not must, extend by the child Crypt_* class}
     *
     * @param string $key
     */
    public function setKey($key)
    {
        if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
            throw new InconsistentSetupException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
        }

        $this->key = $key;
        $this->key_length = strlen($key);
        $this->setEngine();
    }

    /**
     * Sets the password.
     *
     * Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
     *     {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
     *         $hash, $salt, $count, $dkLen
     *
     *         Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
     *     {@link https://en.wikipedia.org/wiki/Bcrypt bcypt}:
     *         $salt, $rounds, $keylen
     *
     *         This is a modified version of bcrypt used by OpenSSH.
     *
     * {@internal Could, but not must, extend by the child Crypt_* class}
     *
     * @see Crypt/Hash.php
     * @param string $password
     * @param string $method
     * @param int|string ...$func_args
     * @throws \LengthException if pbkdf1 is being used and the derived key length exceeds the hash length
     * @throws \RuntimeException if bcrypt is being used and a salt isn't provided
     * @return bool
     */
    public function setPassword($password, $method = 'pbkdf2', ...$func_args)
    {
        $key = '';

        $method = strtolower($method);
        switch ($method) {
            case 'bcrypt':
                if (!isset($func_args[2])) {
                    throw new \RuntimeException('A salt must be provided for bcrypt to work');
                }

                $salt = $func_args[0];

                $rounds = isset($func_args[1]) ? $func_args[1] : 16;
                $keylen = isset($func_args[2]) ? $func_args[2] : $this->key_length;

                $key = Blowfish::bcrypt_pbkdf($password, $salt, $keylen + $this->block_size, $rounds);

                $this->setKey(substr($key, 0, $keylen));
                $this->setIV(substr($key, $keylen));

                return true;
            case 'pkcs12': // from https://tools.ietf.org/html/rfc7292#appendix-B.2
            case 'pbkdf1':
            case 'pbkdf2':
                // Hash function
                $hash = isset($func_args[0]) ? strtolower($func_args[0]) : 'sha1';
                $hashObj = new Hash();
                $hashObj->setHash($hash);

                // WPA and WPA2 use the SSID as the salt
                $salt = isset($func_args[1]) ? $func_args[1] : $this->password_default_salt;

                // RFC2898#section-4.2 uses 1,000 iterations by default
                // WPA and WPA2 use 4,096.
                $count = isset($func_args[2]) ? $func_args[2] : 1000;

                // Keylength
                if (isset($func_args[3])) {
                    if ($func_args[3] <= 0) {
                        throw new \LengthException('Derived key length cannot be longer 0 or less');
                    }
                    $dkLen = $func_args[3];
                } else {
                    $key_length = $this->explicit_key_length !== false ? $this->explicit_key_length : $this->key_length;
                    $dkLen = $method == 'pbkdf1' ? 2 * $key_length : $key_length;
                }

                switch (true) {
                    case $method == 'pkcs12':
                        /*
                         In this specification, however, all passwords are created from
                         BMPStrings with a NULL terminator.  This means that each character in
                         the original BMPString is encoded in 2 bytes in big-endian format
                         (most-significant byte first).  There are no Unicode byte order
                         marks.  The 2 bytes produced from the last character in the BMPString
                         are followed by 2 additional bytes with the value 0x00.

                         -- https://tools.ietf.org/html/rfc7292#appendix-B.1
                         */
                        $password = "\0" . chunk_split($password, 1, "\0") . "\0";

                        /*
                         This standard specifies 3 different values for the ID byte mentioned
                         above:

                         1.  If ID=1, then the pseudorandom bits being produced are to be used
                             as key material for performing encryption or decryption.

                         2.  If ID=2, then the pseudorandom bits being produced are to be used
                             as an IV (Initial Value) for encryption or decryption.

                         3.  If ID=3, then the pseudorandom bits being produced are to be used
                             as an integrity key for MACing.
                         */
                        // Construct a string, D (the "diversifier"), by concatenating v/8
                        // copies of ID.
                        $blockLength = $hashObj->getBlockLengthInBytes();
                        $d1 = str_repeat(chr(1), $blockLength);
                        $d2 = str_repeat(chr(2), $blockLength);
                        $s = '';
                        if (strlen($salt)) {
                            while (strlen($s) < $blockLength) {
                                $s .= $salt;
                            }
                        }
                        $s = substr($s, 0, $blockLength);

                        $p = '';
                        if (strlen($password)) {
                            while (strlen($p) < $blockLength) {
                                $p .= $password;
                            }
                        }
                        $p = substr($p, 0, $blockLength);

                        $i = $s . $p;

                        $this->setKey(self::pkcs12helper($dkLen, $hashObj, $i, $d1, $count));
                        if ($this->usesIV()) {
                            $this->setIV(self::pkcs12helper($this->block_size, $hashObj, $i, $d2, $count));
                        }

                        return true;
                    case $method == 'pbkdf1':
                        if ($dkLen > $hashObj->getLengthInBytes()) {
                            throw new \LengthException('Derived key length cannot be longer than the hash length');
                        }
                        $t = $password . $salt;
                        for ($i = 0; $i < $count; ++$i) {
                            $t = $hashObj->hash($t);
                        }
                        $key = substr($t, 0, $dkLen);

                        $this->setKey(substr($key, 0, $dkLen >> 1));
                        if ($this->usesIV()) {
                            $this->setIV(substr($key, $dkLen >> 1));
                        }

                        return true;
                    case !in_array($hash, hash_algos()):
                        $i = 1;
                        $hashObj->setKey($password);
                        while (strlen($key) < $dkLen) {
                            $f = $u = $hashObj->hash($salt . pack('N', $i++));
                            for ($j = 2; $j <= $count; ++$j) {
                                $u = $hashObj->hash($u);
                                $f ^= $u;
                            }
                            $key .= $f;
                        }
                        $key = substr($key, 0, $dkLen);
                        break;
                    default:
                        $key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
                }
                break;
            default:
                throw new UnsupportedAlgorithmException($method . ' is not a supported password hashing method');
        }

        $this->setKey($key);

        return true;
    }

    /**
     * PKCS#12 KDF Helper Function
     *
     * As discussed here:
     *
     * {@link https://tools.ietf.org/html/rfc7292#appendix-B}
     *
     * @see self::setPassword()
     * @param int $n
     * @param Hash $hashObj
     * @param string $i
     * @param string $d
     * @param int $count
     * @return string $a
     */
    private static function pkcs12helper($n, $hashObj, $i, $d, $count)
    {
        static $one;
        if (!isset($one)) {
            $one = new BigInteger(1);
        }

        $blockLength = $hashObj->getBlockLength() >> 3;

        $c = ceil($n / $hashObj->getLengthInBytes());
        $a = '';
        for ($j = 1; $j <= $c; $j++) {
            $ai = $d . $i;
            for ($k = 0; $k < $count; $k++) {
                $ai = $hashObj->hash($ai);
            }
            $b = '';
            while (strlen($b) < $blockLength) {
                $b .= $ai;
            }
            $b = substr($b, 0, $blockLength);
            $b = new BigInteger($b, 256);
            $newi = '';
            for ($k = 0; $k < strlen($i); $k += $blockLength) {
                $temp = substr($i, $k, $blockLength);
                $temp = new BigInteger($temp, 256);
                $temp->setPrecision($blockLength << 3);
                $temp = $temp->add($b);
                $temp = $temp->add($one);
                $newi .= $temp->toBytes(false);
            }
            $i = $newi;
            $a .= $ai;
        }

        return substr($a, 0, $n);
    }

    /**
     * Encrypts a message.
     *
     * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
     * implementations may or may not pad in the same manner.  Other common approaches to padding and the reasons why it's
     * necessary are discussed in the following
     * URL:
     *
     * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
     *
     * An alternative to padding is to, separately, send the length of the file.  This is what SSH, in fact, does.
     * strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
     * length.
     *
     * {@internal Could, but not must, extend by the child Crypt_* class}
     *
     * @see self::decrypt()
     * @param string $plaintext
     * @return string $ciphertext
     */
    public function encrypt($plaintext)
    {
        if ($this->paddable) {
            $plaintext = $this->pad($plaintext);
        }

        $this->setup();

        if ($this->mode == self::MODE_GCM) {
            $oldIV = $this->iv;
            Strings::increment_str($this->iv);
            $cipher = new static('ctr');
            $cipher->setKey($this->key);
            $cipher->setIV($this->iv);
            $ciphertext = $cipher->encrypt($plaintext);

            $s = $this->ghash(
                self::nullPad128($this->aad) .
                self::nullPad128($ciphertext) .
                self::len64($this->aad) .
                self::len64($ciphertext)
            );
            $cipher->encryptIV = $this->iv = $this->encryptIV = $this->decryptIV = $oldIV;
            $this->newtag = $cipher->encrypt($s);
            return $ciphertext;
        }

        if (isset($this->poly1305Key)) {
            $cipher = clone $this;
            unset($cipher->poly1305Key);
            $this->usePoly1305 = false;
            $ciphertext = $cipher->encrypt($plaintext);
            $this->newtag = $this->poly1305($ciphertext);
            return $ciphertext;
        }

        if ($this->engine === self::ENGINE_OPENSSL) {
            switch ($this->mode) {
                case self::MODE_STREAM:
                    return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
                case self::MODE_ECB:
                    return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
                case self::MODE_CBC:
                    $result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->encryptIV);
                    if ($this->continuousBuffer) {
                        $this->encryptIV = substr($result, -$this->block_size);
                    }
                    return $result;
                case self::MODE_CTR:
                    return $this->openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
                case self::MODE_CFB:
                    // cfb loosely routines inspired by openssl's:
                    // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
                    $ciphertext = '';
                    if ($this->continuousBuffer) {
                        $iv = &$this->encryptIV;
                        $pos = &$this->enbuffer['pos'];
                    } else {
                        $iv = $this->encryptIV;
                        $pos = 0;
                    }
                    $len = strlen($plaintext);
                    $i = 0;
                    if ($pos) {
                        $orig_pos = $pos;
                        $max = $this->block_size - $pos;
                        if ($len >= $max) {
                            $i = $max;
                            $len -= $max;
                            $pos = 0;
                        } else {
                            $i = $len;
                            $pos += $len;
                            $len = 0;
                        }
                        // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
                        $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
                        $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
                        $plaintext = substr($plaintext, $i);
                    }

                    $overflow = $len % $this->block_size;

                    if ($overflow) {
                        $ciphertext .= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
                        $iv = Strings::pop($ciphertext, $this->block_size);

                        $size = $len - $overflow;
                        $block = $iv ^ substr($plaintext, -$overflow);
                        $iv = substr_replace($iv, $block, 0, $overflow);
                        $ciphertext .= $block;
                        $pos = $overflow;
                    } elseif ($len) {
                        $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
                        $iv = substr($ciphertext, -$this->block_size);
                    }

                    return $ciphertext;
                case self::MODE_CFB8:
                    $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->encryptIV);
                    if ($this->continuousBuffer) {
                        if (($len = strlen($ciphertext)) >= $this->block_size) {
                            $this->encryptIV = substr($ciphertext, -$this->block_size);
                        } else {
                            $this->encryptIV = substr($this->encryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
                        }
                    }
                    return $ciphertext;
                case self::MODE_OFB8:
                    $ciphertext = '';
                    $len = strlen($plaintext);
                    $iv = $this->encryptIV;

                    for ($i = 0; $i < $len; ++$i) {
                        $xor = openssl_encrypt($iv, $this->cipher_name_openssl_ecb, $this->key, $this->openssl_options, $this->decryptIV);
                        $ciphertext .= $plaintext[$i] ^ $xor;
                        $iv = substr($iv, 1) . $xor[0];
                    }

                    if ($this->continuousBuffer) {
                        $this->encryptIV = $iv;
                    }
                    break;
                case self::MODE_OFB:
                    return $this->openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
            }
        }

        if ($this->engine === self::ENGINE_MCRYPT) {
            set_error_handler(function () {
            });
            if ($this->enchanged) {
                mcrypt_generic_init($this->enmcrypt, $this->key, $this->getIV($this->encryptIV));
                $this->enchanged = false;
            }

            // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
            // using mcrypt's default handing of CFB the above would output two different things.  using phpseclib's
            // rewritten CFB implementation the above outputs the same thing twice.
            if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
                $block_size = $this->block_size;
                $iv = &$this->encryptIV;
                $pos = &$this->enbuffer['pos'];
                $len = strlen($plaintext);
                $ciphertext = '';
                $i = 0;
                if ($pos) {
                    $orig_pos = $pos;
                    $max = $block_size - $pos;
                    if ($len >= $max) {
                        $i = $max;
                        $len -= $max;
                        $pos = 0;
                    } else {
                        $i = $len;
                        $pos += $len;
                        $len = 0;
                    }
                    $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
                    $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
                    $this->enbuffer['enmcrypt_init'] = true;
                }
                if ($len >= $block_size) {
                    if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
                        if ($this->enbuffer['enmcrypt_init'] === true) {
                            mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
                            $this->enbuffer['enmcrypt_init'] = false;
                        }
                        $ciphertext .= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
                        $iv = substr($ciphertext, -$block_size);
                        $len %= $block_size;
                    } else {
                        while ($len >= $block_size) {
                            $iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
                            $ciphertext .= $iv;
                            $len -= $block_size;
                            $i += $block_size;
                        }
                    }
                }

                if ($len) {
                    $iv = mcrypt_generic($this->ecb, $iv);
                    $block = $iv ^ substr($plaintext, -$len);
                    $iv = substr_replace($iv, $block, 0, $len);
                    $ciphertext .= $block;
                    $pos = $len;
                }

                restore_error_handler();

                return $ciphertext;
            }

            $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);

            if (!$this->continuousBuffer) {
                mcrypt_generic_init($this->enmcrypt, $this->key, $this->getIV($this->encryptIV));
            }

            restore_error_handler();

            return $ciphertext;
        }

        if ($this->engine === self::ENGINE_EVAL) {
            $inline = $this->inline_crypt;
            return $inline('encrypt', $plaintext);
        }

        $buffer = &$this->enbuffer;
        $block_size = $this->block_size;
        $ciphertext = '';
        switch ($this->mode) {
            case self::MODE_ECB:
                for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                    $ciphertext .= $this->encryptBlock(substr($plaintext, $i, $block_size));
                }
                break;
            case self::MODE_CBC:
                $xor = $this->encryptIV;
                for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                    $block = substr($plaintext, $i, $block_size);
                    $block = $this->encryptBlock($block ^ $xor);
                    $xor = $block;
                    $ciphertext .= $block;
                }
                if ($this->continuousBuffer) {
                    $this->encryptIV = $xor;
                }
                break;
            case self::MODE_CTR:
                $xor = $this->encryptIV;
                if (strlen($buffer['ciphertext'])) {
                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                        $block = substr($plaintext, $i, $block_size);
                        if (strlen($block) > strlen($buffer['ciphertext'])) {
                            $buffer['ciphertext'] .= $this->encryptBlock($xor);
                            Strings::increment_str($xor);
                        }
                        $key = Strings::shift($buffer['ciphertext'], $block_size);
                        $ciphertext .= $block ^ $key;
                    }
                } else {
                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                        $block = substr($plaintext, $i, $block_size);
                        $key = $this->encryptBlock($xor);
                        Strings::increment_str($xor);
                        $ciphertext .= $block ^ $key;
                    }
                }
                if ($this->continuousBuffer) {
                    $this->encryptIV = $xor;
                    if ($start = strlen($plaintext) % $block_size) {
                        $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
                    }
                }
                break;
            case self::MODE_CFB:
                // cfb loosely routines inspired by openssl's:
                // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
                if ($this->continuousBuffer) {
                    $iv = &$this->encryptIV;
                    $pos = &$buffer['pos'];
                } else {
                    $iv = $this->encryptIV;
                    $pos = 0;
                }
                $len = strlen($plaintext);
                $i = 0;
                if ($pos) {
                    $orig_pos = $pos;
                    $max = $block_size - $pos;
                    if ($len >= $max) {
                        $i = $max;
                        $len -= $max;
                        $pos = 0;
                    } else {
                        $i = $len;
                        $pos += $len;
                        $len = 0;
                    }
                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
                    $ciphertext = substr($iv, $orig_pos) ^ $plaintext;
                    $iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
                }
                while ($len >= $block_size) {
                    $iv = $this->encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
                    $ciphertext .= $iv;
                    $len -= $block_size;
                    $i += $block_size;
                }
                if ($len) {
                    $iv = $this->encryptBlock($iv);
                    $block = $iv ^ substr($plaintext, $i);
                    $iv = substr_replace($iv, $block, 0, $len);
                    $ciphertext .= $block;
                    $pos = $len;
                }
                break;
            case self::MODE_CFB8:
                $ciphertext = '';
                $len = strlen($plaintext);
                $iv = $this->encryptIV;

                for ($i = 0; $i < $len; ++$i) {
                    $ciphertext .= ($c = $plaintext[$i] ^ $this->encryptBlock($iv));
                    $iv = substr($iv, 1) . $c;
                }

                if ($this->continuousBuffer) {
                    if ($len >= $block_size) {
                        $this->encryptIV = substr($ciphertext, -$block_size);
                    } else {
                        $this->encryptIV = substr($this->encryptIV, $len - $block_size) . substr($ciphertext, -$len);
                    }
                }
                break;
            case self::MODE_OFB8:
                $ciphertext = '';
                $len = strlen($plaintext);
                $iv = $this->encryptIV;

                for ($i = 0; $i < $len; ++$i) {
                    $xor = $this->encryptBlock($iv);
                    $ciphertext .= $plaintext[$i] ^ $xor;
                    $iv = substr($iv, 1) . $xor[0];
                }

                if ($this->continuousBuffer) {
                    $this->encryptIV = $iv;
                }
                break;
            case self::MODE_OFB:
                $xor = $this->encryptIV;
                if (strlen($buffer['xor'])) {
                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                        $block = substr($plaintext, $i, $block_size);
                        if (strlen($block) > strlen($buffer['xor'])) {
                            $xor = $this->encryptBlock($xor);
                            $buffer['xor'] .= $xor;
                        }
                        $key = Strings::shift($buffer['xor'], $block_size);
                        $ciphertext .= $block ^ $key;
                    }
                } else {
                    for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                        $xor = $this->encryptBlock($xor);
                        $ciphertext .= substr($plaintext, $i, $block_size) ^ $xor;
                    }
                    $key = $xor;
                }
                if ($this->continuousBuffer) {
                    $this->encryptIV = $xor;
                    if ($start = strlen($plaintext) % $block_size) {
                        $buffer['xor'] = substr($key, $start) . $buffer['xor'];
                    }
                }
                break;
            case self::MODE_STREAM:
                $ciphertext = $this->encryptBlock($plaintext);
                break;
        }

        return $ciphertext;
    }

    /**
     * Decrypts a message.
     *
     * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
     * it is.
     *
     * {@internal Could, but not must, extend by the child Crypt_* class}
     *
     * @see self::encrypt()
     * @param string $ciphertext
     * @return string $plaintext
     * @throws \LengthException if we're inside a block cipher and the ciphertext length is not a multiple of the block size
     */
    public function decrypt($ciphertext)
    {
        if ($this->paddable && strlen($ciphertext) % $this->block_size) {
            throw new \LengthException('The ciphertext length (' . strlen($ciphertext) . ') needs to be a multiple of the block size (' . $this->block_size . ')');
        }
        $this->setup();

        if ($this->mode == self::MODE_GCM || isset($this->poly1305Key)) {
            if ($this->oldtag === false) {
                throw new InsufficientSetupException('Authentication Tag has not been set');
            }

            if (isset($this->poly1305Key)) {
                $newtag = $this->poly1305($ciphertext);
            } else {
                $oldIV = $this->iv;
                Strings::increment_str($this->iv);
                $cipher = new static('ctr');
                $cipher->setKey($this->key);
                $cipher->setIV($this->iv);
                $plaintext = $cipher->decrypt($ciphertext);

                $s = $this->ghash(
                    self::nullPad128($this->aad) .
                    self::nullPad128($ciphertext) .
                    self::len64($this->aad) .
                    self::len64($ciphertext)
                );
                $cipher->encryptIV = $this->iv = $this->encryptIV = $this->decryptIV = $oldIV;
                $newtag = $cipher->encrypt($s);
            }
            if ($this->oldtag != substr($newtag, 0, strlen($newtag))) {
                $cipher = clone $this;
                unset($cipher->poly1305Key);
                $this->usePoly1305 = false;
                $plaintext = $cipher->decrypt($ciphertext);
                $this->oldtag = false;
                throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match');
            }
            $this->oldtag = false;
            return $plaintext;
        }

        if ($this->engine === self::ENGINE_OPENSSL) {
            switch ($this->mode) {
                case self::MODE_STREAM:
                    $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
                    break;
                case self::MODE_ECB:
                    $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
                    break;
                case self::MODE_CBC:
                    $offset = $this->block_size;
                    $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->decryptIV);
                    if ($this->continuousBuffer) {
                        $this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
                    }
                    break;
                case self::MODE_CTR:
                    $plaintext = $this->openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
                    break;
                case self::MODE_CFB:
                    // cfb loosely routines inspired by openssl's:
                    // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
                    $plaintext = '';
                    if ($this->continuousBuffer) {
                        $iv = &$this->decryptIV;
                        $pos = &$this->debuffer['pos'];
                    } else {
                        $iv = $this->decryptIV;
                        $pos = 0;
                    }
                    $len = strlen($ciphertext);
                    $i = 0;
                    if ($pos) {
                        $orig_pos = $pos;
                        $max = $this->block_size - $pos;
                        if ($len >= $max) {
                            $i = $max;
                            $len -= $max;
                            $pos = 0;
                        } else {
                            $i = $len;
                            $pos += $len;
                            $len = 0;
                        }
                        // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
                        $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
                        $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
                        $ciphertext = substr($ciphertext, $i);
                    }
                    $overflow = $len % $this->block_size;
                    if ($overflow) {
                        $plaintext .= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
                        if ($len - $overflow) {
                            $iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
                        }
                        $iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
                        $plaintext .= $iv ^ substr($ciphertext, -$overflow);
                        $iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
                        $pos = $overflow;
                    } elseif ($len) {
                        $plaintext .= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
                        $iv = substr($ciphertext, -$this->block_size);
                    }
                    break;
                case self::MODE_CFB8:
                    $plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->decryptIV);
                    if ($this->continuousBuffer) {
                        if (($len = strlen($ciphertext)) >= $this->block_size) {
                            $this->decryptIV = substr($ciphertext, -$this->block_size);
                        } else {
                            $this->decryptIV = substr($this->decryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
                        }
                    }
                    break;
                case self::MODE_OFB8:
                    $plaintext = '';
                    $len = strlen($ciphertext);
                    $iv = $this->decryptIV;

                    for ($i = 0; $i < $len; ++$i) {
                        $xor = openssl_encrypt($iv, $this->cipher_name_openssl_ecb, $this->key, $this->openssl_options, $this->decryptIV);
                        $plaintext .= $ciphertext[$i] ^ $xor;
                        $iv = substr($iv, 1) . $xor[0];
                    }

                    if ($this->continuousBuffer) {
                        $this->decryptIV = $iv;
                    }
                    break;
                case self::MODE_OFB:
                    $plaintext = $this->openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
            }

            return $this->paddable ? $this->unpad($plaintext) : $plaintext;
        }

        if ($this->engine === self::ENGINE_MCRYPT) {
            set_error_handler(function () {
            });
            $block_size = $this->block_size;
            if ($this->dechanged) {
                mcrypt_generic_init($this->demcrypt, $this->key, $this->getIV($this->decryptIV));
                $this->dechanged = false;
            }

            if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
                $iv = &$this->decryptIV;
                $pos = &$this->debuffer['pos'];
                $len = strlen($ciphertext);
                $plaintext = '';
                $i = 0;
                if ($pos) {
                    $orig_pos = $pos;
                    $max = $block_size - $pos;
                    if ($len >= $max) {
                        $i = $max;
                        $len -= $max;
                        $pos = 0;
                    } else {
                        $i = $len;
                        $pos += $len;
                        $len = 0;
                    }
                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
                    $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
                    $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
                }
                if ($len >= $block_size) {
                    $cb = substr($ciphertext, $i, $len - $len % $block_size);
                    $plaintext .= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
                    $iv = substr($cb, -$block_size);
                    $len %= $block_size;
                }
                if ($len) {
                    $iv = mcrypt_generic($this->ecb, $iv);
                    $plaintext .= $iv ^ substr($ciphertext, -$len);
                    $iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
                    $pos = $len;
                }

                restore_error_handler();

                return $plaintext;
            }

            $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);

            if (!$this->continuousBuffer) {
                mcrypt_generic_init($this->demcrypt, $this->key, $this->getIV($this->decryptIV));
            }

            restore_error_handler();

            return $this->paddable ? $this->unpad($plaintext) : $plaintext;
        }

        if ($this->engine === self::ENGINE_EVAL) {
            $inline = $this->inline_crypt;
            return $inline('decrypt', $ciphertext);
        }

        $block_size = $this->block_size;

        $buffer = &$this->debuffer;
        $plaintext = '';
        switch ($this->mode) {
            case self::MODE_ECB:
                for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                    $plaintext .= $this->decryptBlock(substr($ciphertext, $i, $block_size));
                }
                break;
            case self::MODE_CBC:
                $xor = $this->decryptIV;
                for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                    $block = substr($ciphertext, $i, $block_size);
                    $plaintext .= $this->decryptBlock($block) ^ $xor;
                    $xor = $block;
                }
                if ($this->continuousBuffer) {
                    $this->decryptIV = $xor;
                }
                break;
            case self::MODE_CTR:
                $xor = $this->decryptIV;
                if (strlen($buffer['ciphertext'])) {
                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                        $block = substr($ciphertext, $i, $block_size);
                        if (strlen($block) > strlen($buffer['ciphertext'])) {
                            $buffer['ciphertext'] .= $this->encryptBlock($xor);
                            Strings::increment_str($xor);
                        }
                        $key = Strings::shift($buffer['ciphertext'], $block_size);
                        $plaintext .= $block ^ $key;
                    }
                } else {
                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                        $block = substr($ciphertext, $i, $block_size);
                        $key = $this->encryptBlock($xor);
                        Strings::increment_str($xor);
                        $plaintext .= $block ^ $key;
                    }
                }
                if ($this->continuousBuffer) {
                    $this->decryptIV = $xor;
                    if ($start = strlen($ciphertext) % $block_size) {
                        $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
                    }
                }
                break;
            case self::MODE_CFB:
                if ($this->continuousBuffer) {
                    $iv = &$this->decryptIV;
                    $pos = &$buffer['pos'];
                } else {
                    $iv = $this->decryptIV;
                    $pos = 0;
                }
                $len = strlen($ciphertext);
                $i = 0;
                if ($pos) {
                    $orig_pos = $pos;
                    $max = $block_size - $pos;
                    if ($len >= $max) {
                        $i = $max;
                        $len -= $max;
                        $pos = 0;
                    } else {
                        $i = $len;
                        $pos += $len;
                        $len = 0;
                    }
                    // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
                    $plaintext = substr($iv, $orig_pos) ^ $ciphertext;
                    $iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
                }
                while ($len >= $block_size) {
                    $iv = $this->encryptBlock($iv);
                    $cb = substr($ciphertext, $i, $block_size);
                    $plaintext .= $iv ^ $cb;
                    $iv = $cb;
                    $len -= $block_size;
                    $i += $block_size;
                }
                if ($len) {
                    $iv = $this->encryptBlock($iv);
                    $plaintext .= $iv ^ substr($ciphertext, $i);
                    $iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
                    $pos = $len;
                }
                break;
            case self::MODE_CFB8:
                $plaintext = '';
                $len = strlen($ciphertext);
                $iv = $this->decryptIV;

                for ($i = 0; $i < $len; ++$i) {
                    $plaintext .= $ciphertext[$i] ^ $this->encryptBlock($iv);
                    $iv = substr($iv, 1) . $ciphertext[$i];
                }

                if ($this->continuousBuffer) {
                    if ($len >= $block_size) {
                        $this->decryptIV = substr($ciphertext, -$block_size);
                    } else {
                        $this->decryptIV = substr($this->decryptIV, $len - $block_size) . substr($ciphertext, -$len);
                    }
                }
                break;
            case self::MODE_OFB8:
                $plaintext = '';
                $len = strlen($ciphertext);
                $iv = $this->decryptIV;

                for ($i = 0; $i < $len; ++$i) {
                    $xor = $this->encryptBlock($iv);
                    $plaintext .= $ciphertext[$i] ^ $xor;
                    $iv = substr($iv, 1) . $xor[0];
                }

                if ($this->continuousBuffer) {
                    $this->decryptIV = $iv;
                }
                break;
            case self::MODE_OFB:
                $xor = $this->decryptIV;
                if (strlen($buffer['xor'])) {
                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                        $block = substr($ciphertext, $i, $block_size);
                        if (strlen($block) > strlen($buffer['xor'])) {
                            $xor = $this->encryptBlock($xor);
                            $buffer['xor'] .= $xor;
                        }
                        $key = Strings::shift($buffer['xor'], $block_size);
                        $plaintext .= $block ^ $key;
                    }
                } else {
                    for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
                        $xor = $this->encryptBlock($xor);
                        $plaintext .= substr($ciphertext, $i, $block_size) ^ $xor;
                    }
                    $key = $xor;
                }
                if ($this->continuousBuffer) {
                    $this->decryptIV = $xor;
                    if ($start = strlen($ciphertext) % $block_size) {
                        $buffer['xor'] = substr($key, $start) . $buffer['xor'];
                    }
                }
                break;
            case self::MODE_STREAM:
                $plaintext = $this->decryptBlock($ciphertext);
                break;
        }
        return $this->paddable ? $this->unpad($plaintext) : $plaintext;
    }

    /**
     * Get the authentication tag
     *
     * Only used in GCM or Poly1305 mode
     *
     * @see self::encrypt()
     * @param int $length optional
     * @return string
     * @throws \LengthException if $length isn't of a sufficient length
     * @throws \RuntimeException if GCM mode isn't being used
     */
    public function getTag($length = 16)
    {
        if ($this->mode != self::MODE_GCM && !$this->usePoly1305) {
            throw new \BadMethodCallException('Authentication tags are only utilized in GCM mode or with Poly1305');
        }

        if ($this->newtag === false) {
            throw new \BadMethodCallException('A tag can only be returned after a round of encryption has been performed');
        }

        // the tag is 128-bits. it can't be greater than 16 bytes because that's bigger than the tag is. if it
        // were 0 you might as well be doing CTR and less than 4 provides minimal security that could be trivially
        // easily brute forced.
        // see https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=36
        // for more info
        if ($length < 4 || $length > 16) {
            throw new \LengthException('The authentication tag must be between 4 and 16 bytes long');
        }

        return $length == 16 ?
            $this->newtag :
            substr($this->newtag, 0, $length);
    }

    /**
     * Sets the authentication tag
     *
     * Only used in GCM mode
     *
     * @see self::decrypt()
     * @param string $tag
     * @throws \LengthException if $length isn't of a sufficient length
     * @throws \RuntimeException if GCM mode isn't being used
     */
    public function setTag($tag)
    {
        if ($this->usePoly1305 && !isset($this->poly1305Key) && method_exists($this, 'createPoly1305Key')) {
            $this->createPoly1305Key();
        }

        if ($this->mode != self::MODE_GCM && !$this->usePoly1305) {
            throw new \BadMethodCallException('Authentication tags are only utilized in GCM mode or with Poly1305');
        }

        $length = strlen($tag);
        if ($length < 4 || $length > 16) {
            throw new \LengthException('The authentication tag must be between 4 and 16 bytes long');
        }
        $this->oldtag = $tag;
    }

    /**
     * Get the IV
     *
     * mcrypt requires an IV even if ECB is used
     *
     * @see self::encrypt()
     * @see self::decrypt()
     * @param string $iv
     * @return string
     */
    protected function getIV($iv)
    {
        return $this->mode == self::MODE_ECB ? str_repeat("\0", $this->block_size) : $iv;
    }

    /**
     * OpenSSL CTR Processor
     *
     * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
     * for CTR is the same for both encrypting and decrypting this function is re-used by both SymmetricKey::encrypt()
     * and SymmetricKey::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
     * function will emulate CTR with ECB when necessary.
     *
     * @see self::encrypt()
     * @see self::decrypt()
     * @param string $plaintext
     * @param string $encryptIV
     * @param array $buffer
     * @return string
     */
    private function openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
    {
        $ciphertext = '';

        $block_size = $this->block_size;
        $key = $this->key;

        if ($this->openssl_emulate_ctr) {
            $xor = $encryptIV;
            if (strlen($buffer['ciphertext'])) {
                for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                    $block = substr($plaintext, $i, $block_size);
                    if (strlen($block) > strlen($buffer['ciphertext'])) {
                        $buffer['ciphertext'] .= openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
                    }
                    Strings::increment_str($xor);
                    $otp = Strings::shift($buffer['ciphertext'], $block_size);
                    $ciphertext .= $block ^ $otp;
                }
            } else {
                for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
                    $block = substr($plaintext, $i, $block_size);
                    $otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
                    Strings::increment_str($xor);
                    $ciphertext .= $block ^ $otp;
                }
            }
            if ($this->continuousBuffer) {
                $encryptIV = $xor;
                if ($start = strlen($plaintext) % $block_size) {
                    $buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
                }
            }

            return $ciphertext;
        }

        if (strlen($buffer['ciphertext'])) {
            $ciphertext = $plaintext ^ Strings::shift($buffer['ciphertext'], strlen($plaintext));
            $plaintext = substr($plaintext, strlen($ciphertext));

            if (!strlen($plaintext)) {
                return $ciphertext;
            }
        }

        $overflow = strlen($plaintext) % $block_size;
        if ($overflow) {
            $plaintext2 = Strings::pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
            $encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
            $temp = Strings::pop($encrypted, $block_size);
            $ciphertext .= $encrypted . ($plaintext2 ^ $temp);
            if ($this->continuousBuffer) {
                $buffer['ciphertext'] = substr($temp, $overflow);
                $encryptIV = $temp;
            }
        } elseif (!strlen($buffer['ciphertext'])) {
            $ciphertext .= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
            $temp = Strings::pop($ciphertext, $block_size);
            if ($this->continuousBuffer) {
                $encryptIV = $temp;
            }
        }
        if ($this->continuousBuffer) {
            $encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
            if ($overflow) {
                Strings::increment_str($encryptIV);
            }
        }

        return $ciphertext;
    }

    /**
     * OpenSSL OFB Processor
     *
     * PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
     * for OFB is the same for both encrypting and decrypting this function is re-used by both SymmetricKey::encrypt()
     * and SymmetricKey::decrypt().
     *
     * @see self::encrypt()
     * @see self::decrypt()
     * @param string $plaintext
     * @param string $encryptIV
     * @param array $buffer
     * @return string
     */
    private function openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
    {
        if (strlen($buffer['xor'])) {
            $ciphertext = $plaintext ^ $buffer['xor'];
            $buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
            $plaintext = substr($plaintext, strlen($ciphertext));
        } else {
            $ciphertext = '';
        }

        $block_size = $this->block_size;

        $len = strlen($plaintext);
        $key = $this->key;
        $overflow = $len % $block_size;

        if (strlen($plaintext)) {
            if ($overflow) {
                $ciphertext .= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
                $xor = Strings::pop($ciphertext, $block_size);
                if ($this->continuousBuffer) {
                    $encryptIV = $xor;
                }
                $ciphertext .= Strings::shift($xor, $overflow) ^ substr($plaintext, -$overflow);
                if ($this->continuousBuffer) {
                    $buffer['xor'] = $xor;
                }
            } else {
                $ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
                if ($this->continuousBuffer) {
                    $encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
                }
            }
        }

        return $ciphertext;
    }

    /**
     * phpseclib <-> OpenSSL Mode Mapper
     *
     * May need to be overwritten by classes extending this one in some cases
     *
     * @return string
     */
    protected function openssl_translate_mode()
    {
        switch ($this->mode) {
            case self::MODE_ECB:
                return 'ecb';
            case self::MODE_CBC:
                return 'cbc';
            case self::MODE_CTR:
            case self::MODE_GCM:
                return 'ctr';
            case self::MODE_CFB:
                return 'cfb';
            case self::MODE_CFB8:
                return 'cfb8';
            case self::MODE_OFB:
                return 'ofb';
        }
    }

    /**
     * Pad "packets".
     *
     * Block ciphers working by encrypting between their specified [$this->]block_size at a time
     * If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
     * pad the input so that it is of the proper length.
     *
     * Padding is enabled by default.  Sometimes, however, it is undesirable to pad strings.  Such is the case in SSH,
     * where "packets" are padded with random bytes before being encrypted.  Unpad these packets and you risk stripping
     * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
     * transmitted separately)
     *
     * @see self::disablePadding()
     */
    public function enablePadding()
    {
        $this->padding = true;
    }

    /**
     * Do not pad packets.
     *
     * @see self::enablePadding()
     */
    public function disablePadding()
    {
        $this->padding = false;
    }

    /**
     * Treat consecutive "packets" as if they are a continuous buffer.
     *
     * Say you have a 32-byte plaintext $plaintext.  Using the default behavior, the two following code snippets
     * will yield different outputs:
     *
     * <code>
     *    echo $rijndael->encrypt(substr($plaintext,  0, 16));
     *    echo $rijndael->encrypt(substr($plaintext, 16, 16));
     * </code>
     * <code>
     *    echo $rijndael->encrypt($plaintext);
     * </code>
     *
     * The solution is to enable the continuous buffer.  Although this will resolve the above discrepancy, it creates
     * another, as demonstrated with the following:
     *
     * <code>
     *    $rijndael->encrypt(substr($plaintext, 0, 16));
     *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
     * </code>
     * <code>
     *    echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
     * </code>
     *
     * With the continuous buffer disabled, these would yield the same output.  With it enabled, they yield different
     * outputs.  The reason is due to the fact that the initialization vector's change after every encryption /
     * decryption round when the continuous buffer is enabled.  When it's disabled, they remain constant.
     *
     * Put another way, when the continuous buffer is enabled, the state of the \phpseclib3\Crypt\*() object changes after each
     * encryption / decryption round, whereas otherwise, it'd remain constant.  For this reason, it's recommended that
     * continuous buffers not be used.  They do offer better security and are, in fact, sometimes required (SSH uses them),
     * however, they are also less intuitive and more likely to cause you problems.
     *
     * {@internal Could, but not must, extend by the child Crypt_* class}
     *
     * @see self::disableContinuousBuffer()
     */
    public function enableContinuousBuffer()
    {
        if ($this->mode == self::MODE_ECB) {
            return;
        }

        if ($this->mode == self::MODE_GCM) {
            throw new \BadMethodCallException('This mode does not run in continuous mode');
        }

        $this->continuousBuffer = true;

        $this->setEngine();
    }

    /**
     * Treat consecutive packets as if they are a discontinuous buffer.
     *
     * The default behavior.
     *
     * {@internal Could, but not must, extend by the child Crypt_* class}
     *
     * @see self::enableContinuousBuffer()
     */
    public function disableContinuousBuffer()
    {
        if ($this->mode == self::MODE_ECB) {
            return;
        }
        if (!$this->continuousBuffer) {
            return;
        }

        $this->continuousBuffer = false;

        $this->setEngine();
    }

    /**
     * Test for engine validity
     *
     * @see self::__construct()
     * @param int $engine
     * @return bool
     */
    protected function isValidEngineHelper($engine)
    {
        switch ($engine) {
            case self::ENGINE_OPENSSL:
                $this->openssl_emulate_ctr = false;
                $result = $this->cipher_name_openssl &&
                          extension_loaded('openssl');
                if (!$result) {
                    return false;
                }

                $methods = openssl_get_cipher_methods();
                if (in_array($this->cipher_name_openssl, $methods)) {
                    return true;
                }
                // not all of openssl's symmetric cipher's support ctr. for those
                // that don't we'll emulate it
                switch ($this->mode) {
                    case self::MODE_CTR:
                        if (in_array($this->cipher_name_openssl_ecb, $methods)) {
                            $this->openssl_emulate_ctr = true;
                            return true;
                        }
                }
                return false;
            case self::ENGINE_MCRYPT:
                set_error_handler(function () {
                });
                $result = $this->cipher_name_mcrypt &&
                          extension_loaded('mcrypt') &&
                          in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms());
                restore_error_handler();
                return $result;
            case self::ENGINE_EVAL:
                return method_exists($this, 'setupInlineCrypt');
            case self::ENGINE_INTERNAL:
                return true;
        }

        return false;
    }

    /**
     * Test for engine validity
     *
     * @see self::__construct()
     * @param string $engine
     * @return bool
     */
    public function isValidEngine($engine)
    {
        static $reverseMap;
        if (!isset($reverseMap)) {
            $reverseMap = array_map('strtolower', self::ENGINE_MAP);
            $reverseMap = array_flip($reverseMap);
        }
        $engine = strtolower($engine);
        if (!isset($reverseMap[$engine])) {
            return false;
        }

        return $this->isValidEngineHelper($reverseMap[$engine]);
    }

    /**
     * Sets the preferred crypt engine
     *
     * Currently, $engine could be:
     *
     * - libsodium[very fast]
     *
     * - OpenSSL  [very fast]
     *
     * - mcrypt   [fast]
     *
     * - Eval     [slow]
     *
     * - PHP      [slowest]
     *
     * If the preferred crypt engine is not available the fastest available one will be used
     *
     * @see self::__construct()
     * @param string $engine
     */
    public function setPreferredEngine($engine)
    {
        static $reverseMap;
        if (!isset($reverseMap)) {
            $reverseMap = array_map('strtolower', self::ENGINE_MAP);
            $reverseMap = array_flip($reverseMap);
        }
        $engine = is_string($engine) ? strtolower($engine) : '';
        $this->preferredEngine = isset($reverseMap[$engine]) ? $reverseMap[$engine] : self::ENGINE_LIBSODIUM;

        $this->setEngine();
    }

    /**
     * Returns the engine currently being utilized
     *
     * @see self::setEngine()
     */
    public function getEngine()
    {
        return self::ENGINE_MAP[$this->engine];
    }

    /**
     * Sets the engine as appropriate
     *
     * @see self::__construct()
     */
    protected function setEngine()
    {
        $this->engine = null;

        $candidateEngines = [
            self::ENGINE_LIBSODIUM,
            self::ENGINE_OPENSSL_GCM,
            self::ENGINE_OPENSSL,
            self::ENGINE_MCRYPT,
            self::ENGINE_EVAL
        ];
        if (isset($this->preferredEngine)) {
            $temp = [$this->preferredEngine];
            $candidateEngines = array_merge(
                $temp,
                array_diff($candidateEngines, $temp)
            );
        }
        foreach ($candidateEngines as $engine) {
            if ($this->isValidEngineHelper($engine)) {
                $this->engine = $engine;
                break;
            }
        }
        if (!$this->engine) {
            $this->engine = self::ENGINE_INTERNAL;
        }

        if ($this->engine != self::ENGINE_MCRYPT && $this->enmcrypt) {
            set_error_handler(function () {
            });
            // Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
            // (re)open them with the module named in $this->cipher_name_mcrypt
            mcrypt_module_close($this->enmcrypt);
            mcrypt_module_close($this->demcrypt);
            $this->enmcrypt = null;
            $this->demcrypt = null;

            if ($this->ecb) {
                mcrypt_module_close($this->ecb);
                $this->ecb = null;
            }
            restore_error_handler();
        }

        $this->changed = $this->nonIVChanged = true;
    }

    /**
     * Encrypts a block
     *
     * Note: Must be extended by the child \phpseclib3\Crypt\* class
     *
     * @param string $in
     * @return string
     */
    abstract protected function encryptBlock($in);

    /**
     * Decrypts a block
     *
     * Note: Must be extended by the child \phpseclib3\Crypt\* class
     *
     * @param string $in
     * @return string
     */
    abstract protected function decryptBlock($in);

    /**
     * Setup the key (expansion)
     *
     * Only used if $engine == self::ENGINE_INTERNAL
     *
     * Note: Must extend by the child \phpseclib3\Crypt\* class
     *
     * @see self::setup()
     */
    abstract protected function setupKey();

    /**
     * Setup the self::ENGINE_INTERNAL $engine
     *
     * (re)init, if necessary, the internal cipher $engine and flush all $buffers
     * Used (only) if $engine == self::ENGINE_INTERNAL
     *
     * _setup() will be called each time if $changed === true
     * typically this happens when using one or more of following public methods:
     *
     * - setKey()
     *
     * - setIV()
     *
     * - disableContinuousBuffer()
     *
     * - First run of encrypt() / decrypt() with no init-settings
     *
     * {@internal setup() is always called before en/decryption.}
     *
     * {@internal Could, but not must, extend by the child Crypt_* class}
     *
     * @see self::setKey()
     * @see self::setIV()
     * @see self::disableContinuousBuffer()
     */
    protected function setup()
    {
        if (!$this->changed) {
            return;
        }

        $this->changed = false;

        if ($this->usePoly1305 && !isset($this->poly1305Key) && method_exists($this, 'createPoly1305Key')) {
            $this->createPoly1305Key();
        }

        $this->enbuffer = $this->debuffer = ['ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true];
        //$this->newtag = $this->oldtag = false;

        if ($this->usesNonce()) {
            if ($this->nonce === false) {
                throw new InsufficientSetupException('No nonce has been defined');
            }
            if ($this->mode == self::MODE_GCM && !in_array($this->engine, [self::ENGINE_LIBSODIUM, self::ENGINE_OPENSSL_GCM])) {
                $this->setupGCM();
            }
        } else {
            $this->iv = $this->origIV;
        }

        if ($this->iv === false && !in_array($this->mode, [self::MODE_STREAM, self::MODE_ECB])) {
            if ($this->mode != self::MODE_GCM || !in_array($this->engine, [self::ENGINE_LIBSODIUM, self::ENGINE_OPENSSL_GCM])) {
                throw new InsufficientSetupException('No IV has been defined');
            }
        }

        if ($this->key === false) {
            throw new InsufficientSetupException('No key has been defined');
        }

        $this->encryptIV = $this->decryptIV = $this->iv;

        switch ($this->engine) {
            case self::ENGINE_MCRYPT:
                $this->enchanged = $this->dechanged = true;

                set_error_handler(function () {
                });

                if (!isset($this->enmcrypt)) {
                    static $mcrypt_modes = [
                        self::MODE_CTR    => 'ctr',
                        self::MODE_ECB    => MCRYPT_MODE_ECB,
                        self::MODE_CBC    => MCRYPT_MODE_CBC,
                        self::MODE_CFB    => 'ncfb',
                        self::MODE_CFB8   => MCRYPT_MODE_CFB,
                        self::MODE_OFB    => MCRYPT_MODE_NOFB,
                        self::MODE_OFB8   => MCRYPT_MODE_OFB,
                        self::MODE_STREAM => MCRYPT_MODE_STREAM,
                    ];

                    $this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
                    $this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');

                    // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
                    // to workaround mcrypt's broken ncfb implementation in buffered mode
                    // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
                    if ($this->mode == self::MODE_CFB) {
                        $this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
                    }
                } // else should mcrypt_generic_deinit be called?

                if ($this->mode == self::MODE_CFB) {
                    mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
                }

                restore_error_handler();

                break;
            case self::ENGINE_INTERNAL:
                $this->setupKey();
                break;
            case self::ENGINE_EVAL:
                if ($this->nonIVChanged) {
                    $this->setupKey();
                    $this->setupInlineCrypt();
                }
        }

        $this->nonIVChanged = false;
    }

    /**
     * Pads a string
     *
     * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
     * $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
     * chr($this->block_size - (strlen($text) % $this->block_size)
     *
     * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
     * and padding will, hence forth, be enabled.
     *
     * @see self::unpad()
     * @param string $text
     * @throws \LengthException if padding is disabled and the plaintext's length is not a multiple of the block size
     * @return string
     */
    protected function pad($text)
    {
        $length = strlen($text);

        if (!$this->padding) {
            if ($length % $this->block_size == 0) {
                return $text;
            } else {
                throw new \LengthException("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size}). Try enabling padding.");
            }
        }

        $pad = $this->block_size - ($length % $this->block_size);

        return str_pad($text, $length + $pad, chr($pad));
    }

    /**
     * Unpads a string.
     *
     * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
     * and false will be returned.
     *
     * @see self::pad()
     * @param string $text
     * @throws \LengthException if the ciphertext's length is not a multiple of the block size
     * @return string
     */
    protected function unpad($text)
    {
        if (!$this->padding) {
            return $text;
        }

        $length = ord($text[strlen($text) - 1]);

        if (!$length | ($length > $this->block_size)) {
            throw new BadDecryptionException("The ciphertext has an invalid padding length ($length) compared to the block size ({$this->block_size})");
        }

        return substr($text, 0, -$length);
    }

    /**
     * Setup the performance-optimized function for de/encrypt()
     *
     * Stores the created (or existing) callback function-name
     * in $this->inline_crypt
     *
     * Internally for phpseclib developers:
     *
     *     _setupInlineCrypt() would be called only if:
     *
     *     - $this->engine === self::ENGINE_EVAL
     *
     *     - each time on _setup(), after(!) _setupKey()
     *
     *
     *     This ensures that _setupInlineCrypt() has always a
     *     full ready2go initializated internal cipher $engine state
     *     where, for example, the keys already expanded,
     *     keys/block_size calculated and such.
     *
     *     It is, each time if called, the responsibility of _setupInlineCrypt():
     *
     *     - to set $this->inline_crypt to a valid and fully working callback function
     *       as a (faster) replacement for encrypt() / decrypt()
     *
     *     - NOT to create unlimited callback functions (for memory reasons!)
     *       no matter how often _setupInlineCrypt() would be called. At some
     *       point of amount they must be generic re-useable.
     *
     *     - the code of _setupInlineCrypt() it self,
     *       and the generated callback code,
     *       must be, in following order:
     *       - 100% safe
     *       - 100% compatible to encrypt()/decrypt()
     *       - using only php5+ features/lang-constructs/php-extensions if
     *         compatibility (down to php4) or fallback is provided
     *       - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
     *       - >= 10% faster than encrypt()/decrypt() [which is, by the way,
     *         the reason for the existence of _setupInlineCrypt() :-)]
     *       - memory-nice
     *       - short (as good as possible)
     *
     * Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
     *       - In case of using inline crypting, _setupInlineCrypt() must extend by the child \phpseclib3\Crypt\* class.
     *       - The following variable names are reserved:
     *         - $_*  (all variable names prefixed with an underscore)
     *         - $self (object reference to it self. Do not use $this, but $self instead)
     *         - $in (the content of $in has to en/decrypt by the generated code)
     *       - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
     *
     * {@internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()}
     *
     * @see self::setup()
     * @see self::createInlineCryptFunction()
     * @see self::encrypt()
     * @see self::decrypt()
     */
    //protected function setupInlineCrypt();

    /**
     * Creates the performance-optimized function for en/decrypt()
     *
     * Internally for phpseclib developers:
     *
     *    _createInlineCryptFunction():
     *
     *    - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
     *      with the current [$this->]mode of operation code
     *
     *    - create the $inline function, which called by encrypt() / decrypt()
     *      as its replacement to speed up the en/decryption operations.
     *
     *    - return the name of the created $inline callback function
     *
     *    - used to speed up en/decryption
     *
     *
     *
     *    The main reason why can speed up things [up to 50%] this way are:
     *
     *    - using variables more effective then regular.
     *      (ie no use of expensive arrays but integers $k_0, $k_1 ...
     *      or even, for example, the pure $key[] values hardcoded)
     *
     *    - avoiding 1000's of function calls of ie _encryptBlock()
     *      but inlining the crypt operations.
     *      in the mode of operation for() loop.
     *
     *    - full loop unroll the (sometimes key-dependent) rounds
     *      avoiding this way ++$i counters and runtime-if's etc...
     *
     *    The basic code architectur of the generated $inline en/decrypt()
     *    lambda function, in pseudo php, is:
     *
     *    <code>
     *    +----------------------------------------------------------------------------------------------+
     *    | callback $inline = create_function:                                                          |
     *    | lambda_function_0001_crypt_ECB($action, $text)                                               |
     *    | {                                                                                            |
     *    |     INSERT PHP CODE OF:                                                                      |
     *    |     $cipher_code['init_crypt'];                  // general init code.                       |
     *    |                                                  // ie: $sbox'es declarations used for       |
     *    |                                                  //     encrypt and decrypt'ing.             |
     *    |                                                                                              |
     *    |     switch ($action) {                                                                       |
     *    |         case 'encrypt':                                                                      |
     *    |             INSERT PHP CODE OF:                                                              |
     *    |             $cipher_code['init_encrypt'];       // encrypt sepcific init code.               |
     *    |                                                    ie: specified $key or $box                |
     *    |                                                        declarations for encrypt'ing.         |
     *    |                                                                                              |
     *    |             foreach ($ciphertext) {                                                          |
     *    |                 $in = $block_size of $ciphertext;                                            |
     *    |                                                                                              |
     *    |                 INSERT PHP CODE OF:                                                          |
     *    |                 $cipher_code['encrypt_block'];  // encrypt's (string) $in, which is always:  |
     *    |                                                 // strlen($in) == $this->block_size          |
     *    |                                                 // here comes the cipher algorithm in action |
     *    |                                                 // for encryption.                           |
     *    |                                                 // $cipher_code['encrypt_block'] has to      |
     *    |                                                 // encrypt the content of the $in variable   |
     *    |                                                                                              |
     *    |                 $plaintext .= $in;                                                           |
     *    |             }                                                                                |
     *    |             return $plaintext;                                                               |
     *    |                                                                                              |
     *    |         case 'decrypt':                                                                      |
     *    |             INSERT PHP CODE OF:                                                              |
     *    |             $cipher_code['init_decrypt'];       // decrypt sepcific init code                |
     *    |                                                    ie: specified $key or $box                |
     *    |                                                        declarations for decrypt'ing.         |
     *    |             foreach ($plaintext) {                                                           |
     *    |                 $in = $block_size of $plaintext;                                             |
     *    |                                                                                              |
     *    |                 INSERT PHP CODE OF:                                                          |
     *    |                 $cipher_code['decrypt_block'];  // decrypt's (string) $in, which is always   |
     *    |                                                 // strlen($in) == $this->block_size          |
     *    |                                                 // here comes the cipher algorithm in action |
     *    |                                                 // for decryption.                           |
     *    |                                                 // $cipher_code['decrypt_block'] has to      |
     *    |                                                 // decrypt the content of the $in variable   |
     *    |                 $ciphertext .= $in;                                                          |
     *    |             }                                                                                |
     *    |             return $ciphertext;                                                              |
     *    |     }                                                                                        |
     *    | }                                                                                            |
     *    +----------------------------------------------------------------------------------------------+
     *    </code>
     *
     *    See also the \phpseclib3\Crypt\*::_setupInlineCrypt()'s for
     *    productive inline $cipher_code's how they works.
     *
     *    Structure of:
     *    <code>
     *    $cipher_code = [
     *        'init_crypt'    => (string) '', // optional
     *        'init_encrypt'  => (string) '', // optional
     *        'init_decrypt'  => (string) '', // optional
     *        'encrypt_block' => (string) '', // required
     *        'decrypt_block' => (string) ''  // required
     *    ];
     *    </code>
     *
     * @see self::setupInlineCrypt()
     * @see self::encrypt()
     * @see self::decrypt()
     * @param array $cipher_code
     * @return string (the name of the created callback function)
     */
    protected function createInlineCryptFunction($cipher_code)
    {
        $block_size = $this->block_size;

        // optional
        $init_crypt    = isset($cipher_code['init_crypt'])    ? $cipher_code['init_crypt']    : '';
        $init_encrypt  = isset($cipher_code['init_encrypt'])  ? $cipher_code['init_encrypt']  : '';
        $init_decrypt  = isset($cipher_code['init_decrypt'])  ? $cipher_code['init_decrypt']  : '';
        // required
        $encrypt_block = $cipher_code['encrypt_block'];
        $decrypt_block = $cipher_code['decrypt_block'];

        // Generating mode of operation inline code,
        // merged with the $cipher_code algorithm
        // for encrypt- and decryption.
        switch ($this->mode) {
            case self::MODE_ECB:
                $encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_plaintext_len = strlen($_text);

                    for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
                        $in = substr($_text, $_i, ' . $block_size . ');
                        ' . $encrypt_block . '
                        $_ciphertext.= $in;
                    }

                    return $_ciphertext;
                    ';

                $decrypt = $init_decrypt . '
                    $_plaintext = "";
                    $_text = str_pad($_text, strlen($_text) + (' . $block_size . ' - strlen($_text) % ' . $block_size . ') % ' . $block_size . ', chr(0));
                    $_ciphertext_len = strlen($_text);

                    for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
                        $in = substr($_text, $_i, ' . $block_size . ');
                        ' . $decrypt_block . '
                        $_plaintext.= $in;
                    }

                    return $this->unpad($_plaintext);
                    ';
                break;
            case self::MODE_CTR:
                $encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_plaintext_len = strlen($_text);
                    $_xor = $this->encryptIV;
                    $_buffer = &$this->enbuffer;
                    if (strlen($_buffer["ciphertext"])) {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
                            $_block = substr($_text, $_i, ' . $block_size . ');
                            if (strlen($_block) > strlen($_buffer["ciphertext"])) {
                                $in = $_xor;
                                ' . $encrypt_block . '
                                \phpseclib3\Common\Functions\Strings::increment_str($_xor);
                                $_buffer["ciphertext"].= $in;
                            }
                            $_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["ciphertext"], ' . $block_size . ');
                            $_ciphertext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
                            $_block = substr($_text, $_i, ' . $block_size . ');
                            $in = $_xor;
                            ' . $encrypt_block . '
                            \phpseclib3\Common\Functions\Strings::increment_str($_xor);
                            $_key = $in;
                            $_ciphertext.= $_block ^ $_key;
                        }
                    }
                    if ($this->continuousBuffer) {
                        $this->encryptIV = $_xor;
                        if ($_start = $_plaintext_len % ' . $block_size . ') {
                            $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
                        }
                    }

                    return $_ciphertext;
                ';

                $decrypt = $init_encrypt . '
                    $_plaintext = "";
                    $_ciphertext_len = strlen($_text);
                    $_xor = $this->decryptIV;
                    $_buffer = &$this->debuffer;

                    if (strlen($_buffer["ciphertext"])) {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
                            $_block = substr($_text, $_i, ' . $block_size . ');
                            if (strlen($_block) > strlen($_buffer["ciphertext"])) {
                                $in = $_xor;
                                ' . $encrypt_block . '
                                \phpseclib3\Common\Functions\Strings::increment_str($_xor);
                                $_buffer["ciphertext"].= $in;
                            }
                            $_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["ciphertext"], ' . $block_size . ');
                            $_plaintext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
                            $_block = substr($_text, $_i, ' . $block_size . ');
                            $in = $_xor;
                            ' . $encrypt_block . '
                            \phpseclib3\Common\Functions\Strings::increment_str($_xor);
                            $_key = $in;
                            $_plaintext.= $_block ^ $_key;
                        }
                    }
                    if ($this->continuousBuffer) {
                        $this->decryptIV = $_xor;
                        if ($_start = $_ciphertext_len % ' . $block_size . ') {
                            $_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
                        }
                    }

                    return $_plaintext;
                    ';
                break;
            case self::MODE_CFB:
                $encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_buffer = &$this->enbuffer;

                    if ($this->continuousBuffer) {
                        $_iv = &$this->encryptIV;
                        $_pos = &$_buffer["pos"];
                    } else {
                        $_iv = $this->encryptIV;
                        $_pos = 0;
                    }
                    $_len = strlen($_text);
                    $_i = 0;
                    if ($_pos) {
                        $_orig_pos = $_pos;
                        $_max = ' . $block_size . ' - $_pos;
                        if ($_len >= $_max) {
                            $_i = $_max;
                            $_len-= $_max;
                            $_pos = 0;
                        } else {
                            $_i = $_len;
                            $_pos+= $_len;
                            $_len = 0;
                        }
                        $_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
                        $_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
                    }
                    while ($_len >= ' . $block_size . ') {
                        $in = $_iv;
                        ' . $encrypt_block . ';
                        $_iv = $in ^ substr($_text, $_i, ' . $block_size . ');
                        $_ciphertext.= $_iv;
                        $_len-= ' . $block_size . ';
                        $_i+= ' . $block_size . ';
                    }
                    if ($_len) {
                        $in = $_iv;
                        ' . $encrypt_block . '
                        $_iv = $in;
                        $_block = $_iv ^ substr($_text, $_i);
                        $_iv = substr_replace($_iv, $_block, 0, $_len);
                        $_ciphertext.= $_block;
                        $_pos = $_len;
                    }
                    return $_ciphertext;
                ';

                $decrypt = $init_encrypt . '
                    $_plaintext = "";
                    $_buffer = &$this->debuffer;

                    if ($this->continuousBuffer) {
                        $_iv = &$this->decryptIV;
                        $_pos = &$_buffer["pos"];
                    } else {
                        $_iv = $this->decryptIV;
                        $_pos = 0;
                    }
                    $_len = strlen($_text);
                    $_i = 0;
                    if ($_pos) {
                        $_orig_pos = $_pos;
                        $_max = ' . $block_size . ' - $_pos;
                        if ($_len >= $_max) {
                            $_i = $_max;
                            $_len-= $_max;
                            $_pos = 0;
                        } else {
                            $_i = $_len;
                            $_pos+= $_len;
                            $_len = 0;
                        }
                        $_plaintext = substr($_iv, $_orig_pos) ^ $_text;
                        $_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
                    }
                    while ($_len >= ' . $block_size . ') {
                        $in = $_iv;
                        ' . $encrypt_block . '
                        $_iv = $in;
                        $cb = substr($_text, $_i, ' . $block_size . ');
                        $_plaintext.= $_iv ^ $cb;
                        $_iv = $cb;
                        $_len-= ' . $block_size . ';
                        $_i+= ' . $block_size . ';
                    }
                    if ($_len) {
                        $in = $_iv;
                        ' . $encrypt_block . '
                        $_iv = $in;
                        $_plaintext.= $_iv ^ substr($_text, $_i);
                        $_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
                        $_pos = $_len;
                    }

                    return $_plaintext;
                    ';
                break;
            case self::MODE_CFB8:
                $encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_len = strlen($_text);
                    $_iv = $this->encryptIV;

                    for ($_i = 0; $_i < $_len; ++$_i) {
                        $in = $_iv;
                        ' . $encrypt_block . '
                        $_ciphertext .= ($_c = $_text[$_i] ^ $in);
                        $_iv = substr($_iv, 1) . $_c;
                    }

                    if ($this->continuousBuffer) {
                        if ($_len >= ' . $block_size . ') {
                            $this->encryptIV = substr($_ciphertext, -' . $block_size . ');
                        } else {
                            $this->encryptIV = substr($this->encryptIV, $_len - ' . $block_size . ') . substr($_ciphertext, -$_len);
                        }
                    }

                    return $_ciphertext;
                    ';
                $decrypt = $init_encrypt . '
                    $_plaintext = "";
                    $_len = strlen($_text);
                    $_iv = $this->decryptIV;

                    for ($_i = 0; $_i < $_len; ++$_i) {
                        $in = $_iv;
                        ' . $encrypt_block . '
                        $_plaintext .= $_text[$_i] ^ $in;
                        $_iv = substr($_iv, 1) . $_text[$_i];
                    }

                    if ($this->continuousBuffer) {
                        if ($_len >= ' . $block_size . ') {
                            $this->decryptIV = substr($_text, -' . $block_size . ');
                        } else {
                            $this->decryptIV = substr($this->decryptIV, $_len - ' . $block_size . ') . substr($_text, -$_len);
                        }
                    }

                    return $_plaintext;
                    ';
                break;
            case self::MODE_OFB8:
                $encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_len = strlen($_text);
                    $_iv = $this->encryptIV;

                    for ($_i = 0; $_i < $_len; ++$_i) {
                        $in = $_iv;
                        ' . $encrypt_block . '
                        $_ciphertext.= $_text[$_i] ^ $in;
                        $_iv = substr($_iv, 1) . $in[0];
                    }

                    if ($this->continuousBuffer) {
                        $this->encryptIV = $_iv;
                    }

                    return $_ciphertext;
                    ';
                $decrypt = $init_encrypt . '
                    $_plaintext = "";
                    $_len = strlen($_text);
                    $_iv = $this->decryptIV;

                    for ($_i = 0; $_i < $_len; ++$_i) {
                        $in = $_iv;
                        ' . $encrypt_block . '
                        $_plaintext.= $_text[$_i] ^ $in;
                        $_iv = substr($_iv, 1) . $in[0];
                    }

                    if ($this->continuousBuffer) {
                        $this->decryptIV = $_iv;
                    }

                    return $_plaintext;
                    ';
                break;
            case self::MODE_OFB:
                $encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_plaintext_len = strlen($_text);
                    $_xor = $this->encryptIV;
                    $_buffer = &$this->enbuffer;

                    if (strlen($_buffer["xor"])) {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
                            $_block = substr($_text, $_i, ' . $block_size . ');
                            if (strlen($_block) > strlen($_buffer["xor"])) {
                                $in = $_xor;
                                ' . $encrypt_block . '
                                $_xor = $in;
                                $_buffer["xor"].= $_xor;
                            }
                            $_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["xor"], ' . $block_size . ');
                            $_ciphertext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
                            $in = $_xor;
                            ' . $encrypt_block . '
                            $_xor = $in;
                            $_ciphertext.= substr($_text, $_i, ' . $block_size . ') ^ $_xor;
                        }
                        $_key = $_xor;
                    }
                    if ($this->continuousBuffer) {
                        $this->encryptIV = $_xor;
                        if ($_start = $_plaintext_len % ' . $block_size . ') {
                             $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
                        }
                    }
                    return $_ciphertext;
                    ';

                $decrypt = $init_encrypt . '
                    $_plaintext = "";
                    $_ciphertext_len = strlen($_text);
                    $_xor = $this->decryptIV;
                    $_buffer = &$this->debuffer;

                    if (strlen($_buffer["xor"])) {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
                            $_block = substr($_text, $_i, ' . $block_size . ');
                            if (strlen($_block) > strlen($_buffer["xor"])) {
                                $in = $_xor;
                                ' . $encrypt_block . '
                                $_xor = $in;
                                $_buffer["xor"].= $_xor;
                            }
                            $_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["xor"], ' . $block_size . ');
                            $_plaintext.= $_block ^ $_key;
                        }
                    } else {
                        for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
                            $in = $_xor;
                            ' . $encrypt_block . '
                            $_xor = $in;
                            $_plaintext.= substr($_text, $_i, ' . $block_size . ') ^ $_xor;
                        }
                        $_key = $_xor;
                    }
                    if ($this->continuousBuffer) {
                        $this->decryptIV = $_xor;
                        if ($_start = $_ciphertext_len % ' . $block_size . ') {
                             $_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
                        }
                    }
                    return $_plaintext;
                    ';
                break;
            case self::MODE_STREAM:
                $encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    ' . $encrypt_block . '
                    return $_ciphertext;
                    ';
                $decrypt = $init_decrypt . '
                    $_plaintext = "";
                    ' . $decrypt_block . '
                    return $_plaintext;
                    ';
                break;
            // case self::MODE_CBC:
            default:
                $encrypt = $init_encrypt . '
                    $_ciphertext = "";
                    $_plaintext_len = strlen($_text);

                    $in = $this->encryptIV;

                    for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
                        $in = substr($_text, $_i, ' . $block_size . ') ^ $in;
                        ' . $encrypt_block . '
                        $_ciphertext.= $in;
                    }

                    if ($this->continuousBuffer) {
                        $this->encryptIV = $in;
                    }

                    return $_ciphertext;
                    ';

                $decrypt = $init_decrypt . '
                    $_plaintext = "";
                    $_text = str_pad($_text, strlen($_text) + (' . $block_size . ' - strlen($_text) % ' . $block_size . ') % ' . $block_size . ', chr(0));
                    $_ciphertext_len = strlen($_text);

                    $_iv = $this->decryptIV;

                    for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
                        $in = $_block = substr($_text, $_i, ' . $block_size . ');
                        ' . $decrypt_block . '
                        $_plaintext.= $in ^ $_iv;
                        $_iv = $_block;
                    }

                    if ($this->continuousBuffer) {
                        $this->decryptIV = $_iv;
                    }

                    return $this->unpad($_plaintext);
                    ';
                break;
        }

        // Before discrediting this, please read the following:
        // @see https://github.com/phpseclib/phpseclib/issues/1293
        // @see https://github.com/phpseclib/phpseclib/pull/1143
        eval('$func = function ($_action, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }};');

        return \Closure::bind($func, $this, static::class);
    }

    /**
     * Convert float to int
     *
     * On ARM CPUs converting floats to ints doesn't always work
     *
     * @param string $x
     * @return int
     */
    protected static function safe_intval($x)
    {
        if (is_int($x)) {
            return $x;
        }

        if (self::$use_reg_intval) {
            return PHP_INT_SIZE == 4 && PHP_VERSION_ID >= 80100 ? intval($x) : $x;
        }

        return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
            ((fmod(floor($x / 0x80000000), 2) & 1) << 31);
    }

    /**
     * eval()'able string for in-line float to int
     *
     * @return string
     */
    protected static function safe_intval_inline()
    {
        if (self::$use_reg_intval) {
            return PHP_INT_SIZE == 4 && PHP_VERSION_ID >= 80100 ? 'intval(%s)' : '%s';
        }

        $safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
        return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
    }

    /**
     * Sets up GCM parameters
     *
     * See steps 1-2 of https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=23
     * for more info
     *
     */
    private function setupGCM()
    {
        // don't keep on re-calculating $this->h
        if (!$this->h || $this->hKey != $this->key) {
            $cipher = new static('ecb');
            $cipher->setKey($this->key);
            $cipher->disablePadding();

            $this->h = self::$gcmField->newInteger(
                Strings::switchEndianness($cipher->encrypt("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"))
            );
            $this->hKey = $this->key;
        }

        if (strlen($this->nonce) == 12) {
            $this->iv = $this->nonce . "\0\0\0\1";
        } else {
            $this->iv = $this->ghash(
                self::nullPad128($this->nonce) . str_repeat("\0", 8) . self::len64($this->nonce)
            );
        }
    }

    /**
     * Performs GHASH operation
     *
     * See https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=20
     * for more info
     *
     * @see self::decrypt()
     * @see self::encrypt()
     * @param string $x
     * @return string
     */
    private function ghash($x)
    {
        $h = $this->h;
        $y = ["\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"];
        $x = str_split($x, 16);
        $n = 0;
        // the switchEndianness calls are necessary because the multiplication algorithm in BinaryField/Integer
        // interprets strings as polynomials in big endian order whereas in GCM they're interpreted in little
        // endian order per https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=19.
        // big endian order is what binary field elliptic curves use per http://www.secg.org/sec1-v2.pdf#page=18.

        // we could switchEndianness here instead of in the while loop but doing so in the while loop seems like it
        // might be slightly more performant
        //$x = Strings::switchEndianness($x);
        foreach ($x as $xn) {
            $xn = Strings::switchEndianness($xn);
            $t = $y[$n] ^ $xn;
            $temp = self::$gcmField->newInteger($t);
            $y[++$n] = $temp->multiply($h)->toBytes();
            $y[$n] = substr($y[$n], 1);
        }
        $y[$n] = Strings::switchEndianness($y[$n]);
        return $y[$n];
    }

    /**
     * Returns the bit length of a string in a packed format
     *
     * @see self::decrypt()
     * @see self::encrypt()
     * @see self::setupGCM()
     * @param string $str
     * @return string
     */
    private static function len64($str)
    {
        return "\0\0\0\0" . pack('N', 8 * strlen($str));
    }

    /**
     * NULL pads a string to be a multiple of 128
     *
     * @see self::decrypt()
     * @see self::encrypt()
     * @see self::setupGCM()
     * @param string $str
     * @return string
     */
    protected static function nullPad128($str)
    {
        $len = strlen($str);
        return $str . str_repeat("\0", 16 * ceil($len / 16) - $len);
    }

    /**
     * Calculates Poly1305 MAC
     *
     * On my system ChaCha20, with libsodium, takes 0.5s. With this custom Poly1305 implementation
     * it takes 1.2s.
     *
     * @see self::decrypt()
     * @see self::encrypt()
     * @param string $text
     * @return string
     */
    protected function poly1305($text)
    {
        $s = $this->poly1305Key; // strlen($this->poly1305Key) == 32
        $r = Strings::shift($s, 16);
        $r = strrev($r);
        $r &= "\x0f\xff\xff\xfc\x0f\xff\xff\xfc\x0f\xff\xff\xfc\x0f\xff\xff\xff";
        $s = strrev($s);

        $r = self::$poly1305Field->newInteger(new BigInteger($r, 256));
        $s = self::$poly1305Field->newInteger(new BigInteger($s, 256));
        $a = self::$poly1305Field->newInteger(new BigInteger());

        $blocks = str_split($text, 16);
        foreach ($blocks as $block) {
            $n = strrev($block . chr(1));
            $n = self::$poly1305Field->newInteger(new BigInteger($n, 256));
            $a = $a->add($n);
            $a = $a->multiply($r);
        }
        $r = $a->toBigInteger()->add($s->toBigInteger());
        $mask = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
        return strrev($r->toBytes()) & $mask;
    }

    /**
     * Return the mode
     *
     * You can do $obj instanceof AES or whatever to get the cipher but you can't do that to get the mode
     *
     * @return string
     */
    public function getMode()
    {
        return array_flip(self::MODE_MAP)[$this->mode];
    }

    /**
     * Is the continuous buffer enabled?
     *
     * @return boolean
     */
    public function continuousBufferEnabled()
    {
        return $this->continuousBuffer;
    }
}
<?php

/**
 * PublicKey interface
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2009 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common;

/**
 * PublicKey interface
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
interface PublicKey
{
    public function verify($message, $signature);
    //public function encrypt($plaintext);
    public function toString($type, array $options = []);
    public function getFingerprint($algorithm);
}
<?php

/**
 * Base Class for all block ciphers
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common;

/**
 * Base Class for all block cipher classes
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class BlockCipher extends SymmetricKey
{
}
<?php

/**
 * Fingerprint Trait for Public Keys
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common\Traits;

use phpseclib3\Crypt\Hash;

/**
 * Fingerprint Trait for Private Keys
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
trait Fingerprint
{
    /**
     * Returns the public key's fingerprint
     *
     * The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is
     * no public key currently loaded, false is returned.
     * Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716)
     *
     * @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned
     * for invalid values.
     * @return mixed
     */
    public function getFingerprint($algorithm = 'md5')
    {
        $type = self::validatePlugin('Keys', 'OpenSSH', 'savePublicKey');
        if ($type === false) {
            return false;
        }
        $key = $this->toString('OpenSSH', ['binary' => true]);
        if ($key === false) {
            return false;
        }
        switch ($algorithm) {
            case 'sha256':
                $hash = new Hash('sha256');
                $base = base64_encode($hash->hash($key));
                return substr($base, 0, strlen($base) - 1);
            case 'md5':
                return substr(chunk_split(md5($key), 2, ':'), 0, -1);
            default:
                return false;
        }
    }
}
<?php

/**
 * Password Protected Trait for Private Keys
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\Common\Traits;

/**
 * Password Protected Trait for Private Keys
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
trait PasswordProtected
{
    /**
     * Password
     *
     * @var string|bool
     */
    private $password = false;

    /**
     * Sets the password
     *
     * Private keys can be encrypted with a password.  To unset the password, pass in the empty string or false.
     * Or rather, pass in $password such that empty($password) && !is_string($password) is true.
     *
     * @see self::createKey()
     * @see self::load()
     * @param string|bool $password
     */
    public function withPassword($password = false)
    {
        $new = clone $this;
        $new->password = $password;
        return $new;
    }
}
<?php

/**
 * ASN1 Signature Handler
 *
 * PHP version 5
 *
 * Handles signatures in the format described in
 * https://tools.ietf.org/html/rfc3279#section-2.2.3
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Signature;

use phpseclib3\File\ASN1 as Encoder;
use phpseclib3\File\ASN1\Maps\EcdsaSigValue;
use phpseclib3\Math\BigInteger;

/**
 * ASN1 Signature Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class ASN1
{
    /**
     * Loads a signature
     *
     * @param string $sig
     * @return array
     */
    public static function load($sig)
    {
        if (!is_string($sig)) {
            return false;
        }

        $decoded = Encoder::decodeBER($sig);
        if (empty($decoded)) {
            return false;
        }
        $components = Encoder::asn1map($decoded[0], EcdsaSigValue::MAP);

        return $components;
    }

    /**
     * Returns a signature in the appropriate format
     *
     * @param BigInteger $r
     * @param BigInteger $s
     * @return string
     */
    public static function save(BigInteger $r, BigInteger $s)
    {
        return Encoder::encodeDER(compact('r', 's'), EcdsaSigValue::MAP);
    }
}
<?php

/**
 * Raw EC Signature Handler
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Signature;

use phpseclib3\Crypt\Common\Formats\Signature\Raw as Progenitor;

/**
 * Raw DSA Signature Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Raw extends Progenitor
{
}
<?php

/**
 * IEEE P1363 Signature Handler
 *
 * PHP version 5
 *
 * Handles signatures in the format described in
 * https://standards.ieee.org/ieee/1363/2049/ and
 * https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign#ecdsa
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Signature;

use phpseclib3\Math\BigInteger;

/**
 * ASN1 Signature Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class IEEE
{
    /**
     * Loads a signature
     *
     * @param string $sig
     * @return array
     */
    public static function load($sig)
    {
        if (!is_string($sig)) {
            return false;
        }

        $len = strlen($sig);
        if ($len & 1) {
            return false;
        }

        $r = new BigInteger(substr($sig, 0, $len >> 1), 256);
        $s = new BigInteger(substr($sig, $len >> 1), 256);

        return compact('r', 's');
    }

    /**
     * Returns a signature in the appropriate format
     *
     * @param BigInteger $r
     * @param BigInteger $s
     * @param string $curve
     * @param int $length
     * @return string
     */
    public static function save(BigInteger $r, BigInteger $s, $curve, $length)
    {
        $r = $r->toBytes();
        $s = $s->toBytes();
        $length = (int) ceil($length / 8);
        return str_pad($r, $length, "\0", STR_PAD_LEFT) . str_pad($s, $length, "\0", STR_PAD_LEFT);
    }
}
<?php

/**
 * SSH2 Signature Handler
 *
 * PHP version 5
 *
 * Handles signatures in the format used by SSH2
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Signature;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Math\BigInteger;

/**
 * SSH2 Signature Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class SSH2
{
    /**
     * Loads a signature
     *
     * @param string $sig
     * @return mixed
     */
    public static function load($sig)
    {
        if (!is_string($sig)) {
            return false;
        }

        $result = Strings::unpackSSH2('ss', $sig);
        if ($result === false) {
            return false;
        }
        list($type, $blob) = $result;
        switch ($type) {
            // see https://tools.ietf.org/html/rfc5656#section-3.1.2
            case 'ecdsa-sha2-nistp256':
            case 'ecdsa-sha2-nistp384':
            case 'ecdsa-sha2-nistp521':
                break;
            default:
                return false;
        }

        $result = Strings::unpackSSH2('ii', $blob);
        if ($result === false) {
            return false;
        }

        return [
            'r' => $result[0],
            's' => $result[1]
        ];
    }

    /**
     * Returns a signature in the appropriate format
     *
     * @param BigInteger $r
     * @param BigInteger $s
     * @param string $curve
     * @return string
     */
    public static function save(BigInteger $r, BigInteger $s, $curve)
    {
        switch ($curve) {
            case 'secp256r1':
                $curve = 'nistp256';
                break;
            case 'secp384r1':
                $curve = 'nistp384';
                break;
            case 'secp521r1':
                $curve = 'nistp521';
                break;
            default:
                return false;
        }

        $blob = Strings::packSSH2('ii', $r, $s);

        return Strings::packSSH2('ss', 'ecdsa-sha2-' . $curve, $blob);
    }
}
<?php

/**
 * Montgomery Private Key Handler
 *
 * "Naked" Curve25519 private keys can pretty much be any sequence of random 32x bytes so unless
 * we have a "hidden" key handler pretty much every 32 byte string will be loaded as a curve25519
 * private key even if it probably isn't one by PublicKeyLoader.
 *
 * "Naked" Curve25519 public keys also a string of 32 bytes so distinguishing between a "naked"
 * curve25519 private key and a public key is nigh impossible, hence separate plugins for each
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Keys;

use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib3\Crypt\EC\Curves\Curve25519;
use phpseclib3\Crypt\EC\Curves\Curve448;
use phpseclib3\Exception\UnsupportedFormatException;
use phpseclib3\Math\BigInteger;

/**
 * Montgomery Curve Private Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class MontgomeryPrivate
{
    /**
     * Is invisible flag
     *
     */
    const IS_INVISIBLE = true;

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        switch (strlen($key)) {
            case 32:
                $curve = new Curve25519();
                break;
            case 56:
                $curve = new Curve448();
                break;
            default:
                throw new \LengthException('The only supported lengths are 32 and 56');
        }

        $components = ['curve' => $curve];
        $components['dA'] = new BigInteger($key, 256);
        $curve->rangeCheck($components['dA']);
        // note that EC::getEncodedCoordinates does some additional "magic" (it does strrev on the result)
        $components['QA'] = $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']);

        return $components;
    }

    /**
     * Convert an EC public key to the appropriate format
     *
     * @param MontgomeryCurve $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @return string
     */
    public static function savePublicKey(MontgomeryCurve $curve, array $publicKey)
    {
        return strrev($publicKey[0]->toBytes());
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $privateKey
     * @param MontgomeryCurve $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @param string $secret optional
     * @param string $password optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $privateKey, MontgomeryCurve $curve, array $publicKey, $secret = null, $password = '')
    {
        if (!empty($password) && is_string($password)) {
            throw new UnsupportedFormatException('MontgomeryPrivate private keys do not support encryption');
        }

        return str_pad($privateKey->toBytes(), $curve::SIZE, "\0", STR_PAD_RIGHT);
    }
}
<?php

/**
 * Montgomery Public Key Handler
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Keys;

use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib3\Crypt\EC\Curves\Curve25519;
use phpseclib3\Crypt\EC\Curves\Curve448;
use phpseclib3\Math\BigInteger;

/**
 * Montgomery Public Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class MontgomeryPublic
{
    /**
     * Is invisible flag
     *
     */
    const IS_INVISIBLE = true;

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        switch (strlen($key)) {
            case 32:
                $curve = new Curve25519();
                break;
            case 56:
                $curve = new Curve448();
                break;
            default:
                throw new \LengthException('The only supported lengths are 32 and 56');
        }

        $components = ['curve' => $curve];
        $components['QA'] = [$components['curve']->convertInteger(new BigInteger(strrev($key), 256))];

        return $components;
    }

    /**
     * Convert an EC public key to the appropriate format
     *
     * @param MontgomeryCurve $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @return string
     */
    public static function savePublicKey(MontgomeryCurve $curve, array $publicKey)
    {
        return strrev($publicKey[0]->toBytes());
    }
}
<?php

/**
 * libsodium Key Handler
 *
 * Different NaCl implementations store the key differently.
 * https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/ elaborates.
 * libsodium appears to use the same format as SUPERCOP.
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Keys;

use phpseclib3\Crypt\EC\Curves\Ed25519;
use phpseclib3\Exception\UnsupportedFormatException;
use phpseclib3\Math\BigInteger;

/**
 * libsodium Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class libsodium
{
    use Common;

    /**
     * Is invisible flag
     *
     */
    const IS_INVISIBLE = true;

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        switch (strlen($key)) {
            case 32:
                $public = $key;
                break;
            case 64:
                $private = substr($key, 0, 32);
                $public = substr($key, -32);
                break;
            case 96:
                $public = substr($key, -32);
                if (substr($key, 32, 32) != $public) {
                    throw new \RuntimeException('Keys with 96 bytes should have the 2nd and 3rd set of 32 bytes match');
                }
                $private = substr($key, 0, 32);
                break;
            default:
                throw new \RuntimeException('libsodium keys need to either be 32 bytes long, 64 bytes long or 96 bytes long');
        }

        $curve = new Ed25519();
        $components = ['curve' => $curve];
        if (isset($private)) {
            $arr = $curve->extractSecret($private);
            $components['dA'] = $arr['dA'];
            $components['secret'] = $arr['secret'];
        }
        $components['QA'] = isset($public) ?
            self::extractPoint($public, $curve) :
            $curve->multiplyPoint($curve->getBasePoint(), $components['dA']);

        return $components;
    }

    /**
     * Convert an EC public key to the appropriate format
     *
     * @param Ed25519 $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @return string
     */
    public static function savePublicKey(Ed25519 $curve, array $publicKey)
    {
        return $curve->encodePoint($publicKey);
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $privateKey
     * @param Ed25519 $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @param string $secret optional
     * @param string $password optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $privateKey, Ed25519 $curve, array $publicKey, $secret = null, $password = '')
    {
        if (!isset($secret)) {
            throw new \RuntimeException('Private Key does not have a secret set');
        }
        if (strlen($secret) != 32) {
            throw new \RuntimeException('Private Key secret is not of the correct length');
        }
        if (!empty($password) && is_string($password)) {
            throw new UnsupportedFormatException('libsodium private keys do not support encryption');
        }
        return $secret . $curve->encodePoint($publicKey);
    }
}
<?php

/**
 * OpenSSH Formatted EC Key Handler
 *
 * PHP version 5
 *
 * Place in $HOME/.ssh/authorized_keys
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\OpenSSH as Progenitor;
use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve;
use phpseclib3\Crypt\EC\Curves\Ed25519;
use phpseclib3\Exception\UnsupportedCurveException;
use phpseclib3\Math\BigInteger;

/**
 * OpenSSH Formatted EC Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OpenSSH extends Progenitor
{
    use Common;

    /**
     * Supported Key Types
     *
     * @var array
     */
    protected static $types = [
        'ecdsa-sha2-nistp256',
        'ecdsa-sha2-nistp384',
        'ecdsa-sha2-nistp521',
        'ssh-ed25519'
    ];

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        $parsed = parent::load($key, $password);

        if (isset($parsed['paddedKey'])) {
            $paddedKey = $parsed['paddedKey'];
            list($type) = Strings::unpackSSH2('s', $paddedKey);
            if ($type != $parsed['type']) {
                throw new \RuntimeException("The public and private keys are not of the same type ($type vs $parsed[type])");
            }
            if ($type == 'ssh-ed25519') {
                list(, $key, $comment) = Strings::unpackSSH2('sss', $paddedKey);
                $key = libsodium::load($key);
                $key['comment'] = $comment;
                return $key;
            }
            list($curveName, $publicKey, $privateKey, $comment) = Strings::unpackSSH2('ssis', $paddedKey);
            $curve = self::loadCurveByParam(['namedCurve' => $curveName]);
            $curve->rangeCheck($privateKey);
            return [
                'curve' => $curve,
                'dA' => $privateKey,
                'QA' => self::extractPoint("\0$publicKey", $curve),
                'comment' => $comment
            ];
        }

        if ($parsed['type'] == 'ssh-ed25519') {
            if (Strings::shift($parsed['publicKey'], 4) != "\0\0\0\x20") {
                throw new \RuntimeException('Length of ssh-ed25519 key should be 32');
            }

            $curve = new Ed25519();
            $qa = self::extractPoint($parsed['publicKey'], $curve);
        } else {
            list($curveName, $publicKey) = Strings::unpackSSH2('ss', $parsed['publicKey']);
            $curveName = '\phpseclib3\Crypt\EC\Curves\\' . $curveName;
            $curve = new $curveName();

            $qa = self::extractPoint("\0" . $publicKey, $curve);
        }

        return [
            'curve' => $curve,
            'QA' => $qa,
            'comment' => $parsed['comment']
        ];
    }

    /**
     * Returns the alias that corresponds to a curve
     *
     * @return string
     */
    private static function getAlias(BaseCurve $curve)
    {
        self::initialize_static_variables();

        $reflect = new \ReflectionClass($curve);
        $name = $reflect->getShortName();

        if (!isset(self::$curveOIDs[$name])) {
            throw new UnsupportedCurveException($name . ' is not a curve that the OpenSSH plugin supports');
        }
        $oid = self::$curveOIDs[$name];
        $aliases = array_filter(self::$curveOIDs, function ($v) use ($oid) {
            return $v == $oid;
        });
        $aliases = array_keys($aliases);

        for ($i = 0; $i < count($aliases); $i++) {
            if (in_array('ecdsa-sha2-' . $aliases[$i], self::$types)) {
                $alias = $aliases[$i];
                break;
            }
        }

        if (!isset($alias)) {
            throw new UnsupportedCurveException($name . ' is not a curve that the OpenSSH plugin supports');
        }

        return $alias;
    }

    /**
     * Convert an EC public key to the appropriate format
     *
     * @param BaseCurve $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @param array $options optional
     * @return string
     */
    public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = [])
    {
        $comment = isset($options['comment']) ? $options['comment'] : self::$comment;

        if ($curve instanceof Ed25519) {
            $key = Strings::packSSH2('ss', 'ssh-ed25519', $curve->encodePoint($publicKey));

            if (isset($options['binary']) ? $options['binary'] : self::$binary) {
                return $key;
            }

            $key = 'ssh-ed25519 ' . base64_encode($key) . ' ' . $comment;
            return $key;
        }

        $alias = self::getAlias($curve);

        $points = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
        $key = Strings::packSSH2('sss', 'ecdsa-sha2-' . $alias, $alias, $points);

        if (isset($options['binary']) ? $options['binary'] : self::$binary) {
            return $key;
        }

        $key = 'ecdsa-sha2-' . $alias . ' ' . base64_encode($key) . ' ' . $comment;

        return $key;
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $privateKey
     * @param Ed25519 $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @param string $secret optional
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve, array $publicKey, $secret = null, $password = '', array $options = [])
    {
        if ($curve instanceof Ed25519) {
            if (!isset($secret)) {
                throw new \RuntimeException('Private Key does not have a secret set');
            }
            if (strlen($secret) != 32) {
                throw new \RuntimeException('Private Key secret is not of the correct length');
            }

            $pubKey = $curve->encodePoint($publicKey);

            $publicKey = Strings::packSSH2('ss', 'ssh-ed25519', $pubKey);
            $privateKey = Strings::packSSH2('sss', 'ssh-ed25519', $pubKey, $secret . $pubKey);

            return self::wrapPrivateKey($publicKey, $privateKey, $password, $options);
        }

        $alias = self::getAlias($curve);

        $points = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
        $publicKey = self::savePublicKey($curve, $publicKey, ['binary' => true]);

        $privateKey = Strings::packSSH2('sssi', 'ecdsa-sha2-' . $alias, $alias, $points, $privateKey);

        return self::wrapPrivateKey($publicKey, $privateKey, $password, $options);
    }
}
<?php

/**
 * XML Formatted EC Key Handler
 *
 * More info:
 *
 * https://www.w3.org/TR/xmldsig-core/#sec-ECKeyValue
 * http://en.wikipedia.org/wiki/XML_Signature
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve;
use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib3\Crypt\EC\BaseCurves\Prime as PrimeCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\UnsupportedCurveException;
use phpseclib3\Math\BigInteger;

/**
 * XML Formatted EC Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class XML
{
    use Common;

    /**
     * Default namespace
     *
     * @var string
     */
    private static $namespace;

    /**
     * Flag for using RFC4050 syntax
     *
     * @var bool
     */
    private static $rfc4050 = false;

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        self::initialize_static_variables();

        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        if (!class_exists('DOMDocument')) {
            throw new BadConfigurationException('The dom extension is not setup correctly on this system');
        }

        $use_errors = libxml_use_internal_errors(true);

        if (substr($key, 0, 5) != '<?xml') {
            $key = '<xml>' . $key . '</xml>';
        }

        $temp = self::isolateNamespace($key, 'http://www.w3.org/2009/xmldsig11#');
        if ($temp) {
            $key = $temp;
        }

        $temp = self::isolateNamespace($key, 'http://www.w3.org/2001/04/xmldsig-more#');
        if ($temp) {
            $key = $temp;
        }

        $dom = new \DOMDocument();

        if (!$dom->loadXML($key)) {
            libxml_use_internal_errors($use_errors);
            throw new \UnexpectedValueException('Key does not appear to contain XML');
        }
        $xpath = new \DOMXPath($dom);
        libxml_use_internal_errors($use_errors);
        $curve = self::loadCurveByParam($xpath);

        $pubkey = self::query($xpath, 'publickey', 'Public Key is not present');

        $QA = self::query($xpath, 'ecdsakeyvalue')->length ?
            self::extractPointRFC4050($xpath, $curve) :
            self::extractPoint("\0" . $pubkey, $curve);

        libxml_use_internal_errors($use_errors);

        return compact('curve', 'QA');
    }

    /**
     * Case-insensitive xpath query
     *
     * @param \DOMXPath $xpath
     * @param string $name
     * @param string $error optional
     * @param bool $decode optional
     * @return \DOMNodeList
     */
    private static function query(\DOMXPath $xpath, $name, $error = null, $decode = true)
    {
        $query = '/';
        $names = explode('/', $name);
        foreach ($names as $name) {
            $query .= "/*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$name']";
        }
        $result = $xpath->query($query);
        if (!isset($error)) {
            return $result;
        }

        if (!$result->length) {
            throw new \RuntimeException($error);
        }
        return $decode ? self::decodeValue($result->item(0)->textContent) : $result->item(0)->textContent;
    }

    /**
     * Finds the first element in the relevant namespace, strips the namespacing and returns the XML for that element.
     *
     * @param string $xml
     * @param string $ns
     */
    private static function isolateNamespace($xml, $ns)
    {
        $dom = new \DOMDocument();
        if (!$dom->loadXML($xml)) {
            return false;
        }
        $xpath = new \DOMXPath($dom);
        $nodes = $xpath->query("//*[namespace::*[.='$ns'] and not(../namespace::*[.='$ns'])]");
        if (!$nodes->length) {
            return false;
        }
        $node = $nodes->item(0);
        $ns_name = $node->lookupPrefix($ns);
        if ($ns_name) {
            $node->removeAttributeNS($ns, $ns_name);
        }
        return $dom->saveXML($node);
    }

    /**
     * Decodes the value
     *
     * @param string $value
     */
    private static function decodeValue($value)
    {
        return Strings::base64_decode(str_replace(["\r", "\n", ' ', "\t"], '', $value));
    }

    /**
     * Extract points from an XML document
     *
     * @param \DOMXPath $xpath
     * @param BaseCurve $curve
     * @return object[]
     */
    private static function extractPointRFC4050(\DOMXPath $xpath, BaseCurve $curve)
    {
        $x = self::query($xpath, 'publickey/x');
        $y = self::query($xpath, 'publickey/y');
        if (!$x->length || !$x->item(0)->hasAttribute('Value')) {
            throw new \RuntimeException('Public Key / X coordinate not found');
        }
        if (!$y->length || !$y->item(0)->hasAttribute('Value')) {
            throw new \RuntimeException('Public Key / Y coordinate not found');
        }
        $point = [
            $curve->convertInteger(new BigInteger($x->item(0)->getAttribute('Value'))),
            $curve->convertInteger(new BigInteger($y->item(0)->getAttribute('Value')))
        ];
        if (!$curve->verifyPoint($point)) {
            throw new \RuntimeException('Unable to verify that point exists on curve');
        }
        return $point;
    }

    /**
     * Returns an instance of \phpseclib3\Crypt\EC\BaseCurves\Base based
     * on the curve parameters
     *
     * @param \DomXPath $xpath
     * @return BaseCurve|false
     */
    private static function loadCurveByParam(\DOMXPath $xpath)
    {
        $namedCurve = self::query($xpath, 'namedcurve');
        if ($namedCurve->length == 1) {
            $oid = $namedCurve->item(0)->getAttribute('URN');
            $oid = preg_replace('#[^\d.]#', '', $oid);
            $name = array_search($oid, self::$curveOIDs);
            if ($name === false) {
                throw new UnsupportedCurveException('Curve with OID of ' . $oid . ' is not supported');
            }

            $curve = '\phpseclib3\Crypt\EC\Curves\\' . $name;
            if (!class_exists($curve)) {
                throw new UnsupportedCurveException('Named Curve of ' . $name . ' is not supported');
            }
            return new $curve();
        }

        $params = self::query($xpath, 'explicitparams');
        if ($params->length) {
            return self::loadCurveByParamRFC4050($xpath);
        }

        $params = self::query($xpath, 'ecparameters');
        if (!$params->length) {
            throw new \RuntimeException('No parameters are present');
        }

        $fieldTypes = [
            'prime-field' => ['fieldid/prime/p'],
            'gnb' => ['fieldid/gnb/m'],
            'tnb' => ['fieldid/tnb/k'],
            'pnb' => ['fieldid/pnb/k1', 'fieldid/pnb/k2', 'fieldid/pnb/k3'],
            'unknown' => []
        ];

        foreach ($fieldTypes as $type => $queries) {
            foreach ($queries as $query) {
                $result = self::query($xpath, $query);
                if (!$result->length) {
                    continue 2;
                }
                $param = preg_replace('#.*/#', '', $query);
                $$param = self::decodeValue($result->item(0)->textContent);
            }
            break;
        }

        $a = self::query($xpath, 'curve/a', 'A coefficient is not present');
        $b = self::query($xpath, 'curve/b', 'B coefficient is not present');
        $base = self::query($xpath, 'base', 'Base point is not present');
        $order = self::query($xpath, 'order', 'Order is not present');

        switch ($type) {
            case 'prime-field':
                $curve = new PrimeCurve();
                $curve->setModulo(new BigInteger($p, 256));
                $curve->setCoefficients(
                    new BigInteger($a, 256),
                    new BigInteger($b, 256)
                );
                $point = self::extractPoint("\0" . $base, $curve);
                $curve->setBasePoint(...$point);
                $curve->setOrder(new BigInteger($order, 256));
                return $curve;
            case 'gnb':
            case 'tnb':
            case 'pnb':
            default:
                throw new UnsupportedCurveException('Field Type of ' . $type . ' is not supported');
        }
    }

    /**
     * Returns an instance of \phpseclib3\Crypt\EC\BaseCurves\Base based
     * on the curve parameters
     *
     * @param \DomXPath $xpath
     * @return BaseCurve|false
     */
    private static function loadCurveByParamRFC4050(\DOMXPath $xpath)
    {
        $fieldTypes = [
            'prime-field' => ['primefieldparamstype/p'],
            'unknown' => []
        ];

        foreach ($fieldTypes as $type => $queries) {
            foreach ($queries as $query) {
                $result = self::query($xpath, $query);
                if (!$result->length) {
                    continue 2;
                }
                $param = preg_replace('#.*/#', '', $query);
                $$param = $result->item(0)->textContent;
            }
            break;
        }

        $a = self::query($xpath, 'curveparamstype/a', 'A coefficient is not present', false);
        $b = self::query($xpath, 'curveparamstype/b', 'B coefficient is not present', false);
        $x = self::query($xpath, 'basepointparams/basepoint/ecpointtype/x', 'Base Point X is not present', false);
        $y = self::query($xpath, 'basepointparams/basepoint/ecpointtype/y', 'Base Point Y is not present', false);
        $order = self::query($xpath, 'order', 'Order is not present', false);

        switch ($type) {
            case 'prime-field':
                $curve = new PrimeCurve();

                $p = str_replace(["\r", "\n", ' ', "\t"], '', $p);
                $curve->setModulo(new BigInteger($p));

                $a = str_replace(["\r", "\n", ' ', "\t"], '', $a);
                $b = str_replace(["\r", "\n", ' ', "\t"], '', $b);
                $curve->setCoefficients(
                    new BigInteger($a),
                    new BigInteger($b)
                );

                $x = str_replace(["\r", "\n", ' ', "\t"], '', $x);
                $y = str_replace(["\r", "\n", ' ', "\t"], '', $y);
                $curve->setBasePoint(
                    new BigInteger($x),
                    new BigInteger($y)
                );

                $order = str_replace(["\r", "\n", ' ', "\t"], '', $order);
                $curve->setOrder(new BigInteger($order));
                return $curve;
            default:
                throw new UnsupportedCurveException('Field Type of ' . $type . ' is not supported');
        }
    }

    /**
     * Sets the namespace. dsig11 is the most common one.
     *
     * Set to null to unset. Used only for creating public keys.
     *
     * @param string $namespace
     */
    public static function setNamespace($namespace)
    {
        self::$namespace = $namespace;
    }

    /**
     * Uses the XML syntax specified in https://tools.ietf.org/html/rfc4050
     */
    public static function enableRFC4050Syntax()
    {
        self::$rfc4050 = true;
    }

    /**
     * Uses the XML syntax specified in https://www.w3.org/TR/xmldsig-core/#sec-ECParameters
     */
    public static function disableRFC4050Syntax()
    {
        self::$rfc4050 = false;
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BaseCurve $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @param array $options optional
     * @return string
     */
    public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = [])
    {
        self::initialize_static_variables();

        if ($curve instanceof TwistedEdwardsCurve || $curve instanceof MontgomeryCurve) {
            throw new UnsupportedCurveException('TwistedEdwards and Montgomery Curves are not supported');
        }

        if (empty(static::$namespace)) {
            $pre = $post = '';
        } else {
            $pre = static::$namespace . ':';
            $post = ':' . static::$namespace;
        }

        if (self::$rfc4050) {
            return '<' . $pre . 'ECDSAKeyValue xmlns' . $post . '="http://www.w3.org/2001/04/xmldsig-more#">' . "\r\n" .
                   self::encodeXMLParameters($curve, $pre, $options) . "\r\n" .
                   '<' . $pre . 'PublicKey>' . "\r\n" .
                   '<' . $pre . 'X Value="' . $publicKey[0] . '" />' . "\r\n" .
                   '<' . $pre . 'Y Value="' . $publicKey[1] . '" />' . "\r\n" .
                   '</' . $pre . 'PublicKey>' . "\r\n" .
                   '</' . $pre . 'ECDSAKeyValue>';
        }

        $publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();

        return '<' . $pre . 'ECDSAKeyValue xmlns' . $post . '="http://www.w3.org/2009/xmldsig11#">' . "\r\n" .
               self::encodeXMLParameters($curve, $pre, $options) . "\r\n" .
               '<' . $pre . 'PublicKey>' . Strings::base64_encode($publicKey) . '</' . $pre . 'PublicKey>' . "\r\n" .
               '</' . $pre . 'ECDSAKeyValue>';
    }

    /**
     * Encode Parameters
     *
     * @param BaseCurve $curve
     * @param string $pre
     * @param array $options optional
     * @return string|false
     */
    private static function encodeXMLParameters(BaseCurve $curve, $pre, array $options = [])
    {
        $result = self::encodeParameters($curve, true, $options);

        if (isset($result['namedCurve'])) {
            $namedCurve = '<' . $pre . 'NamedCurve URI="urn:oid:' . self::$curveOIDs[$result['namedCurve']] . '" />';
            return self::$rfc4050 ?
                '<DomainParameters>' . str_replace('URI', 'URN', $namedCurve) . '</DomainParameters>' :
                $namedCurve;
        }

        if (self::$rfc4050) {
            $xml = '<' . $pre . 'ExplicitParams>' . "\r\n" .
                  '<' . $pre . 'FieldParams>' . "\r\n";
            $temp = $result['specifiedCurve'];
            switch ($temp['fieldID']['fieldType']) {
                case 'prime-field':
                    $xml .= '<' . $pre . 'PrimeFieldParamsType>' . "\r\n" .
                           '<' . $pre . 'P>' . $temp['fieldID']['parameters'] . '</' . $pre . 'P>' . "\r\n" .
                           '</' . $pre . 'PrimeFieldParamsType>' . "\r\n";
                    $a = $curve->getA();
                    $b = $curve->getB();
                    list($x, $y) = $curve->getBasePoint();
                    break;
                default:
                    throw new UnsupportedCurveException('Field Type of ' . $temp['fieldID']['fieldType'] . ' is not supported');
            }
            $xml .= '</' . $pre . 'FieldParams>' . "\r\n" .
                   '<' . $pre . 'CurveParamsType>' . "\r\n" .
                   '<' . $pre . 'A>' . $a . '</' . $pre . 'A>' . "\r\n" .
                   '<' . $pre . 'B>' . $b . '</' . $pre . 'B>' . "\r\n" .
                   '</' . $pre . 'CurveParamsType>' . "\r\n" .
                   '<' . $pre . 'BasePointParams>' . "\r\n" .
                   '<' . $pre . 'BasePoint>' . "\r\n" .
                   '<' . $pre . 'ECPointType>' . "\r\n" .
                   '<' . $pre . 'X>' . $x . '</' . $pre . 'X>' . "\r\n" .
                   '<' . $pre . 'Y>' . $y . '</' . $pre . 'Y>' . "\r\n" .
                   '</' . $pre . 'ECPointType>' . "\r\n" .
                   '</' . $pre . 'BasePoint>' . "\r\n" .
                   '<' . $pre . 'Order>' . $curve->getOrder() . '</' . $pre . 'Order>' . "\r\n" .
                   '</' . $pre . 'BasePointParams>' . "\r\n" .
                   '</' . $pre . 'ExplicitParams>' . "\r\n";

            return $xml;
        }

        if (isset($result['specifiedCurve'])) {
            $xml = '<' . $pre . 'ECParameters>' . "\r\n" .
                   '<' . $pre . 'FieldID>' . "\r\n";
            $temp = $result['specifiedCurve'];
            switch ($temp['fieldID']['fieldType']) {
                case 'prime-field':
                    $xml .= '<' . $pre . 'Prime>' . "\r\n" .
                           '<' . $pre . 'P>' . Strings::base64_encode($temp['fieldID']['parameters']->toBytes()) . '</' . $pre . 'P>' . "\r\n" .
                           '</' . $pre . 'Prime>' . "\r\n" ;
                    break;
                default:
                    throw new UnsupportedCurveException('Field Type of ' . $temp['fieldID']['fieldType'] . ' is not supported');
            }
            $xml .= '</' . $pre . 'FieldID>' . "\r\n" .
                   '<' . $pre . 'Curve>' . "\r\n" .
                   '<' . $pre . 'A>' . Strings::base64_encode($temp['curve']['a']) . '</' . $pre . 'A>' . "\r\n" .
                   '<' . $pre . 'B>' . Strings::base64_encode($temp['curve']['b']) . '</' . $pre . 'B>' . "\r\n" .
                   '</' . $pre . 'Curve>' . "\r\n" .
                   '<' . $pre . 'Base>' . Strings::base64_encode($temp['base']) . '</' . $pre . 'Base>' . "\r\n" .
                   '<' . $pre . 'Order>' . Strings::base64_encode($temp['order']) . '</' . $pre . 'Order>' . "\r\n" .
                   '</' . $pre . 'ECParameters>';
            return $xml;
        }
    }
}
<?php

/**
 * PuTTY Formatted EC Key Handler
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\PuTTY as Progenitor;
use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Math\BigInteger;

/**
 * PuTTY Formatted EC Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PuTTY extends Progenitor
{
    use Common;

    /**
     * Public Handler
     *
     * @var string
     */
    const PUBLIC_HANDLER = 'phpseclib3\Crypt\EC\Formats\Keys\OpenSSH';

    /**
     * Supported Key Types
     *
     * @var array
     */
    protected static $types = [
        'ecdsa-sha2-nistp256',
        'ecdsa-sha2-nistp384',
        'ecdsa-sha2-nistp521',
        'ssh-ed25519'
    ];

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        $components = parent::load($key, $password);
        if (!isset($components['private'])) {
            return $components;
        }

        $private = $components['private'];

        $temp = Strings::base64_encode(Strings::packSSH2('s', $components['type']) . $components['public']);
        $components = OpenSSH::load($components['type'] . ' ' . $temp . ' ' . $components['comment']);

        if ($components['curve'] instanceof TwistedEdwardsCurve) {
            if (Strings::shift($private, 4) != "\0\0\0\x20") {
                throw new \RuntimeException('Length of ssh-ed25519 key should be 32');
            }
            $arr = $components['curve']->extractSecret($private);
            $components['dA'] = $arr['dA'];
            $components['secret'] = $arr['secret'];
        } else {
            list($components['dA']) = Strings::unpackSSH2('i', $private);
            $components['curve']->rangeCheck($components['dA']);
        }

        return $components;
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $privateKey
     * @param BaseCurve $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @param string $secret optional
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve, array $publicKey, $secret = null, $password = false, array $options = [])
    {
        self::initialize_static_variables();

        $public = explode(' ', OpenSSH::savePublicKey($curve, $publicKey));
        $name = $public[0];
        $public = Strings::base64_decode($public[1]);
        list(, $length) = unpack('N', Strings::shift($public, 4));
        Strings::shift($public, $length);

        // PuTTY pads private keys with a null byte per the following:
        // https://github.com/github/putty/blob/a3d14d77f566a41fc61dfdc5c2e0e384c9e6ae8b/sshecc.c#L1926
        if (!$curve instanceof TwistedEdwardsCurve) {
            $private = $privateKey->toBytes();
            if (!(strlen($privateKey->toBits()) & 7)) {
                $private = "\0$private";
            }
        }

        $private = $curve instanceof TwistedEdwardsCurve ?
            Strings::packSSH2('s', $secret) :
            Strings::packSSH2('s', $private);

        return self::wrapPrivateKey($public, $private, $name, $password, $options);
    }

    /**
     * Convert an EC public key to the appropriate format
     *
     * @param BaseCurve $curve
     * @param \phpseclib3\Math\Common\FiniteField[] $publicKey
     * @return string
     */
    public static function savePublicKey(BaseCurve $curve, array $publicKey)
    {
        $public = explode(' ', OpenSSH::savePublicKey($curve, $publicKey));
        $type = $public[0];
        $public = Strings::base64_decode($public[1]);
        list(, $length) = unpack('N', Strings::shift($public, 4));
        Strings::shift($public, $length);

        return self::wrapPublicKey($public, $type);
    }
}
<?php

/**
 * "PKCS1" (RFC5915) Formatted EC Key Handler
 *
 * PHP version 5
 *
 * Used by File/X509.php
 *
 * Processes keys with the following headers:
 *
 * -----BEGIN EC PRIVATE KEY-----
 * -----BEGIN EC PARAMETERS-----
 *
 * Technically, PKCS1 is for RSA keys, only, but we're using PKCS1 to describe
 * DSA, whose format isn't really formally described anywhere, so might as well
 * use it to describe this, too. PKCS1 is easier to remember than RFC5915, after
 * all. I suppose this could also be named IETF but idk
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor;
use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve;
use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Exception\UnsupportedCurveException;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * "PKCS1" (RFC5915) Formatted EC Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS1 extends Progenitor
{
    use Common;

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        self::initialize_static_variables();

        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        if (strpos($key, 'BEGIN EC PARAMETERS') && strpos($key, 'BEGIN EC PRIVATE KEY')) {
            $components = [];

            preg_match('#-*BEGIN EC PRIVATE KEY-*[^-]*-*END EC PRIVATE KEY-*#s', $key, $matches);
            $decoded = parent::load($matches[0], $password);
            $decoded = ASN1::decodeBER($decoded);
            if (!$decoded) {
                throw new \RuntimeException('Unable to decode BER');
            }

            $ecPrivate = ASN1::asn1map($decoded[0], Maps\ECPrivateKey::MAP);
            if (!is_array($ecPrivate)) {
                throw new \RuntimeException('Unable to perform ASN1 mapping');
            }

            if (isset($ecPrivate['parameters'])) {
                $components['curve'] = self::loadCurveByParam($ecPrivate['parameters']);
            }

            preg_match('#-*BEGIN EC PARAMETERS-*[^-]*-*END EC PARAMETERS-*#s', $key, $matches);
            $decoded = parent::load($matches[0], '');
            $decoded = ASN1::decodeBER($decoded);
            if (!$decoded) {
                throw new \RuntimeException('Unable to decode BER');
            }
            $ecParams = ASN1::asn1map($decoded[0], Maps\ECParameters::MAP);
            if (!is_array($ecParams)) {
                throw new \RuntimeException('Unable to perform ASN1 mapping');
            }
            $ecParams = self::loadCurveByParam($ecParams);

            // comparing $ecParams and $components['curve'] directly won't work because they'll have different Math\Common\FiniteField classes
            // even if the modulo is the same
            if (isset($components['curve']) && self::encodeParameters($ecParams, false, []) != self::encodeParameters($components['curve'], false, [])) {
                throw new \RuntimeException('EC PARAMETERS does not correspond to EC PRIVATE KEY');
            }

            if (!isset($components['curve'])) {
                $components['curve'] = $ecParams;
            }

            $components['dA'] = new BigInteger($ecPrivate['privateKey'], 256);
            $components['curve']->rangeCheck($components['dA']);
            $components['QA'] = isset($ecPrivate['publicKey']) ?
                self::extractPoint($ecPrivate['publicKey'], $components['curve']) :
                $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']);

            return $components;
        }

        $key = parent::load($key, $password);

        $decoded = ASN1::decodeBER($key);
        if (!$decoded) {
            throw new \RuntimeException('Unable to decode BER');
        }

        $key = ASN1::asn1map($decoded[0], Maps\ECParameters::MAP);
        if (is_array($key)) {
            return ['curve' => self::loadCurveByParam($key)];
        }

        $key = ASN1::asn1map($decoded[0], Maps\ECPrivateKey::MAP);
        if (!is_array($key)) {
            throw new \RuntimeException('Unable to perform ASN1 mapping');
        }
        if (!isset($key['parameters'])) {
            throw new \RuntimeException('Key cannot be loaded without parameters');
        }

        $components = [];
        $components['curve'] = self::loadCurveByParam($key['parameters']);
        $components['dA'] = new BigInteger($key['privateKey'], 256);
        $components['QA'] = isset($ecPrivate['publicKey']) ?
            self::extractPoint($ecPrivate['publicKey'], $components['curve']) :
            $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']);

        return $components;
    }

    /**
     * Convert EC parameters to the appropriate format
     *
     * @return string
     */
    public static function saveParameters(BaseCurve $curve, array $options = [])
    {
        self::initialize_static_variables();

        if ($curve instanceof TwistedEdwardsCurve || $curve instanceof MontgomeryCurve) {
            throw new UnsupportedCurveException('TwistedEdwards and Montgomery Curves are not supported');
        }

        $key = self::encodeParameters($curve, false, $options);

        return "-----BEGIN EC PARAMETERS-----\r\n" .
               chunk_split(Strings::base64_encode($key), 64) .
               "-----END EC PARAMETERS-----\r\n";
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $privateKey
     * @param BaseCurve $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @param string $secret optional
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve, array $publicKey, $secret = null, $password = '', array $options = [])
    {
        self::initialize_static_variables();

        if ($curve instanceof TwistedEdwardsCurve  || $curve instanceof MontgomeryCurve) {
            throw new UnsupportedCurveException('TwistedEdwards Curves are not supported');
        }

        $publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();

        $key = [
            'version' => 'ecPrivkeyVer1',
            'privateKey' => $privateKey->toBytes(),
            'parameters' => new ASN1\Element(self::encodeParameters($curve)),
            'publicKey' => "\0" . $publicKey
        ];

        $key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP);

        return self::wrapPrivateKey($key, 'EC', $password, $options);
    }
}
<?php

/**
 * PKCS#8 Formatted EC Key Handler
 *
 * PHP version 5
 *
 * Processes keys with the following headers:
 *
 * -----BEGIN ENCRYPTED PRIVATE KEY-----
 * -----BEGIN PRIVATE KEY-----
 * -----BEGIN PUBLIC KEY-----
 *
 * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
 * is specific to private keys it's basically creating a DER-encoded wrapper
 * for keys. This just extends that same concept to public keys (much like ssh-keygen)
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Keys;

use phpseclib3\Math\Common\FiniteField\Integer;
use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve;
use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Crypt\EC\Curves\Curve25519;
use phpseclib3\Crypt\EC\Curves\Curve448;
use phpseclib3\Crypt\EC\Curves\Ed25519;
use phpseclib3\Crypt\EC\Curves\Ed448;
use phpseclib3\Exception\UnsupportedCurveException;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * PKCS#8 Formatted EC Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS8 extends Progenitor
{
    use Common;

    /**
     * OID Name
     *
     * @var array
     */
    const OID_NAME = ['id-ecPublicKey', 'id-Ed25519', 'id-Ed448', 'id-X25519', 'id-X448'];

    /**
     * OID Value
     *
     * @var string
     */
    const OID_VALUE = ['1.2.840.10045.2.1', '1.3.101.112', '1.3.101.113', '1.3.101.110', '1.3.101.111'];

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        // initialize_static_variables() is defined in both the trait and the parent class
        // when it's defined in two places it's the traits one that's called
        // the parent one is needed, as well, but the parent one is called by other methods
        // in the parent class as needed and in the context of the parent it's the parent
        // one that's called
        self::initialize_static_variables();

        $key = parent::load($key, $password);

        $type = isset($key['privateKey']) ? 'privateKey' : 'publicKey';

        switch ($key[$type . 'Algorithm']['algorithm']) {
            case 'id-Ed25519':
            case 'id-Ed448':
                return self::loadEdDSA($key);
            case 'id-X25519':
            case 'id-X448':
                return self::loadECDH($key);
        }

        $decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element);
        if (!$decoded) {
            throw new \RuntimeException('Unable to decode BER');
        }
        $params = ASN1::asn1map($decoded[0], Maps\ECParameters::MAP);
        if (!$params) {
            throw new \RuntimeException('Unable to decode the parameters using Maps\ECParameters');
        }

        $components = [];
        $components['curve'] = self::loadCurveByParam($params);

        if ($type == 'publicKey') {
            $components['QA'] = self::extractPoint("\0" . $key['publicKey'], $components['curve']);

            return $components;
        }

        $decoded = ASN1::decodeBER($key['privateKey']);
        if (!$decoded) {
            throw new \RuntimeException('Unable to decode BER');
        }
        $key = ASN1::asn1map($decoded[0], Maps\ECPrivateKey::MAP);
        if (isset($key['parameters']) && $params != $key['parameters']) {
            throw new \RuntimeException('The PKCS8 parameter field does not match the private key parameter field');
        }

        $components['dA'] = new BigInteger($key['privateKey'], 256);
        $components['curve']->rangeCheck($components['dA']);
        $components['QA'] = isset($key['publicKey']) ?
            self::extractPoint($key['publicKey'], $components['curve']) :
            $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']);

        return $components;
    }

    /**
     * Break a public or private EdDSA key down into its constituent components
     *
     * @return array
     */
    private static function loadEdDSA(array $key)
    {
        $components = [];

        if (isset($key['privateKey'])) {
            $components['curve'] = $key['privateKeyAlgorithm']['algorithm'] == 'id-Ed25519' ? new Ed25519() : new Ed448();
            $expected = chr(ASN1::TYPE_OCTET_STRING) . ASN1::encodeLength($components['curve']::SIZE);
            if (substr($key['privateKey'], 0, 2) != $expected) {
                throw new \RuntimeException(
                    'The first two bytes of the ' .
                    $key['privateKeyAlgorithm']['algorithm'] .
                    ' private key field should be 0x' . bin2hex($expected)
                );
            }
            $arr = $components['curve']->extractSecret(substr($key['privateKey'], 2));
            $components['dA'] = $arr['dA'];
            $components['secret'] = $arr['secret'];
        }

        if (isset($key['publicKey'])) {
            if (!isset($components['curve'])) {
                $components['curve'] = $key['publicKeyAlgorithm']['algorithm'] == 'id-Ed25519' ? new Ed25519() : new Ed448();
            }

            $components['QA'] = self::extractPoint($key['publicKey'], $components['curve']);
        }

        if (isset($key['privateKey']) && !isset($components['QA'])) {
            $components['QA'] = $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']);
        }

        return $components;
    }

    private static function loadECDH(array $key)
    {
        $components = [];

        if (isset($key['privateKey'])) {
            $components['curve'] = $key['privateKeyAlgorithm']['algorithm'] == 'id-X25519' ? new Curve25519() : new Curve448();
            $expected = chr(ASN1::TYPE_OCTET_STRING) . ASN1::encodeLength($components['curve']::SIZE);
            $privateKey = (string) $key['privateKey'];
            if (substr($privateKey, 0, 2) != $expected) {
                throw new \RuntimeException(
                    'The first two bytes of the ' .
                    $key['privateKeyAlgorithm']['algorithm'] .
                    ' private key field should be 0x' . bin2hex($expected)
                );
            }
            $components['dA'] = new BigInteger(substr($privateKey, 2), 256);
        }

        if (isset($key['publicKey'])) {
            if (!isset($components['curve'])) {
                $components['curve'] = $key['publicKeyAlgorithm']['algorithm'] == 'id-X25519' ? new Curve25519() : new Curve448();
            }

            $components['QA'] = [$components['curve']->convertInteger(new BigInteger(strrev($key['publicKey']), 256))];
        }

        if (isset($key['privateKey']) && !isset($components['QA'])) {
            if ($components['curve'] instanceof Curve25519 && function_exists('sodium_crypto_box_publickey_from_secretkey')) {
                //$r = pack('H*', '0900000000000000000000000000000000000000000000000000000000000000');
                //$QA = sodium_crypto_scalarmult($components['dA']->toBytes(), $r);
                $QA = sodium_crypto_box_publickey_from_secretkey(str_pad($components['dA']->toBytes(), 32, chr(0), STR_PAD_LEFT));
                $components['QA'] = [$components['curve']->convertInteger(new BigInteger(strrev($QA), 256))];
            } else {
                $components['QA'] = [$components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA'])[0]];
            }
        }

        return $components;
    }

    /**
     * Convert an EC public key to the appropriate format
     *
     * @param BaseCurve $curve
     * @param Integer[] $publicKey
     * @param array $options optional
     * @return string
     */
    public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = [])
    {
        self::initialize_static_variables();
        if ($curve instanceof MontgomeryCurve) {
            return self::wrapPublicKey(
                str_pad(strrev($publicKey[0]->toBytes()), $curve::SIZE, "\0", STR_PAD_RIGHT),
                null,
                $curve instanceof Curve25519 ? 'id-X25519' : 'id-X448',
                $options
            );
        }

        if ($curve instanceof TwistedEdwardsCurve) {
            return self::wrapPublicKey(
                $curve->encodePoint($publicKey),
                null,
                $curve instanceof Ed25519 ? 'id-Ed25519' : 'id-Ed448',
                $options
            );
        }

        $params = new ASN1\Element(self::encodeParameters($curve, false, $options));

        $key = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();

        return self::wrapPublicKey($key, $params, 'id-ecPublicKey', $options);
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $privateKey
     * @param BaseCurve $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @param string $secret optional
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve, array $publicKey, $secret = null, $password = '', array $options = [])
    {
        self::initialize_static_variables();

        if ($curve instanceof MontgomeryCurve) {
            return self::wrapPrivateKey(
                chr(ASN1::TYPE_OCTET_STRING) . ASN1::encodeLength($curve::SIZE) . str_pad($privateKey->toBytes(), $curve::SIZE, "\0", STR_PAD_LEFT),
                [],
                null,
                $password,
                $curve instanceof Curve25519 ? 'id-X25519' : 'id-X448'
            );
        }

        if ($curve instanceof TwistedEdwardsCurve) {
            return self::wrapPrivateKey(
                chr(ASN1::TYPE_OCTET_STRING) . ASN1::encodeLength($curve::SIZE) . $secret,
                [],
                null,
                $password,
                $curve instanceof Ed25519 ? 'id-Ed25519' : 'id-Ed448'
            );
        }

        $publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();

        $params = new ASN1\Element(self::encodeParameters($curve, false, $options));

        $key = [
            'version' => 'ecPrivkeyVer1',
            'privateKey' => $privateKey->toBytes(),
            //'parameters' => $params,
            'publicKey' => "\0" . $publicKey
        ];

        $key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP);

        return self::wrapPrivateKey($key, [], $params, $password, 'id-ecPublicKey', '', $options);
    }
}
<?php

/**
 * JSON Web Key (RFC7517 / RFC8037) Formatted EC Handler
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\JWK as Progenitor;
use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Crypt\EC\Curves\Ed25519;
use phpseclib3\Crypt\EC\Curves\secp256k1;
use phpseclib3\Crypt\EC\Curves\secp256r1;
use phpseclib3\Crypt\EC\Curves\secp384r1;
use phpseclib3\Crypt\EC\Curves\secp521r1;
use phpseclib3\Exception\UnsupportedCurveException;
use phpseclib3\Math\BigInteger;

/**
 * JWK Formatted EC Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class JWK extends Progenitor
{
    use Common;

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        $key = parent::load($key, $password);

        switch ($key->kty) {
            case 'EC':
                switch ($key->crv) {
                    case 'P-256':
                    case 'P-384':
                    case 'P-521':
                    case 'secp256k1':
                        break;
                    default:
                        throw new UnsupportedCurveException('Only P-256, P-384, P-521 and secp256k1 curves are accepted (' . $key->crv . ' provided)');
                }
                break;
            case 'OKP':
                switch ($key->crv) {
                    case 'Ed25519':
                    case 'Ed448':
                        break;
                    default:
                        throw new UnsupportedCurveException('Only Ed25519 and Ed448 curves are accepted (' . $key->crv . ' provided)');
                }
                break;
            default:
                throw new \Exception('Only EC and OKP JWK keys are supported');
        }

        $curve = '\phpseclib3\Crypt\EC\Curves\\' . str_replace('P-', 'nistp', $key->crv);
        $curve = new $curve();

        if ($curve instanceof TwistedEdwardsCurve) {
            $QA = self::extractPoint(Strings::base64url_decode($key->x), $curve);
            if (!isset($key->d)) {
                return compact('curve', 'QA');
            }
            $arr = $curve->extractSecret(Strings::base64url_decode($key->d));
            return compact('curve', 'QA') + $arr;
        }

        $QA = [
            $curve->convertInteger(new BigInteger(Strings::base64url_decode($key->x), 256)),
            $curve->convertInteger(new BigInteger(Strings::base64url_decode($key->y), 256))
        ];

        if (!$curve->verifyPoint($QA)) {
            throw new \RuntimeException('Unable to verify that point exists on curve');
        }

        if (!isset($key->d)) {
            return compact('curve', 'QA');
        }

        $dA = new BigInteger(Strings::base64url_decode($key->d), 256);

        $curve->rangeCheck($dA);

        return compact('curve', 'dA', 'QA');
    }

    /**
     * Returns the alias that corresponds to a curve
     *
     * @return string
     */
    private static function getAlias(BaseCurve $curve)
    {
        switch (true) {
            case $curve instanceof secp256r1:
                return 'P-256';
            case $curve instanceof secp384r1:
                return 'P-384';
            case $curve instanceof secp521r1:
                return 'P-521';
            case $curve instanceof secp256k1:
                return 'secp256k1';
        }

        $reflect = new \ReflectionClass($curve);
        $curveName = $reflect->isFinal() ?
            $reflect->getParentClass()->getShortName() :
            $reflect->getShortName();
        throw new UnsupportedCurveException("$curveName is not a supported curve");
    }

    /**
     * Return the array superstructure for an EC public key
     *
     * @param BaseCurve $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @return array
     */
    private static function savePublicKeyHelper(BaseCurve $curve, array $publicKey)
    {
        if ($curve instanceof TwistedEdwardsCurve) {
            return [
                'kty' => 'OKP',
                'crv' => $curve instanceof Ed25519 ? 'Ed25519' : 'Ed448',
                'x' => Strings::base64url_encode($curve->encodePoint($publicKey))
            ];
        }

        return [
            'kty' => 'EC',
            'crv' => self::getAlias($curve),
            'x' => Strings::base64url_encode($publicKey[0]->toBytes()),
            'y' => Strings::base64url_encode($publicKey[1]->toBytes())
        ];
    }

    /**
     * Convert an EC public key to the appropriate format
     *
     * @param BaseCurve $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @param array $options optional
     * @return string
     */
    public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = [])
    {
        $key = self::savePublicKeyHelper($curve, $publicKey);

        return self::wrapKey($key, $options);
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $privateKey
     * @param Ed25519 $curve
     * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
     * @param string $secret optional
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve, array $publicKey, $secret = null, $password = '', array $options = [])
    {
        $key = self::savePublicKeyHelper($curve, $publicKey);
        $key['d'] = $curve instanceof TwistedEdwardsCurve ? $secret : $privateKey->toBytes();
        $key['d'] = Strings::base64url_encode($key['d']);

        return self::wrapKey($key, $options);
    }
}
<?php

/**
 * Generic EC Key Parsing Helper functions
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve;
use phpseclib3\Crypt\EC\BaseCurves\Binary as BinaryCurve;
use phpseclib3\Crypt\EC\BaseCurves\Montgomery;
use phpseclib3\Crypt\EC\BaseCurves\Prime as PrimeCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Exception\UnsupportedCurveException;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * Generic EC Key Parsing Helper functions
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
trait Common
{
    /**
     * Curve OIDs
     *
     * @var array
     */
    private static $curveOIDs = [];

    /**
     * Child OIDs loaded
     *
     * @var bool
     */
    protected static $childOIDsLoaded = false;

    /**
     * Use Named Curves
     *
     * @var bool
     */
    private static $useNamedCurves = true;

    /**
     * Initialize static variables
     */
    private static function initialize_static_variables()
    {
        if (empty(self::$curveOIDs)) {
            // the sec* curves are from the standards for efficient cryptography group
            // sect* curves are curves over binary finite fields
            // secp* curves are curves over prime finite fields
            // sec*r* curves are regular curves; sec*k* curves are koblitz curves
            // brainpool*r* curves are regular prime finite field curves
            // brainpool*t* curves are twisted versions of the brainpool*r* curves
            self::$curveOIDs = [
                'prime192v1' => '1.2.840.10045.3.1.1', // J.5.1, example 1 (aka secp192r1)
                'prime192v2' => '1.2.840.10045.3.1.2', // J.5.1, example 2
                'prime192v3' => '1.2.840.10045.3.1.3', // J.5.1, example 3
                'prime239v1' => '1.2.840.10045.3.1.4', // J.5.2, example 1
                'prime239v2' => '1.2.840.10045.3.1.5', // J.5.2, example 2
                'prime239v3' => '1.2.840.10045.3.1.6', // J.5.2, example 3
                'prime256v1' => '1.2.840.10045.3.1.7', // J.5.3, example 1 (aka secp256r1)

                // https://tools.ietf.org/html/rfc5656#section-10
                'nistp256' => '1.2.840.10045.3.1.7', // aka secp256r1
                'nistp384' => '1.3.132.0.34', // aka secp384r1
                'nistp521' => '1.3.132.0.35', // aka secp521r1

                'nistk163' => '1.3.132.0.1', // aka sect163k1
                'nistp192' => '1.2.840.10045.3.1.1', // aka secp192r1
                'nistp224' => '1.3.132.0.33', // aka secp224r1
                'nistk233' => '1.3.132.0.26', // aka sect233k1
                'nistb233' => '1.3.132.0.27', // aka sect233r1
                'nistk283' => '1.3.132.0.16', // aka sect283k1
                'nistk409' => '1.3.132.0.36', // aka sect409k1
                'nistb409' => '1.3.132.0.37', // aka sect409r1
                'nistt571' => '1.3.132.0.38', // aka sect571k1

                // from https://tools.ietf.org/html/rfc5915
                'secp192r1' => '1.2.840.10045.3.1.1', // aka prime192v1
                'sect163k1' => '1.3.132.0.1',
                'sect163r2' => '1.3.132.0.15',
                'secp224r1' => '1.3.132.0.33',
                'sect233k1' => '1.3.132.0.26',
                'sect233r1' => '1.3.132.0.27',
                'secp256r1' => '1.2.840.10045.3.1.7', // aka prime256v1
                'sect283k1' => '1.3.132.0.16',
                'sect283r1' => '1.3.132.0.17',
                'secp384r1' => '1.3.132.0.34',
                'sect409k1' => '1.3.132.0.36',
                'sect409r1' => '1.3.132.0.37',
                'secp521r1' => '1.3.132.0.35',
                'sect571k1' => '1.3.132.0.38',
                'sect571r1' => '1.3.132.0.39',
                // from http://www.secg.org/SEC2-Ver-1.0.pdf
                'secp112r1' => '1.3.132.0.6',
                'secp112r2' => '1.3.132.0.7',
                'secp128r1' => '1.3.132.0.28',
                'secp128r2' => '1.3.132.0.29',
                'secp160k1' => '1.3.132.0.9',
                'secp160r1' => '1.3.132.0.8',
                'secp160r2' => '1.3.132.0.30',
                'secp192k1' => '1.3.132.0.31',
                'secp224k1' => '1.3.132.0.32',
                'secp256k1' => '1.3.132.0.10',

                'sect113r1' => '1.3.132.0.4',
                'sect113r2' => '1.3.132.0.5',
                'sect131r1' => '1.3.132.0.22',
                'sect131r2' => '1.3.132.0.23',
                'sect163r1' => '1.3.132.0.2',
                'sect193r1' => '1.3.132.0.24',
                'sect193r2' => '1.3.132.0.25',
                'sect239k1' => '1.3.132.0.3',

                // from http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf#page=36
                /*
                'c2pnb163v1' => '1.2.840.10045.3.0.1', // J.4.1, example 1
                'c2pnb163v2' => '1.2.840.10045.3.0.2', // J.4.1, example 2
                'c2pnb163v3' => '1.2.840.10045.3.0.3', // J.4.1, example 3
                'c2pnb172w1' => '1.2.840.10045.3.0.4', // J.4.2, example 1
                'c2tnb191v1' => '1.2.840.10045.3.0.5', // J.4.3, example 1
                'c2tnb191v2' => '1.2.840.10045.3.0.6', // J.4.3, example 2
                'c2tnb191v3' => '1.2.840.10045.3.0.7', // J.4.3, example 3
                'c2onb191v4' => '1.2.840.10045.3.0.8', // J.4.3, example 4
                'c2onb191v5' => '1.2.840.10045.3.0.9', // J.4.3, example 5
                'c2pnb208w1' => '1.2.840.10045.3.0.10', // J.4.4, example 1
                'c2tnb239v1' => '1.2.840.10045.3.0.11', // J.4.5, example 1
                'c2tnb239v2' => '1.2.840.10045.3.0.12', // J.4.5, example 2
                'c2tnb239v3' => '1.2.840.10045.3.0.13', // J.4.5, example 3
                'c2onb239v4' => '1.2.840.10045.3.0.14', // J.4.5, example 4
                'c2onb239v5' => '1.2.840.10045.3.0.15', // J.4.5, example 5
                'c2pnb272w1' => '1.2.840.10045.3.0.16', // J.4.6, example 1
                'c2pnb304w1' => '1.2.840.10045.3.0.17', // J.4.7, example 1
                'c2tnb359v1' => '1.2.840.10045.3.0.18', // J.4.8, example 1
                'c2pnb368w1' => '1.2.840.10045.3.0.19', // J.4.9, example 1
                'c2tnb431r1' => '1.2.840.10045.3.0.20', // J.4.10, example 1
                */

                // http://www.ecc-brainpool.org/download/Domain-parameters.pdf
                // https://tools.ietf.org/html/rfc5639
                'brainpoolP160r1' => '1.3.36.3.3.2.8.1.1.1',
                'brainpoolP160t1' => '1.3.36.3.3.2.8.1.1.2',
                'brainpoolP192r1' => '1.3.36.3.3.2.8.1.1.3',
                'brainpoolP192t1' => '1.3.36.3.3.2.8.1.1.4',
                'brainpoolP224r1' => '1.3.36.3.3.2.8.1.1.5',
                'brainpoolP224t1' => '1.3.36.3.3.2.8.1.1.6',
                'brainpoolP256r1' => '1.3.36.3.3.2.8.1.1.7',
                'brainpoolP256t1' => '1.3.36.3.3.2.8.1.1.8',
                'brainpoolP320r1' => '1.3.36.3.3.2.8.1.1.9',
                'brainpoolP320t1' => '1.3.36.3.3.2.8.1.1.10',
                'brainpoolP384r1' => '1.3.36.3.3.2.8.1.1.11',
                'brainpoolP384t1' => '1.3.36.3.3.2.8.1.1.12',
                'brainpoolP512r1' => '1.3.36.3.3.2.8.1.1.13',
                'brainpoolP512t1' => '1.3.36.3.3.2.8.1.1.14'
            ];
            ASN1::loadOIDs([
                'prime-field' => '1.2.840.10045.1.1',
                'characteristic-two-field' => '1.2.840.10045.1.2',
                'characteristic-two-basis' => '1.2.840.10045.1.2.3',
                // per http://www.secg.org/SEC1-Ver-1.0.pdf#page=84, gnBasis "not used here"
                'gnBasis' => '1.2.840.10045.1.2.3.1', // NULL
                'tpBasis' => '1.2.840.10045.1.2.3.2', // Trinomial
                'ppBasis' => '1.2.840.10045.1.2.3.3'  // Pentanomial
            ] + self::$curveOIDs);
        }
    }

    /**
     * Explicitly set the curve
     *
     * If the key contains an implicit curve phpseclib needs the curve
     * to be explicitly provided
     *
     * @param BaseCurve $curve
     */
    public static function setImplicitCurve(BaseCurve $curve)
    {
        self::$implicitCurve = $curve;
    }

    /**
     * Returns an instance of \phpseclib3\Crypt\EC\BaseCurves\Base based
     * on the curve parameters
     *
     * @param array $params
     * @return BaseCurve|false
     */
    protected static function loadCurveByParam(array $params)
    {
        if (count($params) > 1) {
            throw new \RuntimeException('No parameters are present');
        }
        if (isset($params['namedCurve'])) {
            $curve = '\phpseclib3\Crypt\EC\Curves\\' . $params['namedCurve'];
            if (!class_exists($curve)) {
                throw new UnsupportedCurveException('Named Curve of ' . $params['namedCurve'] . ' is not supported');
            }
            return new $curve();
        }
        if (isset($params['implicitCurve'])) {
            if (!isset(self::$implicitCurve)) {
                throw new \RuntimeException('Implicit curves can be provided by calling setImplicitCurve');
            }
            return self::$implicitCurve;
        }
        if (isset($params['specifiedCurve'])) {
            $data = $params['specifiedCurve'];
            switch ($data['fieldID']['fieldType']) {
                case 'prime-field':
                    $curve = new PrimeCurve();
                    $curve->setModulo($data['fieldID']['parameters']);
                    $curve->setCoefficients(
                        new BigInteger($data['curve']['a'], 256),
                        new BigInteger($data['curve']['b'], 256)
                    );
                    $point = self::extractPoint("\0" . $data['base'], $curve);
                    $curve->setBasePoint(...$point);
                    $curve->setOrder($data['order']);
                    return $curve;
                case 'characteristic-two-field':
                    $curve = new BinaryCurve();
                    $params = ASN1::decodeBER($data['fieldID']['parameters']);
                    $params = ASN1::asn1map($params[0], Maps\Characteristic_two::MAP);
                    $modulo = [(int) $params['m']->toString()];
                    switch ($params['basis']) {
                        case 'tpBasis':
                            $modulo[] = (int) $params['parameters']->toString();
                            break;
                        case 'ppBasis':
                            $temp = ASN1::decodeBER($params['parameters']);
                            $temp = ASN1::asn1map($temp[0], Maps\Pentanomial::MAP);
                            $modulo[] = (int) $temp['k3']->toString();
                            $modulo[] = (int) $temp['k2']->toString();
                            $modulo[] = (int) $temp['k1']->toString();
                    }
                    $modulo[] = 0;
                    $curve->setModulo(...$modulo);
                    $len = ceil($modulo[0] / 8);
                    $curve->setCoefficients(
                        Strings::bin2hex($data['curve']['a']),
                        Strings::bin2hex($data['curve']['b'])
                    );
                    $point = self::extractPoint("\0" . $data['base'], $curve);
                    $curve->setBasePoint(...$point);
                    $curve->setOrder($data['order']);
                    return $curve;
                default:
                    throw new UnsupportedCurveException('Field Type of ' . $data['fieldID']['fieldType'] . ' is not supported');
            }
        }
        throw new \RuntimeException('No valid parameters are present');
    }

    /**
     * Extract points from a string
     *
     * Supports both compressed and uncompressed points
     *
     * @param string $str
     * @param BaseCurve $curve
     * @return object[]
     */
    public static function extractPoint($str, BaseCurve $curve)
    {
        if ($curve instanceof Montgomery) {
            return [new BigInteger($str, 256)];
        }
        if ($curve instanceof TwistedEdwardsCurve) {
            // first step of point deciding as discussed at the following URL's:
            // https://tools.ietf.org/html/rfc8032#section-5.1.3
            // https://tools.ietf.org/html/rfc8032#section-5.2.3
            $y = $str;
            $y = strrev($y);
            $sign = (bool) (ord($y[0]) & 0x80);
            $y[0] = $y[0] & chr(0x7F);
            $y = new BigInteger($y, 256);
            if ($y->compare($curve->getModulo()) >= 0) {
                throw new \RuntimeException('The Y coordinate should not be >= the modulo');
            }
            $point = $curve->recoverX($y, $sign);
            if (!$curve->verifyPoint($point)) {
                throw new \RuntimeException('Unable to verify that point exists on curve');
            }
            return $point;
        }

        // the first byte of a bit string represents the number of bits in the last byte that are to be ignored but,
        // currently, bit strings wanting a non-zero amount of bits trimmed are not supported
        if (($val = Strings::shift($str)) != "\0") {
            throw new \UnexpectedValueException('extractPoint expects the first byte to be null - not ' . Strings::bin2hex($val));
        }
        if ($str == "\0") {
            return [];
        }

        $keylen = strlen($str);
        $order = $curve->getLengthInBytes();
        // point compression is being used
        if ($keylen == $order + 1) {
            return $curve->derivePoint($str);
        }

        // point compression is not being used
        if ($keylen == 2 * $order + 1) {
            preg_match("#(.)(.{{$order}})(.{{$order}})#s", $str, $matches);
            list(, $w, $x, $y) = $matches;
            if ($w != "\4") {
                throw new \UnexpectedValueException('The first byte of an uncompressed point should be 04 - not ' . Strings::bin2hex($val));
            }
            $point = [
                $curve->convertInteger(new BigInteger($x, 256)),
                $curve->convertInteger(new BigInteger($y, 256))
            ];

            if (!$curve->verifyPoint($point)) {
                throw new \RuntimeException('Unable to verify that point exists on curve');
            }

            return $point;
        }

        throw new \UnexpectedValueException('The string representation of the points is not of an appropriate length');
    }

    /**
     * Encode Parameters
     *
     * @todo Maybe at some point this could be moved to __toString() for each of the curves?
     * @param BaseCurve $curve
     * @param bool $returnArray optional
     * @param array $options optional
     * @return string|false
     */
    private static function encodeParameters(BaseCurve $curve, $returnArray = false, array $options = [])
    {
        $useNamedCurves = isset($options['namedCurve']) ? $options['namedCurve'] : self::$useNamedCurves;

        $reflect = new \ReflectionClass($curve);
        $name = $reflect->getShortName();
        if ($useNamedCurves) {
            if (isset(self::$curveOIDs[$name])) {
                if ($reflect->isFinal()) {
                    $reflect = $reflect->getParentClass();
                    $name = $reflect->getShortName();
                }
                return $returnArray ?
                    ['namedCurve' => $name] :
                    ASN1::encodeDER(['namedCurve' => $name], Maps\ECParameters::MAP);
            }
            foreach (new \DirectoryIterator(__DIR__ . '/../../Curves/') as $file) {
                if ($file->getExtension() != 'php') {
                    continue;
                }
                $testName = $file->getBasename('.php');
                $class = 'phpseclib3\Crypt\EC\Curves\\' . $testName;
                $reflect = new \ReflectionClass($class);
                if ($reflect->isFinal()) {
                    continue;
                }
                $candidate = new $class();
                switch ($name) {
                    case 'Prime':
                        if (!$candidate instanceof PrimeCurve) {
                            break;
                        }
                        if (!$candidate->getModulo()->equals($curve->getModulo())) {
                            break;
                        }
                        if ($candidate->getA()->toBytes() != $curve->getA()->toBytes()) {
                            break;
                        }
                        if ($candidate->getB()->toBytes() != $curve->getB()->toBytes()) {
                            break;
                        }

                        list($candidateX, $candidateY) = $candidate->getBasePoint();
                        list($curveX, $curveY) = $curve->getBasePoint();
                        if ($candidateX->toBytes() != $curveX->toBytes()) {
                            break;
                        }
                        if ($candidateY->toBytes() != $curveY->toBytes()) {
                            break;
                        }

                        return $returnArray ?
                            ['namedCurve' => $testName] :
                            ASN1::encodeDER(['namedCurve' => $testName], Maps\ECParameters::MAP);
                    case 'Binary':
                        if (!$candidate instanceof BinaryCurve) {
                            break;
                        }
                        if ($candidate->getModulo() != $curve->getModulo()) {
                            break;
                        }
                        if ($candidate->getA()->toBytes() != $curve->getA()->toBytes()) {
                            break;
                        }
                        if ($candidate->getB()->toBytes() != $curve->getB()->toBytes()) {
                            break;
                        }

                        list($candidateX, $candidateY) = $candidate->getBasePoint();
                        list($curveX, $curveY) = $curve->getBasePoint();
                        if ($candidateX->toBytes() != $curveX->toBytes()) {
                            break;
                        }
                        if ($candidateY->toBytes() != $curveY->toBytes()) {
                            break;
                        }

                        return $returnArray ?
                            ['namedCurve' => $testName] :
                            ASN1::encodeDER(['namedCurve' => $testName], Maps\ECParameters::MAP);
                }
            }
        }

        $order = $curve->getOrder();
        // we could try to calculate the order thusly:
        // https://crypto.stackexchange.com/a/27914/4520
        // https://en.wikipedia.org/wiki/Schoof%E2%80%93Elkies%E2%80%93Atkin_algorithm
        if (!$order) {
            throw new \RuntimeException('Specified Curves need the order to be specified');
        }
        $point = $curve->getBasePoint();
        $x = $point[0]->toBytes();
        $y = $point[1]->toBytes();

        if ($curve instanceof PrimeCurve) {
            /*
             * valid versions are:
             *
             * ecdpVer1:
             *   - neither the curve or the base point are generated verifiably randomly.
             * ecdpVer2:
             *   - curve and base point are generated verifiably at random and curve.seed is present
             * ecdpVer3:
             *   - base point is generated verifiably at random but curve is not. curve.seed is present
             */
            // other (optional) parameters can be calculated using the methods discused at
            // https://crypto.stackexchange.com/q/28947/4520
            $data = [
                'version' => 'ecdpVer1',
                'fieldID' => [
                    'fieldType' => 'prime-field',
                    'parameters' => $curve->getModulo()
                ],
                'curve' => [
                    'a' => $curve->getA()->toBytes(),
                    'b' => $curve->getB()->toBytes()
                ],
                'base' => "\4" . $x . $y,
                'order' => $order
            ];

            return $returnArray ?
                ['specifiedCurve' => $data] :
                ASN1::encodeDER(['specifiedCurve' => $data], Maps\ECParameters::MAP);
        }
        if ($curve instanceof BinaryCurve) {
            $modulo = $curve->getModulo();
            $basis = count($modulo);
            $m = array_shift($modulo);
            array_pop($modulo); // the last parameter should always be 0
            //rsort($modulo);
            switch ($basis) {
                case 3:
                    $basis = 'tpBasis';
                    $modulo = new BigInteger($modulo[0]);
                    break;
                case 5:
                    $basis = 'ppBasis';
                    // these should be in strictly ascending order (hence the commented out rsort above)
                    $modulo = [
                        'k1' => new BigInteger($modulo[2]),
                        'k2' => new BigInteger($modulo[1]),
                        'k3' => new BigInteger($modulo[0])
                    ];
                    $modulo = ASN1::encodeDER($modulo, Maps\Pentanomial::MAP);
                    $modulo = new ASN1\Element($modulo);
            }
            $params = ASN1::encodeDER([
                'm' => new BigInteger($m),
                'basis' => $basis,
                'parameters' => $modulo
            ], Maps\Characteristic_two::MAP);
            $params = new ASN1\Element($params);
            $a = ltrim($curve->getA()->toBytes(), "\0");
            if (!strlen($a)) {
                $a = "\0";
            }
            $b = ltrim($curve->getB()->toBytes(), "\0");
            if (!strlen($b)) {
                $b = "\0";
            }
            $data = [
                'version' => 'ecdpVer1',
                'fieldID' => [
                    'fieldType' => 'characteristic-two-field',
                    'parameters' => $params
                ],
                'curve' => [
                    'a' => $a,
                    'b' => $b
                ],
                'base' => "\4" . $x . $y,
                'order' => $order
            ];

            return $returnArray ?
                ['specifiedCurve' => $data] :
                ASN1::encodeDER(['specifiedCurve' => $data], Maps\ECParameters::MAP);
        }

        throw new UnsupportedCurveException('Curve cannot be serialized');
    }

    /**
     * Use Specified Curve
     *
     * A specified curve has all the coefficients, the base points, etc, explicitely included.
     * A specified curve is a more verbose way of representing a curve
     */
    public static function useSpecifiedCurve()
    {
        self::$useNamedCurves = false;
    }

    /**
     * Use Named Curve
     *
     * A named curve does not include any parameters. It is up to the EC parameters to
     * know what the coefficients, the base points, etc, are from the name of the curve.
     * A named curve is a more concise way of representing a curve
     */
    public static function useNamedCurve()
    {
        self::$useNamedCurves = true;
    }
}
<?php

/**
 * EC Private Key
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common;
use phpseclib3\Crypt\EC;
use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Crypt\EC\Curves\Curve25519;
use phpseclib3\Crypt\EC\Curves\Ed25519;
use phpseclib3\Crypt\EC\Formats\Keys\PKCS1;
use phpseclib3\Crypt\EC\Formats\Signature\ASN1 as ASN1Signature;
use phpseclib3\Crypt\Hash;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\UnsupportedOperationException;
use phpseclib3\Math\BigInteger;

/**
 * EC Private Key
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
final class PrivateKey extends EC implements Common\PrivateKey
{
    use Common\Traits\PasswordProtected;

    /**
     * Private Key dA
     *
     * sign() converts this to a BigInteger so one might wonder why this is a FiniteFieldInteger instead of
     * a BigInteger. That's because a FiniteFieldInteger, when converted to a byte string, is null padded by
     * a certain amount whereas a BigInteger isn't.
     *
     * @var object
     */
    protected $dA;

    /**
     * @var string
     */
    protected $secret;

    /**
     * Multiplies an encoded point by the private key
     *
     * Used by ECDH
     *
     * @param string $coordinates
     * @return string
     */
    public function multiply($coordinates)
    {
        if (self::$forcedEngine === 'OpenSSL') {
            throw new BadConfigurationException('Engine OpenSSL is not supported for the multiplication operation');
        }

        if (self::$forcedEngine === 'libsodium' && !$this->curve instanceof Curve25519) {
            throw new BadConfigurationException('Engine libsodium is only supported for Curve25519');
        }

        if ($this->curve instanceof Curve25519 && self::$forcedEngine !== 'PHP') {
            if (self::$forcedEngine === 'libsodium' && !function_exists('sodium_crypto_scalarmult')) {
                throw new BadConfigurationException('Engine libsodium is forced but unsupported for Curve25519');
            }
            if (function_exists('sodium_crypto_scalarmult')) {
                $dA = str_pad($this->dA->toBytes(), 32, "\0", STR_PAD_LEFT);
                return sodium_crypto_scalarmult($dA, $coordinates);
            }
        }

        if ($this->curve instanceof MontgomeryCurve) {
            $point = [$this->curve->convertInteger(new BigInteger(strrev($coordinates), 256))];
            $point = $this->curve->multiplyPoint($point, $this->dA);
            return strrev($point[0]->toBytes(true));
        }

        if (!$this->curve instanceof TwistedEdwardsCurve) {
            $coordinates = "\0$coordinates";
        }

        $point = PKCS1::extractPoint($coordinates, $this->curve);
        $point = $this->curve->multiplyPoint($point, $this->dA);
        if ($this->curve instanceof TwistedEdwardsCurve) {
            return $this->curve->encodePoint($point);
        }
        if (empty($point)) {
            throw new \RuntimeException('The infinity point is invalid');
        }
        return "\4" . $point[0]->toBytes(true) . $point[1]->toBytes(true);
    }

    /**
     * Create a signature
     *
     * @see self::verify()
     * @param string $message
     * @return mixed
     */
    public function sign($message)
    {
        if ($this->curve instanceof MontgomeryCurve) {
            throw new UnsupportedOperationException('Montgomery Curves cannot be used to create signatures');
        }

        $dA = $this->dA;
        $order = $this->curve->getOrder();

        $shortFormat = $this->shortFormat;
        $format = $this->sigFormat;
        if ($format === false) {
            return false;
        }

        if (self::$forcedEngine === 'libsodium' && !$this->curve instanceof Ed25519) {
            throw new BadConfigurationException('Engine libsodium is only supported for Ed25519');
        }

        // at this point either self::$forcedEngine is NOT libsodium or the curve is Ed25519

        if ($this->curve instanceof Ed25519 && self::$forcedEngine !== 'PHP' && self::$forcedEngine !== 'OpenSSL') {
            if (self::$forcedEngine === 'libsodium') {
                if (!function_exists('sodium_crypto_sign_detached')) {
                    throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519 / Ed448');
                }
                if (isset($this->context)) {
                    throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519ctx (context)');
                }
            }
            if (function_exists('sodium_crypto_sign_detached') && !isset($this->context)) {
                $result = sodium_crypto_sign_detached($message, $this->withPassword()->toString('libsodium'));
                return $shortFormat == 'SSH2' ? Strings::packSSH2('ss', 'ssh-' . strtolower($this->getCurve()), $result) : $result;
            }
        }

        // at this point self::$forcedEngine CAN'T be libsodium so we won't check for it henceforth

        if ($this->curve instanceof TwistedEdwardsCurve) {
            if (self::$forcedEngine !== 'PHP') {
                $keyTypeConstant = $this->curve instanceof Ed25519 ? 'OPENSSL_KEYTYPE_ED25519' : 'OPENSSL_KEYTYPE_ED448';
                if (self::$forcedEngine === 'OpenSSL') {
                    if (!defined($keyTypeConstant)) {
                        throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448');
                    }
                    // OpenSSL supports Ed25519/Ed448 but not Ed25519ctx (context), so skip if context is set
                    if (isset($this->context)) {
                        throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448 curves with context\'s');
                    }
                }
                if (defined($keyTypeConstant) && !isset($this->context)) {
                    $result = '';
                    // algorithm 0 is used because EdDSA has a built-in hash
                    openssl_sign($message, $result, $this->withPassword()->toString('PKCS8'), 0);
                    if ($result) {
                        $signature = $shortFormat == 'SSH2'
                            ? Strings::packSSH2('ss', 'ssh-' . strtolower($this->getCurve()), $result)
                            : $result;
                        return $signature;
                    }
                    if (self::$forcedEngine === 'OpenSSL') {
                        throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
                    }
                }
            }

            // contexts (Ed25519ctx) are supported but prehashing (Ed25519ph) is not.
            // quoting https://tools.ietf.org/html/rfc8032#section-8.5 ,
            // "The Ed25519ph and Ed448ph variants ... SHOULD NOT be used"
            $A = $this->curve->encodePoint($this->QA);
            $curve = $this->curve;
            $hash = new Hash($curve::HASH);

            $secret = substr($hash->hash($this->secret), $curve::SIZE);

            if ($curve instanceof Ed25519) {
                $dom = !isset($this->context) ? '' :
                    'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context;
            } else {
                $context = isset($this->context) ? $this->context : '';
                $dom = 'SigEd448' . "\0" . chr(strlen($context)) . $context;
            }
            // SHA-512(dom2(F, C) || prefix || PH(M))
            $r = $hash->hash($dom . $secret . $message);
            $r = strrev($r);
            $r = new BigInteger($r, 256);
            list(, $r) = $r->divide($order);
            $R = $curve->multiplyPoint($curve->getBasePoint(), $r);
            $R = $curve->encodePoint($R);
            $k = $hash->hash($dom . $R . $A . $message);
            $k = strrev($k);
            $k = new BigInteger($k, 256);
            list(, $k) = $k->divide($order);
            $S = $k->multiply($dA)->add($r);
            list(, $S) = $S->divide($order);
            $S = str_pad(strrev($S->toBytes()), $curve::SIZE, "\0");
            return $shortFormat == 'SSH2' ? Strings::packSSH2('ss', 'ssh-' . strtolower($this->getCurve()), $R . $S) : $R . $S;
        }

        if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) {
            throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA');
        }

        // at this point $forcedEngine is either PHP or null. either that OR openssl_get_md_methods() exists

        if (self::$forcedEngine !== 'PHP') {
            if (in_array($this->hash->getHash(), openssl_get_md_methods())) {
                $signature = '';
                // altho PHP's OpenSSL bindings only supported EC key creation in PHP 7.1 they've long
                // supported signing / verification
                // we use specified curves to avoid issues with OpenSSL possibly not supporting a given named curve;
                // doing this may mean some curve-specific optimizations can't be used but idk if OpenSSL even
                // has curve-specific optimizations
                $result = openssl_sign($message, $signature, $this->withPassword()->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash());

                if ($result) {
                    if ($shortFormat == 'ASN1') {
                        return $signature;
                    }

                    $loaded = ASN1Signature::load($signature);
                    $r = $loaded['r'];
                    $s = $loaded['s'];

                    return $this->formatSignature($r, $s);
                } elseif (self::$forcedEngine === 'OpenSSL') {
                    throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
                }
            } elseif (self::$forcedEngine === 'OpenSSL') {
                throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA / ' . $this->hash->getHash());
            }
        }

        $e = $this->hash->hash($message);
        $e = new BigInteger($e, 256);

        $Ln = $this->hash->getLength() - $order->getLength();
        $z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e;

        while (true) {
            $k = BigInteger::randomRange(self::$one, $order->subtract(self::$one));
            list($x, $y) = $this->curve->multiplyPoint($this->curve->getBasePoint(), $k);
            $x = $x->toBigInteger();
            list(, $r) = $x->divide($order);
            if ($r->equals(self::$zero)) {
                continue;
            }
            $kinv = $k->modInverse($order);
            $temp = $z->add($dA->multiply($r));
            $temp = $kinv->multiply($temp);
            list(, $s) = $temp->divide($order);
            if (!$s->equals(self::$zero)) {
                break;
            }
        }

        // the following is an RFC6979 compliant implementation of deterministic ECDSA
        // it's unused because it's mainly intended for use when a good CSPRNG isn't
        // available. if phpseclib's CSPRNG isn't good then even key generation is
        // suspect
        /*
        // if this were actually being used it'd probably be better if this lived in load() and createKey()
        $this->q = $this->curve->getOrder();
        $dA = $this->dA->toBigInteger();
        $this->x = $dA;

        $h1 = $this->hash->hash($message);
        $k = $this->computek($h1);
        list($x, $y) = $this->curve->multiplyPoint($this->curve->getBasePoint(), $k);
        $x = $x->toBigInteger();
        list(, $r) = $x->divide($this->q);
        $kinv = $k->modInverse($this->q);
        $h1 = $this->bits2int($h1);
        $temp = $h1->add($dA->multiply($r));
        $temp = $kinv->multiply($temp);
        list(, $s) = $temp->divide($this->q);
        */

        return $this->formatSignature($r, $s);
    }

    /**
     * Returns the private key
     *
     * @param string $type
     * @param array $options optional
     * @return string
     */
    public function toString($type, array $options = [])
    {
        $type = self::validatePlugin('Keys', $type, 'savePrivateKey');

        return $type::savePrivateKey($this->dA, $this->curve, $this->QA, $this->secret, $this->password, $options);
    }

    /**
     * Returns the public key
     *
     * @see self::getPrivateKey()
     * @return mixed
     */
    public function getPublicKey()
    {
        $format = 'PKCS8';
        if ($this->curve instanceof MontgomeryCurve) {
            $format = 'MontgomeryPublic';
        }

        $type = self::validatePlugin('Keys', $format, 'savePublicKey');

        $key = $type::savePublicKey($this->curve, $this->QA);
        $key = EC::loadFormat($format, $key);
        if ($this->curve instanceof MontgomeryCurve) {
            return $key;
        }
        $key = $key
            ->withHash($this->hash->getHash())
            ->withSignatureFormat($this->shortFormat);
        if ($this->curve instanceof TwistedEdwardsCurve) {
            $key = $key->withContext($this->context);
        }
        return $key;
    }

    /**
     * Returns a signature in the appropriate format
     *
     * @return string
     */
    private function formatSignature(BigInteger $r, BigInteger $s)
    {
        $format = $this->sigFormat;

        $temp = new \ReflectionMethod($format, 'save');
        $paramCount = $temp->getNumberOfRequiredParameters();

        // @codingStandardsIgnoreStart
        switch ($paramCount) {
            case 2: return $format::save($r, $s);
            case 3: return $format::save($r, $s, $this->getCurve());
            case 4: return $format::save($r, $s, $this->getCurve(), $this->getLength());
        }
        // @codingStandardsIgnoreEnd

        // presumably the only way you could get to this is if you were using a custom plugin
        throw new UnsupportedOperationException("$format::save() has $paramCount parameters - the only valid parameter counts are 2 or 3");
    }
}
<?php

/**
 * Curve methods common to all curves
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\BaseCurves;

use phpseclib3\Math\BigInteger;

/**
 * Base
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Base
{
    /**
     * The Order
     *
     * @var BigInteger
     */
    protected $order;

    /**
     * Finite Field Integer factory
     *
     * @var FiniteField\Integer
     */
    protected $factory;

    /**
     * Returns a random integer
     *
     * @return object
     */
    public function randomInteger()
    {
        return $this->factory->randomInteger();
    }

    /**
     * Converts a BigInteger to a FiniteField\Integer integer
     *
     * @return object
     */
    public function convertInteger(BigInteger $x)
    {
        return $this->factory->newInteger($x);
    }

    /**
     * Returns the length, in bytes, of the modulo
     *
     * @return integer
     */
    public function getLengthInBytes()
    {
        return $this->factory->getLengthInBytes();
    }

    /**
     * Returns the length, in bits, of the modulo
     *
     * @return integer
     */
    public function getLength()
    {
        return $this->factory->getLength();
    }

    /**
     * Multiply a point on the curve by a scalar
     *
     * Uses the montgomery ladder technique as described here:
     *
     * https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Montgomery_ladder
     * https://github.com/phpecc/phpecc/issues/16#issuecomment-59176772
     *
     * @return array
     */
    public function multiplyPoint(array $p, BigInteger $d)
    {
        $alreadyInternal = isset($p[2]);
        $r = $alreadyInternal ?
            [[], $p] :
            [[], $this->convertToInternal($p)];

        $d = $d->toBits();
        for ($i = 0; $i < strlen($d); $i++) {
            $d_i = (int) $d[$i];
            $r[1 - $d_i] = $this->addPoint($r[0], $r[1]);
            $r[$d_i] = $this->doublePoint($r[$d_i]);
        }

        return $alreadyInternal ? $r[0] : $this->convertToAffine($r[0]);
    }

    /**
     * Creates a random scalar multiplier
     *
     * @return BigInteger
     */
    public function createRandomMultiplier()
    {
        static $one;
        if (!isset($one)) {
            $one = new BigInteger(1);
        }

        return BigInteger::randomRange($one, $this->order->subtract($one));
    }

    /**
     * Performs range check
     */
    public function rangeCheck(BigInteger $x)
    {
        static $zero;
        if (!isset($zero)) {
            $zero = new BigInteger();
        }

        if (!isset($this->order)) {
            throw new \RuntimeException('setOrder needs to be called before this method');
        }
        if ($x->compare($this->order) > 0 || $x->compare($zero) <= 0) {
            throw new \RangeException('x must be between 1 and the order of the curve');
        }
    }

    /**
     * Sets the Order
     */
    public function setOrder(BigInteger $order)
    {
        $this->order = $order;
    }

    /**
     * Returns the Order
     *
     * @return BigInteger
     */
    public function getOrder()
    {
        return $this->order;
    }

    /**
     * Use a custom defined modular reduction function
     *
     * @return object
     */
    public function setReduction(callable $func)
    {
        $this->factory->setReduction($func);
    }

    /**
     * Returns the affine point
     *
     * @return object[]
     */
    public function convertToAffine(array $p)
    {
        return $p;
    }

    /**
     * Converts an affine point to a jacobian coordinate
     *
     * @return object[]
     */
    public function convertToInternal(array $p)
    {
        return $p;
    }

    /**
     * Negates a point
     *
     * @return object[]
     */
    public function negatePoint(array $p)
    {
        $temp = [
            $p[0],
            $p[1]->negate()
        ];
        if (isset($p[2])) {
            $temp[] = $p[2];
        }
        return $temp;
    }

    /**
     * Multiply and Add Points
     *
     * @return int[]
     */
    public function multiplyAddPoints(array $points, array $scalars)
    {
        $p1 = $this->convertToInternal($points[0]);
        $p2 = $this->convertToInternal($points[1]);
        $p1 = $this->multiplyPoint($p1, $scalars[0]);
        $p2 = $this->multiplyPoint($p2, $scalars[1]);
        $r = $this->addPoint($p1, $p2);
        return $this->convertToAffine($r);
    }
}
<?php

/**
 * Curves over y^2 + x*y = x^3 + a*x^2 + b
 *
 * These are curves used in SEC 2 over prime fields: http://www.secg.org/SEC2-Ver-1.0.pdf
 * The curve is a weierstrass curve with a[3] and a[2] set to 0.
 *
 * Uses Jacobian Coordinates for speed if able:
 *
 * https://en.wikipedia.org/wiki/Jacobian_curve
 * https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\BaseCurves;

use phpseclib3\Math\BigInteger;
use phpseclib3\Math\BinaryField;
use phpseclib3\Math\BinaryField\Integer as BinaryInteger;

/**
 * Curves over y^2 + x*y = x^3 + a*x^2 + b
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Binary extends Base
{
    /**
     * Binary Field Integer factory
     *
     * @var BinaryField
     */
    protected $factory;

    /**
     * Cofficient for x^1
     *
     * @var object
     */
    protected $a;

    /**
     * Cofficient for x^0
     *
     * @var object
     */
    protected $b;

    /**
     * Base Point
     *
     * @var object
     */
    protected $p;

    /**
     * The number one over the specified finite field
     *
     * @var object
     */
    protected $one;

    /**
     * The modulo
     *
     * @var BigInteger
     */
    protected $modulo;

    /**
     * The Order
     *
     * @var BigInteger
     */
    protected $order;

    /**
     * Sets the modulo
     */
    public function setModulo(...$modulo)
    {
        $this->modulo = $modulo;
        $this->factory = new BinaryField(...$modulo);

        $this->one = $this->factory->newInteger("\1");
    }

    /**
     * Set coefficients a and b
     *
     * @param string $a
     * @param string $b
     */
    public function setCoefficients($a, $b)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        $this->a = $this->factory->newInteger(pack('H*', $a));
        $this->b = $this->factory->newInteger(pack('H*', $b));
    }

    /**
     * Set x and y coordinates for the base point
     *
     * @param string|BinaryInteger $x
     * @param string|BinaryInteger $y
     */
    public function setBasePoint($x, $y)
    {
        switch (true) {
            case !is_string($x) && !$x instanceof BinaryInteger:
                throw new \UnexpectedValueException('Argument 1 passed to Binary::setBasePoint() must be a string or an instance of BinaryField\Integer');
            case !is_string($y) && !$y instanceof BinaryInteger:
                throw new \UnexpectedValueException('Argument 2 passed to Binary::setBasePoint() must be a string or an instance of BinaryField\Integer');
        }
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        $this->p = [
            is_string($x) ? $this->factory->newInteger(pack('H*', $x)) : $x,
            is_string($y) ? $this->factory->newInteger(pack('H*', $y)) : $y
        ];
    }

    /**
     * Retrieve the base point as an array
     *
     * @return array
     */
    public function getBasePoint()
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        /*
        if (!isset($this->p)) {
            throw new \RuntimeException('setBasePoint needs to be called before this method');
        }
        */
        return $this->p;
    }

    /**
     * Adds two points on the curve
     *
     * @return FiniteField[]
     */
    public function addPoint(array $p, array $q)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }

        if (!count($p) || !count($q)) {
            if (count($q)) {
                return $q;
            }
            if (count($p)) {
                return $p;
            }
            return [];
        }

        if (!isset($p[2]) || !isset($q[2])) {
            throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
        }

        if ($p[0]->equals($q[0])) {
            return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p);
        }

        // formulas from http://hyperelliptic.org/EFD/g12o/auto-shortw-jacobian.html

        list($x1, $y1, $z1) = $p;
        list($x2, $y2, $z2) = $q;

        $o1 = $z1->multiply($z1);
        $b = $x2->multiply($o1);

        if ($z2->equals($this->one)) {
            $d = $y2->multiply($o1)->multiply($z1);
            $e = $x1->add($b);
            $f = $y1->add($d);
            $z3 = $e->multiply($z1);
            $h = $f->multiply($x2)->add($z3->multiply($y2));
            $i = $f->add($z3);
            $g = $z3->multiply($z3);
            $p1 = $this->a->multiply($g);
            $p2 = $f->multiply($i);
            $p3 = $e->multiply($e)->multiply($e);
            $x3 = $p1->add($p2)->add($p3);
            $y3 = $i->multiply($x3)->add($g->multiply($h));

            return [$x3, $y3, $z3];
        }

        $o2 = $z2->multiply($z2);
        $a = $x1->multiply($o2);
        $c = $y1->multiply($o2)->multiply($z2);
        $d = $y2->multiply($o1)->multiply($z1);
        $e = $a->add($b);
        $f = $c->add($d);
        $g = $e->multiply($z1);
        $h = $f->multiply($x2)->add($g->multiply($y2));
        $z3 = $g->multiply($z2);
        $i = $f->add($z3);
        $p1 = $this->a->multiply($z3->multiply($z3));
        $p2 = $f->multiply($i);
        $p3 = $e->multiply($e)->multiply($e);
        $x3 = $p1->add($p2)->add($p3);
        $y3 = $i->multiply($x3)->add($g->multiply($g)->multiply($h));

        return [$x3, $y3, $z3];
    }

    /**
     * Doubles a point on a curve
     *
     * @return FiniteField[]
     */
    public function doublePoint(array $p)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }

        if (!count($p)) {
            return [];
        }

        if (!isset($p[2])) {
            throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
        }

        // formulas from http://hyperelliptic.org/EFD/g12o/auto-shortw-jacobian.html

        list($x1, $y1, $z1) = $p;

        $a = $x1->multiply($x1);
        $b = $a->multiply($a);

        if ($z1->equals($this->one)) {
            $x3 = $b->add($this->b);
            $z3 = clone $x1;
            $p1 = $a->add($y1)->add($z3)->multiply($this->b);
            $p2 = $a->add($y1)->multiply($b);
            $y3 = $p1->add($p2);

            return [$x3, $y3, $z3];
        }

        $c = $z1->multiply($z1);
        $d = $c->multiply($c);
        $x3 = $b->add($this->b->multiply($d->multiply($d)));
        $z3 = $x1->multiply($c);
        $p1 = $b->multiply($z3);
        $p2 = $a->add($y1->multiply($z1))->add($z3)->multiply($x3);
        $y3 = $p1->add($p2);

        return [$x3, $y3, $z3];
    }

    /**
     * Returns the X coordinate and the derived Y coordinate
     *
     * Not supported because it is covered by patents.
     * Quoting https://www.openssl.org/docs/man1.1.0/apps/ecparam.html ,
     *
     * "Due to patent issues the compressed option is disabled by default for binary curves
     *  and can be enabled by defining the preprocessor macro OPENSSL_EC_BIN_PT_COMP at
     *  compile time."
     *
     * @return array
     */
    public function derivePoint($m)
    {
        throw new \RuntimeException('Point compression on binary finite field elliptic curves is not supported');
    }

    /**
     * Tests whether or not the x / y values satisfy the equation
     *
     * @return boolean
     */
    public function verifyPoint(array $p)
    {
        list($x, $y) = $p;
        $lhs = $y->multiply($y);
        $lhs = $lhs->add($x->multiply($y));
        $x2 = $x->multiply($x);
        $x3 = $x2->multiply($x);
        $rhs = $x3->add($this->a->multiply($x2))->add($this->b);

        return $lhs->equals($rhs);
    }

    /**
     * Returns the modulo
     *
     * @return BigInteger
     */
    public function getModulo()
    {
        return $this->modulo;
    }

    /**
     * Returns the a coefficient
     *
     * @return \phpseclib3\Math\PrimeField\Integer
     */
    public function getA()
    {
        return $this->a;
    }

    /**
     * Returns the a coefficient
     *
     * @return \phpseclib3\Math\PrimeField\Integer
     */
    public function getB()
    {
        return $this->b;
    }

    /**
     * Returns the affine point
     *
     * A Jacobian Coordinate is of the form (x, y, z).
     * To convert a Jacobian Coordinate to an Affine Point
     * you do (x / z^2, y / z^3)
     *
     * @return \phpseclib3\Math\PrimeField\Integer[]
     */
    public function convertToAffine(array $p)
    {
        if (!isset($p[2])) {
            return $p;
        }
        list($x, $y, $z) = $p;
        $z = $this->one->divide($z);
        $z2 = $z->multiply($z);
        return [
            $x->multiply($z2),
            $y->multiply($z2)->multiply($z)
        ];
    }

    /**
     * Converts an affine point to a jacobian coordinate
     *
     * @return \phpseclib3\Math\PrimeField\Integer[]
     */
    public function convertToInternal(array $p)
    {
        if (isset($p[2])) {
            return $p;
        }

        $p[2] = clone $this->one;
        $p['fresh'] = true;
        return $p;
    }
}
<?php

/**
 * Curves over y^2 = x^3 + a*x + x
 *
 * Technically, a Montgomery curve has a coefficient for y^2 but for Curve25519 and Curve448 that
 * coefficient is 1.
 *
 * Curve25519 and Curve448 do not make use of the y coordinate, which makes it unsuitable for use
 * with ECDSA / EdDSA. A few other differences between Curve25519 and Ed25519 are discussed at
 * https://crypto.stackexchange.com/a/43058/4520
 *
 * More info:
 *
 * https://en.wikipedia.org/wiki/Montgomery_curve
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2019 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\BaseCurves;

use phpseclib3\Crypt\EC\Curves\Curve25519;
use phpseclib3\Math\BigInteger;
use phpseclib3\Math\PrimeField;
use phpseclib3\Math\PrimeField\Integer as PrimeInteger;

/**
 * Curves over y^2 = x^3 + a*x + x
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Montgomery extends Base
{
    /**
     * Prime Field Integer factory
     *
     * @var PrimeField
     */
    protected $factory;

    /**
     * Cofficient for x
     *
     * @var object
     */
    protected $a;

    /**
     * Constant used for point doubling
     *
     * @var object
     */
    protected $a24;

    /**
     * The Number Zero
     *
     * @var object
     */
    protected $zero;

    /**
     * The Number One
     *
     * @var object
     */
    protected $one;

    /**
     * Base Point
     *
     * @var object
     */
    protected $p;

    /**
     * The modulo
     *
     * @var BigInteger
     */
    protected $modulo;

    /**
     * The Order
     *
     * @var BigInteger
     */
    protected $order;

    /**
     * Sets the modulo
     */
    public function setModulo(BigInteger $modulo)
    {
        $this->modulo = $modulo;
        $this->factory = new PrimeField($modulo);
        $this->zero = $this->factory->newInteger(new BigInteger());
        $this->one = $this->factory->newInteger(new BigInteger(1));
    }

    /**
     * Set coefficients a
     */
    public function setCoefficients(BigInteger $a)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        $this->a = $this->factory->newInteger($a);
        $two = $this->factory->newInteger(new BigInteger(2));
        $four = $this->factory->newInteger(new BigInteger(4));
        $this->a24 = $this->a->subtract($two)->divide($four);
    }

    /**
     * Set x and y coordinates for the base point
     *
     * @param BigInteger|PrimeInteger $x
     * @param BigInteger|PrimeInteger $y
     * @return PrimeInteger[]
     */
    public function setBasePoint($x, $y)
    {
        switch (true) {
            case !$x instanceof BigInteger && !$x instanceof PrimeInteger:
                throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
            case !$y instanceof BigInteger && !$y instanceof PrimeInteger:
                throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
        }
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        $this->p = [
            $x instanceof BigInteger ? $this->factory->newInteger($x) : $x,
            $y instanceof BigInteger ? $this->factory->newInteger($y) : $y
        ];
    }

    /**
     * Retrieve the base point as an array
     *
     * @return array
     */
    public function getBasePoint()
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        /*
        if (!isset($this->p)) {
            throw new \RuntimeException('setBasePoint needs to be called before this method');
        }
        */
        return $this->p;
    }

    /**
     * Doubles and adds a point on a curve
     *
     * See https://tools.ietf.org/html/draft-ietf-tls-curve25519-01#appendix-A.1.3
     *
     * @return FiniteField[][]
     */
    private function doubleAndAddPoint(array $p, array $q, PrimeInteger $x1)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }

        if (!count($p) || !count($q)) {
            return [];
        }

        if (!isset($p[1])) {
            throw new \RuntimeException('Affine coordinates need to be manually converted to XZ coordinates');
        }

        list($x2, $z2) = $p;
        list($x3, $z3) = $q;

        $a = $x2->add($z2);
        $aa = $a->multiply($a);
        $b = $x2->subtract($z2);
        $bb = $b->multiply($b);
        $e = $aa->subtract($bb);
        $c = $x3->add($z3);
        $d = $x3->subtract($z3);
        $da = $d->multiply($a);
        $cb = $c->multiply($b);
        $temp = $da->add($cb);
        $x5 = $temp->multiply($temp);
        $temp = $da->subtract($cb);
        $z5 = $x1->multiply($temp->multiply($temp));
        $x4 = $aa->multiply($bb);
        $temp = static::class == Curve25519::class ? $bb : $aa;
        $z4 = $e->multiply($temp->add($this->a24->multiply($e)));

        return [
            [$x4, $z4],
            [$x5, $z5]
        ];
    }

    /**
     * Multiply a point on the curve by a scalar
     *
     * Uses the montgomery ladder technique as described here:
     *
     * https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Montgomery_ladder
     * https://github.com/phpecc/phpecc/issues/16#issuecomment-59176772
     *
     * @return array
     */
    public function multiplyPoint(array $p, BigInteger $d)
    {
        $p1 = [$this->one, $this->zero];
        $alreadyInternal = isset($p[1]);
        $p2 = $this->convertToInternal($p);
        $x = $p[0];

        $b = $d->toBits();
        $b = str_pad($b, 256, '0', STR_PAD_LEFT);
        for ($i = 0; $i < strlen($b); $i++) {
            $b_i = (int) $b[$i];
            if ($b_i) {
                list($p2, $p1) = $this->doubleAndAddPoint($p2, $p1, $x);
            } else {
                list($p1, $p2) = $this->doubleAndAddPoint($p1, $p2, $x);
            }
        }

        return $alreadyInternal ? $p1 : $this->convertToAffine($p1);
    }

    /**
     * Converts an affine point to an XZ coordinate
     *
     * From https://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html
     *
     * XZ coordinates represent x y as X Z satsfying the following equations:
     *
     *   x=X/Z
     *
     * @return PrimeInteger[]
     */
    public function convertToInternal(array $p)
    {
        if (empty($p)) {
            return [clone $this->zero, clone $this->one];
        }

        if (isset($p[1])) {
            return $p;
        }

        $p[1] = clone $this->one;

        return $p;
    }

    /**
     * Returns the affine point
     *
     * @return PrimeInteger[]
     */
    public function convertToAffine(array $p)
    {
        if (!isset($p[1])) {
            return $p;
        }
        list($x, $z) = $p;
        return [$x->divide($z)];
    }
}
<?php

/**
 * Curves over a*x^2 + y^2 = 1 + d*x^2*y^2
 *
 * http://www.secg.org/SEC2-Ver-1.0.pdf provides for curves with custom parameters.
 * ie. the coefficients can be arbitrary set through specially formatted keys, etc.
 * As such, Prime.php is built very generically and it's not able to take full
 * advantage of curves with 0 coefficients to produce simplified point doubling,
 * point addition. Twisted Edwards curves, in contrast, do not have a way, currently,
 * to customize them. As such, we can omit the super generic stuff from this class
 * and let the named curves (Ed25519 and Ed448) define their own custom tailored
 * point addition and point doubling methods.
 *
 * More info:
 *
 * https://en.wikipedia.org/wiki/Twisted_Edwards_curve
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\BaseCurves;

use phpseclib3\Math\BigInteger;
use phpseclib3\Math\PrimeField;
use phpseclib3\Math\PrimeField\Integer as PrimeInteger;

/**
 * Curves over a*x^2 + y^2 = 1 + d*x^2*y^2
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class TwistedEdwards extends Base
{
    /**
     * The modulo
     *
     * @var BigInteger
     */
    protected $modulo;

    /**
     * Cofficient for x^2
     *
     * @var object
     */
    protected $a;

    /**
     * Cofficient for x^2*y^2
     *
     * @var object
     */
    protected $d;

    /**
     * Base Point
     *
     * @var object[]
     */
    protected $p;

    /**
     * The number zero over the specified finite field
     *
     * @var object
     */
    protected $zero;

    /**
     * The number one over the specified finite field
     *
     * @var object
     */
    protected $one;

    /**
     * The number two over the specified finite field
     *
     * @var object
     */
    protected $two;

    /**
     * Sets the modulo
     */
    public function setModulo(BigInteger $modulo)
    {
        $this->modulo = $modulo;
        $this->factory = new PrimeField($modulo);
        $this->zero = $this->factory->newInteger(new BigInteger(0));
        $this->one = $this->factory->newInteger(new BigInteger(1));
        $this->two = $this->factory->newInteger(new BigInteger(2));
    }

    /**
     * Set coefficients a and b
     */
    public function setCoefficients(BigInteger $a, BigInteger $d)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        $this->a = $this->factory->newInteger($a);
        $this->d = $this->factory->newInteger($d);
    }

    /**
     * Set x and y coordinates for the base point
     */
    public function setBasePoint($x, $y)
    {
        switch (true) {
            case !$x instanceof BigInteger && !$x instanceof PrimeInteger:
                throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
            case !$y instanceof BigInteger && !$y instanceof PrimeInteger:
                throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
        }
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        $this->p = [
            $x instanceof BigInteger ? $this->factory->newInteger($x) : $x,
            $y instanceof BigInteger ? $this->factory->newInteger($y) : $y
        ];
    }

    /**
     * Returns the a coefficient
     *
     * @return PrimeInteger
     */
    public function getA()
    {
        return $this->a;
    }

    /**
     * Returns the a coefficient
     *
     * @return PrimeInteger
     */
    public function getD()
    {
        return $this->d;
    }

    /**
     * Retrieve the base point as an array
     *
     * @return array
     */
    public function getBasePoint()
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        /*
        if (!isset($this->p)) {
            throw new \RuntimeException('setBasePoint needs to be called before this method');
        }
        */
        return $this->p;
    }

    /**
     * Returns the affine point
     *
     * @return PrimeInteger[]
     */
    public function convertToAffine(array $p)
    {
        if (!isset($p[2])) {
            return $p;
        }
        list($x, $y, $z) = $p;
        $z = $this->one->divide($z);
        return [
            $x->multiply($z),
            $y->multiply($z)
        ];
    }

    /**
     * Returns the modulo
     *
     * @return BigInteger
     */
    public function getModulo()
    {
        return $this->modulo;
    }

    /**
     * Tests whether or not the x / y values satisfy the equation
     *
     * @return boolean
     */
    public function verifyPoint(array $p)
    {
        list($x, $y) = $p;
        $x2 = $x->multiply($x);
        $y2 = $y->multiply($y);

        $lhs = $this->a->multiply($x2)->add($y2);
        $rhs = $this->d->multiply($x2)->multiply($y2)->add($this->one);

        return $lhs->equals($rhs);
    }
}
<?php

/**
 * Generalized Koblitz Curves over y^2 = x^3 + b.
 *
 * According to http://www.secg.org/SEC2-Ver-1.0.pdf Koblitz curves are over the GF(2**m)
 * finite field. Both the $a$ and $b$ coefficients are either 0 or 1. However, SEC2
 * generalizes the definition to include curves over GF(P) "which possess an efficiently
 * computable endomorphism".
 *
 * For these generalized Koblitz curves $b$ doesn't have to be 0 or 1. Whether or not $a$
 * has any restrictions on it is unclear, however, for all the GF(P) Koblitz curves defined
 * in SEC2 v1.0 $a$ is $0$ so all of the methods defined herein will assume that it is.
 *
 * I suppose we could rename the $b$ coefficient to $a$, however, the documentation refers
 * to $b$ so we'll just keep it.
 *
 * If a later version of SEC2 comes out wherein some $a$ values are non-zero we can create a
 * new method for those. eg. KoblitzA1Prime.php or something.
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\BaseCurves;

use phpseclib3\Math\BigInteger;
use phpseclib3\Math\PrimeField;

/**
 * Curves over y^2 = x^3 + b
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class KoblitzPrime extends Prime
{
    /**
     * Basis
     *
     * @var list<array{a: BigInteger, b: BigInteger}>
     */
    protected $basis;

    /**
     * Beta
     *
     * @var PrimeField\Integer
     */
    protected $beta;

    // don't overwrite setCoefficients() with one that only accepts one parameter so that
    // one might be able to switch between KoblitzPrime and Prime more easily (for benchmarking
    // purposes).

    /**
     * Multiply and Add Points
     *
     * Uses a efficiently computable endomorphism to achieve a slight speedup
     *
     * Adapted from:
     * https://github.com/indutny/elliptic/blob/725bd91/lib/elliptic/curve/short.js#L219
     *
     * @return int[]
     */
    public function multiplyAddPoints(array $points, array $scalars)
    {
        static $zero, $one, $two;
        if (!isset($two)) {
            $two = new BigInteger(2);
            $one = new BigInteger(1);
        }

        if (!isset($this->beta)) {
            // get roots
            $inv = $this->one->divide($this->two)->negate();
            $s = $this->three->negate()->squareRoot()->multiply($inv);
            $betas = [
                $inv->add($s),
                $inv->subtract($s)
            ];
            $this->beta = $betas[0]->compare($betas[1]) < 0 ? $betas[0] : $betas[1];
            //echo strtoupper($this->beta->toHex(true)) . "\n"; exit;
        }

        if (!isset($this->basis)) {
            $factory = new PrimeField($this->order);
            $tempOne = $factory->newInteger($one);
            $tempTwo = $factory->newInteger($two);
            $tempThree = $factory->newInteger(new BigInteger(3));

            $inv = $tempOne->divide($tempTwo)->negate();
            $s = $tempThree->negate()->squareRoot()->multiply($inv);

            $lambdas = [
                $inv->add($s),
                $inv->subtract($s)
            ];

            $lhs = $this->multiplyPoint($this->p, $lambdas[0])[0];
            $rhs = $this->p[0]->multiply($this->beta);
            $lambda = $lhs->equals($rhs) ? $lambdas[0] : $lambdas[1];

            $this->basis = static::extendedGCD($lambda->toBigInteger(), $this->order);
            ///*
            foreach ($this->basis as $basis) {
                echo strtoupper($basis['a']->toHex(true)) . "\n";
                echo strtoupper($basis['b']->toHex(true)) . "\n\n";
            }
            exit;
            //*/
        }

        $npoints = $nscalars = [];
        for ($i = 0; $i < count($points); $i++) {
            $p = $points[$i];
            $k = $scalars[$i]->toBigInteger();

            // begin split
            list($v1, $v2) = $this->basis;

            $c1 = $v2['b']->multiply($k);
            list($c1, $r) = $c1->divide($this->order);
            if ($this->order->compare($r->multiply($two)) <= 0) {
                $c1 = $c1->add($one);
            }

            $c2 = $v1['b']->negate()->multiply($k);
            list($c2, $r) = $c2->divide($this->order);
            if ($this->order->compare($r->multiply($two)) <= 0) {
                $c2 = $c2->add($one);
            }

            $p1 = $c1->multiply($v1['a']);
            $p2 = $c2->multiply($v2['a']);
            $q1 = $c1->multiply($v1['b']);
            $q2 = $c2->multiply($v2['b']);

            $k1 = $k->subtract($p1)->subtract($p2);
            $k2 = $q1->add($q2)->negate();
            // end split

            $beta = [
                $p[0]->multiply($this->beta),
                $p[1],
                clone $this->one
            ];

            if (isset($p['naf'])) {
                $beta['naf'] = array_map(function ($p) {
                    return [
                        $p[0]->multiply($this->beta),
                        $p[1],
                        clone $this->one
                    ];
                }, $p['naf']);
                $beta['nafwidth'] = $p['nafwidth'];
            }

            if ($k1->isNegative()) {
                $k1 = $k1->negate();
                $p = $this->negatePoint($p);
            }

            if ($k2->isNegative()) {
                $k2 = $k2->negate();
                $beta = $this->negatePoint($beta);
            }

            $pos = 2 * $i;
            $npoints[$pos] = $p;
            $nscalars[$pos] = $this->factory->newInteger($k1);

            $pos++;
            $npoints[$pos] = $beta;
            $nscalars[$pos] = $this->factory->newInteger($k2);
        }

        return parent::multiplyAddPoints($npoints, $nscalars);
    }

    /**
     * Returns the numerator and denominator of the slope
     *
     * @return FiniteField[]
     */
    protected function doublePointHelper(array $p)
    {
        $numerator = $this->three->multiply($p[0])->multiply($p[0]);
        $denominator = $this->two->multiply($p[1]);
        return [$numerator, $denominator];
    }

    /**
     * Doubles a jacobian coordinate on the curve
     *
     * See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
     *
     * @return FiniteField[]
     */
    protected function jacobianDoublePoint(array $p)
    {
        list($x1, $y1, $z1) = $p;
        $a = $x1->multiply($x1);
        $b = $y1->multiply($y1);
        $c = $b->multiply($b);
        $d = $x1->add($b);
        $d = $d->multiply($d)->subtract($a)->subtract($c)->multiply($this->two);
        $e = $this->three->multiply($a);
        $f = $e->multiply($e);
        $x3 = $f->subtract($this->two->multiply($d));
        $y3 = $e->multiply($d->subtract($x3))->subtract(
            $this->eight->multiply($c)
        );
        $z3 = $this->two->multiply($y1)->multiply($z1);
        return [$x3, $y3, $z3];
    }

    /**
     * Doubles a "fresh" jacobian coordinate on the curve
     *
     * See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl
     *
     * @return FiniteField[]
     */
    protected function jacobianDoublePointMixed(array $p)
    {
        list($x1, $y1) = $p;
        $xx = $x1->multiply($x1);
        $yy = $y1->multiply($y1);
        $yyyy = $yy->multiply($yy);
        $s = $x1->add($yy);
        $s = $s->multiply($s)->subtract($xx)->subtract($yyyy)->multiply($this->two);
        $m = $this->three->multiply($xx);
        $t = $m->multiply($m)->subtract($this->two->multiply($s));
        $x3 = $t;
        $y3 = $s->subtract($t);
        $y3 = $m->multiply($y3)->subtract($this->eight->multiply($yyyy));
        $z3 = $this->two->multiply($y1);
        return [$x3, $y3, $z3];
    }

    /**
     * Tests whether or not the x / y values satisfy the equation
     *
     * @return boolean
     */
    public function verifyPoint(array $p)
    {
        list($x, $y) = $p;
        $lhs = $y->multiply($y);
        $temp = $x->multiply($x)->multiply($x);
        $rhs = $temp->add($this->b);

        return $lhs->equals($rhs);
    }

    /**
     * Calculates the parameters needed from the Euclidean algorithm as discussed at
     * http://diamond.boisestate.edu/~liljanab/MATH308/GuideToECC.pdf#page=148
     *
     * @param BigInteger $u
     * @param BigInteger $v
     * @return BigInteger[]
     */
    protected static function extendedGCD(BigInteger $u, BigInteger $v)
    {
        $one = new BigInteger(1);
        $zero = new BigInteger();

        $a = clone $one;
        $b = clone $zero;
        $c = clone $zero;
        $d = clone $one;

        $stop = $v->bitwise_rightShift($v->getLength() >> 1);

        $a1 = clone $zero;
        $b1 = clone $zero;
        $a2 = clone $zero;
        $b2 = clone $zero;

        $postGreatestIndex = 0;

        while (!$v->equals($zero)) {
            list($q) = $u->divide($v);

            $temp = $u;
            $u = $v;
            $v = $temp->subtract($v->multiply($q));

            $temp = $a;
            $a = $c;
            $c = $temp->subtract($a->multiply($q));

            $temp = $b;
            $b = $d;
            $d = $temp->subtract($b->multiply($q));

            if ($v->compare($stop) > 0) {
                $a0 = $v;
                $b0 = $c;
            } else {
                $postGreatestIndex++;
            }

            if ($postGreatestIndex == 1) {
                $a1 = $v;
                $b1 = $c->negate();
            }

            if ($postGreatestIndex == 2) {
                $rhs = $a0->multiply($a0)->add($b0->multiply($b0));
                $lhs = $v->multiply($v)->add($b->multiply($b));
                if ($lhs->compare($rhs) <= 0) {
                    $a2 = $a0;
                    $b2 = $b0->negate();
                } else {
                    $a2 = $v;
                    $b2 = $c->negate();
                }

                break;
            }
        }

        return [
            ['a' => $a1, 'b' => $b1],
            ['a' => $a2, 'b' => $b2]
        ];
    }
}
<?php

/**
 * Curves over y^2 = x^3 + a*x + b
 *
 * These are curves used in SEC 2 over prime fields: http://www.secg.org/SEC2-Ver-1.0.pdf
 * The curve is a weierstrass curve with a[1], a[3] and a[2] set to 0.
 *
 * Uses Jacobian Coordinates for speed if able:
 *
 * https://en.wikipedia.org/wiki/Jacobian_curve
 * https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\BaseCurves;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Math\BigInteger;
use phpseclib3\Math\Common\FiniteField\Integer;
use phpseclib3\Math\PrimeField;
use phpseclib3\Math\PrimeField\Integer as PrimeInteger;

/**
 * Curves over y^2 = x^3 + a*x + b
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Prime extends Base
{
    /**
     * Prime Field Integer factory
     *
     * @var \phpseclib3\Math\PrimeFields
     */
    protected $factory;

    /**
     * Cofficient for x^1
     *
     * @var object
     */
    protected $a;

    /**
     * Cofficient for x^0
     *
     * @var object
     */
    protected $b;

    /**
     * Base Point
     *
     * @var object
     */
    protected $p;

    /**
     * The number one over the specified finite field
     *
     * @var object
     */
    protected $one;

    /**
     * The number two over the specified finite field
     *
     * @var object
     */
    protected $two;

    /**
     * The number three over the specified finite field
     *
     * @var object
     */
    protected $three;

    /**
     * The number four over the specified finite field
     *
     * @var object
     */
    protected $four;

    /**
     * The number eight over the specified finite field
     *
     * @var object
     */
    protected $eight;

    /**
     * The modulo
     *
     * @var BigInteger
     */
    protected $modulo;

    /**
     * The Order
     *
     * @var BigInteger
     */
    protected $order;

    /**
     * Sets the modulo
     */
    public function setModulo(BigInteger $modulo)
    {
        $this->modulo = $modulo;
        $this->factory = new PrimeField($modulo);
        $this->two = $this->factory->newInteger(new BigInteger(2));
        $this->three = $this->factory->newInteger(new BigInteger(3));
        // used by jacobian coordinates
        $this->one = $this->factory->newInteger(new BigInteger(1));
        $this->four = $this->factory->newInteger(new BigInteger(4));
        $this->eight = $this->factory->newInteger(new BigInteger(8));
    }

    /**
     * Set coefficients a and b
     */
    public function setCoefficients(BigInteger $a, BigInteger $b)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        $this->a = $this->factory->newInteger($a);
        $this->b = $this->factory->newInteger($b);
    }

    /**
     * Set x and y coordinates for the base point
     *
     * @param BigInteger|PrimeInteger $x
     * @param BigInteger|PrimeInteger $y
     * @return PrimeInteger[]
     */
    public function setBasePoint($x, $y)
    {
        switch (true) {
            case !$x instanceof BigInteger && !$x instanceof PrimeInteger:
                throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
            case !$y instanceof BigInteger && !$y instanceof PrimeInteger:
                throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
        }
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        $this->p = [
            $x instanceof BigInteger ? $this->factory->newInteger($x) : $x,
            $y instanceof BigInteger ? $this->factory->newInteger($y) : $y
        ];
    }

    /**
     * Retrieve the base point as an array
     *
     * @return array
     */
    public function getBasePoint()
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }
        /*
        if (!isset($this->p)) {
            throw new \RuntimeException('setBasePoint needs to be called before this method');
        }
        */
        return $this->p;
    }

    /**
     * Adds two "fresh" jacobian form on the curve
     *
     * @return FiniteField[]
     */
    protected function jacobianAddPointMixedXY(array $p, array $q)
    {
        list($u1, $s1) = $p;
        list($u2, $s2) = $q;
        if ($u1->equals($u2)) {
            if (!$s1->equals($s2)) {
                return [];
            } else {
                return $this->doublePoint($p);
            }
        }
        $h = $u2->subtract($u1);
        $r = $s2->subtract($s1);
        $h2 = $h->multiply($h);
        $h3 = $h2->multiply($h);
        $v = $u1->multiply($h2);
        $x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
        $y3 = $r->multiply(
            $v->subtract($x3)
        )->subtract(
            $s1->multiply($h3)
        );
        return [$x3, $y3, $h];
    }

    /**
     * Adds one "fresh" jacobian form on the curve
     *
     * The second parameter should be the "fresh" one
     *
     * @return FiniteField[]
     */
    protected function jacobianAddPointMixedX(array $p, array $q)
    {
        list($u1, $s1, $z1) = $p;
        list($x2, $y2) = $q;

        $z12 = $z1->multiply($z1);

        $u2 = $x2->multiply($z12);
        $s2 = $y2->multiply($z12->multiply($z1));
        if ($u1->equals($u2)) {
            if (!$s1->equals($s2)) {
                return [];
            } else {
                return $this->doublePoint($p);
            }
        }
        $h = $u2->subtract($u1);
        $r = $s2->subtract($s1);
        $h2 = $h->multiply($h);
        $h3 = $h2->multiply($h);
        $v = $u1->multiply($h2);
        $x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
        $y3 = $r->multiply(
            $v->subtract($x3)
        )->subtract(
            $s1->multiply($h3)
        );
        $z3 = $h->multiply($z1);
        return [$x3, $y3, $z3];
    }

    /**
     * Adds two jacobian coordinates on the curve
     *
     * @return FiniteField[]
     */
    protected function jacobianAddPoint(array $p, array $q)
    {
        list($x1, $y1, $z1) = $p;
        list($x2, $y2, $z2) = $q;

        $z12 = $z1->multiply($z1);
        $z22 = $z2->multiply($z2);

        $u1 = $x1->multiply($z22);
        $u2 = $x2->multiply($z12);
        $s1 = $y1->multiply($z22->multiply($z2));
        $s2 = $y2->multiply($z12->multiply($z1));
        if ($u1->equals($u2)) {
            if (!$s1->equals($s2)) {
                return [];
            } else {
                return $this->doublePoint($p);
            }
        }
        $h = $u2->subtract($u1);
        $r = $s2->subtract($s1);
        $h2 = $h->multiply($h);
        $h3 = $h2->multiply($h);
        $v = $u1->multiply($h2);
        $x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
        $y3 = $r->multiply(
            $v->subtract($x3)
        )->subtract(
            $s1->multiply($h3)
        );
        $z3 = $h->multiply($z1)->multiply($z2);
        return [$x3, $y3, $z3];
    }

    /**
     * Adds two points on the curve
     *
     * @return FiniteField[]
     */
    public function addPoint(array $p, array $q)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }

        if (!count($p) || !count($q)) {
            if (count($q)) {
                return $q;
            }
            if (count($p)) {
                return $p;
            }
            return [];
        }

        // use jacobian coordinates
        if (isset($p[2]) && isset($q[2])) {
            if (isset($p['fresh']) && isset($q['fresh'])) {
                return $this->jacobianAddPointMixedXY($p, $q);
            }
            if (isset($p['fresh'])) {
                return $this->jacobianAddPointMixedX($q, $p);
            }
            if (isset($q['fresh'])) {
                return $this->jacobianAddPointMixedX($p, $q);
            }
            return $this->jacobianAddPoint($p, $q);
        }

        if (isset($p[2]) || isset($q[2])) {
            throw new \RuntimeException('Affine coordinates need to be manually converted to Jacobi coordinates or vice versa');
        }

        if ($p[0]->equals($q[0])) {
            if (!$p[1]->equals($q[1])) {
                return [];
            } else { // eg. doublePoint
                list($numerator, $denominator) = $this->doublePointHelper($p);
            }
        } else {
            $numerator = $q[1]->subtract($p[1]);
            $denominator = $q[0]->subtract($p[0]);
        }
        $slope = $numerator->divide($denominator);
        $x = $slope->multiply($slope)->subtract($p[0])->subtract($q[0]);
        $y = $slope->multiply($p[0]->subtract($x))->subtract($p[1]);

        return [$x, $y];
    }

    /**
     * Returns the numerator and denominator of the slope
     *
     * @return FiniteField[]
     */
    protected function doublePointHelper(array $p)
    {
        $numerator = $this->three->multiply($p[0])->multiply($p[0])->add($this->a);
        $denominator = $this->two->multiply($p[1]);
        return [$numerator, $denominator];
    }

    /**
     * Doubles a jacobian coordinate on the curve
     *
     * @return FiniteField[]
     */
    protected function jacobianDoublePoint(array $p)
    {
        list($x, $y, $z) = $p;
        $x2 = $x->multiply($x);
        $y2 = $y->multiply($y);
        $z2 = $z->multiply($z);
        $s = $this->four->multiply($x)->multiply($y2);
        $m1 = $this->three->multiply($x2);
        $m2 = $this->a->multiply($z2->multiply($z2));
        $m = $m1->add($m2);
        $x1 = $m->multiply($m)->subtract($this->two->multiply($s));
        $y1 = $m->multiply($s->subtract($x1))->subtract(
            $this->eight->multiply($y2->multiply($y2))
        );
        $z1 = $this->two->multiply($y)->multiply($z);
        return [$x1, $y1, $z1];
    }

    /**
     * Doubles a "fresh" jacobian coordinate on the curve
     *
     * @return FiniteField[]
     */
    protected function jacobianDoublePointMixed(array $p)
    {
        list($x, $y) = $p;
        $x2 = $x->multiply($x);
        $y2 = $y->multiply($y);
        $s = $this->four->multiply($x)->multiply($y2);
        $m1 = $this->three->multiply($x2);
        $m = $m1->add($this->a);
        $x1 = $m->multiply($m)->subtract($this->two->multiply($s));
        $y1 = $m->multiply($s->subtract($x1))->subtract(
            $this->eight->multiply($y2->multiply($y2))
        );
        $z1 = $this->two->multiply($y);
        return [$x1, $y1, $z1];
    }

    /**
     * Doubles a point on a curve
     *
     * @return FiniteField[]
     */
    public function doublePoint(array $p)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }

        if (!count($p)) {
            return [];
        }

        // use jacobian coordinates
        if (isset($p[2])) {
            if (isset($p['fresh'])) {
                return $this->jacobianDoublePointMixed($p);
            }
            return $this->jacobianDoublePoint($p);
        }

        list($numerator, $denominator) = $this->doublePointHelper($p);

        $slope = $numerator->divide($denominator);

        $x = $slope->multiply($slope)->subtract($p[0])->subtract($p[0]);
        $y = $slope->multiply($p[0]->subtract($x))->subtract($p[1]);

        return [$x, $y];
    }

    /**
     * Returns the X coordinate and the derived Y coordinate
     *
     * @return array
     */
    public function derivePoint($m)
    {
        $y = ord(Strings::shift($m));
        $x = new BigInteger($m, 256);
        $xp = $this->convertInteger($x);
        switch ($y) {
            case 2:
                $ypn = false;
                break;
            case 3:
                $ypn = true;
                break;
            default:
                throw new \RuntimeException('Coordinate not in recognized format');
        }
        $temp = $xp->multiply($this->a);
        $temp = $xp->multiply($xp)->multiply($xp)->add($temp);
        $temp = $temp->add($this->b);
        $b = $temp->squareRoot();
        if (!$b) {
            throw new \RuntimeException('Unable to derive Y coordinate');
        }
        $bn = $b->isOdd();
        $yp = $ypn == $bn ? $b : $b->negate();
        return [$xp, $yp];
    }

    /**
     * Tests whether or not the x / y values satisfy the equation
     *
     * @return boolean
     */
    public function verifyPoint(array $p)
    {
        list($x, $y) = $p;
        $lhs = $y->multiply($y);
        $temp = $x->multiply($this->a);
        $temp = $x->multiply($x)->multiply($x)->add($temp);
        $rhs = $temp->add($this->b);

        return $lhs->equals($rhs);
    }

    /**
     * Returns the modulo
     *
     * @return BigInteger
     */
    public function getModulo()
    {
        return $this->modulo;
    }

    /**
     * Returns the a coefficient
     *
     * @return PrimeInteger
     */
    public function getA()
    {
        return $this->a;
    }

    /**
     * Returns the a coefficient
     *
     * @return PrimeInteger
     */
    public function getB()
    {
        return $this->b;
    }

    /**
     * Multiply and Add Points
     *
     * Adapted from:
     * https://github.com/indutny/elliptic/blob/725bd91/lib/elliptic/curve/base.js#L125
     *
     * @return int[]
     */
    public function multiplyAddPoints(array $points, array $scalars)
    {
        $length = count($points);

        foreach ($points as &$point) {
            $point = $this->convertToInternal($point);
        }

        $wnd = [$this->getNAFPoints($points[0], 7)];
        $wndWidth = [isset($points[0]['nafwidth']) ? $points[0]['nafwidth'] : 7];
        for ($i = 1; $i < $length; $i++) {
            $wnd[] = $this->getNAFPoints($points[$i], 1);
            $wndWidth[] = isset($points[$i]['nafwidth']) ? $points[$i]['nafwidth'] : 1;
        }

        $naf = [];

        // comb all window NAFs

        $max = 0;
        for ($i = $length - 1; $i >= 1; $i -= 2) {
            $a = $i - 1;
            $b = $i;
            if ($wndWidth[$a] != 1 || $wndWidth[$b] != 1) {
                $naf[$a] = $scalars[$a]->getNAF($wndWidth[$a]);
                $naf[$b] = $scalars[$b]->getNAF($wndWidth[$b]);
                $max = max(count($naf[$a]), count($naf[$b]), $max);
                continue;
            }

            $comb = [
                $points[$a], // 1
                null,        // 3
                null,        // 5
                $points[$b]  // 7
            ];

            $comb[1] = $this->addPoint($points[$a], $points[$b]);
            $comb[2] = $this->addPoint($points[$a], $this->negatePoint($points[$b]));

            $index = [
                -3, /* -1 -1 */
                -1, /* -1  0 */
                -5, /* -1  1 */
                -7, /*  0 -1 */
                 0, /*  0 -1 */
                 7, /*  0  1 */
                 5, /*  1 -1 */
                 1, /*  1  0 */
                 3  /*  1  1 */
            ];

            $jsf = self::getJSFPoints($scalars[$a], $scalars[$b]);

            $max = max(count($jsf[0]), $max);
            if ($max > 0) {
                $naf[$a] = array_fill(0, $max, 0);
                $naf[$b] = array_fill(0, $max, 0);
            } else {
                $naf[$a] = [];
                $naf[$b] = [];
            }

            for ($j = 0; $j < $max; $j++) {
                $ja = isset($jsf[0][$j]) ? $jsf[0][$j] : 0;
                $jb = isset($jsf[1][$j]) ? $jsf[1][$j] : 0;

                $naf[$a][$j] = $index[3 * ($ja + 1) + $jb + 1];
                $naf[$b][$j] = 0;
                $wnd[$a] = $comb;
            }
        }

        $acc = [];
        $temp = [0, 0, 0, 0];
        for ($i = $max; $i >= 0; $i--) {
            $k = 0;
            while ($i >= 0) {
                $zero = true;
                for ($j = 0; $j < $length; $j++) {
                    $temp[$j] = isset($naf[$j][$i]) ? $naf[$j][$i] : 0;
                    if ($temp[$j] != 0) {
                        $zero = false;
                    }
                }
                if (!$zero) {
                    break;
                }
                $k++;
                $i--;
            }

            if ($i >= 0) {
                $k++;
            }
            while ($k--) {
                $acc = $this->doublePoint($acc);
            }

            if ($i < 0) {
                break;
            }

            for ($j = 0; $j < $length; $j++) {
                $z = $temp[$j];
                $p = null;
                if ($z == 0) {
                    continue;
                }
                $p = $z > 0 ?
                    $wnd[$j][($z - 1) >> 1] :
                    $this->negatePoint($wnd[$j][(-$z - 1) >> 1]);
                $acc = $this->addPoint($acc, $p);
            }
        }

        return $this->convertToAffine($acc);
    }

    /**
     * Precomputes NAF points
     *
     * Adapted from:
     * https://github.com/indutny/elliptic/blob/725bd91/lib/elliptic/curve/base.js#L351
     *
     * @return int[]
     */
    private function getNAFPoints(array $point, $wnd)
    {
        if (isset($point['naf'])) {
            return $point['naf'];
        }

        $res = [$point];
        $max = (1 << $wnd) - 1;
        $dbl = $max == 1 ? null : $this->doublePoint($point);
        for ($i = 1; $i < $max; $i++) {
            $res[] = $this->addPoint($res[$i - 1], $dbl);
        }

        $point['naf'] = $res;

        /*
        $str = '';
        foreach ($res as $re) {
            $re[0] = bin2hex($re[0]->toBytes());
            $re[1] = bin2hex($re[1]->toBytes());
            $str.= "            ['$re[0]', '$re[1]'],\r\n";
        }
        file_put_contents('temp.txt', $str);
        exit;
        */

        return $res;
    }

    /**
     * Precomputes points in Joint Sparse Form
     *
     * Adapted from:
     * https://github.com/indutny/elliptic/blob/725bd91/lib/elliptic/utils.js#L96
     *
     * @return int[]
     */
    private static function getJSFPoints(Integer $k1, Integer $k2)
    {
        static $three;
        if (!isset($three)) {
            $three = new BigInteger(3);
        }

        $jsf = [[], []];
        $k1 = $k1->toBigInteger();
        $k2 = $k2->toBigInteger();
        $d1 = 0;
        $d2 = 0;

        while ($k1->compare(new BigInteger(-$d1)) > 0 || $k2->compare(new BigInteger(-$d2)) > 0) {
            // first phase
            $m14 = $k1->testBit(0) + 2 * $k1->testBit(1);
            $m14 += $d1;
            $m14 &= 3;

            $m24 = $k2->testBit(0) + 2 * $k2->testBit(1);
            $m24 += $d2;
            $m24 &= 3;

            if ($m14 == 3) {
                $m14 = -1;
            }
            if ($m24 == 3) {
                $m24 = -1;
            }

            $u1 = 0;
            if ($m14 & 1) { // if $m14 is odd
                $m8 = $k1->testBit(0) + 2 * $k1->testBit(1) + 4 * $k1->testBit(2);
                $m8 += $d1;
                $m8 &= 7;
                $u1 = ($m8 == 3 || $m8 == 5) && $m24 == 2 ? -$m14 : $m14;
            }
            $jsf[0][] = $u1;

            $u2 = 0;
            if ($m24 & 1) { // if $m24 is odd
                $m8 = $k2->testBit(0) + 2 * $k2->testBit(1) + 4 * $k2->testBit(2);
                $m8 += $d2;
                $m8 &= 7;
                $u2 = ($m8 == 3 || $m8 == 5) && $m14 == 2 ? -$m24 : $m24;
            }
            $jsf[1][] = $u2;

            // second phase
            if (2 * $d1 == $u1 + 1) {
                $d1 = 1 - $d1;
            }
            if (2 * $d2 == $u2 + 1) {
                $d2 = 1 - $d2;
            }
            $k1 = $k1->bitwise_rightShift(1);
            $k2 = $k2->bitwise_rightShift(1);
        }

        return $jsf;
    }

    /**
     * Returns the affine point
     *
     * A Jacobian Coordinate is of the form (x, y, z).
     * To convert a Jacobian Coordinate to an Affine Point
     * you do (x / z^2, y / z^3)
     *
     * @return PrimeInteger[]
     */
    public function convertToAffine(array $p)
    {
        if (!isset($p[2])) {
            return $p;
        }
        list($x, $y, $z) = $p;
        $z = $this->one->divide($z);
        $z2 = $z->multiply($z);
        return [
            $x->multiply($z2),
            $y->multiply($z2)->multiply($z)
        ];
    }

    /**
     * Converts an affine point to a jacobian coordinate
     *
     * @return PrimeInteger[]
     */
    public function convertToInternal(array $p)
    {
        if (isset($p[2])) {
            return $p;
        }

        $p[2] = clone $this->one;
        $p['fresh'] = true;
        return $p;
    }
}
<?php

/**
 * EC Public Key
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common;
use phpseclib3\Crypt\EC;
use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Crypt\EC\Curves\Ed25519;
use phpseclib3\Crypt\EC\Formats\Keys\PKCS1;
use phpseclib3\Crypt\EC\Formats\Signature\ASN1 as ASN1Signature;
use phpseclib3\Crypt\Hash;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\UnsupportedOperationException;
use phpseclib3\Math\BigInteger;

/**
 * EC Public Key
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
final class PublicKey extends EC implements Common\PublicKey
{
    use Common\Traits\Fingerprint;

    /**
     * Verify a signature
     *
     * @see self::verify()
     * @param string $message
     * @param string $signature
     * @return mixed
     */
    public function verify($message, $signature)
    {
        if ($this->curve instanceof MontgomeryCurve) {
            throw new UnsupportedOperationException('Montgomery Curves cannot be used to create signatures');
        }

        $shortFormat = $this->shortFormat;
        $format = $this->sigFormat;
        if ($format === false) {
            return false;
        }

        if (self::$forcedEngine === 'libsodium' && !$this->curve instanceof Ed25519) {
            throw new BadConfigurationException('Engine libsodium is only supported for Ed25519');
        }

        // at this point either self::$forcedEngine is NOT libsodium or the curve is Ed25519

        if ($this->curve instanceof Ed25519 && self::$forcedEngine !== 'PHP' && self::$forcedEngine !== 'OpenSSL') {
            if (self::$forcedEngine === 'libsodium') {
                if (!function_exists('sodium_crypto_sign_verify_detached')) {
                    throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519 / Ed448');
                }
                if (isset($this->context)) {
                    throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519ctx (context)');
                }
            }
            if (function_exists('sodium_crypto_sign_verify_detached') && !isset($this->context)) {
                if ($shortFormat == 'SSH2') {
                    list(, $signature) = Strings::unpackSSH2('ss', $signature);
                }

                return sodium_crypto_sign_verify_detached($signature, $message, $this->toString('libsodium'));
            }
        }

        // at this point self::$forcedEngine CAN'T be libsodium so we won't check for it henceforth

        if ($this->curve instanceof TwistedEdwardsCurve) {
            if ($shortFormat == 'SSH2') {
                list(, $signature) = Strings::unpackSSH2('ss', $signature);
            }

            if (self::$forcedEngine !== 'PHP') {
                $keyTypeConstant = $this->curve instanceof Ed25519 ? 'OPENSSL_KEYTYPE_ED25519' : 'OPENSSL_KEYTYPE_ED448';
                if (self::$forcedEngine === 'OpenSSL') {
                    if (!defined($keyTypeConstant)) {
                        throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448');
                    }
                    // OpenSSL supports Ed25519/Ed448 but not Ed25519ctx (context), so skip if context is set
                    if (isset($this->context)) {
                        throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448 curves with context\'s');
                    }
                }
                if (defined($keyTypeConstant) && !isset($this->context)) {
                    // algorithm 0 is used because EdDSA has a built-in hash
                    $result = openssl_verify($message, $signature, $this->toString('PKCS8'), 0) === 1;
                    if ($result !== -1 && $result !== false) {
                        return (bool) $result;
                    }
                    if (self::$forcedEngine === 'OpenSSL') {
                        throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
                    }
                }
            }

            $order = $this->curve->getOrder();

            $curve = $this->curve;
            if (strlen($signature) != 2 * $curve::SIZE) {
                return false;
            }

            $R = substr($signature, 0, $curve::SIZE);
            $S = substr($signature, $curve::SIZE);

            try {
                $R = PKCS1::extractPoint($R, $curve);
                $R = $this->curve->convertToInternal($R);
            } catch (\Exception $e) {
                return false;
            }

            $S = strrev($S);
            $S = new BigInteger($S, 256);

            if ($S->compare($order) >= 0) {
                return false;
            }

            $A = $curve->encodePoint($this->QA);

            if ($curve instanceof Ed25519) {
                $dom2 = !isset($this->context) ? '' :
                    'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context;
            } else {
                $context = isset($this->context) ? $this->context : '';
                $dom2 = 'SigEd448' . "\0" . chr(strlen($context)) . $context;
            }

            $hash = new Hash($curve::HASH);
            $k = $hash->hash($dom2 . substr($signature, 0, $curve::SIZE) . $A . $message);
            $k = strrev($k);
            $k = new BigInteger($k, 256);
            list(, $k) = $k->divide($order);

            $qa = $curve->convertToInternal($this->QA);

            $lhs = $curve->multiplyPoint($curve->getBasePoint(), $S);
            $rhs = $curve->multiplyPoint($qa, $k);
            $rhs = $curve->addPoint($rhs, $R);
            $rhs = $curve->convertToAffine($rhs);

            return $lhs[0]->equals($rhs[0]) && $lhs[1]->equals($rhs[1]);
        }

        $params = $format::load($signature);
        if ($params === false || count($params) != 2) {
            return false;
        }
        $r = $params['r'];
        $s = $params['s'];

        if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) {
            throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA');
        }

        // at this point $forcedEngine is either PHP or null. either that OR openssl_get_md_methods() exists

        if (self::$forcedEngine !== 'PHP') {
            if (in_array($this->hash->getHash(), openssl_get_md_methods())) {
                $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;

                $result = openssl_verify($message, $sig, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash());

                if ($result !== -1 && $result !== false) {
                    return (bool) $result;
                }
                if (self::$forcedEngine === 'OpenSSL') {
                    throw new BadConfigurationException('Engine OpenSSL is forced but was unable to verify signature because of ' . openssl_error_string());
                }
            } elseif (self::$forcedEngine === 'OpenSSL') {
                throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA / ' . $this->hash->getHash());
            }
        }

        $order = $this->curve->getOrder();

        $n_1 = $order->subtract(self::$one);
        if (!$r->between(self::$one, $n_1) || !$s->between(self::$one, $n_1)) {
            return false;
        }

        $e = $this->hash->hash($message);
        $e = new BigInteger($e, 256);

        $Ln = $this->hash->getLength() - $order->getLength();
        $z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e;

        $w = $s->modInverse($order);
        list(, $u1) = $z->multiply($w)->divide($order);
        list(, $u2) = $r->multiply($w)->divide($order);

        $u1 = $this->curve->convertInteger($u1);
        $u2 = $this->curve->convertInteger($u2);

        list($x1, $y1) = $this->curve->multiplyAddPoints(
            [$this->curve->getBasePoint(), $this->QA],
            [$u1, $u2]
        );

        $x1 = $x1->toBigInteger();
        list(, $x1) = $x1->divide($order);

        return $x1->equals($r);
    }

    /**
     * Returns the public key
     *
     * @param string $type
     * @param array $options optional
     * @return string
     */
    public function toString($type, array $options = [])
    {
        $type = self::validatePlugin('Keys', $type, 'savePublicKey');

        return $type::savePublicKey($this->curve, $this->QA, $options);
    }
}
<?php

/**
 * EC Parameters
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\EC;

use phpseclib3\Crypt\EC;

/**
 * EC Parameters
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
final class Parameters extends EC
{
    /**
     * Returns the parameters
     *
     * @param string $type
     * @param array $options optional
     * @return string
     */
    public function toString($type = 'PKCS1', array $options = [])
    {
        $type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');

        return $type::saveParameters($this->curve, $options);
    }
}
<?php

/**
 * prime192v2
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class prime192v2 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF', 16));
        $this->setCoefficients(
            new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC', 16),
            new BigInteger('CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953', 16)
        );
        $this->setBasePoint(
            new BigInteger('EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A', 16),
            new BigInteger('6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15', 16)
        );
        $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31', 16));
    }
}
<?php

/**
 * secp521r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class secp521r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
                                        'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
                                        'FFFF', 16));
        $this->setCoefficients(
            new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
                           'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
                           'FFFC', 16),
            new BigInteger('0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF1' .
                           '09E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B50' .
                           '3F00', 16)
        );
        $this->setBasePoint(
            new BigInteger('00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D' .
                           '3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5' .
                           'BD66', 16),
            new BigInteger('011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E' .
                           '662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD1' .
                           '6650', 16)
        );
        $this->setOrder(new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
                                       'FFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E9138' .
                                       '6409', 16));
    }
}
<?php

/**
 * brainpoolP160t1
 *
 * This curve is a twisted version of brainpoolP160r1 with A = -3. With brainpool,
 * the curves ending in r1 are the "regular" curves and the curves ending in "t1"
 * are the twisted version of the r1 curves. Per https://tools.ietf.org/html/rfc5639#page-7
 * you can convert a point on an r1 curve to a point on a t1 curve thusly:
 *
 *     F(x,y) := (x*Z^2, y*Z^3)
 *
 * The advantage of A = -3 is that some of the point doubling and point addition can be
 * slightly optimized. See http://hyperelliptic.org/EFD/g1p/auto-shortw-projective-3.html
 * vs http://hyperelliptic.org/EFD/g1p/auto-shortw-projective.html for example.
 *
 * phpseclib does not currently take advantage of this optimization opportunity
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP160t1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('E95E4A5F737059DC60DFC7AD95B3D8139515620F', 16));
        $this->setCoefficients(
            new BigInteger('E95E4A5F737059DC60DFC7AD95B3D8139515620C', 16), // eg. -3
            new BigInteger('7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380', 16)
        );
        $this->setBasePoint(
            new BigInteger('B199B13B9B34EFC1397E64BAEB05ACC265FF2378', 16),
            new BigInteger('ADD6718B7C7C1961F0991B842443772152C9E0AD', 16)
        );
        $this->setOrder(new BigInteger('E95E4A5F737059DC60DF5991D45029409E60FC09', 16));
    }
}
<?php

/**
 * Ed25519
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards;
use phpseclib3\Crypt\Hash;
use phpseclib3\Crypt\Random;
use phpseclib3\Math\BigInteger;

class Ed25519 extends TwistedEdwards
{
    const HASH = 'sha512';
    /*
      Per https://tools.ietf.org/html/rfc8032#page-6 EdDSA has several parameters, one of which is b:

      2.   An integer b with 2^(b-1) > p.  EdDSA public keys have exactly b
           bits, and EdDSA signatures have exactly 2*b bits.  b is
           recommended to be a multiple of 8, so public key and signature
           lengths are an integral number of octets.

      SIZE corresponds to b
    */
    const SIZE = 32;

    public function __construct()
    {
        // 2^255 - 19
        $this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED', 16));
        $this->setCoefficients(
            // -1
            new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC', 16), // a
            // -121665/121666
            new BigInteger('52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3', 16)  // d
        );
        $this->setBasePoint(
            new BigInteger('216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A', 16),
            new BigInteger('6666666666666666666666666666666666666666666666666666666666666658', 16)
        );
        $this->setOrder(new BigInteger('1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED', 16));
        // algorithm 14.47 from http://cacr.uwaterloo.ca/hac/about/chap14.pdf#page=16
        /*
        $this->setReduction(function($x) {
            $parts = $x->bitwise_split(255);
            $className = $this->className;

            if (count($parts) > 2) {
                list(, $r) = $x->divide($className::$modulo);
                return $r;
            }

            $zero = new BigInteger();
            $c = new BigInteger(19);

            switch (count($parts)) {
                case 2:
                    list($qi, $ri) = $parts;
                    break;
                case 1:
                    $qi = $zero;
                    list($ri) = $parts;
                    break;
                case 0:
                    return $zero;
            }
            $r = $ri;

            while ($qi->compare($zero) > 0) {
                $temp = $qi->multiply($c)->bitwise_split(255);
                if (count($temp) == 2) {
                    list($qi, $ri) = $temp;
                } else {
                    $qi = $zero;
                    list($ri) = $temp;
                }
                $r = $r->add($ri);
            }

            while ($r->compare($className::$modulo) > 0) {
                $r = $r->subtract($className::$modulo);
            }
            return $r;
        });
        */
    }

    /**
     * Recover X from Y
     *
     * Implements steps 2-4 at https://tools.ietf.org/html/rfc8032#section-5.1.3
     *
     * Used by EC\Keys\Common.php
     *
     * @param BigInteger $y
     * @param boolean $sign
     * @return object[]
     */
    public function recoverX(BigInteger $y, $sign)
    {
        $y = $this->factory->newInteger($y);

        $y2 = $y->multiply($y);
        $u = $y2->subtract($this->one);
        $v = $this->d->multiply($y2)->add($this->one);
        $x2 = $u->divide($v);
        if ($x2->equals($this->zero)) {
            if ($sign) {
                throw new \RuntimeException('Unable to recover X coordinate (x2 = 0)');
            }
            return clone $this->zero;
        }
        // find the square root
        /* we don't do $x2->squareRoot() because, quoting from
           https://tools.ietf.org/html/rfc8032#section-5.1.1:

           "For point decoding or "decompression", square roots modulo p are
            needed.  They can be computed using the Tonelli-Shanks algorithm or
            the special case for p = 5 (mod 8).  To find a square root of a,
            first compute the candidate root x = a^((p+3)/8) (mod p)."
         */
        $exp = $this->getModulo()->add(new BigInteger(3));
        $exp = $exp->bitwise_rightShift(3);
        $x = $x2->pow($exp);

        // If v x^2 = -u (mod p), set x <-- x * 2^((p-1)/4), which is a square root.
        if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) {
            $temp = $this->getModulo()->subtract(new BigInteger(1));
            $temp = $temp->bitwise_rightShift(2);
            $temp = $this->two->pow($temp);
            $x = $x->multiply($temp);
            if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) {
                throw new \RuntimeException('Unable to recover X coordinate');
            }
        }
        if ($x->isOdd() != $sign) {
            $x = $x->negate();
        }

        return [$x, $y];
    }

    /**
     * Extract Secret Scalar
     *
     * Implements steps 1-3 at https://tools.ietf.org/html/rfc8032#section-5.1.5
     *
     * Used by the various key handlers
     *
     * @param string $str
     * @return array
     */
    public function extractSecret($str)
    {
        if (strlen($str) != 32) {
            throw new \LengthException('Private Key should be 32-bytes long');
        }
        // 1.  Hash the 32-byte private key using SHA-512, storing the digest in
        //     a 64-octet large buffer, denoted h.  Only the lower 32 bytes are
        //     used for generating the public key.
        $hash = new Hash('sha512');
        $h = $hash->hash($str);
        $h = substr($h, 0, 32);
        // 2.  Prune the buffer: The lowest three bits of the first octet are
        //     cleared, the highest bit of the last octet is cleared, and the
        //     second highest bit of the last octet is set.
        $h[0] = $h[0] & chr(0xF8);
        $h = strrev($h);
        $h[0] = ($h[0] & chr(0x3F)) | chr(0x40);
        // 3.  Interpret the buffer as the little-endian integer, forming a
        //     secret scalar s.
        $dA = new BigInteger($h, 256);

        return [
            'dA' => $dA,
            'secret' => $str
        ];
    }

    /**
     * Encode a point as a string
     *
     * @param array $point
     * @return string
     */
    public function encodePoint($point)
    {
        list($x, $y) = $point;
        $y = $y->toBytes();
        $y[0] = $y[0] & chr(0x7F);
        if ($x->isOdd()) {
            $y[0] = $y[0] | chr(0x80);
        }
        $y = strrev($y);

        return $y;
    }

    /**
     * Creates a random scalar multiplier
     *
     * @return \phpseclib3\Math\PrimeField\Integer
     */
    public function createRandomMultiplier()
    {
        return $this->extractSecret(Random::string(32))['dA'];
    }

    /**
     * Converts an affine point to an extended homogeneous coordinate
     *
     * From https://tools.ietf.org/html/rfc8032#section-5.1.4 :
     *
     * A point (x,y) is represented in extended homogeneous coordinates (X, Y, Z, T),
     * with x = X/Z, y = Y/Z, x * y = T/Z.
     *
     * @return \phpseclib3\Math\PrimeField\Integer[]
     */
    public function convertToInternal(array $p)
    {
        if (empty($p)) {
            return [clone $this->zero, clone $this->one, clone $this->one, clone $this->zero];
        }

        if (isset($p[2])) {
            return $p;
        }

        $p[2] = clone $this->one;
        $p[3] = $p[0]->multiply($p[1]);

        return $p;
    }

    /**
     * Doubles a point on a curve
     *
     * @return FiniteField[]
     */
    public function doublePoint(array $p)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }

        if (!count($p)) {
            return [];
        }

        if (!isset($p[2])) {
            throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
        }

        // from https://tools.ietf.org/html/rfc8032#page-12

        list($x1, $y1, $z1, $t1) = $p;

        $a = $x1->multiply($x1);
        $b = $y1->multiply($y1);
        $c = $this->two->multiply($z1)->multiply($z1);
        $h = $a->add($b);
        $temp = $x1->add($y1);
        $e = $h->subtract($temp->multiply($temp));
        $g = $a->subtract($b);
        $f = $c->add($g);

        $x3 = $e->multiply($f);
        $y3 = $g->multiply($h);
        $t3 = $e->multiply($h);
        $z3 = $f->multiply($g);

        return [$x3, $y3, $z3, $t3];
    }

    /**
     * Adds two points on the curve
     *
     * @return FiniteField[]
     */
    public function addPoint(array $p, array $q)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }

        if (!count($p) || !count($q)) {
            if (count($q)) {
                return $q;
            }
            if (count($p)) {
                return $p;
            }
            return [];
        }

        if (!isset($p[2]) || !isset($q[2])) {
            throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
        }

        if ($p[0]->equals($q[0])) {
            return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p);
        }

        // from https://tools.ietf.org/html/rfc8032#page-12

        list($x1, $y1, $z1, $t1) = $p;
        list($x2, $y2, $z2, $t2) = $q;

        $a = $y1->subtract($x1)->multiply($y2->subtract($x2));
        $b = $y1->add($x1)->multiply($y2->add($x2));
        $c = $t1->multiply($this->two)->multiply($this->d)->multiply($t2);
        $d = $z1->multiply($this->two)->multiply($z2);
        $e = $b->subtract($a);
        $f = $d->subtract($c);
        $g = $d->add($c);
        $h = $b->add($a);

        $x3 = $e->multiply($f);
        $y3 = $g->multiply($h);
        $t3 = $e->multiply($h);
        $z3 = $f->multiply($g);

        return [$x3, $y3, $z3, $t3];
    }
}
<?php

/**
 * brainpoolP384r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP384r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger(
            '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A7' .
            '1874700133107EC53',
            16
        ));
        $this->setCoefficients(
            new BigInteger(
                '7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503' .
                'AD4EB04A8C7DD22CE2826',
                16
            ),
            new BigInteger(
                '4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DB' .
                'C9943AB78696FA504C11',
                16
            )
        );
        $this->setBasePoint(
            new BigInteger(
                '1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D' .
                '646AAEF87B2E247D4AF1E',
                16
            ),
            new BigInteger(
                '8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E464621779' .
                '1811142820341263C5315',
                16
            )
        );
        $this->setOrder(new BigInteger(
            '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC31' .
            '03B883202E9046565',
            16
        ));
    }
}
<?php

/**
 * Ed448
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards;
use phpseclib3\Crypt\Hash;
use phpseclib3\Crypt\Random;
use phpseclib3\Math\BigInteger;

class Ed448 extends TwistedEdwards
{
    const HASH = 'shake256-912';
    const SIZE = 57;

    public function __construct()
    {
        // 2^448 - 2^224 - 1
        $this->setModulo(new BigInteger(
            'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE' .
            'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
            16
        ));
        $this->setCoefficients(
            new BigInteger(1),
            // -39081
            new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE' .
                           'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6756', 16)
        );
        $this->setBasePoint(
            new BigInteger('4F1970C66BED0DED221D15A622BF36DA9E146570470F1767EA6DE324' .
                           'A3D3A46412AE1AF72AB66511433B80E18B00938E2626A82BC70CC05E', 16),
            new BigInteger('693F46716EB6BC248876203756C9C7624BEA73736CA3984087789C1E' .
                           '05A0C2D73AD3FF1CE67C39C4FDBD132C4ED7C8AD9808795BF230FA14', 16)
        );
        $this->setOrder(new BigInteger(
            '3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
            '7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3',
            16
        ));
    }

    /**
     * Recover X from Y
     *
     * Implements steps 2-4 at https://tools.ietf.org/html/rfc8032#section-5.2.3
     *
     * Used by EC\Keys\Common.php
     *
     * @param BigInteger $y
     * @param boolean $sign
     * @return object[]
     */
    public function recoverX(BigInteger $y, $sign)
    {
        $y = $this->factory->newInteger($y);

        $y2 = $y->multiply($y);
        $u = $y2->subtract($this->one);
        $v = $this->d->multiply($y2)->subtract($this->one);
        $x2 = $u->divide($v);
        if ($x2->equals($this->zero)) {
            if ($sign) {
                throw new \RuntimeException('Unable to recover X coordinate (x2 = 0)');
            }
            return clone $this->zero;
        }
        // find the square root
        $exp = $this->getModulo()->add(new BigInteger(1));
        $exp = $exp->bitwise_rightShift(2);
        $x = $x2->pow($exp);

        if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) {
            throw new \RuntimeException('Unable to recover X coordinate');
        }
        if ($x->isOdd() != $sign) {
            $x = $x->negate();
        }

        return [$x, $y];
    }

    /**
     * Extract Secret Scalar
     *
     * Implements steps 1-3 at https://tools.ietf.org/html/rfc8032#section-5.2.5
     *
     * Used by the various key handlers
     *
     * @param string $str
     * @return array
     */
    public function extractSecret($str)
    {
        if (strlen($str) != 57) {
            throw new \LengthException('Private Key should be 57-bytes long');
        }
        // 1.  Hash the 57-byte private key using SHAKE256(x, 114), storing the
        //     digest in a 114-octet large buffer, denoted h.  Only the lower 57
        //     bytes are used for generating the public key.
        $hash = new Hash('shake256-912');
        $h = $hash->hash($str);
        $h = substr($h, 0, 57);
        // 2.  Prune the buffer: The two least significant bits of the first
        //     octet are cleared, all eight bits the last octet are cleared, and
        //     the highest bit of the second to last octet is set.
        $h[0] = $h[0] & chr(0xFC);
        $h = strrev($h);
        $h[0] = "\0";
        $h[1] = $h[1] | chr(0x80);
        // 3.  Interpret the buffer as the little-endian integer, forming a
        //     secret scalar s.
        $dA = new BigInteger($h, 256);

        return [
            'dA' => $dA,
            'secret' => $str
        ];

        $dA->secret = $str;
        return $dA;
    }

    /**
     * Encode a point as a string
     *
     * @param array $point
     * @return string
     */
    public function encodePoint($point)
    {
        list($x, $y) = $point;
        $y = "\0" . $y->toBytes();
        if ($x->isOdd()) {
            $y[0] = $y[0] | chr(0x80);
        }
        $y = strrev($y);

        return $y;
    }

    /**
     * Creates a random scalar multiplier
     *
     * @return \phpseclib3\Math\PrimeField\Integer
     */
    public function createRandomMultiplier()
    {
        return $this->extractSecret(Random::string(57))['dA'];
    }

    /**
     * Converts an affine point to an extended homogeneous coordinate
     *
     * From https://tools.ietf.org/html/rfc8032#section-5.2.4 :
     *
     * A point (x,y) is represented in extended homogeneous coordinates (X, Y, Z, T),
     * with x = X/Z, y = Y/Z, x * y = T/Z.
     *
     * @return \phpseclib3\Math\PrimeField\Integer[]
     */
    public function convertToInternal(array $p)
    {
        if (empty($p)) {
            return [clone $this->zero, clone $this->one, clone $this->one];
        }

        if (isset($p[2])) {
            return $p;
        }

        $p[2] = clone $this->one;

        return $p;
    }

    /**
     * Doubles a point on a curve
     *
     * @return FiniteField[]
     */
    public function doublePoint(array $p)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }

        if (!count($p)) {
            return [];
        }

        if (!isset($p[2])) {
            throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
        }

        // from https://tools.ietf.org/html/rfc8032#page-18

        list($x1, $y1, $z1) = $p;

        $b = $x1->add($y1);
        $b = $b->multiply($b);
        $c = $x1->multiply($x1);
        $d = $y1->multiply($y1);
        $e = $c->add($d);
        $h = $z1->multiply($z1);
        $j = $e->subtract($this->two->multiply($h));

        $x3 = $b->subtract($e)->multiply($j);
        $y3 = $c->subtract($d)->multiply($e);
        $z3 = $e->multiply($j);

        return [$x3, $y3, $z3];
    }

    /**
     * Adds two points on the curve
     *
     * @return FiniteField[]
     */
    public function addPoint(array $p, array $q)
    {
        if (!isset($this->factory)) {
            throw new \RuntimeException('setModulo needs to be called before this method');
        }

        if (!count($p) || !count($q)) {
            if (count($q)) {
                return $q;
            }
            if (count($p)) {
                return $p;
            }
            return [];
        }

        if (!isset($p[2]) || !isset($q[2])) {
            throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
        }

        if ($p[0]->equals($q[0])) {
            return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p);
        }

        // from https://tools.ietf.org/html/rfc8032#page-17

        list($x1, $y1, $z1) = $p;
        list($x2, $y2, $z2) = $q;

        $a = $z1->multiply($z2);
        $b = $a->multiply($a);
        $c = $x1->multiply($x2);
        $d = $y1->multiply($y2);
        $e = $this->d->multiply($c)->multiply($d);
        $f = $b->subtract($e);
        $g = $b->add($e);
        $h = $x1->add($y1)->multiply($x2->add($y2));

        $x3 = $a->multiply($f)->multiply($h->subtract($c)->subtract($d));
        $y3 = $a->multiply($g)->multiply($d->subtract($c));
        $z3 = $f->multiply($g);

        return [$x3, $y3, $z3];
    }
}
<?php

/**
 * secp224k1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\KoblitzPrime;
use phpseclib3\Math\BigInteger;

class secp224k1 extends KoblitzPrime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D', 16));
        $this->setCoefficients(
            new BigInteger('00000000000000000000000000000000000000000000000000000000', 16),
            new BigInteger('00000000000000000000000000000000000000000000000000000005', 16)
        );
        $this->setBasePoint(
            new BigInteger('A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C', 16),
            new BigInteger('7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5', 16)
        );
        $this->setOrder(new BigInteger('010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7', 16));

        $this->basis = [];
        $this->basis[] = [
            'a' => new BigInteger('00B8ADF1378A6EB73409FA6C9C637D', -16),
            'b' => new BigInteger('94730F82B358A3776A826298FA6F', -16)
        ];
        $this->basis[] = [
            'a' => new BigInteger('01DCE8D2EC6184CAF0A972769FCC8B', -16),
            'b' => new BigInteger('4D2100BA3DC75AAB747CCF355DEC', -16)
        ];
        $this->beta = $this->factory->newInteger(new BigInteger('01F178FFA4B17C89E6F73AECE2AAD57AF4C0A748B63C830947B27E04', -16));
    }
}
<?php

/**
 * sect113r2
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect113r2 extends Binary
{
    public function __construct()
    {
        $this->setModulo(113, 9, 0);
        $this->setCoefficients(
            '00689918DBEC7E5A0DD6DFC0AA55C7',
            '0095E9A9EC9B297BD4BF36E059184F'
        );
        $this->setBasePoint(
            '01A57A6A7B26CA5EF52FCDB8164797',
            '00B3ADC94ED1FE674C06E695BABA1D'
        );
        $this->setOrder(new BigInteger('010000000000000108789B2496AF93', 16));
    }
}
<?php

/**
 * sect113r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect113r1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(113, 9, 0);
        $this->setCoefficients(
            '003088250CA6E7C7FE649CE85820F7',
            '00E8BEE4D3E2260744188BE0E9C723'
        );
        $this->setBasePoint(
            '009D73616F35F4AB1407D73562C10F',
            '00A52830277958EE84D1315ED31886'
        );
        $this->setOrder(new BigInteger('0100000000000000D9CCEC8A39E56F', 16));
    }
}
<?php

/**
 * sect131r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect131r1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(131, 8, 3, 2, 0);
        $this->setCoefficients(
            '07A11B09A76B562144418FF3FF8C2570B8',
            '0217C05610884B63B9C6C7291678F9D341'
        );
        $this->setBasePoint(
            '0081BAF91FDF9833C40F9C181343638399',
            '078C6E7EA38C001F73C8134B1B4EF9E150'
        );
        $this->setOrder(new BigInteger('0400000000000000023123953A9464B54D', 16));
    }
}
<?php

/**
 * sect233r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect233r1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(233, 74, 0);
        $this->setCoefficients(
            '000000000000000000000000000000000000000000000000000000000001',
            '0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD'
        );
        $this->setBasePoint(
            '00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B',
            '01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052'
        );
        $this->setOrder(new BigInteger('01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7', 16));
    }
}
<?php

/**
 * Curve25519
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2019 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Montgomery;
use phpseclib3\Math\BigInteger;

class Curve25519 extends Montgomery
{
    const SIZE = 32;

    public function __construct()
    {
        // 2^255 - 19
        $this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED', 16));
        $this->a24 = $this->factory->newInteger(new BigInteger('121666'));
        $this->p = [$this->factory->newInteger(new BigInteger(9))];
        // 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed
        $this->setOrder(new BigInteger('1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED', 16));

        /*
        $this->setCoefficients(
            new BigInteger('486662'), // a
        );
        $this->setBasePoint(
            new BigInteger(9),
            new BigInteger('14781619447589544791020593568409986887264606134616475288964881837755586237401')
        );
        */
    }

    /**
     * Multiply a point on the curve by a scalar
     *
     * Modifies the scalar as described at https://tools.ietf.org/html/rfc7748#page-8
     *
     * @return array
     */
    public function multiplyPoint(array $p, BigInteger $d)
    {
        $d = $d->toBytes();
        $d = str_pad($d, 32, "\0", STR_PAD_LEFT);

        //$r = strrev(sodium_crypto_scalarmult($d, strrev($p[0]->toBytes())));
        //return [$this->factory->newInteger(new BigInteger($r, 256))];

        $d &= "\xF8" . str_repeat("\xFF", 30) . "\x7F";
        $d = strrev($d);
        $d |= "\x40";
        $d = new BigInteger($d, -256);

        return parent::multiplyPoint($p, $d);
    }

    /**
     * Creates a random scalar multiplier
     *
     * @return BigInteger
     */
    public function createRandomMultiplier()
    {
        return BigInteger::random(256);
    }

    /**
     * Performs range check
     */
    public function rangeCheck(BigInteger $x)
    {
        if ($x->getLength() > 256 || $x->isNegative()) {
            throw new \RangeException('x must be a positive integer less than 256 bytes in length');
        }
    }
}
<?php

/**
 * brainpoolP320t1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP320t1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F9' .
                                        '2B9EC7893EC28FCD412B1F1B32E27', 16));
        $this->setCoefficients(
            new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28' .
                           'FCD412B1F1B32E24', 16), // eg. -3
            new BigInteger('A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CE' .
                           'B5B4FEF422340353', 16)
        );
        $this->setBasePoint(
            new BigInteger('925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF' .
                           '3357F624A21BED52', 16),
            new BigInteger('63BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B' .
                           '1B9BC0455FB0D2C3', 16)
        );
        $this->setOrder(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D4' .
                                       '82EC7EE8658E98691555B44C59311', 16));
    }
}
<?php

/**
 * secp224r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class secp224r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001', 16));
        $this->setCoefficients(
            new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE', 16),
            new BigInteger('B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4', 16)
        );
        $this->setBasePoint(
            new BigInteger('B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21', 16),
            new BigInteger('BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34', 16)
        );
        $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D', 16));
    }
}
<?php

/**
 * sect193r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect193r1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(193, 15, 0);
        $this->setCoefficients(
            '0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01',
            '00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814'
        );
        $this->setBasePoint(
            '01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1',
            '0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05'
        );
        $this->setOrder(new BigInteger('01000000000000000000000000C7F34A778F443ACC920EBA49', 16));
    }
}
<?php

/**
 * sect283k1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wiggint  on <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect283k1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(283, 12, 7, 5, 0);
        $this->setCoefficients(
            '000000000000000000000000000000000000000000000000000000000000000000000000',
            '000000000000000000000000000000000000000000000000000000000000000000000001'
        );
        $this->setBasePoint(
            '0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836',
            '01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259'
        );
        $this->setOrder(new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61', 16));
    }
}
<?php

/**
 * brainpoolP384t1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP384t1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger(
            '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A7' .
            '1874700133107EC53',
            16
        ));
        $this->setCoefficients(
            new BigInteger(
                '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901' .
                'D1A71874700133107EC50',
                16
            ), // eg. -3
            new BigInteger(
                '7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B8' .
                '8805CED70355A33B471EE',
                16
            )
        );
        $this->setBasePoint(
            new BigInteger(
                '18DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946' .
                'A5F54D8D0AA2F418808CC',
                16
            ),
            new BigInteger(
                '25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC' .
                '2B2912675BF5B9E582928',
                16
            )
        );
        $this->setOrder(new BigInteger(
            '8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC31' .
            '03B883202E9046565',
            16
        ));
    }
}
<?php

/**
 * sect409r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wiggint  on <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect409r1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(409, 87, 0);
        $this->setCoefficients(
            '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001',
            '0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F'
        );
        $this->setBasePoint(
            '015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7',
            '0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706'
        );
        $this->setOrder(new BigInteger(
            '010000000000000000000000000000000000000000000000000001E2' .
            'AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173',
            16
        ));
    }
}
<?php

/**
 * brainpoolP224t1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP224t1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF', 16));
        $this->setCoefficients(
            new BigInteger('D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC', 16), // eg. -3
            new BigInteger('4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D', 16)
        );
        $this->setBasePoint(
            new BigInteger('6AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D580', 16),
            new BigInteger('0374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C', 16)
        );
        $this->setOrder(new BigInteger('D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F', 16));
    }
}
<?php

/**
 * prime256v1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class prime256v1 extends secp256r1
{
}
<?php

/**
 * nistb409
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistb409 extends sect409r1
{
}
<?php

/**
 * sect571k1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wiggint  on <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect571k1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(571, 10, 5, 2, 0);
        $this->setCoefficients(
            '000000000000000000000000000000000000000000000000000000000000000000000000' .
            '000000000000000000000000000000000000000000000000000000000000000000000000',
            '000000000000000000000000000000000000000000000000000000000000000000000000' .
            '000000000000000000000000000000000000000000000000000000000000000000000001'
        );
        $this->setBasePoint(
            '026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA443709584' .
            '93B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972',
            '0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0' .
            'AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3'
        );
        $this->setOrder(new BigInteger(
            '020000000000000000000000000000000000000000000000000000000000000000000000' .
            '131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001',
            16
        ));
    }
}
<?php

/**
 * Curve448
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2019 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Montgomery;
use phpseclib3\Math\BigInteger;

class Curve448 extends Montgomery
{
    const SIZE = 56;

    public function __construct()
    {
        // 2^448 - 2^224 - 1
        $this->setModulo(new BigInteger(
            'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE' .
            'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',
            16
        ));
        $this->a24 = $this->factory->newInteger(new BigInteger('39081'));
        $this->p = [$this->factory->newInteger(new BigInteger(5))];
        // 2^446 - 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d
        $this->setOrder(new BigInteger(
            '3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
            '7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3',
            16
        ));

        /*
        $this->setCoefficients(
            new BigInteger('156326'), // a
        );
        $this->setBasePoint(
            new BigInteger(5),
            new BigInteger(
                '355293926785568175264127502063783334808976399387714271831880898' .
                '435169088786967410002932673765864550910142774147268105838985595290' .
                '606362')
        );
        */
    }

    /**
     * Multiply a point on the curve by a scalar
     *
     * Modifies the scalar as described at https://tools.ietf.org/html/rfc7748#page-8
     *
     * @return array
     */
    public function multiplyPoint(array $p, BigInteger $d)
    {
        $d = $d->toBytes();
        $d = str_pad($d, 56, "\0", STR_PAD_LEFT);

        //$r = strrev(sodium_crypto_scalarmult($d, strrev($p[0]->toBytes())));
        //return [$this->factory->newInteger(new BigInteger($r, 256))];

        $d[0] = $d[0] & "\xFC";
        $d = strrev($d);
        $d |= "\x80";
        $d = new BigInteger($d, 256);

        return parent::multiplyPoint($p, $d);
    }

    /**
     * Creates a random scalar multiplier
     *
     * @return BigInteger
     */
    public function createRandomMultiplier()
    {
        return BigInteger::random(446);
    }

    /**
     * Performs range check
     */
    public function rangeCheck(BigInteger $x)
    {
        if ($x->getLength() > 448 || $x->isNegative()) {
            throw new \RangeException('x must be a positive integer less than 446 bytes in length');
        }
    }
}
<?php

/**
 * secp112r2
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class secp112r2 extends Prime
{
    public function __construct()
    {
        // same modulo as secp112r1
        $this->setModulo(new BigInteger('DB7C2ABF62E35E668076BEAD208B', 16));
        $this->setCoefficients(
            new BigInteger('6127C24C05F38A0AAAF65C0EF02C', 16),
            new BigInteger('51DEF1815DB5ED74FCC34C85D709', 16)
        );
        $this->setBasePoint(
            new BigInteger('4BA30AB5E892B4E1649DD0928643', 16),
            new BigInteger('ADCD46F5882E3747DEF36E956E97', 16)
        );
        $this->setOrder(new BigInteger('36DF0AAFD8B8D7597CA10520D04B', 16));
    }
}
<?php

/**
 * sect571r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wiggint  on <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect571r1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(571, 10, 5, 2, 0);
        $this->setCoefficients(
            '000000000000000000000000000000000000000000000000000000000000000000000000' .
            '000000000000000000000000000000000000000000000000000000000000000000000001',
            '02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD' .
            '8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A'
        );
        $this->setBasePoint(
            '0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950' .
            'F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19',
            '037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43' .
            'BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B'
        );
        $this->setOrder(new BigInteger(
            '03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
            'E661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47',
            16
        ));
    }
}
<?php

/**
 * prime239v1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class prime239v1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF', 16));
        $this->setCoefficients(
            new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC', 16),
            new BigInteger('6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A', 16)
        );
        $this->setBasePoint(
            new BigInteger('0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF', 16),
            new BigInteger('7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE', 16)
        );
        $this->setOrder(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B', 16));
    }
}
<?php

/**
 * secp160k1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\KoblitzPrime;
use phpseclib3\Math\BigInteger;

class secp160k1 extends KoblitzPrime
{
    public function __construct()
    {
        // same as secp160r2
        $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73', 16));
        $this->setCoefficients(
            new BigInteger('0000000000000000000000000000000000000000', 16),
            new BigInteger('0000000000000000000000000000000000000007', 16)
        );
        $this->setBasePoint(
            new BigInteger('3B4C382CE37AA192A4019E763036F4F5DD4D7EBB', 16),
            new BigInteger('938CF935318FDCED6BC28286531733C3F03C4FEE', 16)
        );
        $this->setOrder(new BigInteger('0100000000000000000001B8FA16DFAB9ACA16B6B3', 16));

        $this->basis = [];
        $this->basis[] = [
            'a' => new BigInteger('0096341F1138933BC2F505', -16),
            'b' => new BigInteger('FF6E9D0418C67BB8D5F562', -16)
        ];
        $this->basis[] = [
            'a' => new BigInteger('01BDCB3A09AAAABEAFF4A8', -16),
            'b' => new BigInteger('04D12329FF0EF498EA67', -16)
        ];
        $this->beta = $this->factory->newInteger(new BigInteger('645B7345A143464942CC46D7CF4D5D1E1E6CBB68', -16));
    }
}
<?php

/**
 * nistk163
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistk163 extends sect163k1
{
}
<?php

/**
 * sect283k1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistk283 extends sect283k1
{
}
<?php

/**
 * nistp521
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistp521 extends secp521r1
{
}
<?php

/**
 * secp128r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class secp128r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF', 16));
        $this->setCoefficients(
            new BigInteger('FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC', 16),
            new BigInteger('E87579C11079F43DD824993C2CEE5ED3', 16)
        );
        $this->setBasePoint(
            new BigInteger('161FF7528B899B2D0C28607CA52C5B86', 16),
            new BigInteger('CF5AC8395BAFEB13C02DA292DDED7A83', 16)
        );
        $this->setOrder(new BigInteger('FFFFFFFE0000000075A30D1B9038A115', 16));
    }
}
<?php

/**
 * prime239v2
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class prime239v2 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF', 16));
        $this->setCoefficients(
            new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC', 16),
            new BigInteger('617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C', 16)
        );
        $this->setBasePoint(
            new BigInteger('38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7', 16),
            new BigInteger('5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA', 16)
        );
        $this->setOrder(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063', 16));
    }
}
<?php

/**
 * brainpoolP160r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP160r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('E95E4A5F737059DC60DFC7AD95B3D8139515620F', 16));
        $this->setCoefficients(
            new BigInteger('340E7BE2A280EB74E2BE61BADA745D97E8F7C300', 16),
            new BigInteger('1E589A8595423412134FAA2DBDEC95C8D8675E58', 16)
        );
        $this->setBasePoint(
            new BigInteger('BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3', 16),
            new BigInteger('1667CB477A1A8EC338F94741669C976316DA6321', 16)
        );
        $this->setOrder(new BigInteger('E95E4A5F737059DC60DF5991D45029409E60FC09', 16));
    }
}
<?php

/**
 * sect193r2
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect193r2 extends Binary
{
    public function __construct()
    {
        $this->setModulo(193, 15, 0);
        $this->setCoefficients(
            '0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B',
            '00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE'
        );
        $this->setBasePoint(
            '00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F',
            '01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C'
        );
        $this->setOrder(new BigInteger('010000000000000000000000015AAB561B005413CCD4EE99D5', 16));
    }
}
<?php

/**
 * secp192r1
 *
 * This is the NIST P-192 curve
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class secp192r1 extends Prime
{
    public function __construct()
    {
        $modulo = new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF', 16);
        $this->setModulo($modulo);

        // algorithm 2.27 from http://diamond.boisestate.edu/~liljanab/MATH308/GuideToECC.pdf#page=66
        /* in theory this should be faster than regular modular reductions save for one small issue.
           to convert to / from base-2**8 with BCMath you have to call bcmul() and bcdiv() a lot.
           to convert to / from base-2**8 with PHP64 you have to call base256_rshift() a lot.
           in short, converting to / from base-2**8 is pretty expensive and that expense is
           enough to offset whatever else might be gained by a simplified reduction algorithm.
           now, if PHP supported unsigned integers things might be different. no bit-shifting
           would be required for the PHP engine and it'd be a lot faster. but as is, BigInteger
           uses base-2**31 or base-2**26 depending on whether or not the system is has a 32-bit
           or a 64-bit OS.
        */
        /*
        $m_length = $this->getLengthInBytes();
        $this->setReduction(function($c) use ($m_length) {
            $cBytes = $c->toBytes();
            $className = $this->className;

            if (strlen($cBytes) > 2 * $m_length) {
                list(, $r) = $c->divide($className::$modulo);
                return $r;
            }

            $c = str_pad($cBytes, 48, "\0", STR_PAD_LEFT);
            $c = array_reverse(str_split($c, 8));

            $null = "\0\0\0\0\0\0\0\0";
            $s1 = new BigInteger($c[2] . $c[1] . $c[0], 256);
            $s2 = new BigInteger($null . $c[3] . $c[3], 256);
            $s3 = new BigInteger($c[4] . $c[4] . $null, 256);
            $s4 = new BigInteger($c[5] . $c[5] . $c[5], 256);

            $r = $s1->add($s2)->add($s3)->add($s4);
            while ($r->compare($className::$modulo) >= 0) {
                $r = $r->subtract($className::$modulo);
            }

            return $r;
        });
        */

        $this->setCoefficients(
            new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC', 16),
            new BigInteger('64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1', 16)
        );
        $this->setBasePoint(
            new BigInteger('188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012', 16),
            new BigInteger('07192B95FFC8DA78631011ED6B24CDD573F977A11E794811', 16)
        );
        $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831', 16));
    }
}
<?php

/**
 * brainpoolP512r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP512r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger(
            'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC' .
            '66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3',
            16
        ));
        $this->setCoefficients(
            new BigInteger(
                '7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA82' .
                '53AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA',
                16
            ),
            new BigInteger(
                '3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C' .
                '1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723',
                16
            )
        );
        $this->setBasePoint(
            new BigInteger(
                '81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D' .
                '0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822',
                16
            ),
            new BigInteger(
                '7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5' .
                'F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892',
                16
            )
        );
        $this->setOrder(new BigInteger(
            'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA' .
            '92619418661197FAC10471DB1D381085DDADDB58796829CA90069',
            16
        ));
    }
}
<?php

/**
 * brainpoolP512t1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP512t1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger(
            'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC' .
            '66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3',
            16
        ));
        $this->setCoefficients(
            new BigInteger(
                'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC' .
                '66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0',
                16
            ), // eg. -3
            new BigInteger(
                '7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA23049' .
                '76540F6450085F2DAE145C22553B465763689180EA2571867423E',
                16
            )
        );
        $this->setBasePoint(
            new BigInteger(
                '640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CD' .
                'B3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA',
                16
            ),
            new BigInteger(
                '5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEE' .
                'F216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332',
                16
            )
        );
        $this->setOrder(new BigInteger(
            'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA' .
            '92619418661197FAC10471DB1D381085DDADDB58796829CA90069',
            16
        ));
    }
}
<?php

/**
 * prime239v3
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class prime239v3 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF', 16));
        $this->setCoefficients(
            new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC', 16),
            new BigInteger('255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E', 16)
        );
        $this->setBasePoint(
            new BigInteger('6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A', 16),
            new BigInteger('1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3', 16)
        );
        $this->setOrder(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551', 16));
    }
}
<?php

/**
 * sect233k1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect233k1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(233, 74, 0);
        $this->setCoefficients(
            '000000000000000000000000000000000000000000000000000000000000',
            '000000000000000000000000000000000000000000000000000000000001'
        );
        $this->setBasePoint(
            '017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126',
            '01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3'
        );
        $this->setOrder(new BigInteger('8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF', 16));
    }
}
<?php

/**
 * secp384r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class secp384r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger(
            'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF',
            16
        ));
        $this->setCoefficients(
            new BigInteger(
                'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC',
                16
            ),
            new BigInteger(
                'B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF',
                16
            )
        );
        $this->setBasePoint(
            new BigInteger(
                'AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7',
                16
            ),
            new BigInteger(
                '3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F',
                16
            )
        );
        $this->setOrder(new BigInteger(
            'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973',
            16
        ));
    }
}
<?php

/**
 * nistp192
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistp192 extends secp192r1
{
}
<?php

/**
 * nistp224
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistp224 extends secp224r1
{
}
<?php

/**
 * nistp256
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistp256 extends secp256r1
{
}
<?php

/**
 * brainpoolP256t1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP256t1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377', 16));
        $this->setCoefficients(
            new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374', 16), // eg. -3
            new BigInteger('662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04', 16)
        );
        $this->setBasePoint(
            new BigInteger('A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F4', 16),
            new BigInteger('2D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE', 16)
        );
        $this->setOrder(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7', 16));
    }
}
<?php

/**
 * sect409k1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wiggint  on <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect409k1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(409, 87, 0);
        $this->setCoefficients(
            '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
            '00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001'
        );
        $this->setBasePoint(
            '0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746',
            '01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B'
        );
        $this->setOrder(new BigInteger(
            '7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F' .
            '83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF',
            16
        ));
    }
}
<?php

/**
 * brainpoolP256r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP256r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377', 16));
        $this->setCoefficients(
            new BigInteger('7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9', 16),
            new BigInteger('26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6', 16)
        );
        $this->setBasePoint(
            new BigInteger('8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262', 16),
            new BigInteger('547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997', 16)
        );
        $this->setOrder(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7', 16));
    }
}
<?php

/**
 * secp256k1
 *
 * This is the curve used in Bitcoin
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

//use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Crypt\EC\BaseCurves\KoblitzPrime;
use phpseclib3\Math\BigInteger;

//class secp256k1 extends Prime
class secp256k1 extends KoblitzPrime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', 16));
        $this->setCoefficients(
            new BigInteger('0000000000000000000000000000000000000000000000000000000000000000', 16),
            new BigInteger('0000000000000000000000000000000000000000000000000000000000000007', 16)
        );
        $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 16));
        $this->setBasePoint(
            new BigInteger('79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', 16),
            new BigInteger('483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8', 16)
        );

        $this->basis = [];
        $this->basis[] = [
            'a' => new BigInteger('3086D221A7D46BCDE86C90E49284EB15', -16),
            'b' => new BigInteger('FF1BBC8129FEF177D790AB8056F5401B3D', -16)
        ];
        $this->basis[] = [
            'a' => new BigInteger('114CA50F7A8E2F3F657C1108D9D44CFD8', -16),
            'b' => new BigInteger('3086D221A7D46BCDE86C90E49284EB15', -16)
        ];
        $this->beta = $this->factory->newInteger(new BigInteger('7AE96A2B657C07106E64479EAC3434E99CF0497512F58995C1396C28719501EE', -16));
    }
}
<?php

/**
 * brainpoolP224r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP224r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF', 16));
        $this->setCoefficients(
            new BigInteger('68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43', 16),
            new BigInteger('2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B', 16)
        );
        $this->setBasePoint(
            new BigInteger('0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D', 16),
            new BigInteger('58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD', 16)
        );
        $this->setOrder(new BigInteger('D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F', 16));
    }
}
<?php

/**
 * brainpoolP320r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP320r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F9' .
                                        '2B9EC7893EC28FCD412B1F1B32E27', 16));
        $this->setCoefficients(
            new BigInteger('3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F4' .
                           '92F375A97D860EB4', 16),
            new BigInteger('520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD88453981' .
                           '6F5EB4AC8FB1F1A6', 16)
        );
        $this->setBasePoint(
            new BigInteger('43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C7' .
                           '10AF8D0D39E20611', 16),
            new BigInteger('14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7' .
                           'D35245D1692E8EE1', 16)
        );
        $this->setOrder(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D4' .
                                       '82EC7EE8658E98691555B44C59311', 16));
    }
}
<?php

/**
 * sect283r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wiggint  on <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect283r1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(283, 12, 7, 5, 0);
        $this->setCoefficients(
            '000000000000000000000000000000000000000000000000000000000000000000000001',
            '027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5'
        );
        $this->setBasePoint(
            '05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053',
            '03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4'
        );
        $this->setOrder(new BigInteger('03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307', 16));
    }
}
<?php

/**
 * sect163k1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect163k1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(163, 7, 6, 3, 0);
        $this->setCoefficients(
            '000000000000000000000000000000000000000001',
            '000000000000000000000000000000000000000001'
        );
        $this->setBasePoint(
            '02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8',
            '0289070FB05D38FF58321F2E800536D538CCDAA3D9'
        );
        $this->setOrder(new BigInteger('04000000000000000000020108A2E0CC0D99F8A5EF', 16));
    }
}
<?php

/**
 * sect163r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect163r1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(163, 7, 6, 3, 0);
        $this->setCoefficients(
            '07B6882CAAEFA84F9554FF8428BD88E246D2782AE2',
            '0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9'
        );
        $this->setBasePoint(
            '0369979697AB43897789566789567F787A7876A654',
            '00435EDB42EFAFB2989D51FEFCE3C80988F41FF883'
        );
        $this->setOrder(new BigInteger('03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B', 16));
    }
}
<?php

/**
 * nistp384
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistp384 extends secp384r1
{
}
<?php

/**
 * nistk409
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistk409 extends sect409k1
{
}
<?php

/**
 * secp128r2
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class secp128r2 extends Prime
{
    public function __construct()
    {
        // same as secp128r1
        $this->setModulo(new BigInteger('FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF', 16));
        $this->setCoefficients(
            new BigInteger('D6031998D1B3BBFEBF59CC9BBFF9AEE1', 16),
            new BigInteger('5EEEFCA380D02919DC2C6558BB6D8A5D', 16)
        );
        $this->setBasePoint(
            new BigInteger('7B6AA5D85E572983E6FB32A7CDEBC140', 16),
            new BigInteger('27B6916A894D3AEE7106FE805FC34B44', 16)
        );
        $this->setOrder(new BigInteger('3FFFFFFF7FFFFFFFBE0024720613B5A3', 16));
    }
}
<?php

/**
 * sect239k1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wiggint  on <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect239k1 extends Binary
{
    public function __construct()
    {
        $this->setModulo(239, 158, 0);
        $this->setCoefficients(
            '000000000000000000000000000000000000000000000000000000000000',
            '000000000000000000000000000000000000000000000000000000000001'
        );
        $this->setBasePoint(
            '29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC',
            '76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA'
        );
        $this->setOrder(new BigInteger('2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5', 16));
    }
}
<?php

/**
 * prime192v1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class prime192v1 extends secp192r1
{
}
<?php

/**
 * nistb233
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistb233 extends sect233r1
{
}
<?php

/**
 * brainpoolP192r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP192r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297', 16));
        $this->setCoefficients(
            new BigInteger('6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF', 16),
            new BigInteger('469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9', 16)
        );
        $this->setBasePoint(
            new BigInteger('C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6', 16),
            new BigInteger('14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F', 16)
        );
        $this->setOrder(new BigInteger('C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1', 16));
    }
}
<?php

/**
 * secp160r2
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class secp160r2 extends Prime
{
    public function __construct()
    {
        // same as secp160k1
        $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73', 16));
        $this->setCoefficients(
            new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70', 16),
            new BigInteger('B4E134D3FB59EB8BAB57274904664D5AF50388BA', 16)
        );
        $this->setBasePoint(
            new BigInteger('52DCB034293A117E1F4FF11B30F7199D3144CE6D', 16),
            new BigInteger('FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E', 16)
        );
        $this->setOrder(new BigInteger('0100000000000000000000351EE786A818F3A1A16B', 16));
    }
}
<?php

/**
 * sect163r2
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect163r2 extends Binary
{
    public function __construct()
    {
        $this->setModulo(163, 7, 6, 3, 0);
        $this->setCoefficients(
            '000000000000000000000000000000000000000001',
            '020A601907B8C953CA1481EB10512F78744A3205FD'
        );
        $this->setBasePoint(
            '03F0EBA16286A2D57EA0991168D4994637E8343E36',
            '00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1'
        );
        $this->setOrder(new BigInteger('040000000000000000000292FE77E70C12A4234C33', 16));
    }
}
<?php

/**
 * nistk233
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistk233 extends sect233k1
{
}
<?php

/**
 * secp192k1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\KoblitzPrime;
use phpseclib3\Math\BigInteger;

class secp192k1 extends KoblitzPrime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37', 16));
        $this->setCoefficients(
            new BigInteger('000000000000000000000000000000000000000000000000', 16),
            new BigInteger('000000000000000000000000000000000000000000000003', 16)
        );
        $this->setBasePoint(
            new BigInteger('DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D', 16),
            new BigInteger('9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D', 16)
        );
        $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D', 16));

        $this->basis = [];
        $this->basis[] = [
            'a' => new BigInteger('00B3FB3400DEC5C4ADCEB8655C', -16),
            'b' => new BigInteger('8EE96418CCF4CFC7124FDA0F', -16)
        ];
        $this->basis[] = [
            'a' => new BigInteger('01D90D03E8F096B9948B20F0A9', -16),
            'b' => new BigInteger('42E49819ABBA9474E1083F6B', -16)
        ];
        $this->beta = $this->factory->newInteger(new BigInteger('447A96E6C647963E2F7809FEAAB46947F34B0AA3CA0BBA74', -16));
    }
}
<?php

/**
 * sect131r2
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Binary;
use phpseclib3\Math\BigInteger;

class sect131r2 extends Binary
{
    public function __construct()
    {
        $this->setModulo(131, 8, 3, 2, 0);
        $this->setCoefficients(
            '03E5A88919D7CAFCBF415F07C2176573B2',
            '04B8266A46C55657AC734CE38F018F2192'
        );
        $this->setBasePoint(
            '0356DCD8F2F95031AD652D23951BB366A8',
            '0648F06D867940A5366D9E265DE9EB240F'
        );
        $this->setOrder(new BigInteger('0400000000000000016954A233049BA98F', 16));
    }
}
<?php

/**
 * brainpoolP192t1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class brainpoolP192t1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297', 16));
        $this->setCoefficients(
            new BigInteger('C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294', 16), // eg. -3
            new BigInteger('13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79', 16)
        );
        $this->setBasePoint(
            new BigInteger('3AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129', 16),
            new BigInteger('097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9', 16)
        );
        $this->setOrder(new BigInteger('C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1', 16));
    }
}
<?php

/**
 * secp256r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class secp256r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF', 16));
        $this->setCoefficients(
            new BigInteger('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC', 16),
            new BigInteger('5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B', 16)
        );
        $this->setBasePoint(
            new BigInteger('6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296', 16),
            new BigInteger('4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5', 16)
        );
        $this->setOrder(new BigInteger('FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551', 16));
    }
}
<?php

/**
 * secp112r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class secp112r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('DB7C2ABF62E35E668076BEAD208B', 16));
        $this->setCoefficients(
            new BigInteger('DB7C2ABF62E35E668076BEAD2088', 16),
            new BigInteger('659EF8BA043916EEDE8911702B22', 16)
        );
        $this->setBasePoint(
            new BigInteger('09487239995A5EE76B55F9C2F098', 16),
            new BigInteger('A89CE5AF8724C0A23E0E0FF77500', 16)
        );
        $this->setOrder(new BigInteger('DB7C2ABF62E35E7628DFAC6561C5', 16));
    }
}
<?php

/**
 * prime192v3
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class prime192v3 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF', 16));
        $this->setCoefficients(
            new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC', 16),
            new BigInteger('22123DC2395A05CAA7423DAECCC94760A7D462256BD56916', 16)
        );
        $this->setBasePoint(
            new BigInteger('7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896', 16),
            new BigInteger('38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0', 16)
        );
        $this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13', 16));
    }
}
<?php

/**
 * secp160r1
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

use phpseclib3\Crypt\EC\BaseCurves\Prime;
use phpseclib3\Math\BigInteger;

class secp160r1 extends Prime
{
    public function __construct()
    {
        $this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF', 16));
        $this->setCoefficients(
            new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC', 16),
            new BigInteger('1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45', 16)
        );
        $this->setBasePoint(
            new BigInteger('4A96B5688EF573284664698968C38BB913CBFC82', 16),
            new BigInteger('23A628553168947D59DCC912042351377AC5FB32', 16)
        );
        $this->setOrder(new BigInteger('0100000000000000000001F4C8F927AED3CA752257', 16));
    }
}
<?php

/**
 * nistt571
 *
 * PHP version 5 and 7
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2017 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://pear.php.net/package/Math_BigInteger
 */

namespace phpseclib3\Crypt\EC\Curves;

final class nistt571 extends sect571k1
{
}
<?php

/**
 * Pure-PHP implementation of Rijndael.
 *
 * Uses mcrypt, if available/possible, and an internal implementation, otherwise.
 *
 * PHP version 5
 *
 * If {@link self::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits.  If
 * {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
 * {@link self::setKey() setKey()}.  ie. if the key is 128-bits, the key length will be 128-bits.  If it's
 * 136-bits it'll be null-padded to 192-bits and 192 bits will be the key length until
 * {@link self::setKey() setKey()} is called, again, at which point, it'll be recalculated.
 *
 * Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length.  mcrypt, for example,
 * does not.  AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
 * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
 * algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224.  Indeed, 160 and 224
 * are first defined as valid key / block lengths in
 * {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
 * Extensions: Other block and Cipher Key lengths.
 * Note: Use of 160/224-bit Keys must be explicitly set by setKeyLength(160) respectively setKeyLength(224).
 *
 * {@internal The variable names are the same as those in
 * {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}}
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $rijndael = new \phpseclib3\Crypt\Rijndael('ctr');
 *
 *    $rijndael->setKey('abcdefghijklmnop');
 *
 *    $size = 10 * 1024;
 *    $plaintext = '';
 *    for ($i = 0; $i < $size; $i++) {
 *        $plaintext.= 'a';
 *    }
 *
 *    echo $rijndael->decrypt($rijndael->encrypt($plaintext));
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2008 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\BlockCipher;
use phpseclib3\Exception\BadDecryptionException;
use phpseclib3\Exception\BadModeException;
use phpseclib3\Exception\InconsistentSetupException;
use phpseclib3\Exception\InsufficientSetupException;

/**
 * Pure-PHP implementation of Rijndael.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Rijndael extends BlockCipher
{
    /**
     * The mcrypt specific name of the cipher
     *
     * Mcrypt is useable for 128/192/256-bit $block_size/$key_length. For 160/224 not.
     * \phpseclib3\Crypt\Rijndael determines automatically whether mcrypt is useable
     * or not for the current $block_size/$key_length.
     * In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly.
     *
     * @see Common\SymmetricKey::cipher_name_mcrypt
     * @see Common\SymmetricKey::engine
     * @see self::isValidEngine()
     * @var string
     */
    protected $cipher_name_mcrypt = 'rijndael-128';

    /**
     * The Key Schedule
     *
     * @see self::setup()
     * @var array
     */
    private $w;

    /**
     * The Inverse Key Schedule
     *
     * @see self::setup()
     * @var array
     */
    private $dw;

    /**
     * The Block Length divided by 32
     *
     * {@internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4.  Exists in conjunction with $block_size
     *    because the encryption / decryption / key schedule creation requires this number and not $block_size.  We could
     *    derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
     *    of that, we'll just precompute it once.}
     *
     * @see self::setBlockLength()
     * @var int
     */
    private $Nb = 4;

    /**
     * The Key Length (in bytes)
     *
     * {@internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16.  Exists in conjunction with $Nk
     *    because the encryption / decryption / key schedule creation requires this number and not $key_length.  We could
     *    derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
     *    of that, we'll just precompute it once.}
     *
     * @see self::setKeyLength()
     * @var int
     */
    protected $key_length = 16;

    /**
     * The Key Length divided by 32
     *
     * @see self::setKeyLength()
     * @var int
     * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
     */
    private $Nk = 4;

    /**
     * The Number of Rounds
     *
     * {@internal The max value is 14, the min value is 10.}
     *
     * @var int
     */
    private $Nr;

    /**
     * Shift offsets
     *
     * @var array
     */
    private $c;

    /**
     * Holds the last used key- and block_size information
     *
     * @var array
     */
    private $kl;

    /**
     * Default Constructor.
     *
     * @param string $mode
     * @throws \InvalidArgumentException if an invalid / unsupported mode is provided
     */
    public function __construct($mode)
    {
        parent::__construct($mode);

        if ($this->mode == self::MODE_STREAM) {
            throw new BadModeException('Block ciphers cannot be ran in stream mode');
        }
    }

    /**
     * Sets the key length.
     *
     * Valid key lengths are 128, 160, 192, 224, and 256.
     *
     * Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
     *       and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
     *       192/256 bits as, for example, mcrypt will do.
     *
     *       That said, if you want be compatible with other Rijndael and AES implementations,
     *       you should not setKeyLength(160) or setKeyLength(224).
     *
     * Additional: In case of 160- and 224-bit keys, phpseclib will/can, for that reason, not use
     *             the mcrypt php extension, even if available.
     *             This results then in slower encryption.
     *
     * @throws \LengthException if the key length is invalid
     * @param int $length
     */
    public function setKeyLength($length)
    {
        switch ($length) {
            case 128:
            case 160:
            case 192:
            case 224:
            case 256:
                $this->key_length = $length >> 3;
                break;
            default:
                throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128, 160, 192, 224 or 256 bits are supported');
        }

        parent::setKeyLength($length);
    }

    /**
     * Sets the key.
     *
     * Rijndael supports five different key lengths
     *
     * @see setKeyLength()
     * @param string $key
     * @throws \LengthException if the key length isn't supported
     */
    public function setKey($key)
    {
        switch (strlen($key)) {
            case 16:
            case 20:
            case 24:
            case 28:
            case 32:
                break;
            default:
                throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 20, 24, 28 or 32 are supported');
        }

        parent::setKey($key);
    }

    /**
     * Sets the block length
     *
     * Valid block lengths are 128, 160, 192, 224, and 256.
     *
     * @param int $length
     */
    public function setBlockLength($length)
    {
        switch ($length) {
            case 128:
            case 160:
            case 192:
            case 224:
            case 256:
                break;
            default:
                throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128, 160, 192, 224 or 256 bits are supported');
        }

        $this->Nb = $length >> 5;
        $this->block_size = $length >> 3;
        $this->changed = $this->nonIVChanged = true;
        $this->setEngine();
    }

    /**
     * Test for engine validity
     *
     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
     * @param int $engine
     * @return bool
     */
    protected function isValidEngineHelper($engine)
    {
        switch ($engine) {
            case self::ENGINE_LIBSODIUM:
                return function_exists('sodium_crypto_aead_aes256gcm_is_available') &&
                       sodium_crypto_aead_aes256gcm_is_available() &&
                       $this->mode == self::MODE_GCM &&
                       $this->key_length == 32 &&
                       $this->nonce && strlen($this->nonce) == 12 &&
                       $this->block_size == 16;
            case self::ENGINE_OPENSSL_GCM:
                if (!extension_loaded('openssl')) {
                    return false;
                }
                $methods = openssl_get_cipher_methods();
                return $this->mode == self::MODE_GCM &&
                       version_compare(PHP_VERSION, '7.1.0', '>=') &&
                       in_array('aes-' . $this->getKeyLength() . '-gcm', $methods) &&
                       $this->block_size == 16;
            case self::ENGINE_OPENSSL:
                if ($this->block_size != 16) {
                    return false;
                }
                $this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb';
                $this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->openssl_translate_mode();
                break;
            case self::ENGINE_MCRYPT:
                $this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
                if ($this->key_length % 8) { // is it a 160/224-bit key?
                    // mcrypt is not usable for them, only for 128/192/256-bit keys
                    return false;
                }
        }

        return parent::isValidEngineHelper($engine);
    }

    /**
     * Encrypts a block
     *
     * @param string $in
     * @return string
     */
    protected function encryptBlock($in)
    {
        static $tables;
        if (empty($tables)) {
            $tables = &$this->getTables();
        }
        $t0   = $tables[0];
        $t1   = $tables[1];
        $t2   = $tables[2];
        $t3   = $tables[3];
        $sbox = $tables[4];

        $state = [];
        $words = unpack('N*', $in);

        $c = $this->c;
        $w = $this->w;
        $Nb = $this->Nb;
        $Nr = $this->Nr;

        // addRoundKey
        $wc = $Nb - 1;
        foreach ($words as $word) {
            $state[] = $word ^ $w[++$wc];
        }

        // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
        // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
        // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
        // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
        // Unfortunately, the description given there is not quite correct.  Per aes.spec.v316.pdf#page=19 [1],
        // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.

        // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
        $temp = [];
        for ($round = 1; $round < $Nr; ++$round) {
            $i = 0; // $c[0] == 0
            $j = $c[1];
            $k = $c[2];
            $l = $c[3];

            while ($i < $Nb) {
                $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^
                            $t1[$state[$j] >> 16 & 0x000000FF] ^
                            $t2[$state[$k] >>  8 & 0x000000FF] ^
                            $t3[$state[$l]       & 0x000000FF] ^
                            $w[++$wc];
                ++$i;
                $j = ($j + 1) % $Nb;
                $k = ($k + 1) % $Nb;
                $l = ($l + 1) % $Nb;
            }
            $state = $temp;
        }

        // subWord
        for ($i = 0; $i < $Nb; ++$i) {
            $state[$i] =   $sbox[$state[$i]       & 0x000000FF]        |
                          ($sbox[$state[$i] >>  8 & 0x000000FF] <<  8) |
                          ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) |
                          ($sbox[$state[$i] >> 24 & 0x000000FF] << 24);
        }

        // shiftRows + addRoundKey
        $i = 0; // $c[0] == 0
        $j = $c[1];
        $k = $c[2];
        $l = $c[3];
        while ($i < $Nb) {
            $temp[$i] = ($state[$i] & (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216)) ^
                        ($state[$j] & 0x00FF0000) ^
                        ($state[$k] & 0x0000FF00) ^
                        ($state[$l] & 0x000000FF) ^
                         $w[$i];
            ++$i;
            $j = ($j + 1) % $Nb;
            $k = ($k + 1) % $Nb;
            $l = ($l + 1) % $Nb;
        }

        return pack('N*', ...$temp);
    }

    /**
     * Decrypts a block
     *
     * @param string $in
     * @return string
     */
    protected function decryptBlock($in)
    {
        static $invtables;
        if (empty($invtables)) {
            $invtables = &$this->getInvTables();
        }
        $dt0   = $invtables[0];
        $dt1   = $invtables[1];
        $dt2   = $invtables[2];
        $dt3   = $invtables[3];
        $isbox = $invtables[4];

        $state = [];
        $words = unpack('N*', $in);

        $c  = $this->c;
        $dw = $this->dw;
        $Nb = $this->Nb;
        $Nr = $this->Nr;

        // addRoundKey
        $wc = $Nb - 1;
        foreach ($words as $word) {
            $state[] = $word ^ $dw[++$wc];
        }

        $temp = [];
        for ($round = $Nr - 1; $round > 0; --$round) {
            $i = 0; // $c[0] == 0
            $j = $Nb - $c[1];
            $k = $Nb - $c[2];
            $l = $Nb - $c[3];

            while ($i < $Nb) {
                $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^
                            $dt1[$state[$j] >> 16 & 0x000000FF] ^
                            $dt2[$state[$k] >>  8 & 0x000000FF] ^
                            $dt3[$state[$l]       & 0x000000FF] ^
                            $dw[++$wc];
                ++$i;
                $j = ($j + 1) % $Nb;
                $k = ($k + 1) % $Nb;
                $l = ($l + 1) % $Nb;
            }
            $state = $temp;
        }

        // invShiftRows + invSubWord + addRoundKey
        $i = 0; // $c[0] == 0
        $j = $Nb - $c[1];
        $k = $Nb - $c[2];
        $l = $Nb - $c[3];

        while ($i < $Nb) {
            $word = ($state[$i] & (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216)) |
                    ($state[$j] & 0x00FF0000) |
                    ($state[$k] & 0x0000FF00) |
                    ($state[$l] & 0x000000FF);

            $temp[$i] = $dw[$i] ^ ($isbox[$word       & 0x000000FF]        |
                                  ($isbox[$word >>  8 & 0x000000FF] <<  8) |
                                  ($isbox[$word >> 16 & 0x000000FF] << 16) |
                                  ($isbox[$word >> 24 & 0x000000FF] << 24));
            ++$i;
            $j = ($j + 1) % $Nb;
            $k = ($k + 1) % $Nb;
            $l = ($l + 1) % $Nb;
        }

        return pack('N*', ...$temp);
    }

    /**
     * Setup the self::ENGINE_INTERNAL $engine
     *
     * (re)init, if necessary, the internal cipher $engine and flush all $buffers
     * Used (only) if $engine == self::ENGINE_INTERNAL
     *
     * _setup() will be called each time if $changed === true
     * typically this happens when using one or more of following public methods:
     *
     * - setKey()
     *
     * - setIV()
     *
     * - disableContinuousBuffer()
     *
     * - First run of encrypt() / decrypt() with no init-settings
     *
     * {@internal setup() is always called before en/decryption.}
     *
     * {@internal Could, but not must, extend by the child Crypt_* class}
     *
     * @see self::setKey()
     * @see self::setIV()
     * @see self::disableContinuousBuffer()
     */
    protected function setup()
    {
        if (!$this->changed) {
            return;
        }

        parent::setup();

        if (is_string($this->iv) && strlen($this->iv) != $this->block_size) {
            throw new InconsistentSetupException('The IV length (' . strlen($this->iv) . ') does not match the block size (' . $this->block_size . ')');
        }
    }

    /**
     * Setup the key (expansion)
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::setupKey()
     */
    protected function setupKey()
    {
        // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
        // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
        static $rcon;

        if (!isset($rcon)) {
            $rcon = [0,
                0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
                0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
                0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
                0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
                0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
                0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
            ];
            $rcon = array_map([self::class, 'safe_intval'], $rcon);
        }

        if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) {
            // already expanded
            return;
        }
        $this->kl = ['key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size];

        $this->Nk = $this->key_length >> 2;
        // see Rijndael-ammended.pdf#page=44
        $this->Nr = max($this->Nk, $this->Nb) + 6;

        // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
        //     "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
        // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
        //     "Table 2: Shift offsets for different block lengths"
        switch ($this->Nb) {
            case 4:
            case 5:
            case 6:
                $this->c = [0, 1, 2, 3];
                break;
            case 7:
                $this->c = [0, 1, 2, 4];
                break;
            case 8:
                $this->c = [0, 1, 3, 4];
        }

        $w = array_values(unpack('N*words', $this->key));

        $length = $this->Nb * ($this->Nr + 1);
        for ($i = $this->Nk; $i < $length; $i++) {
            $temp = $w[$i - 1];
            if ($i % $this->Nk == 0) {
                // according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
                // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
                // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
                // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
                $temp = PHP_INT_SIZE == 8 ? // rotWord
                    (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF) :
                    ($temp << 8) | (($temp >> 24) & 0x000000FF);
                $temp = $this->subWord($temp) ^ $rcon[$i / $this->Nk];
            } elseif ($this->Nk > 6 && $i % $this->Nk == 4) {
                $temp = $this->subWord($temp);
            }
            $w[$i] = $w[$i - $this->Nk] ^ $temp;
        }

        // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
        // and generate the inverse key schedule.  more specifically,
        // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
        // "The key expansion for the Inverse Cipher is defined as follows:
        //        1. Apply the Key Expansion.
        //        2. Apply InvMixColumn to all Round Keys except the first and the last one."
        // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
        list($dt0, $dt1, $dt2, $dt3) = $this->getInvTables();
        $temp = $this->w = $this->dw = [];
        for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
            if ($col == $this->Nb) {
                if ($row == 0) {
                    $this->dw[0] = $this->w[0];
                } else {
                    // subWord + invMixColumn + invSubWord = invMixColumn
                    $j = 0;
                    while ($j < $this->Nb) {
                        $dw = $this->subWord($this->w[$row][$j]);
                        $temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^
                                    $dt1[$dw >> 16 & 0x000000FF] ^
                                    $dt2[$dw >>  8 & 0x000000FF] ^
                                    $dt3[$dw       & 0x000000FF];
                        $j++;
                    }
                    $this->dw[$row] = $temp;
                }

                $col = 0;
                $row++;
            }
            $this->w[$row][$col] = $w[$i];
        }

        $this->dw[$row] = $this->w[$row];

        // Converting to 1-dim key arrays (both ascending)
        $this->dw = array_reverse($this->dw);
        $w  = array_pop($this->w);
        $dw = array_pop($this->dw);
        foreach ($this->w as $r => $wr) {
            foreach ($wr as $c => $wc) {
                $w[]  = $wc;
                $dw[] = $this->dw[$r][$c];
            }
        }
        $this->w  = $w;
        $this->dw = $dw;
    }

    /**
     * Performs S-Box substitutions
     *
     * @return array
     * @param int $word
     */
    private function subWord($word)
    {
        static $sbox;
        if (empty($sbox)) {
            list(, , , , $sbox) = self::getTables();
        }

        return  $sbox[$word       & 0x000000FF]        |
               ($sbox[$word >>  8 & 0x000000FF] <<  8) |
               ($sbox[$word >> 16 & 0x000000FF] << 16) |
               ($sbox[$word >> 24 & 0x000000FF] << 24);
    }

    /**
     * Provides the mixColumns and sboxes tables
     *
     * @see self::encryptBlock()
     * @see self::setupInlineCrypt()
     * @see self::subWord()
     * @return array &$tables
     */
    protected function &getTables()
    {
        static $tables;
        if (empty($tables)) {
            // according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
            // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
            // those are the names we'll use.
            $t3 = array_map([self::class, 'safe_intval'], [
                // with array_map('intval', ...) we ensure we have only int's and not
                // some slower floats converted by php automatically on high values
                0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
                0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
                0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
                0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
                0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
                0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
                0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
                0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
                0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
                0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
                0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
                0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
                0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
                0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
                0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
                0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
                0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
                0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
                0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
                0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
                0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
                0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
                0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
                0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
                0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
                0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
                0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
                0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
                0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
                0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
                0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
                0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
            ]);

            foreach ($t3 as $t3i) {
                $t0[] = (($t3i << 24) & self::safe_intval(0xFF000000)) | (($t3i >>  8) & 0x00FFFFFF);
                $t1[] = (($t3i << 16) & self::safe_intval(0xFFFF0000)) | (($t3i >> 16) & 0x0000FFFF);
                $t2[] = (($t3i <<  8) & self::safe_intval(0xFFFFFF00)) | (($t3i >> 24) & 0x000000FF);
            }

            $tables = [
                // The Precomputed mixColumns tables t0 - t3
                $t0,
                $t1,
                $t2,
                $t3,
                // The SubByte S-Box
                [
                    0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
                    0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
                    0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
                    0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
                    0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
                    0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
                    0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
                    0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
                    0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
                    0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
                    0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
                    0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
                    0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
                    0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
                    0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
                    0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
                ]
            ];
        }
        return $tables;
    }

    /**
     * Provides the inverse mixColumns and inverse sboxes tables
     *
     * @see self::decryptBlock()
     * @see self::setupInlineCrypt()
     * @see self::setupKey()
     * @return array &$tables
     */
    protected function &getInvTables()
    {
        static $tables;
        if (empty($tables)) {
            $dt3 = array_map([self::class, 'safe_intval'], [
                0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
                0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
                0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
                0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
                0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
                0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
                0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
                0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
                0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
                0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
                0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
                0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
                0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
                0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
                0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
                0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
                0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
                0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
                0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
                0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
                0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
                0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
                0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
                0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
                0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
                0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
                0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
                0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
                0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
                0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
                0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
                0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
            ]);

            if (PHP_INT_SIZE === 8) {
                foreach ($dt3 as $dt3i) {
                    $dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >>  8) & 0x00FFFFFF);
                    $dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF);
                    $dt2[] = (($dt3i <<  8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF);
                };
            } else {
                foreach ($dt3 as $dt3i) {
                    $dt0[] = ($dt3i << 24) | (($dt3i >>  8) & 0x00FFFFFF);
                    $dt1[] = ($dt3i << 16) | (($dt3i >> 16) & 0x0000FFFF);
                    $dt2[] = ($dt3i <<  8) | (($dt3i >> 24) & 0x000000FF);
                };
            }

            $tables = [
                // The Precomputed inverse mixColumns tables dt0 - dt3
                $dt0,
                $dt1,
                $dt2,
                $dt3,
                // The inverse SubByte S-Box
                [
                    0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
                    0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
                    0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
                    0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
                    0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
                    0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
                    0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
                    0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
                    0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
                    0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
                    0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
                    0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
                    0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
                    0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
                    0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
                    0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
                ]
            ];
        }
        return $tables;
    }

    /**
     * Setup the performance-optimized function for de/encrypt()
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::setupInlineCrypt()
     */
    protected function setupInlineCrypt()
    {
        $w  = $this->w;
        $dw = $this->dw;
        $init_encrypt = '';
        $init_decrypt = '';

        $Nr = $this->Nr;
        $Nb = $this->Nb;
        $c  = $this->c;

        // Generating encrypt code:
        $init_encrypt .= '
            if (empty($tables)) {
                $tables = &$this->getTables();
            }
            $t0   = $tables[0];
            $t1   = $tables[1];
            $t2   = $tables[2];
            $t3   = $tables[3];
            $sbox = $tables[4];
        ';

        $s  = 'e';
        $e  = 's';
        $wc = $Nb - 1;

        // Preround: addRoundKey
        $encrypt_block = '$in = unpack("N*", $in);' . "\n";
        for ($i = 0; $i < $Nb; ++$i) {
            $encrypt_block .= '$s' . $i . ' = $in[' . ($i + 1) . '] ^ ' . $w[++$wc] . ";\n";
        }

        // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
        for ($round = 1; $round < $Nr; ++$round) {
            list($s, $e) = [$e, $s];
            for ($i = 0; $i < $Nb; ++$i) {
                $encrypt_block .=
                    '$' . $e . $i . ' =
                    $t0[($' . $s . $i                  . ' >> 24) & 0xff] ^
                    $t1[($' . $s . (($i + $c[1]) % $Nb) . ' >> 16) & 0xff] ^
                    $t2[($' . $s . (($i + $c[2]) % $Nb) . ' >>  8) & 0xff] ^
                    $t3[ $' . $s . (($i + $c[3]) % $Nb) . '        & 0xff] ^
                    ' . $w[++$wc] . ";\n";
            }
        }

        // Finalround: subWord + shiftRows + addRoundKey
        for ($i = 0; $i < $Nb; ++$i) {
            $encrypt_block .=
                '$' . $e . $i . ' =
                 $sbox[ $' . $e . $i . '        & 0xff]        |
                ($sbox[($' . $e . $i . ' >>  8) & 0xff] <<  8) |
                ($sbox[($' . $e . $i . ' >> 16) & 0xff] << 16) |
                ($sbox[($' . $e . $i . ' >> 24) & 0xff] << 24);' . "\n";
        }
        $encrypt_block .= '$in = pack("N*"' . "\n";
        for ($i = 0; $i < $Nb; ++$i) {
            $encrypt_block .= ',
                ($' . $e . $i                   . ' & ' . (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216) . ') ^
                ($' . $e . (($i + $c[1]) % $Nb) . ' &         0x00FF0000   ) ^
                ($' . $e . (($i + $c[2]) % $Nb) . ' &         0x0000FF00   ) ^
                ($' . $e . (($i + $c[3]) % $Nb) . ' &         0x000000FF   ) ^
                ' . $w[$i] . "\n";
        }
        $encrypt_block .= ');';

        // Generating decrypt code:
        $init_decrypt .= '
            if (empty($invtables)) {
                $invtables = &$this->getInvTables();
            }
            $dt0   = $invtables[0];
            $dt1   = $invtables[1];
            $dt2   = $invtables[2];
            $dt3   = $invtables[3];
            $isbox = $invtables[4];
        ';

        $s  = 'e';
        $e  = 's';
        $wc = $Nb - 1;

        // Preround: addRoundKey
        $decrypt_block = '$in = unpack("N*", $in);' . "\n";
        for ($i = 0; $i < $Nb; ++$i) {
            $decrypt_block .= '$s' . $i . ' = $in[' . ($i + 1) . '] ^ ' . $dw[++$wc] . ';' . "\n";
        }

        // Mainrounds: shiftRows + subWord + mixColumns + addRoundKey
        for ($round = 1; $round < $Nr; ++$round) {
            list($s, $e) = [$e, $s];
            for ($i = 0; $i < $Nb; ++$i) {
                $decrypt_block .=
                    '$' . $e . $i . ' =
                    $dt0[($' . $s . $i                        . ' >> 24) & 0xff] ^
                    $dt1[($' . $s . (($Nb + $i - $c[1]) % $Nb) . ' >> 16) & 0xff] ^
                    $dt2[($' . $s . (($Nb + $i - $c[2]) % $Nb) . ' >>  8) & 0xff] ^
                    $dt3[ $' . $s . (($Nb + $i - $c[3]) % $Nb) . '        & 0xff] ^
                    ' . $dw[++$wc] . ";\n";
            }
        }

        // Finalround: subWord + shiftRows + addRoundKey
        for ($i = 0; $i < $Nb; ++$i) {
            $decrypt_block .=
                '$' . $e . $i . ' =
                 $isbox[ $' . $e . $i . '        & 0xff]        |
                ($isbox[($' . $e . $i . ' >>  8) & 0xff] <<  8) |
                ($isbox[($' . $e . $i . ' >> 16) & 0xff] << 16) |
                ($isbox[($' . $e . $i . ' >> 24) & 0xff] << 24);' . "\n";
        }
        $decrypt_block .= '$in = pack("N*"' . "\n";
        for ($i = 0; $i < $Nb; ++$i) {
            $decrypt_block .= ',
                ($' . $e . $i .                         ' & ' . (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216) . ') ^
                ($' . $e . (($Nb + $i - $c[1]) % $Nb) . ' &         0x00FF0000   ) ^
                ($' . $e . (($Nb + $i - $c[2]) % $Nb) . ' &         0x0000FF00   ) ^
                ($' . $e . (($Nb + $i - $c[3]) % $Nb) . ' &         0x000000FF   ) ^
                ' . $dw[$i] . "\n";
        }
        $decrypt_block .= ');';

        $this->inline_crypt = $this->createInlineCryptFunction(
            [
               'init_crypt'    => 'static $tables; static $invtables;',
               'init_encrypt'  => $init_encrypt,
               'init_decrypt'  => $init_decrypt,
               'encrypt_block' => $encrypt_block,
               'decrypt_block' => $decrypt_block
            ]
        );
    }

    /**
     * Encrypts a message.
     *
     * @see self::decrypt()
     * @see parent::encrypt()
     * @param string $plaintext
     * @return string
     */
    public function encrypt($plaintext)
    {
        $this->setup();

        switch ($this->engine) {
            case self::ENGINE_LIBSODIUM:
                $this->newtag = sodium_crypto_aead_aes256gcm_encrypt($plaintext, $this->aad, $this->nonce, $this->key);
                return Strings::shift($this->newtag, strlen($plaintext));
            case self::ENGINE_OPENSSL_GCM:
                return openssl_encrypt(
                    $plaintext,
                    'aes-' . $this->getKeyLength() . '-gcm',
                    $this->key,
                    OPENSSL_RAW_DATA,
                    $this->nonce,
                    $this->newtag,
                    $this->aad
                );
        }

        return parent::encrypt($plaintext);
    }

    /**
     * Decrypts a message.
     *
     * @see self::encrypt()
     * @see parent::decrypt()
     * @param string $ciphertext
     * @return string
     */
    public function decrypt($ciphertext)
    {
        $this->setup();

        switch ($this->engine) {
            case self::ENGINE_LIBSODIUM:
                if ($this->oldtag === false) {
                    throw new InsufficientSetupException('Authentication Tag has not been set');
                }
                if (strlen($this->oldtag) != 16) {
                    break;
                }
                $plaintext = sodium_crypto_aead_aes256gcm_decrypt($ciphertext . $this->oldtag, $this->aad, $this->nonce, $this->key);
                if ($plaintext === false) {
                    $this->oldtag = false;
                    throw new BadDecryptionException('Error decrypting ciphertext with libsodium');
                }
                return $plaintext;
            case self::ENGINE_OPENSSL_GCM:
                if ($this->oldtag === false) {
                    throw new InsufficientSetupException('Authentication Tag has not been set');
                }
                $plaintext = openssl_decrypt(
                    $ciphertext,
                    'aes-' . $this->getKeyLength() . '-gcm',
                    $this->key,
                    OPENSSL_RAW_DATA,
                    $this->nonce,
                    $this->oldtag,
                    $this->aad
                );
                if ($plaintext === false) {
                    $this->oldtag = false;
                    throw new BadDecryptionException('Error decrypting ciphertext with OpenSSL');
                }
                return $plaintext;
        }

        return parent::decrypt($ciphertext);
    }
}
<?php

/**
 * Pure-PHP implementation of RC2.
 *
 * Uses mcrypt, if available, and an internal implementation, otherwise.
 *
 * PHP version 5
 *
 * Useful resources are as follows:
 *
 *  - {@link http://tools.ietf.org/html/rfc2268}
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $rc2 = new \phpseclib3\Crypt\RC2('ctr');
 *
 *    $rc2->setKey('abcdefgh');
 *
 *    $plaintext = str_repeat('a', 1024);
 *
 *    echo $rc2->decrypt($rc2->encrypt($plaintext));
 * ?>
 * </code>
 *
 * @author   Patrick Monnerat <pm@datasphere.ch>
 * @license  http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link     http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Crypt\Common\BlockCipher;
use phpseclib3\Exception\BadModeException;

/**
 * Pure-PHP implementation of RC2.
 *
 */
class RC2 extends BlockCipher
{
    /**
     * Block Length of the cipher
     *
     * @see Common\SymmetricKey::block_size
     * @var int
     */
    protected $block_size = 8;

    /**
     * The Key
     *
     * @see Common\SymmetricKey::key
     * @see self::setKey()
     * @var string
     */
    protected $key;

    /**
     * The Original (unpadded) Key
     *
     * @see Common\SymmetricKey::key
     * @see self::setKey()
     * @see self::encrypt()
     * @see self::decrypt()
     * @var string
     */
    private $orig_key;

    /**
     * Key Length (in bytes)
     *
     * @see \phpseclib3\Crypt\RC2::setKeyLength()
     * @var int
     */
    protected $key_length = 16; // = 128 bits

    /**
     * The mcrypt specific name of the cipher
     *
     * @see Common\SymmetricKey::cipher_name_mcrypt
     * @var string
     */
    protected $cipher_name_mcrypt = 'rc2';

    /**
     * Optimizing value while CFB-encrypting
     *
     * @see Common\SymmetricKey::cfb_init_len
     * @var int
     */
    protected $cfb_init_len = 500;

    /**
     * The key length in bits.
     *
     * {@internal Should be in range [1..1024].}
     *
     * {@internal Changing this value after setting the key has no effect.}
     *
     * @see self::setKeyLength()
     * @see self::setKey()
     * @var int
     */
    private $default_key_length = 1024;

    /**
     * The key length in bits.
     *
     * {@internal Should be in range [1..1024].}
     *
     * @see self::isValidEnine()
     * @see self::setKey()
     * @var int
     */
    private $current_key_length;

    /**
     * The Key Schedule
     *
     * @see self::setupKey()
     * @var array
     */
    private $keys;

    /**
     * Key expansion randomization table.
     * Twice the same 256-value sequence to save a modulus in key expansion.
     *
     * @see self::setKey()
     * @var array
     */
    private static $pitable = [
        0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
        0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
        0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
        0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
        0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
        0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
        0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
        0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
        0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
        0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
        0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
        0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
        0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
        0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
        0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
        0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
        0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
        0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
        0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
        0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
        0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
        0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
        0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
        0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
        0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
        0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
        0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
        0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
        0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
        0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
        0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
        0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD,
        0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED,
        0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D,
        0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E,
        0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2,
        0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13,
        0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32,
        0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B,
        0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82,
        0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C,
        0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC,
        0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1,
        0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26,
        0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57,
        0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03,
        0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7,
        0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7,
        0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7,
        0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A,
        0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74,
        0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC,
        0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC,
        0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39,
        0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A,
        0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31,
        0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE,
        0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9,
        0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C,
        0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9,
        0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0,
        0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E,
        0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77,
        0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD
    ];

    /**
     * Inverse key expansion randomization table.
     *
     * @see self::setKey()
     * @var array
     */
    private static $invpitable = [
        0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66,
        0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4,
        0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20,
        0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53,
        0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68,
        0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B,
        0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12,
        0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB,
        0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3,
        0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26,
        0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67,
        0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB,
        0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC,
        0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60,
        0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7,
        0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD,
        0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24,
        0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31,
        0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE,
        0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99,
        0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C,
        0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA,
        0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35,
        0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61,
        0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72,
        0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3,
        0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F,
        0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9,
        0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77,
        0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75,
        0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87,
        0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
    ];

    /**
     * Default Constructor.
     *
     * @param string $mode
     * @throws \InvalidArgumentException if an invalid / unsupported mode is provided
     */
    public function __construct($mode)
    {
        parent::__construct($mode);

        if ($this->mode == self::MODE_STREAM) {
            throw new BadModeException('Block ciphers cannot be ran in stream mode');
        }
    }

    /**
     * Test for engine validity
     *
     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
     *
     * @see Common\SymmetricKey::__construct()
     * @param int $engine
     * @return bool
     */
    protected function isValidEngineHelper($engine)
    {
        switch ($engine) {
            case self::ENGINE_OPENSSL:
                if ($this->current_key_length != 128 || strlen($this->orig_key) < 16) {
                    return false;
                }
                // quoting https://www.openssl.org/news/openssl-3.0-notes.html, OpenSSL 3.0.1
                // "Moved all variations of the EVP ciphers CAST5, BF, IDEA, SEED, RC2, RC4, RC5, and DES to the legacy provider"
                // in theory openssl_get_cipher_methods() should catch this but, on GitHub Actions, at least, it does not
                if (defined('OPENSSL_VERSION_TEXT') && version_compare(preg_replace('#OpenSSL (\d+\.\d+\.\d+) .*#', '$1', OPENSSL_VERSION_TEXT), '3.0.1', '>=')) {
                    return false;
                }
                $this->cipher_name_openssl_ecb = 'rc2-ecb';
                $this->cipher_name_openssl = 'rc2-' . $this->openssl_translate_mode();
        }

        return parent::isValidEngineHelper($engine);
    }

    /**
     * Sets the key length.
     *
     * Valid key lengths are 8 to 1024.
     * Calling this function after setting the key has no effect until the next
     *  \phpseclib3\Crypt\RC2::setKey() call.
     *
     * @param int $length in bits
     * @throws \LengthException if the key length isn't supported
     */
    public function setKeyLength($length)
    {
        if ($length < 8 || $length > 1024) {
            throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported');
        }

        $this->default_key_length = $this->current_key_length = $length;
        $this->explicit_key_length = $length >> 3;
    }

    /**
     * Returns the current key length
     *
     * @return int
     */
    public function getKeyLength()
    {
        return $this->current_key_length;
    }

    /**
     * Sets the key.
     *
     * Keys can be of any length. RC2, itself, uses 8 to 1024 bit keys (eg.
     * strlen($key) <= 128), however, we only use the first 128 bytes if $key
     * has more then 128 bytes in it, and set $key to a single null byte if
     * it is empty.
     *
     * @see Common\SymmetricKey::setKey()
     * @param string $key
     * @param int|boolean $t1 optional Effective key length in bits.
     * @throws \LengthException if the key length isn't supported
     */
    public function setKey($key, $t1 = false)
    {
        $this->orig_key = $key;

        if ($t1 === false) {
            $t1 = $this->default_key_length;
        }

        if ($t1 < 1 || $t1 > 1024) {
            throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported');
        }

        $this->current_key_length = $t1;
        if (strlen($key) < 1 || strlen($key) > 128) {
            throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes between 8 and 1024 bits, inclusive, are supported');
        }

        $t = strlen($key);

        // The mcrypt RC2 implementation only supports effective key length
        // of 1024 bits. It is however possible to handle effective key
        // lengths in range 1..1024 by expanding the key and applying
        // inverse pitable mapping to the first byte before submitting it
        // to mcrypt.

        // Key expansion.
        $l = array_values(unpack('C*', $key));
        $t8 = ($t1 + 7) >> 3;
        $tm = 0xFF >> (8 * $t8 - $t1);

        // Expand key.
        $pitable = self::$pitable;
        for ($i = $t; $i < 128; $i++) {
            $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]];
        }
        $i = 128 - $t8;
        $l[$i] = $pitable[$l[$i] & $tm];
        while ($i--) {
            $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]];
        }

        // Prepare the key for mcrypt.
        $l[0] = self::$invpitable[$l[0]];
        array_unshift($l, 'C*');

        $this->key = pack(...$l);
        $this->key_length = strlen($this->key);
        $this->changed = $this->nonIVChanged = true;
        $this->setEngine();
    }

    /**
     * Encrypts a message.
     *
     * Mostly a wrapper for \phpseclib3\Crypt\Common\SymmetricKey::encrypt, with some additional OpenSSL handling code
     *
     * @see self::decrypt()
     * @param string $plaintext
     * @return string $ciphertext
     */
    public function encrypt($plaintext)
    {
        if ($this->engine == self::ENGINE_OPENSSL) {
            $temp = $this->key;
            $this->key = $this->orig_key;
            $result = parent::encrypt($plaintext);
            $this->key = $temp;
            return $result;
        }

        return parent::encrypt($plaintext);
    }

    /**
     * Decrypts a message.
     *
     * Mostly a wrapper for \phpseclib3\Crypt\Common\SymmetricKey::decrypt, with some additional OpenSSL handling code
     *
     * @see self::encrypt()
     * @param string $ciphertext
     * @return string $plaintext
     */
    public function decrypt($ciphertext)
    {
        if ($this->engine == self::ENGINE_OPENSSL) {
            $temp = $this->key;
            $this->key = $this->orig_key;
            $result = parent::decrypt($ciphertext);
            $this->key = $temp;
            return $result;
        }

        return parent::decrypt($ciphertext);
    }

    /**
     * Encrypts a block
     *
     * @see Common\SymmetricKey::encryptBlock()
     * @see Common\SymmetricKey::encrypt()
     * @param string $in
     * @return string
     */
    protected function encryptBlock($in)
    {
        list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
        $keys = $this->keys;
        $limit = 20;
        $actions = [$limit => 44, 44 => 64];
        $j = 0;

        for (;;) {
            // Mixing round.
            $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
            $r0 |= $r0 >> 16;
            $r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
            $r1 |= $r1 >> 16;
            $r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
            $r2 |= $r2 >> 16;
            $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
            $r3 |= $r3 >> 16;

            if ($j === $limit) {
                if ($limit === 64) {
                    break;
                }

                // Mashing round.
                $r0 += $keys[$r3 & 0x3F];
                $r1 += $keys[$r0 & 0x3F];
                $r2 += $keys[$r1 & 0x3F];
                $r3 += $keys[$r2 & 0x3F];
                $limit = $actions[$limit];
            }
        }

        return pack('vvvv', $r0, $r1, $r2, $r3);
    }

    /**
     * Decrypts a block
     *
     * @see Common\SymmetricKey::decryptBlock()
     * @see Common\SymmetricKey::decrypt()
     * @param string $in
     * @return string
     */
    protected function decryptBlock($in)
    {
        list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in));
        $keys = $this->keys;
        $limit = 44;
        $actions = [$limit => 20, 20 => 0];
        $j = 64;

        for (;;) {
            // R-mixing round.
            $r3 = ($r3 | ($r3 << 16)) >> 5;
            $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
            $r2 = ($r2 | ($r2 << 16)) >> 3;
            $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
            $r1 = ($r1 | ($r1 << 16)) >> 2;
            $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
            $r0 = ($r0 | ($r0 << 16)) >> 1;
            $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;

            if ($j === $limit) {
                if ($limit === 0) {
                    break;
                }

                // R-mashing round.
                $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
                $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
                $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
                $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;
                $limit = $actions[$limit];
            }
        }

        return pack('vvvv', $r0, $r1, $r2, $r3);
    }

    /**
     * Creates the key schedule
     *
     * @see Common\SymmetricKey::setupKey()
     */
    protected function setupKey()
    {
        if (!isset($this->key)) {
            $this->setKey('');
        }

        // Key has already been expanded in \phpseclib3\Crypt\RC2::setKey():
        // Only the first value must be altered.
        $l = unpack('Ca/Cb/v*', $this->key);
        array_unshift($l, self::$pitable[$l['a']] | ($l['b'] << 8));
        unset($l['a']);
        unset($l['b']);
        $this->keys = $l;
    }

    /**
     * Setup the performance-optimized function for de/encrypt()
     *
     * @see Common\SymmetricKey::setupInlineCrypt()
     */
    protected function setupInlineCrypt()
    {
        // Init code for both, encrypt and decrypt.
        $init_crypt = '$keys = $this->keys;';

        $keys = $this->keys;

        // $in is the current 8 bytes block which has to be en/decrypt
        $encrypt_block = $decrypt_block = '
            $in = unpack("v4", $in);
            $r0 = $in[1];
            $r1 = $in[2];
            $r2 = $in[3];
            $r3 = $in[4];
        ';

        // Create code for encryption.
        $limit = 20;
        $actions = [$limit => 44, 44 => 64];
        $j = 0;

        for (;;) {
            // Mixing round.
            $encrypt_block .= '
                $r0 = (($r0 + ' . $keys[$j++] . ' +
                       ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1;
                $r0 |= $r0 >> 16;
                $r1 = (($r1 + ' . $keys[$j++] . ' +
                       ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2;
                $r1 |= $r1 >> 16;
                $r2 = (($r2 + ' . $keys[$j++] . ' +
                       ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3;
                $r2 |= $r2 >> 16;
                $r3 = (($r3 + ' . $keys[$j++] . ' +
                       ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5;
                $r3 |= $r3 >> 16;';

            if ($j === $limit) {
                if ($limit === 64) {
                    break;
                }

                // Mashing round.
                $encrypt_block .= '
                    $r0 += $keys[$r3 & 0x3F];
                    $r1 += $keys[$r0 & 0x3F];
                    $r2 += $keys[$r1 & 0x3F];
                    $r3 += $keys[$r2 & 0x3F];';
                $limit = $actions[$limit];
            }
        }

        $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';

        // Create code for decryption.
        $limit = 44;
        $actions = [$limit => 20, 20 => 0];
        $j = 64;

        for (;;) {
            // R-mixing round.
            $decrypt_block .= '
                $r3 = ($r3 | ($r3 << 16)) >> 5;
                $r3 = ($r3 - ' . $keys[--$j] . ' -
                       ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF;
                $r2 = ($r2 | ($r2 << 16)) >> 3;
                $r2 = ($r2 - ' . $keys[--$j] . ' -
                       ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF;
                $r1 = ($r1 | ($r1 << 16)) >> 2;
                $r1 = ($r1 - ' . $keys[--$j] . ' -
                       ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF;
                $r0 = ($r0 | ($r0 << 16)) >> 1;
                $r0 = ($r0 - ' . $keys[--$j] . ' -
                       ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;';

            if ($j === $limit) {
                if ($limit === 0) {
                    break;
                }

                // R-mashing round.
                $decrypt_block .= '
                    $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF;
                    $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF;
                    $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF;
                    $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;';
                $limit = $actions[$limit];
            }
        }

        $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);';

        // Creates the inline-crypt function
        $this->inline_crypt = $this->createInlineCryptFunction(
            [
               'init_crypt'    => $init_crypt,
               'encrypt_block' => $encrypt_block,
               'decrypt_block' => $decrypt_block
            ]
        );
    }
}
<?php

/**
 * Pure-PHP implementation of Twofish.
 *
 * Uses mcrypt, if available, and an internal implementation, otherwise.
 *
 * PHP version 5
 *
 * Useful resources are as follows:
 *
 *  - {@link http://en.wikipedia.org/wiki/Twofish Wikipedia description of Twofish}
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $twofish = new \phpseclib3\Crypt\Twofish('ctr');
 *
 *    $twofish->setKey('12345678901234567890123456789012');
 *
 *    $plaintext = str_repeat('a', 1024);
 *
 *    echo $twofish->decrypt($twofish->encrypt($plaintext));
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @author    Hans-Juergen Petrich <petrich@tronic-media.com>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Crypt\Common\BlockCipher;
use phpseclib3\Exception\BadModeException;

/**
 * Pure-PHP implementation of Twofish.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 * @author  Hans-Juergen Petrich <petrich@tronic-media.com>
 */
class Twofish extends BlockCipher
{
    /**
     * The mcrypt specific name of the cipher
     *
     * @see Common\SymmetricKey::cipher_name_mcrypt
     * @var string
     */
    protected $cipher_name_mcrypt = 'twofish';

    /**
     * Optimizing value while CFB-encrypting
     *
     * @see Common\SymmetricKey::cfb_init_len
     * @var int
     */
    protected $cfb_init_len = 800;

    /**
     * Q-Table
     *
     * @var array
     */
    private static $q0 = [
        0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76,
        0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38,
        0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
        0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48,
        0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23,
        0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
        0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C,
        0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61,
        0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
        0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1,
        0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66,
        0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
        0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA,
        0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71,
        0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
        0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7,
        0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2,
        0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
        0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB,
        0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF,
        0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
        0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64,
        0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A,
        0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
        0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02,
        0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D,
        0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
        0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
        0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8,
        0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
        0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00,
        0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0
    ];

    /**
     * Q-Table
     *
     * @var array
     */
    private static $q1 = [
        0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8,
        0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B,
        0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
        0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F,
        0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D,
        0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
        0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3,
        0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51,
        0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
        0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C,
        0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70,
        0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
        0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC,
        0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2,
        0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
        0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17,
        0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3,
        0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
        0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49,
        0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9,
        0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
        0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48,
        0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19,
        0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
        0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5,
        0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69,
        0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
        0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC,
        0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB,
        0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
        0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2,
        0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91
    ];

    /**
     * M-Table
     *
     * @var array
     */
    private static $m0 = [
        0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B, 0xE2E22BFB, 0x9E9EFAC8,
        0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B, 0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B,
        0x3C3C57D6, 0x93938A32, 0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
        0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA, 0xB0B0B306, 0x7575DE3F,
        0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B, 0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D,
        0xAEAE2C6D, 0x7F7FABC1, 0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
        0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490, 0x3131272C, 0x808065A3,
        0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154, 0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51,
        0x2A2A3638, 0xC4C49CB0, 0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
        0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228, 0x6767C027, 0xE9E9AF8C,
        0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7, 0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70,
        0x29294CCA, 0xF0F035E3, 0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
        0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477, 0xC8C81DC3, 0x9999FFCC,
        0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF, 0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2,
        0xB5B53D79, 0x09090F0C, 0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
        0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA, 0xEDEDD07A, 0x4343FC17,
        0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D, 0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3,
        0x5656E70B, 0xE3E3DA72, 0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
        0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76, 0x8181942A, 0x91910149,
        0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321, 0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9,
        0x7878AEC5, 0xC5C56D39, 0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
        0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D, 0x55559DF9, 0x7E7E5A48,
        0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E, 0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519,
        0x0606F48D, 0x404086E5, 0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
        0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7, 0x2D2D333C, 0x3030D6A5,
        0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544, 0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969,
        0xD9D97929, 0x8686912E, 0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
        0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A, 0xC1C112CF, 0x8585EBDC,
        0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B, 0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB,
        0xABABA212, 0x6F6F3EA2, 0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
        0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504, 0x04047FF6, 0x272746C2,
        0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756, 0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91
    ];

    /**
     * M-Table
     *
     * @var array
     */
    private static $m1 = [
        0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252, 0xA3658080, 0x76DFE4E4,
        0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A, 0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A,
        0x0D54E6E6, 0xC6432020, 0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
        0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444, 0x94B1FBFB, 0x485A7E7E,
        0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424, 0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060,
        0x1945FDFD, 0x5BA33A3A, 0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
        0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383, 0x9B53AAAA, 0x7C635D5D,
        0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A, 0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7,
        0xC0F09090, 0x8CAFE9E9, 0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
        0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1, 0xB499C3C3, 0xF1975B5B,
        0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898, 0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8,
        0xCCFF9999, 0x95EA1414, 0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
        0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1, 0xBF7E9595, 0xBA207D7D,
        0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989, 0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB,
        0x81FB0F0F, 0x793DB5B5, 0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
        0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E, 0x86135050, 0xE730F7F7,
        0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E, 0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B,
        0x410B9F9F, 0x7B8B0202, 0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
        0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565, 0xB1C72B2B, 0xAB6F8E8E,
        0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A, 0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9,
        0x91EF1313, 0x85FE0808, 0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
        0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A, 0x6929A9A9, 0x647D4F4F,
        0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969, 0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED,
        0xAC87D1D1, 0x7F8E0505, 0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
        0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D, 0x4C5F7979, 0x02B6B7B7,
        0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343, 0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2,
        0x57AC3333, 0xC718CFCF, 0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
        0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F, 0x99E51D1D, 0x34392323,
        0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646, 0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA,
        0xC8FA9E9E, 0xA882D6D6, 0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
        0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A, 0x0FE25151, 0x00000000,
        0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7, 0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8
    ];

    /**
     * M-Table
     *
     * @var array
     */
    private static $m2 = [
        0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B, 0xE2FBE22B, 0x9EC89EFA,
        0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F, 0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7,
        0x3CD63C57, 0x9332938A, 0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
        0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70, 0xB006B0B3, 0x753F75DE,
        0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3, 0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0,
        0xAE6DAE2C, 0x7FC17FAB, 0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
        0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4, 0x312C3127, 0x80A38065,
        0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41, 0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F,
        0x2A382A36, 0xC4B0C49C, 0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
        0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622, 0x672767C0, 0xE98CE9AF,
        0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18, 0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C,
        0x29CA294C, 0xF0E3F035, 0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
        0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84, 0xC8C3C81D, 0x99CC99FF,
        0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E, 0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E,
        0xB579B53D, 0x090C090F, 0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
        0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558, 0xED7AEDD0, 0x431743FC,
        0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40, 0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71,
        0x560B56E7, 0xE372E3DA, 0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
        0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF, 0x812A8194, 0x91499101,
        0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773, 0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5,
        0x78C578AE, 0xC539C56D, 0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
        0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C, 0x55F9559D, 0x7E487E5A,
        0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19, 0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45,
        0x068D06F4, 0x40E54086, 0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
        0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74, 0x2D3C2D33, 0x30A530D6,
        0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755, 0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929,
        0xD929D979, 0x862E8691, 0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
        0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4, 0xC1CFC112, 0x85DC85EB,
        0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53, 0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F,
        0xAB12ABA2, 0x6FA26F3E, 0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
        0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705, 0x04F6047F, 0x27C22746,
        0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7, 0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF
    ];

    /**
     * M-Table
     *
     * @var array
     */
    private static $m3 = [
        0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98, 0x6580A365, 0xDFE476DF,
        0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866, 0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836,
        0x54E60D54, 0x4320C643, 0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
        0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9, 0xB1FB94B1, 0x5A7E485A,
        0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C, 0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5,
        0x45FD1945, 0xA33A5BA3, 0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
        0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F, 0x53AA9B53, 0x635D7C63,
        0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25, 0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123,
        0xF090C0F0, 0xAFE98CAF, 0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
        0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4, 0x99C3B499, 0x975BF197,
        0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E, 0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB,
        0xFF99CCFF, 0xEA1495EA, 0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
        0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12, 0x7E95BF7E, 0x207DBA20,
        0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A, 0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137,
        0xFB0F81FB, 0x3DB5793D, 0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
        0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A, 0x13508613, 0x30F7E730,
        0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C, 0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252,
        0x0B9F410B, 0x8B027B8B, 0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
        0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B, 0xC72BB1C7, 0x6F8EAB6F,
        0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3, 0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A,
        0xEF1391EF, 0xFE0885FE, 0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
        0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85, 0x29A96929, 0x7D4F647D,
        0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA, 0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0,
        0x87D1AC87, 0x8E057F8E, 0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
        0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33, 0x5F794C5F, 0xB6B702B6,
        0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC, 0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38,
        0xAC3357AC, 0x18CFC718, 0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
        0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8, 0xE51D99E5, 0x39233439,
        0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872, 0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6,
        0xFA9EC8FA, 0x82D6A882, 0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
        0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10, 0xE2510FE2, 0x00000000,
        0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6, 0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8
    ];

    /**
     * The Key Schedule Array
     *
     * @var array
     */
    private $K = [];

    /**
     * The Key depended S-Table 0
     *
     * @var array
     */
    private $S0 = [];

    /**
     * The Key depended S-Table 1
     *
     * @var array
     */
    private $S1 = [];

    /**
     * The Key depended S-Table 2
     *
     * @var array
     */
    private $S2 = [];

    /**
     * The Key depended S-Table 3
     *
     * @var array
     */
    private $S3 = [];

    /**
     * Holds the last used key
     *
     * @var array
     */
    private $kl;

    /**
     * The Key Length (in bytes)
     *
     * @see Crypt_Twofish::setKeyLength()
     * @var int
     */
    protected $key_length = 16;

    /**
     * Default Constructor.
     *
     * @param string $mode
     * @throws BadModeException if an invalid / unsupported mode is provided
     */
    public function __construct($mode)
    {
        parent::__construct($mode);

        if ($this->mode == self::MODE_STREAM) {
            throw new BadModeException('Block ciphers cannot be ran in stream mode');
        }
    }

    /**
     * Initialize Static Variables
     */
    protected static function initialize_static_variables()
    {
        if (is_float(self::$m3[0])) {
            self::$m0 = array_map([self::class, 'safe_intval'], self::$m0);
            self::$m1 = array_map([self::class, 'safe_intval'], self::$m1);
            self::$m2 = array_map([self::class, 'safe_intval'], self::$m2);
            self::$m3 = array_map([self::class, 'safe_intval'], self::$m3);
            self::$q0 = array_map([self::class, 'safe_intval'], self::$q0);
            self::$q1 = array_map([self::class, 'safe_intval'], self::$q1);
        }

        parent::initialize_static_variables();
    }

    /**
     * Sets the key length.
     *
     * Valid key lengths are 128, 192 or 256 bits
     *
     * @param int $length
     */
    public function setKeyLength($length)
    {
        switch ($length) {
            case 128:
            case 192:
            case 256:
                break;
            default:
                throw new \LengthException('Key of size ' . $length . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
        }

        parent::setKeyLength($length);
    }

    /**
     * Sets the key.
     *
     * Rijndael supports five different key lengths
     *
     * @see setKeyLength()
     * @param string $key
     * @throws \LengthException if the key length isn't supported
     */
    public function setKey($key)
    {
        switch (strlen($key)) {
            case 16:
            case 24:
            case 32:
                break;
            default:
                throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
        }

        parent::setKey($key);
    }

    /**
     * Setup the key (expansion)
     *
     * @see Common\SymmetricKey::_setupKey()
     */
    protected function setupKey()
    {
        if (isset($this->kl['key']) && $this->key === $this->kl['key']) {
            // already expanded
            return;
        }
        $this->kl = ['key' => $this->key];

        /* Key expanding and generating the key-depended s-boxes */
        $le_longs = unpack('V*', $this->key);
        $key = unpack('C*', $this->key);
        $m0 = self::$m0;
        $m1 = self::$m1;
        $m2 = self::$m2;
        $m3 = self::$m3;
        $q0 = self::$q0;
        $q1 = self::$q1;

        $K = $S0 = $S1 = $S2 = $S3 = [];

        switch (strlen($this->key)) {
            case 16:
                list($s7, $s6, $s5, $s4) = $this->mdsrem($le_longs[1], $le_longs[2]);
                list($s3, $s2, $s1, $s0) = $this->mdsrem($le_longs[3], $le_longs[4]);
                for ($i = 0, $j = 1; $i < 40; $i += 2, $j += 2) {
                    $A = $m0[$q0[$q0[$i] ^ $key[ 9]] ^ $key[1]] ^
                         $m1[$q0[$q1[$i] ^ $key[10]] ^ $key[2]] ^
                         $m2[$q1[$q0[$i] ^ $key[11]] ^ $key[3]] ^
                         $m3[$q1[$q1[$i] ^ $key[12]] ^ $key[4]];
                    $B = $m0[$q0[$q0[$j] ^ $key[13]] ^ $key[5]] ^
                         $m1[$q0[$q1[$j] ^ $key[14]] ^ $key[6]] ^
                         $m2[$q1[$q0[$j] ^ $key[15]] ^ $key[7]] ^
                         $m3[$q1[$q1[$j] ^ $key[16]] ^ $key[8]];
                    $B = ($B << 8) | ($B >> 24 & 0xff);
                    $A = self::safe_intval($A + $B);
                    $K[] = $A;
                    $A = self::safe_intval($A + $B);
                    $K[] = ($A << 9 | $A >> 23 & 0x1ff);
                }
                for ($i = 0; $i < 256; ++$i) {
                    $S0[$i] = $m0[$q0[$q0[$i] ^ $s4] ^ $s0];
                    $S1[$i] = $m1[$q0[$q1[$i] ^ $s5] ^ $s1];
                    $S2[$i] = $m2[$q1[$q0[$i] ^ $s6] ^ $s2];
                    $S3[$i] = $m3[$q1[$q1[$i] ^ $s7] ^ $s3];
                }
                break;
            case 24:
                list($sb, $sa, $s9, $s8) = $this->mdsrem($le_longs[1], $le_longs[2]);
                list($s7, $s6, $s5, $s4) = $this->mdsrem($le_longs[3], $le_longs[4]);
                list($s3, $s2, $s1, $s0) = $this->mdsrem($le_longs[5], $le_longs[6]);
                for ($i = 0, $j = 1; $i < 40; $i += 2, $j += 2) {
                    $A = $m0[$q0[$q0[$q1[$i] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
                         $m1[$q0[$q1[$q1[$i] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
                         $m2[$q1[$q0[$q0[$i] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
                         $m3[$q1[$q1[$q0[$i] ^ $key[20]] ^ $key[12]] ^ $key[4]];
                    $B = $m0[$q0[$q0[$q1[$j] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
                         $m1[$q0[$q1[$q1[$j] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
                         $m2[$q1[$q0[$q0[$j] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
                         $m3[$q1[$q1[$q0[$j] ^ $key[24]] ^ $key[16]] ^ $key[8]];
                    $B = ($B << 8) | ($B >> 24 & 0xff);
                    $A = self::safe_intval($A + $B);
                    $K[] = $A;
                    $A = self::safe_intval($A + $B);
                    $K[] = ($A << 9 | $A >> 23 & 0x1ff);
                }
                for ($i = 0; $i < 256; ++$i) {
                    $S0[$i] = $m0[$q0[$q0[$q1[$i] ^ $s8] ^ $s4] ^ $s0];
                    $S1[$i] = $m1[$q0[$q1[$q1[$i] ^ $s9] ^ $s5] ^ $s1];
                    $S2[$i] = $m2[$q1[$q0[$q0[$i] ^ $sa] ^ $s6] ^ $s2];
                    $S3[$i] = $m3[$q1[$q1[$q0[$i] ^ $sb] ^ $s7] ^ $s3];
                }
                break;
            default: // 32
                list($sf, $se, $sd, $sc) = $this->mdsrem($le_longs[1], $le_longs[2]);
                list($sb, $sa, $s9, $s8) = $this->mdsrem($le_longs[3], $le_longs[4]);
                list($s7, $s6, $s5, $s4) = $this->mdsrem($le_longs[5], $le_longs[6]);
                list($s3, $s2, $s1, $s0) = $this->mdsrem($le_longs[7], $le_longs[8]);
                for ($i = 0, $j = 1; $i < 40; $i += 2, $j += 2) {
                    $A = $m0[$q0[$q0[$q1[$q1[$i] ^ $key[25]] ^ $key[17]] ^ $key[ 9]] ^ $key[1]] ^
                         $m1[$q0[$q1[$q1[$q0[$i] ^ $key[26]] ^ $key[18]] ^ $key[10]] ^ $key[2]] ^
                         $m2[$q1[$q0[$q0[$q0[$i] ^ $key[27]] ^ $key[19]] ^ $key[11]] ^ $key[3]] ^
                         $m3[$q1[$q1[$q0[$q1[$i] ^ $key[28]] ^ $key[20]] ^ $key[12]] ^ $key[4]];
                    $B = $m0[$q0[$q0[$q1[$q1[$j] ^ $key[29]] ^ $key[21]] ^ $key[13]] ^ $key[5]] ^
                         $m1[$q0[$q1[$q1[$q0[$j] ^ $key[30]] ^ $key[22]] ^ $key[14]] ^ $key[6]] ^
                         $m2[$q1[$q0[$q0[$q0[$j] ^ $key[31]] ^ $key[23]] ^ $key[15]] ^ $key[7]] ^
                         $m3[$q1[$q1[$q0[$q1[$j] ^ $key[32]] ^ $key[24]] ^ $key[16]] ^ $key[8]];
                    $B = ($B << 8) | ($B >> 24 & 0xff);
                    $A = self::safe_intval($A + $B);
                    $K[] = $A;
                    $A = self::safe_intval($A + $B);
                    $K[] = ($A << 9 | $A >> 23 & 0x1ff);
                }
                for ($i = 0; $i < 256; ++$i) {
                    $S0[$i] = $m0[$q0[$q0[$q1[$q1[$i] ^ $sc] ^ $s8] ^ $s4] ^ $s0];
                    $S1[$i] = $m1[$q0[$q1[$q1[$q0[$i] ^ $sd] ^ $s9] ^ $s5] ^ $s1];
                    $S2[$i] = $m2[$q1[$q0[$q0[$q0[$i] ^ $se] ^ $sa] ^ $s6] ^ $s2];
                    $S3[$i] = $m3[$q1[$q1[$q0[$q1[$i] ^ $sf] ^ $sb] ^ $s7] ^ $s3];
                }
        }

        $this->K  = $K;
        $this->S0 = $S0;
        $this->S1 = $S1;
        $this->S2 = $S2;
        $this->S3 = $S3;
    }

    /**
     * _mdsrem function using by the twofish cipher algorithm
     *
     * @param string $A
     * @param string $B
     * @return array
     */
    private function mdsrem($A, $B)
    {
        // No gain by unrolling this loop.
        for ($i = 0; $i < 8; ++$i) {
            // Get most significant coefficient.
            $t = 0xff & ($B >> 24);

            // Shift the others up.
            $B = ($B << 8) | (0xff & ($A >> 24));
            $A <<= 8;

            $u = $t << 1;

            // Subtract the modular polynomial on overflow.
            if ($t & 0x80) {
                $u ^= 0x14d;
            }

            // Remove t * (a * x^2 + 1).
            $B ^= $t ^ ($u << 16);

            // Form u = a*t + t/a = t*(a + 1/a).
            $u ^= 0x7fffffff & ($t >> 1);

            // Add the modular polynomial on underflow.
            if ($t & 0x01) {
                $u ^= 0xa6 ;
            }

            // Remove t * (a + 1/a) * (x^3 + x).
            $B ^= ($u << 24) | ($u << 8);
        }

        return [
            0xff & $B >> 24,
            0xff & $B >> 16,
            0xff & $B >>  8,
            0xff & $B];
    }

    /**
     * Encrypts a block
     *
     * @param string $in
     * @return string
     */
    protected function encryptBlock($in)
    {
        $S0 = $this->S0;
        $S1 = $this->S1;
        $S2 = $this->S2;
        $S3 = $this->S3;
        $K  = $this->K;

        $in = unpack("V4", $in);
        $R0 = $K[0] ^ $in[1];
        $R1 = $K[1] ^ $in[2];
        $R2 = $K[2] ^ $in[3];
        $R3 = $K[3] ^ $in[4];

        $ki = 7;
        while ($ki < 39) {
            $t0 = $S0[ $R0        & 0xff] ^
                  $S1[($R0 >>  8) & 0xff] ^
                  $S2[($R0 >> 16) & 0xff] ^
                  $S3[($R0 >> 24) & 0xff];
            $t1 = $S0[($R1 >> 24) & 0xff] ^
                  $S1[ $R1        & 0xff] ^
                  $S2[($R1 >>  8) & 0xff] ^
                  $S3[($R1 >> 16) & 0xff];
            $R2 ^= self::safe_intval($t0 + $t1 + $K[++$ki]);
            $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
            $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ self::safe_intval($t0 + ($t1 << 1) + $K[++$ki]);

            $t0 = $S0[ $R2        & 0xff] ^
                  $S1[($R2 >>  8) & 0xff] ^
                  $S2[($R2 >> 16) & 0xff] ^
                  $S3[($R2 >> 24) & 0xff];
            $t1 = $S0[($R3 >> 24) & 0xff] ^
                  $S1[ $R3        & 0xff] ^
                  $S2[($R3 >>  8) & 0xff] ^
                  $S3[($R3 >> 16) & 0xff];
            $R0 ^= self::safe_intval($t0 + $t1 + $K[++$ki]);
            $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
            $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ self::safe_intval($t0 + ($t1 << 1) + $K[++$ki]);
        }

        // @codingStandardsIgnoreStart
        return pack("V4", $K[4] ^ $R2,
                          $K[5] ^ $R3,
                          $K[6] ^ $R0,
                          $K[7] ^ $R1);
        // @codingStandardsIgnoreEnd
    }

    /**
     * Decrypts a block
     *
     * @param string $in
     * @return string
     */
    protected function decryptBlock($in)
    {
        $S0 = $this->S0;
        $S1 = $this->S1;
        $S2 = $this->S2;
        $S3 = $this->S3;
        $K  = $this->K;

        $in = unpack("V4", $in);
        $R0 = $K[4] ^ $in[1];
        $R1 = $K[5] ^ $in[2];
        $R2 = $K[6] ^ $in[3];
        $R3 = $K[7] ^ $in[4];

        $ki = 40;
        while ($ki > 8) {
            $t0 = $S0[$R0       & 0xff] ^
                  $S1[$R0 >>  8 & 0xff] ^
                  $S2[$R0 >> 16 & 0xff] ^
                  $S3[$R0 >> 24 & 0xff];
            $t1 = $S0[$R1 >> 24 & 0xff] ^
                  $S1[$R1       & 0xff] ^
                  $S2[$R1 >>  8 & 0xff] ^
                  $S3[$R1 >> 16 & 0xff];
            $R3 ^= self::safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
            $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
            $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ self::safe_intval($t0 + $t1 + $K[--$ki]);

            $t0 = $S0[$R2       & 0xff] ^
                  $S1[$R2 >>  8 & 0xff] ^
                  $S2[$R2 >> 16 & 0xff] ^
                  $S3[$R2 >> 24 & 0xff];
            $t1 = $S0[$R3 >> 24 & 0xff] ^
                  $S1[$R3       & 0xff] ^
                  $S2[$R3 >>  8 & 0xff] ^
                  $S3[$R3 >> 16 & 0xff];
            $R1 ^= self::safe_intval($t0 + ($t1 << 1) + $K[--$ki]);
            $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
            $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ self::safe_intval($t0 + $t1 + $K[--$ki]);
        }

        // @codingStandardsIgnoreStart
        return pack("V4", $K[0] ^ $R2,
                          $K[1] ^ $R3,
                          $K[2] ^ $R0,
                          $K[3] ^ $R1);
        // @codingStandardsIgnoreEnd
    }

    /**
     * Setup the performance-optimized function for de/encrypt()
     *
     * @see Common\SymmetricKey::_setupInlineCrypt()
     */
    protected function setupInlineCrypt()
    {
        $K = $this->K;
        $init_crypt = '
            static $S0, $S1, $S2, $S3;
            if (!$S0) {
                for ($i = 0; $i < 256; ++$i) {
                    $S0[] = (int)$this->S0[$i];
                    $S1[] = (int)$this->S1[$i];
                    $S2[] = (int)$this->S2[$i];
                    $S3[] = (int)$this->S3[$i];
                }
            }
        ';

        $safeint = self::safe_intval_inline();

        // Generating encrypt code:
        $encrypt_block = '
            $in = unpack("V4", $in);
            $R0 = ' . $K[0] . ' ^ $in[1];
            $R1 = ' . $K[1] . ' ^ $in[2];
            $R2 = ' . $K[2] . ' ^ $in[3];
            $R3 = ' . $K[3] . ' ^ $in[4];
        ';
        for ($ki = 7, $i = 0; $i < 8; ++$i) {
            $encrypt_block .= '
                $t0 = $S0[ $R0        & 0xff] ^
                      $S1[($R0 >>  8) & 0xff] ^
                      $S2[($R0 >> 16) & 0xff] ^
                      $S3[($R0 >> 24) & 0xff];
                $t1 = $S0[($R1 >> 24) & 0xff] ^
                      $S1[ $R1        & 0xff] ^
                      $S2[($R1 >>  8) & 0xff] ^
                      $S3[($R1 >> 16) & 0xff];
                    $R2^= ' . sprintf($safeint, '$t0 + $t1 + ' . $K[++$ki]) . ';
                $R2 = ($R2 >> 1 & 0x7fffffff) | ($R2 << 31);
                $R3 = ((($R3 >> 31) & 1) | ($R3 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';

                $t0 = $S0[ $R2        & 0xff] ^
                      $S1[($R2 >>  8) & 0xff] ^
                      $S2[($R2 >> 16) & 0xff] ^
                      $S3[($R2 >> 24) & 0xff];
                $t1 = $S0[($R3 >> 24) & 0xff] ^
                      $S1[ $R3        & 0xff] ^
                      $S2[($R3 >>  8) & 0xff] ^
                      $S3[($R3 >> 16) & 0xff];
                $R0^= ' . sprintf($safeint, '($t0 + $t1 + ' . $K[++$ki] . ')') . ';
                $R0 = ($R0 >> 1 & 0x7fffffff) | ($R0 << 31);
                $R1 = ((($R1 >> 31) & 1) | ($R1 << 1)) ^ ' . sprintf($safeint, '($t0 + ($t1 << 1) + ' . $K[++$ki] . ')') . ';
            ';
        }
        $encrypt_block .= '
            $in = pack("V4", ' . $K[4] . ' ^ $R2,
                             ' . $K[5] . ' ^ $R3,
                             ' . $K[6] . ' ^ $R0,
                             ' . $K[7] . ' ^ $R1);
        ';

        // Generating decrypt code:
        $decrypt_block = '
            $in = unpack("V4", $in);
            $R0 = ' . $K[4] . ' ^ $in[1];
            $R1 = ' . $K[5] . ' ^ $in[2];
            $R2 = ' . $K[6] . ' ^ $in[3];
            $R3 = ' . $K[7] . ' ^ $in[4];
        ';
        for ($ki = 40, $i = 0; $i < 8; ++$i) {
            $decrypt_block .= '
                $t0 = $S0[$R0       & 0xff] ^
                      $S1[$R0 >>  8 & 0xff] ^
                      $S2[$R0 >> 16 & 0xff] ^
                      $S3[$R0 >> 24 & 0xff];
                $t1 = $S0[$R1 >> 24 & 0xff] ^
                      $S1[$R1       & 0xff] ^
                      $S2[$R1 >>  8 & 0xff] ^
                      $S3[$R1 >> 16 & 0xff];
                $R3^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
                $R3 = $R3 >> 1 & 0x7fffffff | $R3 << 31;
                $R2 = ($R2 >> 31 & 0x1 | $R2 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + ' . $K[--$ki] . ')') . ';

                $t0 = $S0[$R2       & 0xff] ^
                      $S1[$R2 >>  8 & 0xff] ^
                      $S2[$R2 >> 16 & 0xff] ^
                      $S3[$R2 >> 24 & 0xff];
                $t1 = $S0[$R3 >> 24 & 0xff] ^
                      $S1[$R3       & 0xff] ^
                      $S2[$R3 >>  8 & 0xff] ^
                      $S3[$R3 >> 16 & 0xff];
                $R1^= ' . sprintf($safeint, '$t0 + ($t1 << 1) + ' . $K[--$ki]) . ';
                $R1 = $R1 >> 1 & 0x7fffffff | $R1 << 31;
                $R0 = ($R0 >> 31 & 0x1 | $R0 << 1) ^ ' . sprintf($safeint, '($t0 + $t1 + ' . $K[--$ki] . ')') . ';
            ';
        }
        $decrypt_block .= '
            $in = pack("V4", ' . $K[0] . ' ^ $R2,
                             ' . $K[1] . ' ^ $R3,
                             ' . $K[2] . ' ^ $R0,
                             ' . $K[3] . ' ^ $R1);
        ';

        $this->inline_crypt = $this->createInlineCryptFunction(
            [
               'init_crypt'    => $init_crypt,
               'init_encrypt'  => '',
               'init_decrypt'  => '',
               'encrypt_block' => $encrypt_block,
               'decrypt_block' => $decrypt_block
            ]
        );
    }
}
<?php

/**
 * Pure-PHP implementation of RC4.
 *
 * Uses mcrypt, if available, and an internal implementation, otherwise.
 *
 * PHP version 5
 *
 * Useful resources are as follows:
 *
 *  - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
 *  - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
 *
 * RC4 is also known as ARCFOUR or ARC4.  The reason is elaborated upon at Wikipedia.  This class is named RC4 and not
 * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $rc4 = new \phpseclib3\Crypt\RC4();
 *
 *    $rc4->setKey('abcdefgh');
 *
 *    $size = 10 * 1024;
 *    $plaintext = '';
 *    for ($i = 0; $i < $size; $i++) {
 *        $plaintext.= 'a';
 *    }
 *
 *    echo $rc4->decrypt($rc4->encrypt($plaintext));
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Crypt\Common\StreamCipher;

/**
 * Pure-PHP implementation of RC4.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class RC4 extends StreamCipher
{
    /**
     * @see \phpseclib3\Crypt\RC4::_crypt()
     */
    const ENCRYPT = 0;

    /**
     * @see \phpseclib3\Crypt\RC4::_crypt()
     */
    const DECRYPT = 1;

    /**
     * Key Length (in bytes)
     *
     * @see \phpseclib3\Crypt\RC4::setKeyLength()
     * @var int
     */
    protected $key_length = 128; // = 1024 bits

    /**
     * The mcrypt specific name of the cipher
     *
     * @see Common\SymmetricKey::cipher_name_mcrypt
     * @var string
     */
    protected $cipher_name_mcrypt = 'arcfour';

    /**
     * The Key
     *
     * @see self::setKey()
     * @var string
     */
    protected $key;

    /**
     * The Key Stream for decryption and encryption
     *
     * @see self::setKey()
     * @var array
     */
    private $stream;

    /**
     * Test for engine validity
     *
     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
     *
     * @see Common\SymmetricKey::__construct()
     * @param int $engine
     * @return bool
     */
    protected function isValidEngineHelper($engine)
    {
        if ($engine == self::ENGINE_OPENSSL) {
            if ($this->continuousBuffer) {
                return false;
            }
            // quoting https://www.openssl.org/news/openssl-3.0-notes.html, OpenSSL 3.0.1
            // "Moved all variations of the EVP ciphers CAST5, BF, IDEA, SEED, RC2, RC4, RC5, and DES to the legacy provider"
            // in theory openssl_get_cipher_methods() should catch this but, on GitHub Actions, at least, it does not
            if (defined('OPENSSL_VERSION_TEXT') && version_compare(preg_replace('#OpenSSL (\d+\.\d+\.\d+) .*#', '$1', OPENSSL_VERSION_TEXT), '3.0.1', '>=')) {
                return false;
            }
            $this->cipher_name_openssl = 'rc4-40';
        }

        return parent::isValidEngineHelper($engine);
    }

    /**
     * Sets the key length
     *
     * Keys can be between 1 and 256 bytes long.
     *
     * @param int $length
     * @throws \LengthException if the key length is invalid
     */
    public function setKeyLength($length)
    {
        if ($length < 8 || $length > 2048) {
            throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 256 bytes are supported');
        }

        $this->key_length = $length >> 3;

        parent::setKeyLength($length);
    }

    /**
     * Sets the key length
     *
     * Keys can be between 1 and 256 bytes long.
     *
     * @param string $key
     */
    public function setKey($key)
    {
        $length = strlen($key);
        if ($length < 1 || $length > 256) {
            throw new \LengthException('Key size of ' . $length . ' bytes is not supported by RC4. Keys must be between 1 and 256 bytes long');
        }

        parent::setKey($key);
    }

    /**
     * Encrypts a message.
     *
     * @see Common\SymmetricKey::decrypt()
     * @see self::crypt()
     * @param string $plaintext
     * @return string $ciphertext
     */
    public function encrypt($plaintext)
    {
        if ($this->engine != self::ENGINE_INTERNAL) {
            return parent::encrypt($plaintext);
        }
        return $this->crypt($plaintext, self::ENCRYPT);
    }

    /**
     * Decrypts a message.
     *
     * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
     * At least if the continuous buffer is disabled.
     *
     * @see Common\SymmetricKey::encrypt()
     * @see self::crypt()
     * @param string $ciphertext
     * @return string $plaintext
     */
    public function decrypt($ciphertext)
    {
        if ($this->engine != self::ENGINE_INTERNAL) {
            return parent::decrypt($ciphertext);
        }
        return $this->crypt($ciphertext, self::DECRYPT);
    }

    /**
     * Encrypts a block
     *
     * @param string $in
     */
    protected function encryptBlock($in)
    {
        // RC4 does not utilize this method
    }

    /**
     * Decrypts a block
     *
     * @param string $in
     */
    protected function decryptBlock($in)
    {
        // RC4 does not utilize this method
    }

    /**
     * Setup the key (expansion)
     *
     * @see Common\SymmetricKey::_setupKey()
     */
    protected function setupKey()
    {
        $key = $this->key;
        $keyLength = strlen($key);
        $keyStream = range(0, 255);
        $j = 0;
        for ($i = 0; $i < 256; $i++) {
            $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
            $temp = $keyStream[$i];
            $keyStream[$i] = $keyStream[$j];
            $keyStream[$j] = $temp;
        }

        $this->stream = [];
        $this->stream[self::DECRYPT] = $this->stream[self::ENCRYPT] = [
            0, // index $i
            0, // index $j
            $keyStream
        ];
    }

    /**
     * Encrypts or decrypts a message.
     *
     * @see self::encrypt()
     * @see self::decrypt()
     * @param string $text
     * @param int $mode
     * @return string $text
     */
    private function crypt($text, $mode)
    {
        if ($this->changed) {
            $this->setup();
        }

        $stream = &$this->stream[$mode];
        if ($this->continuousBuffer) {
            $i = &$stream[0];
            $j = &$stream[1];
            $keyStream = &$stream[2];
        } else {
            $i = $stream[0];
            $j = $stream[1];
            $keyStream = $stream[2];
        }

        $len = strlen($text);
        for ($k = 0; $k < $len; ++$k) {
            $i = ($i + 1) & 255;
            $ksi = $keyStream[$i];
            $j = ($j + $ksi) & 255;
            $ksj = $keyStream[$j];

            $keyStream[$i] = $ksj;
            $keyStream[$j] = $ksi;
            $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
        }

        return $text;
    }
}
<?php

/**
 * PublicKeyLoader
 *
 * Returns a PublicKey or PrivateKey object.
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2009 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Crypt\Common\AsymmetricKey;
use phpseclib3\Crypt\Common\PrivateKey;
use phpseclib3\Crypt\Common\PublicKey;
use phpseclib3\Exception\NoKeyLoadedException;
use phpseclib3\File\X509;

/**
 * PublicKeyLoader
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PublicKeyLoader
{
    /**
     * Loads a public or private key
     *
     * @return AsymmetricKey
     * @param string|array $key
     * @param string $password optional
     * @throws NoKeyLoadedException if key is not valid
     */
    public static function load($key, $password = false)
    {
        try {
            return EC::load($key, $password);
        } catch (NoKeyLoadedException $e) {
        }

        try {
            return RSA::load($key, $password);
        } catch (NoKeyLoadedException $e) {
        }

        try {
            return DSA::load($key, $password);
        } catch (NoKeyLoadedException $e) {
        }

        try {
            $x509 = new X509();
            $x509->loadX509($key);
            $key = $x509->getPublicKey();
            if ($key) {
                return $key;
            }
        } catch (\Exception $e) {
        }

        throw new NoKeyLoadedException('Unable to read key');
    }

    /**
     * Loads a private key
     *
     * @return PrivateKey
     * @param string|array $key
     * @param string $password optional
     */
    public static function loadPrivateKey($key, $password = false)
    {
        $key = self::load($key, $password);
        if (!$key instanceof PrivateKey) {
            throw new NoKeyLoadedException('The key that was loaded was not a private key');
        }
        return $key;
    }

    /**
     * Loads a public key
     *
     * @return PublicKey
     * @param string|array $key
     */
    public static function loadPublicKey($key)
    {
        $key = self::load($key);
        if (!$key instanceof PublicKey) {
            throw new NoKeyLoadedException('The key that was loaded was not a public key');
        }
        return $key;
    }

    /**
     * Loads parameters
     *
     * @return AsymmetricKey
     * @param string|array $key
     */
    public static function loadParameters($key)
    {
        $key = self::load($key);
        if (!$key instanceof PrivateKey && !$key instanceof PublicKey) {
            throw new NoKeyLoadedException('The key that was loaded was not a parameter');
        }
        return $key;
    }
}
<?php

/**
 * Pure-PHP FIPS 186-4 compliant implementation of DSA.
 *
 * PHP version 5
 *
 * Here's an example of how to create signatures and verify signatures with this library:
 * <code>
 * <?php
 * include 'vendor/autoload.php';
 *
 * $private = \phpseclib3\Crypt\DSA::createKey();
 * $public = $private->getPublicKey();
 *
 * $plaintext = 'terrafrost';
 *
 * $signature = $private->sign($plaintext);
 *
 * echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified';
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Crypt\Common\AsymmetricKey;
use phpseclib3\Crypt\DSA\Parameters;
use phpseclib3\Crypt\DSA\PrivateKey;
use phpseclib3\Crypt\DSA\PublicKey;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\InsufficientSetupException;
use phpseclib3\Math\BigInteger;

/**
 * Pure-PHP FIPS 186-4 compliant implementation of DSA.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DSA extends AsymmetricKey
{
    /**
     * Algorithm Name
     *
     * @var string
     */
    const ALGORITHM = 'DSA';

    /**
     * DSA Prime P
     *
     * @var BigInteger
     */
    protected $p;

    /**
     * DSA Group Order q
     *
     * Prime divisor of p-1
     *
     * @var BigInteger
     */
    protected $q;

    /**
     * DSA Group Generator G
     *
     * @var BigInteger
     */
    protected $g;

    /**
     * DSA public key value y
     *
     * @var BigInteger
     */
    protected $y;

    /**
     * Signature Format
     *
     * @var string
     */
    protected $sigFormat;

    /**
     * Forced Engine
     *
     * @var ?string
     * @see parent::forceEngine()
     */
    protected static $forcedEngine = null;

    /**
     * Signature Format (Short)
     *
     * @var string
     */
    protected $shortFormat;

    /**
     * Create DSA parameters
     *
     * @param int $L
     * @param int $N
     * @return DSA|bool
     */
    public static function createParameters($L = 2048, $N = 224)
    {
        self::initialize_static_variables();

        $class = new \ReflectionClass(static::class);
        if ($class->isFinal()) {
            throw new \RuntimeException('createParameters() should not be called from final classes (' . static::class . ')');
        }

        switch (true) {
            case $N == 160:
            /*
              in FIPS 186-1 and 186-2 N was fixed at 160 whereas K had an upper bound of 1024.
              RFC 4253 (SSH Transport Layer Protocol) references FIPS 186-2 and as such most
              SSH DSA implementations only support keys with an N of 160.
              puttygen let's you set the size of L (but not the size of N) and uses 2048 as the
              default L value. that's not really compliant with any of the FIPS standards, however,
              for the purposes of maintaining compatibility with puttygen, we'll support it
            */
            //case ($L >= 512 || $L <= 1024) && (($L & 0x3F) == 0) && $N == 160:
            // FIPS 186-3 changed this as follows:
            //case $L == 1024 && $N == 160:
            case $L == 2048 && $N == 224:
            case $L == 2048 && $N == 256:
            case $L == 3072 && $N == 256:
                break;
            default:
                throw new \InvalidArgumentException('Invalid values for N and L');
        }

        $two = new BigInteger(2);

        $q = BigInteger::randomPrime($N);
        $divisor = $q->multiply($two);

        do {
            $x = BigInteger::random($L);
            list(, $c) = $x->divide($divisor);
            $p = $x->subtract($c->subtract(self::$one));
        } while ($p->getLength() != $L || !$p->isPrime());

        $p_1 = $p->subtract(self::$one);
        list($e) = $p_1->divide($q);

        // quoting http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf#page=50 ,
        // "h could be obtained from a random number generator or from a counter that
        //  changes after each use". PuTTY (sshdssg.c) starts h off at 1 and increments
        // it on each loop. wikipedia says "commonly h = 2 is used" so we'll just do that
        $h = clone $two;
        while (true) {
            $g = $h->powMod($e, $p);
            if (!$g->equals(self::$one)) {
                break;
            }
            $h = $h->add(self::$one);
        }

        $dsa = new Parameters();
        $dsa->p = $p;
        $dsa->q = $q;
        $dsa->g = $g;

        return $dsa;
    }

    /**
     * Create public / private key pair.
     *
     * This method is a bit polymorphic. It can take a DSA/Parameters object, L / N as two distinct parameters or
     * no parameters (at which point L and N will be generated with this method)
     *
     * Returns the private key, from which the publickey can be extracted
     *
     * @param int[] ...$args
     * @return PrivateKey
     */
    public static function createKey(...$args)
    {
        self::initialize_static_variables();

        if (self::$forcedEngine == 'libsodium') {
            throw new BadConfigurationException('Engine ' . self::$forcedEngine . ' is forced but unsupported for DSA');
        }

        if (self::$forcedEngine == 'OpenSSL' && !defined('OPENSSL_KEYTYPE_DSA')) {
            throw new BadConfigurationException("Engine OpenSSL is forced but unsupported for DSA");
        }

        $class = new \ReflectionClass(static::class);
        if ($class->isFinal()) {
            throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
        }

        if (count($args) == 2 && is_int($args[0]) && is_int($args[1])) {
            $params = self::createParameters($args[0], $args[1]);
        } elseif (count($args) == 1 && $args[0] instanceof Parameters) {
            $params = $args[0];
        } elseif (!count($args)) {
            $params = self::createParameters();
        } else {
            throw new InsufficientSetupException('Valid parameters are either two integers (L and N), a single DSA object or no parameters at all.');
        }

        // at this point the only two supported values for self::$forcedEngine are OpenSSL, PHP and null
        // if it's either OpenSSL or null we'll use OpenSSL (if it's available)
        if (self::$forcedEngine !== 'PHP' && defined('OPENSSL_KEYTYPE_DSA')) {
            $config = [];
            if (self::$configFile) {
                $config['config'] = self::$configFile;
            }
            $dsa = openssl_pkey_new($config + [
                'private_key_type' => OPENSSL_KEYTYPE_DSA,
                'p' => $params->p,
                'q' => $params->q,
                'g' => $params->g,
            ]);
            if ($dsa && openssl_pkey_export($dsa, $privatekeystr, null, $config)) {
                // clear the buffer of error strings stemming from a minimalistic openssl.cnf
                // https://github.com/php/php-src/issues/11054 talks about other errors this'll pick up
                while (openssl_error_string() !== false) {
                }

                return DSA::load($privatekeystr)
                    ->withHash($params->hash->getHash())
                    ->withSignatureFormat($params->shortFormat);
            } elseif (isset(self::$forcedEngine)) {
                throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA');
            }
        }

        $private = new PrivateKey();
        $private->p = $params->p;
        $private->q = $params->q;
        $private->g = $params->g;

        $private->x = BigInteger::randomRange(self::$one, $private->q->subtract(self::$one));
        $private->y = $private->g->powMod($private->x, $private->p);

        //$public = clone $private;
        //unset($public->x);

        return $private
            ->withHash($params->hash->getHash())
            ->withSignatureFormat($params->shortFormat);
    }

    /**
     * OnLoad Handler
     *
     * @return bool
     */
    protected static function onLoad(array $components)
    {
        if (!isset($components['x']) && !isset($components['y'])) {
            $new = new Parameters();
        } elseif (isset($components['x'])) {
            $new = new PrivateKey();
            $new->x = $components['x'];
        } else {
            $new = new PublicKey();
        }

        $new->p = $components['p'];
        $new->q = $components['q'];
        $new->g = $components['g'];

        if (isset($components['y'])) {
            $new->y = $components['y'];
        }

        return $new;
    }

    /**
     * Constructor
     *
     * PublicKey and PrivateKey objects can only be created from abstract RSA class
     */
    protected function __construct()
    {
        $this->sigFormat = self::validatePlugin('Signature', 'ASN1');
        $this->shortFormat = 'ASN1';

        parent::__construct();
    }

    /**
     * Returns the key size
     *
     * More specifically, this L (the length of DSA Prime P) and N (the length of DSA Group Order q)
     *
     * @return array
     */
    public function getLength()
    {
        return ['L' => $this->p->getLength(), 'N' => $this->q->getLength()];
    }

    /**
     * Returns the parameters
     *
     * A public / private key is only returned if the currently loaded "key" contains an x or y
     * value.
     *
     * @see self::getPublicKey()
     * @return mixed
     */
    public function getParameters()
    {
        $type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');

        $key = $type::saveParameters($this->p, $this->q, $this->g);
        return DSA::load($key, 'PKCS1')
            ->withHash($this->hash->getHash())
            ->withSignatureFormat($this->shortFormat);
    }

    /**
     * Determines the signature padding mode
     *
     * Valid values are: ASN1, SSH2, Raw
     *
     * @param string $format
     */
    public function withSignatureFormat($format)
    {
        $new = clone $this;
        $new->shortFormat = $format;
        $new->sigFormat = self::validatePlugin('Signature', $format);
        return $new;
    }

    /**
     * Returns the signature format currently being used
     *
     */
    public function getSignatureFormat()
    {
        return $this->shortFormat;
    }
}
<?php

/**
 * Pure-PHP implementation of ChaCha20.
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2019 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Exception\BadDecryptionException;
use phpseclib3\Exception\InsufficientSetupException;

/**
 * Pure-PHP implementation of ChaCha20.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class ChaCha20 extends Salsa20
{
    /**
     * The OpenSSL specific name of the cipher
     *
     * @var string
     */
    protected $cipher_name_openssl = 'chacha20';

    /**
     * Test for engine validity
     *
     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
     * @param int $engine
     * @return bool
     */
    protected function isValidEngineHelper($engine)
    {
        switch ($engine) {
            case self::ENGINE_LIBSODIUM:
                // PHP 7.2.0 (30 Nov 2017) added support for libsodium

                // we could probably make it so that if $this->counter == 0 then the first block would be done with either OpenSSL
                // or PHP and then subsequent blocks would then be done with libsodium but idk - it's not a high priority atm

                // we could also make it so that if $this->counter == 0 and $this->continuousBuffer then do the first string
                // with libsodium and subsequent strings with openssl or pure-PHP but again not a high priority
                return function_exists('sodium_crypto_aead_chacha20poly1305_ietf_encrypt') &&
                       $this->key_length == 32 &&
                       (($this->usePoly1305 && !isset($this->poly1305Key) && $this->counter == 0) || $this->counter == 1) &&
                       !$this->continuousBuffer;
            case self::ENGINE_OPENSSL:
                // OpenSSL 1.1.0 (released 25 Aug 2016) added support for chacha20.
                // PHP didn't support OpenSSL 1.1.0 until 7.0.19 (11 May 2017)

                // if you attempt to provide openssl with a 128 bit key (as opposed to a 256 bit key) openssl will null
                // pad the key to 256 bits and still use the expansion constant for 256-bit keys. the fact that
                // openssl treats the IV as both the counter and nonce, however, let's us use openssl in continuous mode
                // whereas libsodium does not
                if ($this->key_length != 32) {
                    return false;
                }
        }

        return parent::isValidEngineHelper($engine);
    }

    /**
     * Encrypts a message.
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
     * @see self::crypt()
     * @param string $plaintext
     * @return string $ciphertext
     */
    public function encrypt($plaintext)
    {
        $this->setup();

        if ($this->engine == self::ENGINE_LIBSODIUM) {
            return $this->encrypt_with_libsodium($plaintext);
        }

        return parent::encrypt($plaintext);
    }

    /**
     * Decrypts a message.
     *
     * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
     * At least if the continuous buffer is disabled.
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
     * @see self::crypt()
     * @param string $ciphertext
     * @return string $plaintext
     */
    public function decrypt($ciphertext)
    {
        $this->setup();

        if ($this->engine == self::ENGINE_LIBSODIUM) {
            return $this->decrypt_with_libsodium($ciphertext);
        }

        return parent::decrypt($ciphertext);
    }

    /**
     * Encrypts a message with libsodium
     *
     * @see self::encrypt()
     * @param string $plaintext
     * @return string $text
     */
    private function encrypt_with_libsodium($plaintext)
    {
        $params = [$plaintext, $this->aad, $this->nonce, $this->key];
        $ciphertext = strlen($this->nonce) == 8 ?
            sodium_crypto_aead_chacha20poly1305_encrypt(...$params) :
            sodium_crypto_aead_chacha20poly1305_ietf_encrypt(...$params);
        if (!$this->usePoly1305) {
            return substr($ciphertext, 0, strlen($plaintext));
        }

        $newciphertext = substr($ciphertext, 0, strlen($plaintext));

        $this->newtag = $this->usingGeneratedPoly1305Key && strlen($this->nonce) == 12 ?
            substr($ciphertext, strlen($plaintext)) :
            $this->poly1305($newciphertext);

        return $newciphertext;
    }

    /**
     * Decrypts a message with libsodium
     *
     * @see self::decrypt()
     * @param string $ciphertext
     * @return string $text
     */
    private function decrypt_with_libsodium($ciphertext)
    {
        $params = [$ciphertext, $this->aad, $this->nonce, $this->key];

        if (isset($this->poly1305Key)) {
            if ($this->oldtag === false) {
                throw new InsufficientSetupException('Authentication Tag has not been set');
            }
            if ($this->usingGeneratedPoly1305Key && strlen($this->nonce) == 12) {
                $plaintext = sodium_crypto_aead_chacha20poly1305_ietf_decrypt(...$params);
                $this->oldtag = false;
                if ($plaintext === false) {
                    throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match');
                }
                return $plaintext;
            }
            $newtag = $this->poly1305($ciphertext);
            if ($this->oldtag != substr($newtag, 0, strlen($this->oldtag))) {
                $this->oldtag = false;
                throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match');
            }
            $this->oldtag = false;
        }

        $plaintext = strlen($this->nonce) == 8 ?
            sodium_crypto_aead_chacha20poly1305_encrypt(...$params) :
            sodium_crypto_aead_chacha20poly1305_ietf_encrypt(...$params);

        return substr($plaintext, 0, strlen($ciphertext));
    }

    /**
     * Sets the nonce.
     *
     * @param string $nonce
     */
    public function setNonce($nonce)
    {
        if (!is_string($nonce)) {
            throw new \UnexpectedValueException('The nonce should be a string');
        }

        /*
          from https://tools.ietf.org/html/rfc7539#page-7

          "Note also that the original ChaCha had a 64-bit nonce and 64-bit
           block count.  We have modified this here to be more consistent with
           recommendations in Section 3.2 of [RFC5116]."
         */
        switch (strlen($nonce)) {
            case 8:  // 64 bits
            case 12: // 96 bits
                break;
            default:
                throw new \LengthException('Nonce of size ' . strlen($nonce) . ' not supported by this algorithm. Only 64-bit nonces or 96-bit nonces are supported');
        }

        $this->nonce = $nonce;
        $this->changed = true;
        $this->setEngine();
    }

    /**
     * Setup the self::ENGINE_INTERNAL $engine
     *
     * (re)init, if necessary, the internal cipher $engine
     *
     * _setup() will be called each time if $changed === true
     * typically this happens when using one or more of following public methods:
     *
     * - setKey()
     *
     * - setNonce()
     *
     * - First run of encrypt() / decrypt() with no init-settings
     *
     * @see self::setKey()
     * @see self::setNonce()
     * @see self::disableContinuousBuffer()
     */
    protected function setup()
    {
        if (!$this->changed) {
            return;
        }

        $this->enbuffer = $this->debuffer = ['ciphertext' => '', 'counter' => $this->counter];

        $this->changed = $this->nonIVChanged = false;

        if ($this->nonce === false) {
            throw new InsufficientSetupException('No nonce has been defined');
        }

        if ($this->key === false) {
            throw new InsufficientSetupException('No key has been defined');
        }

        if ($this->usePoly1305 && !isset($this->poly1305Key)) {
            $this->usingGeneratedPoly1305Key = true;
            if ($this->engine == self::ENGINE_LIBSODIUM) {
                return;
            }
            $this->createPoly1305Key();
        }

        $key = $this->key;
        if (strlen($key) == 16) {
            $constant = 'expand 16-byte k';
            $key .= $key;
        } else {
            $constant = 'expand 32-byte k';
        }

        $this->p1 = $constant . $key;
        $this->p2 = $this->nonce;
        if (strlen($this->nonce) == 8) {
            $this->p2 = "\0\0\0\0" . $this->p2;
        }
    }

    /**
     * The quarterround function
     *
     * @param int $a
     * @param int $b
     * @param int $c
     * @param int $d
     */
    protected static function quarterRound(&$a, &$b, &$c, &$d)
    {
        // in https://datatracker.ietf.org/doc/html/rfc7539#section-2.1 the addition,
        // xor'ing and rotation are all on the same line so i'm keeping it on the same
        // line here as well
        // @codingStandardsIgnoreStart
        $a+= $b; $d = self::leftRotate(self::safe_intval($d) ^ self::safe_intval($a), 16);
        $c+= $d; $b = self::leftRotate(self::safe_intval($b) ^ self::safe_intval($c), 12);
        $a+= $b; $d = self::leftRotate(self::safe_intval($d) ^ self::safe_intval($a), 8);
        $c+= $d; $b = self::leftRotate(self::safe_intval($b) ^ self::safe_intval($c), 7);
        // @codingStandardsIgnoreEnd
    }

    /**
     * The doubleround function
     *
     * @param int $x0 (by reference)
     * @param int $x1 (by reference)
     * @param int $x2 (by reference)
     * @param int $x3 (by reference)
     * @param int $x4 (by reference)
     * @param int $x5 (by reference)
     * @param int $x6 (by reference)
     * @param int $x7 (by reference)
     * @param int $x8 (by reference)
     * @param int $x9 (by reference)
     * @param int $x10 (by reference)
     * @param int $x11 (by reference)
     * @param int $x12 (by reference)
     * @param int $x13 (by reference)
     * @param int $x14 (by reference)
     * @param int $x15 (by reference)
     */
    protected static function doubleRound(&$x0, &$x1, &$x2, &$x3, &$x4, &$x5, &$x6, &$x7, &$x8, &$x9, &$x10, &$x11, &$x12, &$x13, &$x14, &$x15)
    {
        // columnRound
        static::quarterRound($x0, $x4, $x8, $x12);
        static::quarterRound($x1, $x5, $x9, $x13);
        static::quarterRound($x2, $x6, $x10, $x14);
        static::quarterRound($x3, $x7, $x11, $x15);
        // rowRound
        static::quarterRound($x0, $x5, $x10, $x15);
        static::quarterRound($x1, $x6, $x11, $x12);
        static::quarterRound($x2, $x7, $x8, $x13);
        static::quarterRound($x3, $x4, $x9, $x14);
    }

    /**
     * The Salsa20 hash function function
     *
     * On my laptop this loop unrolled / function dereferenced version of parent::salsa20 encrypts 1mb of text in
     * 0.65s vs the 0.85s that it takes with the parent method.
     *
     * If we were free to assume that the host OS would always be 64-bits then the if condition in leftRotate could
     * be eliminated and we could knock this done to 0.60s.
     *
     * For comparison purposes, RC4 takes 0.16s and AES in CTR mode with the Eval engine takes 0.48s.
     * AES in CTR mode with the PHP engine takes 1.19s. Salsa20 / ChaCha20 do not benefit as much from the Eval
     * approach due to the fact that there are a lot less variables to de-reference, fewer loops to unroll, etc
     *
     * @param string $x
     */
    protected static function salsa20($x)
    {
        list(, $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15) = unpack('V*', $x);
        $z0 = $x0;
        $z1 = $x1;
        $z2 = $x2;
        $z3 = $x3;
        $z4 = $x4;
        $z5 = $x5;
        $z6 = $x6;
        $z7 = $x7;
        $z8 = $x8;
        $z9 = $x9;
        $z10 = $x10;
        $z11 = $x11;
        $z12 = $x12;
        $z13 = $x13;
        $z14 = $x14;
        $z15 = $x15;

        // @codingStandardsIgnoreStart
        // columnRound
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);

        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);

        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);

        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);

        // rowRound
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);

        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);

        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);

        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);

        // columnRound
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);

        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);

        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);

        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);

        // rowRound
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);

        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);

        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);

        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);

        // columnRound
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);

        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);

        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);

        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);

        // rowRound
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);

        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);

        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);

        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);

        // columnRound
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);

        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);

        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);

        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);

        // rowRound
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);

        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);

        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);

        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);

        // columnRound
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);

        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);

        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);

        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);

        // rowRound
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);

        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);

        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);

        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);

        // columnRound
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);

        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);

        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);

        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);

        // rowRound
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);

        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);

        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);

        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);

        // columnRound
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);

        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);

        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);

        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);

        // rowRound
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);

        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);

        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);

        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);

        // columnRound
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);

        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);

        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);

        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);

        // rowRound
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);

        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);

        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);

        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);

        // columnRound
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);

        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);

        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);

        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);

        // rowRound
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);

        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);

        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);

        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);

        // columnRound
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12);
        $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8);
        $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7);

        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12);
        $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8);
        $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7);

        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12);
        $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8);
        $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7);

        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12);
        $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8);
        $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7);

        // rowRound
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12);
        $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8);
        $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7);

        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12);
        $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8);
        $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7);

        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12);
        $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8);
        $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7);

        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12);
        $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8);
        $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7);
        // @codingStandardsIgnoreEnd

        $x0 += $z0;
        $x1 += $z1;
        $x2 += $z2;
        $x3 += $z3;
        $x4 += $z4;
        $x5 += $z5;
        $x6 += $z6;
        $x7 += $z7;
        $x8 += $z8;
        $x9 += $z9;
        $x10 += $z10;
        $x11 += $z11;
        $x12 += $z12;
        $x13 += $z13;
        $x14 += $z14;
        $x15 += $z15;

        return pack('V*', self::safe_intval($x0), self::safe_intval($x1), self::safe_intval($x2), self::safe_intval($x3), self::safe_intval($x4), self::safe_intval($x5), self::safe_intval($x6), self::safe_intval($x7), self::safe_intval($x8), self::safe_intval($x9), self::safe_intval($x10), self::safe_intval($x11), self::safe_intval($x12), self::safe_intval($x13), self::safe_intval($x14), self::safe_intval($x15));
    }
}
<?php

/**
 * Wrapper around hash() and hash_hmac() functions supporting truncated hashes
 * such as sha256-96.  Any hash algorithm returned by hash_algos() (and
 * truncated versions thereof) are supported.
 *
 * If {@link self::setKey() setKey()} is called, {@link self::hash() hash()} will
 * return the HMAC as opposed to the hash.
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $hash = new \phpseclib3\Crypt\Hash('sha512');
 *
 *    $hash->setKey('abcdefg');
 *
 *    echo base64_encode($hash->hash('abcdefg'));
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @author    Andreas Fischer <bantu@phpbb.com>
 * @copyright 2015 Andreas Fischer
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Exception\InsufficientSetupException;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\Math\BigInteger;
use phpseclib3\Math\PrimeField;

/**
 * @author  Jim Wigginton <terrafrost@php.net>
 * @author  Andreas Fischer <bantu@phpbb.com>
 */
class Hash
{
    /**
     * Padding Types
     *
     */
    const PADDING_KECCAK = 1;

    /**
     * Padding Types
     *
     */
    const PADDING_SHA3 = 2;

    /**
     * Padding Types
     *
     */
    const PADDING_SHAKE = 3;

    /**
     * Padding Type
     *
     * Only used by SHA3
     *
     * @var int
     */
    private $paddingType = 0;

    /**
     * Hash Parameter
     *
     * @see self::setHash()
     * @var int
     */
    private $hashParam;

    /**
     * Byte-length of hash output (Internal HMAC)
     *
     * @see self::setHash()
     * @var int
     */
    private $length;

    /**
     * Hash Algorithm
     *
     * @see self::setHash()
     * @var string
     */
    private $algo;

    /**
     * Key
     *
     * @see self::setKey()
     * @var string
     */
    private $key = false;

    /**
     * Nonce
     *
     * @see self::setNonce()
     * @var string
     */
    private $nonce = false;

    /**
     * Hash Parameters
     *
     * @var array
     */
    private $parameters = [];

    /**
     * Computed Key
     *
     * @see self::_computeKey()
     * @var string
     */
    private $computedKey = false;

    /**
     * Outer XOR (Internal HMAC)
     *
     * Used only for sha512
     *
     * @see self::hash()
     * @var string
     */
    private $opad;

    /**
     * Inner XOR (Internal HMAC)
     *
     * Used only for sha512
     *
     * @see self::hash()
     * @var string
     */
    private $ipad;

    /**
     * Recompute AES Key
     *
     * Used only for umac
     *
     * @see self::hash()
     * @var boolean
     */
    private $recomputeAESKey;

    /**
     * umac cipher object
     *
     * @see self::hash()
     * @var AES
     */
    private $c;

    /**
     * umac pad
     *
     * @see self::hash()
     * @var string
     */
    private $pad;

    /**
     * Block Size
     *
     * @var int
     */
    private $blockSize;

    /**#@+
     * UMAC variables
     *
     * @var PrimeField
     */
    private static $factory36;
    private static $factory64;
    private static $factory128;
    private static $offset64;
    private static $offset128;
    private static $marker64;
    private static $marker128;
    private static $maxwordrange64;
    private static $maxwordrange128;
    /**#@-*/

    /**#@+
     * AES_CMAC variables
     *
     * @var string
     */
    private $k1;
    private $k2;
    /**#@-*/

    /**
     * Default Constructor.
     *
     * @param string $hash
     */
    public function __construct($hash = 'sha256')
    {
        $this->setHash($hash);
    }

    /**
     * Sets the key for HMACs
     *
     * Keys can be of any length.
     *
     * @param string $key
     */
    public function setKey($key = false)
    {
        $this->key = $key;
        $this->computeKey();
        $this->recomputeAESKey = true;
    }

    /**
     * Sets the nonce for UMACs
     *
     * Keys can be of any length.
     *
     * @param string $nonce
     */
    public function setNonce($nonce = false)
    {
        switch (true) {
            case !is_string($nonce):
            case strlen($nonce) > 0 && strlen($nonce) <= 16:
                $this->recomputeAESKey = true;
                $this->nonce = $nonce;
                return;
        }

        throw new \LengthException('The nonce length must be between 1 and 16 bytes, inclusive');
    }

    /**
     * Pre-compute the key used by the HMAC
     *
     * Quoting http://tools.ietf.org/html/rfc2104#section-2, "Applications that use keys longer than B bytes
     * will first hash the key using H and then use the resultant L byte string as the actual key to HMAC."
     *
     * As documented in https://www.reddit.com/r/PHP/comments/9nct2l/symfonypolyfill_hash_pbkdf2_correct_fix_for/
     * when doing an HMAC multiple times it's faster to compute the hash once instead of computing it during
     * every call
     *
     */
    private function computeKey()
    {
        if ($this->key === false) {
            $this->computedKey = false;
            return;
        }

        if (strlen($this->key) <= $this->getBlockLengthInBytes()) {
            $this->computedKey = $this->key;
            return;
        }

        $this->computedKey = is_array($this->algo) ?
            call_user_func($this->algo, $this->key) :
            hash($this->algo, $this->key, true);
    }

    /**
     * Gets the hash function.
     *
     * As set by the constructor or by the setHash() method.
     *
     * @return string
     */
    public function getHash()
    {
        return $this->hashParam;
    }

    /**
     * Sets the hash function.
     *
     * @param string $hash
     */
    public function setHash($hash)
    {
        $oldHash = $this->hashParam;
        $this->hashParam = $hash = strtolower(str_replace('/', '-', $hash));
        switch ($hash) {
            case 'umac-32':
            case 'umac-64':
            case 'umac-96':
            case 'umac-128':
                if ($oldHash != $this->hashParam) {
                    $this->recomputeAESKey = true;
                }
                $this->blockSize = 128;
                $this->length = abs(substr($hash, -3)) >> 3;
                $this->algo = 'umac';
                return;
            case 'aes_cmac':
                if ($oldHash != $this->hashParam) {
                    $this->recomputeAESKey = true;
                }
                $this->blockSize = 128;
                $this->length = 16;
                $this->algo = 'aes_cmac';
                return;
            case 'md2-96':
            case 'md5-96':
            case 'sha1-96':
            case 'sha224-96':
            case 'sha256-96':
            case 'sha384-96':
            case 'sha512-96':
            case 'sha512-224-96':
            case 'sha512-256-96':
                $hash = substr($hash, 0, -3);
                $this->length = 12; // 96 / 8 = 12
                break;
            case 'md2':
            case 'md5':
                $this->length = 16;
                break;
            case 'sha1':
                $this->length = 20;
                break;
            case 'sha224':
            case 'sha512-224':
            case 'sha3-224':
                $this->length = 28;
                break;
            case 'keccak256':
                $this->paddingType = self::PADDING_KECCAK;
                // fall-through
            case 'sha256':
            case 'sha512-256':
            case 'sha3-256':
                $this->length = 32;
                break;
            case 'sha384':
            case 'sha3-384':
                $this->length = 48;
                break;
            case 'sha512':
            case 'sha3-512':
                $this->length = 64;
                break;
            default:
                if (preg_match('#^(shake(?:128|256))-(\d+)$#', $hash, $matches)) {
                    $this->paddingType = self::PADDING_SHAKE;
                    $hash = $matches[1];
                    $this->length = $matches[2] >> 3;
                } else {
                    throw new UnsupportedAlgorithmException(
                        "$hash is not a supported algorithm"
                    );
                }
        }

        switch ($hash) {
            case 'md2':
            case 'md2-96':
                $this->blockSize = 128;
                break;
            case 'md5-96':
            case 'sha1-96':
            case 'sha224-96':
            case 'sha256-96':
            case 'md5':
            case 'sha1':
            case 'sha224':
            case 'sha256':
                $this->blockSize = 512;
                break;
            case 'sha3-224':
                $this->blockSize = 1152; // 1600 - 2*224
                break;
            case 'sha3-256':
            case 'shake256':
            case 'keccak256':
                $this->blockSize = 1088; // 1600 - 2*256
                break;
            case 'sha3-384':
                $this->blockSize = 832; // 1600 - 2*384
                break;
            case 'sha3-512':
                $this->blockSize = 576; // 1600 - 2*512
                break;
            case 'shake128':
                $this->blockSize = 1344; // 1600 - 2*128
                break;
            default:
                $this->blockSize = 1024;
        }

        if (in_array(substr($hash, 0, 5), ['sha3-', 'shake', 'kecca'])) {
            // PHP 7.1.0 introduced support for "SHA3 fixed mode algorithms":
            // http://php.net/ChangeLog-7.php#7.1.0
            if (version_compare(PHP_VERSION, '7.1.0') < 0 || substr($hash, 0, 5) != 'sha3-') {
                //preg_match('#(\d+)$#', $hash, $matches);
                //$this->parameters['capacity'] = 2 * $matches[1]; // 1600 - $this->blockSize
                //$this->parameters['rate'] = 1600 - $this->parameters['capacity']; // == $this->blockSize
                if (!$this->paddingType) {
                    $this->paddingType = self::PADDING_SHA3;
                }
                $this->parameters = [
                    'capacity' => 1600 - $this->blockSize,
                    'rate' => $this->blockSize,
                    'length' => $this->length,
                    'padding' => $this->paddingType
                ];
                $hash = ['phpseclib3\Crypt\Hash', PHP_INT_SIZE == 8 ? 'sha3_64' : 'sha3_32'];
            }
        }

        if ($hash == 'sha512-224' || $hash == 'sha512-256') {
            // PHP 7.1.0 introduced sha512/224 and sha512/256 support:
            // http://php.net/ChangeLog-7.php#7.1.0
            if (version_compare(PHP_VERSION, '7.1.0') < 0) {
                // from http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#page=24
                $initial = $hash == 'sha512-256' ?
                    [
                        '22312194FC2BF72C', '9F555FA3C84C64C2', '2393B86B6F53B151', '963877195940EABD',
                        '96283EE2A88EFFE3', 'BE5E1E2553863992', '2B0199FC2C85B8AA', '0EB72DDC81C52CA2'
                    ] :
                    [
                        '8C3D37C819544DA2', '73E1996689DCD4D6', '1DFAB7AE32FF9C82', '679DD514582F9FCF',
                        '0F6D2B697BD44DA8', '77E36F7304C48942', '3F9D85A86A1D36C8', '1112E6AD91D692A1'
                    ];
                for ($i = 0; $i < 8; $i++) {
                    if (PHP_INT_SIZE == 8) {
                        list(, $initial[$i]) = unpack('J', pack('H*', $initial[$i]));
                    } else {
                        $initial[$i] = new BigInteger($initial[$i], 16);
                        $initial[$i]->setPrecision(64);
                    }
                }

                $this->parameters = compact('initial');

                $hash = ['phpseclib3\Crypt\Hash', PHP_INT_SIZE == 8 ? 'sha512_64' : 'sha512'];
            }
        }

        if (is_array($hash)) {
            $b = $this->blockSize >> 3;
            $this->ipad = str_repeat(chr(0x36), $b);
            $this->opad = str_repeat(chr(0x5C), $b);
        }

        // PHP's built in hash function does sha3-256 but sha512/256 so we'll update those accordingly
        switch ($hash) {
            case 'sha512-224':
                $hash = 'sha512/224';
                break;
            case 'sha512-256':
                $hash = 'sha512/256';
        }

        $this->algo = $hash;

        $this->computeKey();
    }

    /**
     * KDF: Key-Derivation Function
     *
     * The key-derivation function generates pseudorandom bits used to key the hash functions.
     *
     * @param int $index a non-negative integer less than 2^64
     * @param int $numbytes a non-negative integer less than 2^64
     * @return string string of length numbytes bytes
     */
    private function kdf($index, $numbytes)
    {
        $this->c->setIV(pack('N4', 0, $index, 0, 1));

        return $this->c->encrypt(str_repeat("\0", $numbytes));
    }

    /**
     * PDF Algorithm
     *
     * @return string string of length taglen bytes.
     */
    private function pdf()
    {
        $k = $this->key;
        $nonce = $this->nonce;
        $taglen = $this->length;

        //
        // Extract and zero low bit(s) of Nonce if needed
        //
        if ($taglen <= 8) {
            $last = strlen($nonce) - 1;
            $mask = $taglen == 4 ? "\3" : "\1";
            $index = $nonce[$last] & $mask;
            $nonce[$last] = $nonce[$last] ^ $index;
        }

        //
        // Make Nonce BLOCKLEN bytes by appending zeroes if needed
        //
        $nonce = str_pad($nonce, 16, "\0");

        //
        // Generate subkey, encipher and extract indexed substring
        //
        $kp = $this->kdf(0, 16);
        $c = new AES('ctr');
        $c->disablePadding();
        $c->setKey($kp);
        $c->setIV($nonce);
        $t = $c->encrypt("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");

        // we could use ord() but per https://paragonie.com/blog/2016/06/constant-time-encoding-boring-cryptography-rfc-4648-and-you
        // unpack() doesn't leak timing info
        return $taglen <= 8 ?
            substr($t, unpack('C', $index)[1] * $taglen, $taglen) :
            substr($t, 0, $taglen);
    }

    /**
     * UHASH Algorithm
     *
     * @param string $m string of length less than 2^67 bits.
     * @param int $taglen the integer 4, 8, 12 or 16.
     * @return string string of length taglen bytes.
     */
    private function uhash($m, $taglen)
    {
        //
        // One internal iteration per 4 bytes of output
        //
        $iters = $taglen >> 2;

        //
        // Define total key needed for all iterations using KDF.
        // L1Key reuses most key material between iterations.
        //
        //$L1Key  = $this->kdf(1, 1024 + ($iters - 1) * 16);
        $L1Key  = $this->kdf(1, (1024 + ($iters - 1)) * 16);
        $L2Key  = $this->kdf(2, $iters * 24);
        $L3Key1 = $this->kdf(3, $iters * 64);
        $L3Key2 = $this->kdf(4, $iters * 4);

        //
        // For each iteration, extract key and do three-layer hash.
        // If bytelength(M) <= 1024, then skip L2-HASH.
        //
        $y = '';
        for ($i = 0; $i < $iters; $i++) {
            $L1Key_i  = substr($L1Key, $i * 16, 1024);
            $L2Key_i  = substr($L2Key, $i * 24, 24);
            $L3Key1_i = substr($L3Key1, $i * 64, 64);
            $L3Key2_i = substr($L3Key2, $i * 4, 4);

            $a = self::L1Hash($L1Key_i, $m);
            $b = strlen($m) <= 1024 ? "\0\0\0\0\0\0\0\0$a" : self::L2Hash($L2Key_i, $a);
            $c = self::L3Hash($L3Key1_i, $L3Key2_i, $b);
            $y .= $c;
        }

        return $y;
    }

    /**
     * L1-HASH Algorithm
     *
     * The first-layer hash breaks the message into 1024-byte chunks and
     * hashes each with a function called NH.  Concatenating the results
     * forms a string, which is up to 128 times shorter than the original.
     *
     * @param string $k string of length 1024 bytes.
     * @param string $m string of length less than 2^67 bits.
     * @return string string of length (8 * ceil(bitlength(M)/8192)) bytes.
     */
    private static function L1Hash($k, $m)
    {
        //
        // Break M into 1024 byte chunks (final chunk may be shorter)
        //
        $m = str_split($m, 1024);

        //
        // For each chunk, except the last: endian-adjust, NH hash
        // and add bit-length.  Use results to build Y.
        //
        $length = 1024 * 8;
        $y = '';

        for ($i = 0; $i < count($m) - 1; $i++) {
            $m[$i] = pack('N*', ...unpack('V*', $m[$i])); // ENDIAN-SWAP
            $y .= PHP_INT_SIZE == 8 ?
                static::nh64($k, $m[$i], $length) :
                static::nh32($k, $m[$i], $length);
        }

        //
        // For the last chunk: pad to 32-byte boundary, endian-adjust,
        // NH hash and add bit-length.  Concatenate the result to Y.
        //
        $length = count($m) ? strlen($m[$i]) : 0;
        $pad = 32 - ($length % 32);
        $pad = max(32, $length + $pad % 32);
        $m[$i] = str_pad(isset($m[$i]) ? $m[$i] : '', $pad, "\0"); // zeropad
        $m[$i] = pack('N*', ...unpack('V*', $m[$i])); // ENDIAN-SWAP

        $y .= PHP_INT_SIZE == 8 ?
            static::nh64($k, $m[$i], $length * 8) :
            static::nh32($k, $m[$i], $length * 8);

        return $y;
    }

    /**
     * 32-bit safe 64-bit Multiply with 2x 32-bit ints
     *
     * @param int $x
     * @param int $y
     * @return string $x * $y
     */
    private static function mul32_64($x, $y)
    {
        // see mul64() for a more detailed explanation of how this works

        $x1 = ($x >> 16) & 0xFFFF;
        $x0 = $x & 0xFFFF;

        $y1 = ($y >> 16) & 0xFFFF;
        $y0 = $y & 0xFFFF;

        // the following 3x lines will possibly yield floats
        $z2 = $x1 * $y1;
        $z0 = $x0 * $y0;
        $z1 = $x1 * $y0 + $x0 * $y1;

        $a = intval(fmod($z0, 65536));
        $b = intval($z0 / 65536) + intval(fmod($z1, 65536));
        $c = intval($z1 / 65536) + intval(fmod($z2, 65536)) + intval($b / 65536);
        $b = intval(fmod($b, 65536));
        $d = intval($z2 / 65536) + intval($c / 65536);
        $c = intval(fmod($c, 65536));
        $d = intval(fmod($d, 65536));

        return pack('n4', $d, $c, $b, $a);
    }

    /**
     * 32-bit safe 64-bit Addition with 2x 64-bit strings
     *
     * @param int $x
     * @param int $y
     * @return int $x * $y
     */
    private static function add32_64($x, $y)
    {
        list(, $x1, $x2, $x3, $x4) = unpack('n4', $x);
        list(, $y1, $y2, $y3, $y4) = unpack('n4', $y);
        $a = $x4 + $y4;
        $b = $x3 + $y3 + ($a >> 16);
        $c = $x2 + $y2 + ($b >> 16);
        $d = $x1 + $y1 + ($c >> 16);
        return pack('n4', $d, $c, $b, $a);
    }

    /**
     * 32-bit safe 32-bit Addition with 2x 32-bit strings
     *
     * @param int $x
     * @param int $y
     * @return int $x * $y
     */
    private static function add32($x, $y)
    {
        // see add64() for a more detailed explanation of how this works

        $x1 = $x & 0xFFFF;
        $x2 = ($x >> 16) & 0xFFFF;
        $y1 = $y & 0xFFFF;
        $y2 = ($y >> 16) & 0xFFFF;

        $a = $x1 + $y1;
        $b = ($x2 + $y2 + ($a >> 16)) << 16;
        $a &= 0xFFFF;

        return $a | $b;
    }

    /**
     * NH Algorithm / 32-bit safe
     *
     * @param string $k string of length 1024 bytes.
     * @param string $m string with length divisible by 32 bytes.
     * @return string string of length 8 bytes.
     */
    private static function nh32($k, $m, $length)
    {
        //
        // Break M and K into 4-byte chunks
        //
        $k = unpack('N*', $k);
        $m = unpack('N*', $m);
        $t = count($m);

        //
        // Perform NH hash on the chunks, pairing words for multiplication
        // which are 4 apart to accommodate vector-parallelism.
        //
        $i = 1;
        $y = "\0\0\0\0\0\0\0\0";
        while ($i <= $t) {
            $temp  = self::add32($m[$i], $k[$i]);
            $temp2 = self::add32($m[$i + 4], $k[$i + 4]);
            $y = self::add32_64($y, self::mul32_64($temp, $temp2));

            $temp  = self::add32($m[$i + 1], $k[$i + 1]);
            $temp2 = self::add32($m[$i + 5], $k[$i + 5]);
            $y = self::add32_64($y, self::mul32_64($temp, $temp2));

            $temp  = self::add32($m[$i + 2], $k[$i + 2]);
            $temp2 = self::add32($m[$i + 6], $k[$i + 6]);
            $y = self::add32_64($y, self::mul32_64($temp, $temp2));

            $temp  = self::add32($m[$i + 3], $k[$i + 3]);
            $temp2 = self::add32($m[$i + 7], $k[$i + 7]);
            $y = self::add32_64($y, self::mul32_64($temp, $temp2));

            $i += 8;
        }

        return self::add32_64($y, pack('N2', 0, $length));
    }

    /**
     * 64-bit Multiply with 2x 32-bit ints
     *
     * @param int $x
     * @param int $y
     * @return int $x * $y
     */
    private static function mul64($x, $y)
    {
        // since PHP doesn't implement unsigned integers we'll implement them with signed integers
        // to do this we'll use karatsuba multiplication

        $x1 = $x >> 16;
        $x0 = $x & 0xFFFF;

        $y1 = $y >> 16;
        $y0 = $y & 0xFFFF;

        $z2 = $x1 * $y1; // up to 32 bits long
        $z0 = $x0 * $y0; // up to 32 bits long
        $z1 = $x1 * $y0 + $x0 * $y1; // up to 33 bit long
        // normally karatsuba multiplication calculates $z1 thusly:
        //$z1 = ($x1 + $x0) * ($y0 + $y1) - $z2 - $z0;
        // the idea being to eliminate one extra multiplication. for arbitrary precision math that makes sense
        // but not for this purpose

        // at this point karatsuba would normally return this:
        //return ($z2 << 64) + ($z1 << 32) + $z0;
        // the problem is that the output could be out of range for signed 64-bit ints,
        // which would cause PHP to switch to floats, which would risk losing the lower few bits
        // as such we'll OR 4x 16-bit blocks together like so:
        /*
          ........  |  ........  |  ........  |  ........
          upper $z2 |  lower $z2 |  lower $z1 |  lower $z0
                    | +upper $z1 | +upper $z0 |
         +   $carry | +   $carry |            |
        */
        // technically upper $z1 is 17 bit - not 16 - but the most significant digit of that will
        // just get added to $carry

        $a = $z0 & 0xFFFF;
        $b = ($z0 >> 16) + ($z1 & 0xFFFF);
        $c = ($z1 >> 16) + ($z2 & 0xFFFF) + ($b >> 16);
        $b = ($b & 0xFFFF) << 16;
        $d = ($z2 >> 16) + ($c >> 16);
        $c = ($c & 0xFFFF) << 32;
        $d = ($d & 0xFFFF) << 48;

        return $a | $b | $c | $d;
    }

    /**
     * 64-bit Addition with 2x 64-bit ints
     *
     * @param int $x
     * @param int $y
     * @return int $x + $y
     */
    private static function add64($x, $y)
    {
        // doing $x + $y risks returning a result that's out of range for signed 64-bit ints
        // in that event PHP would convert the result to a float and precision would be lost
        // so we'll just add 2x 32-bit ints together like so:
        /*
           ........ | ........
           upper $x | lower $x
          +upper $y |+lower $y
          +  $carry |
        */
        $x1 = $x & 0xFFFFFFFF;
        $x2 = ($x >> 32) & 0xFFFFFFFF;
        $y1 = $y & 0xFFFFFFFF;
        $y2 = ($y >> 32) & 0xFFFFFFFF;

        $a = $x1 + $y1;
        $b = ($x2 + $y2 + ($a >> 32)) << 32;
        $a &= 0xFFFFFFFF;

        return $a | $b;
    }

    /**
     * NH Algorithm / 64-bit safe
     *
     * @param string $k string of length 1024 bytes.
     * @param string $m string with length divisible by 32 bytes.
     * @return string string of length 8 bytes.
     */
    private static function nh64($k, $m, $length)
    {
        //
        // Break M and K into 4-byte chunks
        //
        $k = unpack('N*', $k);
        $m = unpack('N*', $m);
        $t = count($m);

        //
        // Perform NH hash on the chunks, pairing words for multiplication
        // which are 4 apart to accommodate vector-parallelism.
        //
        $i = 1;
        $y = 0;
        while ($i <= $t) {
            $temp  = ($m[$i] + $k[$i]) & 0xFFFFFFFF;
            $temp2 = ($m[$i + 4] + $k[$i + 4]) & 0xFFFFFFFF;
            $y = self::add64($y, self::mul64($temp, $temp2));

            $temp  = ($m[$i + 1] + $k[$i + 1]) & 0xFFFFFFFF;
            $temp2 = ($m[$i + 5] + $k[$i + 5]) & 0xFFFFFFFF;
            $y = self::add64($y, self::mul64($temp, $temp2));

            $temp  = ($m[$i + 2] + $k[$i + 2]) & 0xFFFFFFFF;
            $temp2 = ($m[$i + 6] + $k[$i + 6]) & 0xFFFFFFFF;
            $y = self::add64($y, self::mul64($temp, $temp2));

            $temp  = ($m[$i + 3] + $k[$i + 3]) & 0xFFFFFFFF;
            $temp2 = ($m[$i + 7] + $k[$i + 7]) & 0xFFFFFFFF;
            $y = self::add64($y, self::mul64($temp, $temp2));

            $i += 8;
        }

        return pack('J', self::add64($y, $length));
    }

    /**
     * L2-HASH: Second-Layer Hash
     *
     * The second-layer rehashes the L1-HASH output using a polynomial hash
     * called POLY.  If the L1-HASH output is long, then POLY is called once
     * on a prefix of the L1-HASH output and called using different settings
     * on the remainder.  (This two-step hashing of the L1-HASH output is
     * needed only if the message length is greater than 16 megabytes.)
     * Careful implementation of POLY is necessary to avoid a possible
     * timing attack (see Section 6.6 for more information).
     *
     * @param string $k string of length 24 bytes.
     * @param string $m string of length less than 2^64 bytes.
     * @return string string of length 16 bytes.
     */
    private static function L2Hash($k, $m)
    {
        //
        //  Extract keys and restrict to special key-sets
        //
        $k64 = $k & "\x01\xFF\xFF\xFF\x01\xFF\xFF\xFF";
        $k64 = new BigInteger($k64, 256);
        $k128 = substr($k, 8) & "\x01\xFF\xFF\xFF\x01\xFF\xFF\xFF\x01\xFF\xFF\xFF\x01\xFF\xFF\xFF";
        $k128 = new BigInteger($k128, 256);

        //
        // If M is no more than 2^17 bytes, hash under 64-bit prime,
        // otherwise, hash first 2^17 bytes under 64-bit prime and
        // remainder under 128-bit prime.
        //
        if (strlen($m) <= 0x20000) { // 2^14 64-bit words
            $y = self::poly(64, self::$maxwordrange64, $k64, $m);
        } else {
            $m_1 = substr($m, 0, 0x20000); // 1 << 17
            $m_2 = substr($m, 0x20000) . "\x80";
            $length = strlen($m_2);
            $pad = 16 - ($length % 16);
            $pad %= 16;
            $m_2 = str_pad($m_2, $length + $pad, "\0"); // zeropad
            $y = self::poly(64, self::$maxwordrange64, $k64, $m_1);
            $y = str_pad($y, 16, "\0", STR_PAD_LEFT);
            $y = self::poly(128, self::$maxwordrange128, $k128, $y . $m_2);
        }

        return str_pad($y, 16, "\0", STR_PAD_LEFT);
    }

    /**
     * POLY Algorithm
     *
     * @param int $wordbits the integer 64 or 128.
     * @param BigInteger $maxwordrange positive integer less than 2^wordbits.
     * @param BigInteger $k integer in the range 0 ... prime(wordbits) - 1.
     * @param string $m string with length divisible by (wordbits / 8) bytes.
     * @return integer in the range 0 ... prime(wordbits) - 1.
     */
    private static function poly($wordbits, $maxwordrange, $k, $m)
    {
        //
        // Define constants used for fixing out-of-range words
        //
        $wordbytes = $wordbits >> 3;
        if ($wordbits == 128) {
            $factory = self::$factory128;
            $offset = self::$offset128;
            $marker = self::$marker128;
        } else {
            $factory = self::$factory64;
            $offset = self::$offset64;
            $marker = self::$marker64;
        }

        $k = $factory->newInteger($k);

        //
        // Break M into chunks of length wordbytes bytes
        //
        $m_i = str_split($m, $wordbytes);

        //
        // Each input word m is compared with maxwordrange.  If not smaller
        // then 'marker' and (m - offset), both in range, are hashed.
        //
        $y = $factory->newInteger(new BigInteger(1));
        foreach ($m_i as $m) {
            $m = $factory->newInteger(new BigInteger($m, 256));
            if ($m->compare($maxwordrange) >= 0) {
                $y = $k->multiply($y)->add($marker);
                $y = $k->multiply($y)->add($m->subtract($offset));
            } else {
                $y = $k->multiply($y)->add($m);
            }
        }

        return $y->toBytes();
    }

    /**
     * L3-HASH: Third-Layer Hash
     *
     * The output from L2-HASH is 16 bytes long.  This final hash function
     * hashes the 16-byte string to a fixed length of 4 bytes.
     *
     * @param string $k1 string of length 64 bytes.
     * @param string $k2 string of length 4 bytes.
     * @param string $m string of length 16 bytes.
     * @return string string of length 4 bytes.
     */
    private static function L3Hash($k1, $k2, $m)
    {
        $factory = self::$factory36;

        $y = $factory->newInteger(new BigInteger());
        for ($i = 0; $i < 8; $i++) {
            $m_i = $factory->newInteger(new BigInteger(substr($m, 2 * $i, 2), 256));
            $k_i = $factory->newInteger(new BigInteger(substr($k1, 8 * $i, 8), 256));
            $y = $y->add($m_i->multiply($k_i));
        }
        $y = str_pad(substr($y->toBytes(), -4), 4, "\0", STR_PAD_LEFT);
        $y = $y ^ $k2;

        return $y;
    }

    /**
     * Compute the Hash / HMAC / UMAC.
     *
     * @param string $text
     * @return string
     */
    public function hash($text)
    {
        $algo = $this->algo;
        // https://www.rfc-editor.org/rfc/rfc4493.html
        // https://en.wikipedia.org/wiki/One-key_MAC
        if ($algo == 'aes_cmac') {
            $constZero = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
            if ($this->recomputeAESKey) {
                if (!is_string($this->key)) {
                    throw new InsufficientSetupException('No key has been set');
                }
                if (strlen($this->key) != 16) {
                    throw new \LengthException('Key must be 16 bytes long');
                }
                // Algorithm Generate_Subkey
                $constRb = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x87";
                $this->c = new AES('ecb');
                $this->c->setKey($this->key);
                $this->c->disablePadding();
                $l = $this->c->encrypt($constZero);
                $msb = ($l & "\x80") == "\x80";
                $l = new BigInteger($l, 256);
                $l->setPrecision(128);
                $l = $l->bitwise_leftShift(1)->toBytes();
                // make it constant time
                $k1 = $msb ? $l ^ $constRb : $l | $constZero;

                $msb = ($k1 & "\x80") == "\x80";
                $k2 = new BigInteger($k1, 256);
                $k2->setPrecision(128);
                $k2 = $k2->bitwise_leftShift(1)->toBytes();
                // make it constant time
                $k2 = $msb ? $k2 ^ $constRb : $k2 | $constZero;

                $this->k1 = $k1;
                $this->k2 = $k2;
            }

            $len = strlen($text);
            $const_Bsize = 16;
            $M = strlen($text) ? str_split($text, $const_Bsize) : [''];

            // Step 2
            $n = ceil($len / $const_Bsize);
            // Step 3
            if ($n == 0) {
                $n = 1;
                $flag = false;
            } else {
                $flag = $len % $const_Bsize == 0;
            }
            // Step 4
            $M_last = $flag ?
                $M[$n - 1] ^ $k1 :
                self::OMAC_padding($M[$n - 1], $const_Bsize) ^ $k2;
            // Step 5
            $x = $constZero;
            // Step 6
            $c = &$this->c;
            for ($i = 0; $i < $n - 1; $i++) {
                $y = $x ^ $M[$i];
                $x = $c->encrypt($y);
            }
            $y = $M_last ^ $x;
            return $c->encrypt($y);
        }
        if ($algo == 'umac') {
            if ($this->recomputeAESKey) {
                if (!is_string($this->nonce)) {
                    throw new InsufficientSetupException('No nonce has been set');
                }
                if (!is_string($this->key)) {
                    throw new InsufficientSetupException('No key has been set');
                }
                if (strlen($this->key) != 16) {
                    throw new \LengthException('Key must be 16 bytes long');
                }

                if (!isset(self::$maxwordrange64)) {
                    $one = new BigInteger(1);

                    $prime36 = new BigInteger("\x00\x00\x00\x0F\xFF\xFF\xFF\xFB", 256);
                    self::$factory36 = new PrimeField($prime36);

                    $prime64 = new BigInteger("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xC5", 256);
                    self::$factory64 = new PrimeField($prime64);

                    $prime128 = new BigInteger("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x61", 256);
                    self::$factory128 = new PrimeField($prime128);

                    self::$offset64 = new BigInteger("\1\0\0\0\0\0\0\0\0", 256);
                    self::$offset64 = self::$factory64->newInteger(self::$offset64->subtract($prime64));
                    self::$offset128 = new BigInteger("\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 256);
                    self::$offset128 = self::$factory128->newInteger(self::$offset128->subtract($prime128));

                    self::$marker64 = self::$factory64->newInteger($prime64->subtract($one));
                    self::$marker128 = self::$factory128->newInteger($prime128->subtract($one));

                    $maxwordrange64 = $one->bitwise_leftShift(64)->subtract($one->bitwise_leftShift(32));
                    self::$maxwordrange64 = self::$factory64->newInteger($maxwordrange64);

                    $maxwordrange128 = $one->bitwise_leftShift(128)->subtract($one->bitwise_leftShift(96));
                    self::$maxwordrange128 = self::$factory128->newInteger($maxwordrange128);
                }

                $this->c = new AES('ctr');
                $this->c->disablePadding();
                $this->c->setKey($this->key);

                $this->pad = $this->pdf();

                $this->recomputeAESKey = false;
            }

            $hashedmessage = $this->uhash($text, $this->length);
            return $hashedmessage ^ $this->pad;
        }

        if (is_array($algo)) {
            if (empty($this->key) || !is_string($this->key)) {
                return substr($algo($text, ...array_values($this->parameters)), 0, $this->length);
            }

            // SHA3 HMACs are discussed at https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf#page=30

            $key    = str_pad($this->computedKey, $b, chr(0));
            $temp   = $this->ipad ^ $key;
            $temp  .= $text;
            $temp   = substr($algo($temp, ...array_values($this->parameters)), 0, $this->length);
            $output = $this->opad ^ $key;
            $output .= $temp;
            $output = $algo($output, ...array_values($this->parameters));

            return substr($output, 0, $this->length);
        }

        $output = !empty($this->key) || is_string($this->key) ?
            hash_hmac($algo, $text, $this->computedKey, true) :
            hash($algo, $text, true);

        return strlen($output) > $this->length
            ? substr($output, 0, $this->length)
            : $output;
    }

    /**
     * Returns the hash length (in bits)
     *
     * @return int
     */
    public function getLength()
    {
        return $this->length << 3;
    }

    /**
     * Returns the hash length (in bytes)
     *
     * @return int
     */
    public function getLengthInBytes()
    {
        return $this->length;
    }

    /**
     * Returns the block length (in bits)
     *
     * @return int
     */
    public function getBlockLength()
    {
        return $this->blockSize;
    }

    /**
     * Returns the block length (in bytes)
     *
     * @return int
     */
    public function getBlockLengthInBytes()
    {
        return $this->blockSize >> 3;
    }

    /**
     * Pads SHA3 based on the mode
     *
     * @param int $padLength
     * @param int $padType
     * @return string
     */
    private static function sha3_pad($padLength, $padType)
    {
        switch ($padType) {
            case self::PADDING_KECCAK:
                $temp = chr(0x01) . str_repeat("\0", $padLength - 1);
                $temp[$padLength - 1] = $temp[$padLength - 1] | chr(0x80);
                return $temp;
            case self::PADDING_SHAKE:
                $temp = chr(0x1F) . str_repeat("\0", $padLength - 1);
                $temp[$padLength - 1] = $temp[$padLength - 1] | chr(0x80);
                return $temp;
            //case self::PADDING_SHA3:
            default:
                // from https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf#page=36
                return $padLength == 1 ? chr(0x86) : chr(0x06) . str_repeat("\0", $padLength - 2) . chr(0x80);
        }
    }

    /**
     * Pure-PHP 32-bit implementation of SHA3
     *
     * Whereas BigInteger.php's 32-bit engine works on PHP 64-bit this 32-bit implementation
     * of SHA3 will *not* work on PHP 64-bit. This is because this implementation
     * employees bitwise NOTs and bitwise left shifts. And the round constants only work
     * on 32-bit PHP. eg. dechex(-2147483648) returns 80000000 on 32-bit PHP and
     * FFFFFFFF80000000 on 64-bit PHP. Sure, we could do bitwise ANDs but that would slow
     * things down.
     *
     * SHA512 requires BigInteger to simulate 64-bit unsigned integers because SHA2 employees
     * addition whereas SHA3 just employees bitwise operators. PHP64 only supports signed
     * 64-bit integers, which complicates addition, whereas that limitation isn't an issue
     * for SHA3.
     *
     * In https://ws680.nist.gov/publication/get_pdf.cfm?pub_id=919061#page=16 KECCAK[C] is
     * defined as "the KECCAK instance with KECCAK-f[1600] as the underlying permutation and
     * capacity c". This is relevant because, altho the KECCAK standard defines a mode
     * (KECCAK-f[800]) designed for 32-bit machines that mode is incompatible with SHA3
     *
     * @param string $p
     * @param int $c
     * @param int $r
     * @param int $d
     * @param int $padType
     */
    private static function sha3_32($p, $c, $r, $d, $padType)
    {
        $block_size = $r >> 3;
        $padLength = $block_size - (strlen($p) % $block_size);
        $num_ints = $block_size >> 2;

        $p .= static::sha3_pad($padLength, $padType);

        $n = strlen($p) / $r; // number of blocks

        $s = [
            [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]],
            [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]],
            [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]],
            [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]],
            [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
        ];

        $p = str_split($p, $block_size);

        foreach ($p as $pi) {
            $pi = unpack('V*', $pi);
            $x = $y = 0;
            for ($i = 1; $i <= $num_ints; $i += 2) {
                $s[$x][$y][0] ^= $pi[$i + 1];
                $s[$x][$y][1] ^= $pi[$i];
                if (++$y == 5) {
                    $y = 0;
                    $x++;
                }
            }
            static::processSHA3Block32($s);
        }

        $z = '';
        $i = $j = 0;
        while (strlen($z) < $d) {
            $z .= pack('V2', $s[$i][$j][1], $s[$i][$j++][0]);
            if ($j == 5) {
                $j = 0;
                $i++;
                if ($i == 5) {
                    $i = 0;
                    static::processSHA3Block32($s);
                }
            }
        }

        return $z;
    }

    /**
     * 32-bit block processing method for SHA3
     *
     * @param array $s
     */
    private static function processSHA3Block32(&$s)
    {
        static $rotationOffsets = [
            [ 0,  1, 62, 28, 27],
            [36, 44,  6, 55, 20],
            [ 3, 10, 43, 25, 39],
            [41, 45, 15, 21,  8],
            [18,  2, 61, 56, 14]
        ];

        // the standards give these constants in hexadecimal notation. it's tempting to want to use
        // that same notation, here, however, we can't, because 0x80000000, on PHP32, is a positive
        // float - not the negative int that we need to be in PHP32. so we use -2147483648 instead
        static $roundConstants = [
            [0, 1],
            [0, 32898],
            [-2147483648, 32906],
            [-2147483648, -2147450880],
            [0, 32907],
            [0, -2147483647],
            [-2147483648, -2147450751],
            [-2147483648, 32777],
            [0, 138],
            [0, 136],
            [0, -2147450871],
            [0, -2147483638],
            [0, -2147450741],
            [-2147483648, 139],
            [-2147483648, 32905],
            [-2147483648, 32771],
            [-2147483648, 32770],
            [-2147483648, 128],
            [0, 32778],
            [-2147483648, -2147483638],
            [-2147483648, -2147450751],
            [-2147483648, 32896],
            [0, -2147483647],
            [-2147483648, -2147450872]
        ];

        for ($round = 0; $round < 24; $round++) {
            // theta step
            $parity = $rotated = [];
            for ($i = 0; $i < 5; $i++) {
                $parity[] = [
                    $s[0][$i][0] ^ $s[1][$i][0] ^ $s[2][$i][0] ^ $s[3][$i][0] ^ $s[4][$i][0],
                    $s[0][$i][1] ^ $s[1][$i][1] ^ $s[2][$i][1] ^ $s[3][$i][1] ^ $s[4][$i][1]
                ];
                $rotated[] = static::rotateLeft32($parity[$i], 1);
            }

            $temp = [
                [$parity[4][0] ^ $rotated[1][0], $parity[4][1] ^ $rotated[1][1]],
                [$parity[0][0] ^ $rotated[2][0], $parity[0][1] ^ $rotated[2][1]],
                [$parity[1][0] ^ $rotated[3][0], $parity[1][1] ^ $rotated[3][1]],
                [$parity[2][0] ^ $rotated[4][0], $parity[2][1] ^ $rotated[4][1]],
                [$parity[3][0] ^ $rotated[0][0], $parity[3][1] ^ $rotated[0][1]]
            ];
            for ($i = 0; $i < 5; $i++) {
                for ($j = 0; $j < 5; $j++) {
                    $s[$i][$j][0] ^= $temp[$j][0];
                    $s[$i][$j][1] ^= $temp[$j][1];
                }
            }

            $st = $s;

            // rho and pi steps
            for ($i = 0; $i < 5; $i++) {
                for ($j = 0; $j < 5; $j++) {
                    $st[(2 * $i + 3 * $j) % 5][$j] = static::rotateLeft32($s[$j][$i], $rotationOffsets[$j][$i]);
                }
            }

            // chi step
            for ($i = 0; $i < 5; $i++) {
                $s[$i][0] = [
                    $st[$i][0][0] ^ (~$st[$i][1][0] & $st[$i][2][0]),
                    $st[$i][0][1] ^ (~$st[$i][1][1] & $st[$i][2][1])
                ];
                $s[$i][1] = [
                    $st[$i][1][0] ^ (~$st[$i][2][0] & $st[$i][3][0]),
                    $st[$i][1][1] ^ (~$st[$i][2][1] & $st[$i][3][1])
                ];
                $s[$i][2] = [
                    $st[$i][2][0] ^ (~$st[$i][3][0] & $st[$i][4][0]),
                    $st[$i][2][1] ^ (~$st[$i][3][1] & $st[$i][4][1])
                ];
                $s[$i][3] = [
                    $st[$i][3][0] ^ (~$st[$i][4][0] & $st[$i][0][0]),
                    $st[$i][3][1] ^ (~$st[$i][4][1] & $st[$i][0][1])
                ];
                $s[$i][4] = [
                    $st[$i][4][0] ^ (~$st[$i][0][0] & $st[$i][1][0]),
                    $st[$i][4][1] ^ (~$st[$i][0][1] & $st[$i][1][1])
                ];
            }

            // iota step
            $s[0][0][0] ^= $roundConstants[$round][0];
            $s[0][0][1] ^= $roundConstants[$round][1];
        }
    }

    /**
     * Rotate 32-bit int
     *
     * @param array $x
     * @param int $shift
     */
    private static function rotateLeft32($x, $shift)
    {
        if ($shift < 32) {
            list($hi, $lo) = $x;
        } else {
            $shift -= 32;
            list($lo, $hi) = $x;
        }

        $mask = -1 ^ (-1 << $shift);
        return [
            ($hi << $shift) | (($lo >> (32 - $shift)) & $mask),
            ($lo << $shift) | (($hi >> (32 - $shift)) & $mask)
        ];
    }

    /**
     * Pure-PHP 64-bit implementation of SHA3
     *
     * @param string $p
     * @param int $c
     * @param int $r
     * @param int $d
     * @param int $padType
     */
    private static function sha3_64($p, $c, $r, $d, $padType)
    {
        $block_size = $r >> 3;
        $padLength = $block_size - (strlen($p) % $block_size);
        $num_ints = $block_size >> 2;

        $p .= static::sha3_pad($padLength, $padType);

        $n = strlen($p) / $r; // number of blocks

        $s = [
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0]
        ];

        $p = str_split($p, $block_size);

        foreach ($p as $pi) {
            $pi = unpack('P*', $pi);
            $x = $y = 0;
            foreach ($pi as $subpi) {
                $s[$x][$y++] ^= $subpi;
                if ($y == 5) {
                    $y = 0;
                    $x++;
                }
            }
            static::processSHA3Block64($s);
        }

        $z = '';
        $i = $j = 0;
        while (strlen($z) < $d) {
            $z .= pack('P', $s[$i][$j++]);
            if ($j == 5) {
                $j = 0;
                $i++;
                if ($i == 5) {
                    $i = 0;
                    static::processSHA3Block64($s);
                }
            }
        }

        return $z;
    }

    /**
     * 64-bit block processing method for SHA3
     *
     * @param array $s
     */
    private static function processSHA3Block64(&$s)
    {
        static $rotationOffsets = [
            [ 0,  1, 62, 28, 27],
            [36, 44,  6, 55, 20],
            [ 3, 10, 43, 25, 39],
            [41, 45, 15, 21,  8],
            [18,  2, 61, 56, 14]
        ];

        static $roundConstants = [
            1,
            32898,
            -9223372036854742902,
            -9223372034707259392,
            32907,
            2147483649,
            -9223372034707259263,
            -9223372036854743031,
            138,
            136,
            2147516425,
            2147483658,
            2147516555,
            -9223372036854775669,
            -9223372036854742903,
            -9223372036854743037,
            -9223372036854743038,
            -9223372036854775680,
            32778,
            -9223372034707292150,
            -9223372034707259263,
            -9223372036854742912,
            2147483649,
            -9223372034707259384
        ];

        for ($round = 0; $round < 24; $round++) {
            // theta step
            $parity = [];
            for ($i = 0; $i < 5; $i++) {
                $parity[] = $s[0][$i] ^ $s[1][$i] ^ $s[2][$i] ^ $s[3][$i] ^ $s[4][$i];
            }
            $temp = [
                $parity[4] ^ static::rotateLeft64($parity[1], 1),
                $parity[0] ^ static::rotateLeft64($parity[2], 1),
                $parity[1] ^ static::rotateLeft64($parity[3], 1),
                $parity[2] ^ static::rotateLeft64($parity[4], 1),
                $parity[3] ^ static::rotateLeft64($parity[0], 1)
            ];
            for ($i = 0; $i < 5; $i++) {
                for ($j = 0; $j < 5; $j++) {
                    $s[$i][$j] ^= $temp[$j];
                }
            }

            $st = $s;

            // rho and pi steps
            for ($i = 0; $i < 5; $i++) {
                for ($j = 0; $j < 5; $j++) {
                    $st[(2 * $i + 3 * $j) % 5][$j] = static::rotateLeft64($s[$j][$i], $rotationOffsets[$j][$i]);
                }
            }

            // chi step
            for ($i = 0; $i < 5; $i++) {
                $s[$i] = [
                    $st[$i][0] ^ (~$st[$i][1] & $st[$i][2]),
                    $st[$i][1] ^ (~$st[$i][2] & $st[$i][3]),
                    $st[$i][2] ^ (~$st[$i][3] & $st[$i][4]),
                    $st[$i][3] ^ (~$st[$i][4] & $st[$i][0]),
                    $st[$i][4] ^ (~$st[$i][0] & $st[$i][1])
                ];
            }

            // iota step
            $s[0][0] ^= $roundConstants[$round];
        }
    }

    /**
     * Left rotate 64-bit int
     *
     * @param int $x
     * @param int $shift
     */
    private static function rotateLeft64($x, $shift)
    {
        $mask = -1 ^ (-1 << $shift);
        return ($x << $shift) | (($x >> (64 - $shift)) & $mask);
    }

    /**
     * Right rotate 64-bit int
     *
     * @param int $x
     * @param int $shift
     */
    private static function rotateRight64($x, $shift)
    {
        $mask = -1 ^ (-1 << (64 - $shift));
        return (($x >> $shift) & $mask) | ($x << (64 - $shift));
    }

    /**
     * Pure-PHP implementation of SHA512
     *
     * @param string $m
     * @param array $hash
     * @return string
     */
    private static function sha512($m, $hash)
    {
        static $k;

        if (!isset($k)) {
            // Initialize table of round constants
            // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
            $k = [
                '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
                '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
                'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
                '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
                'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
                '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
                '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
                'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
                '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
                '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
                'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
                'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
                '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
                '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
                '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
                '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
                'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
                '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
                '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
                '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
            ];

            for ($i = 0; $i < 80; $i++) {
                $k[$i] = new BigInteger($k[$i], 16);
            }
        }

        // Pre-processing
        $length = strlen($m);
        // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
        $m .= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
        $m[$length] = chr(0x80);
        // we don't support hashing strings 512MB long
        $m .= pack('N4', 0, 0, 0, $length << 3);

        // Process the message in successive 1024-bit chunks
        $chunks = str_split($m, 128);
        foreach ($chunks as $chunk) {
            $w = [];
            for ($i = 0; $i < 16; $i++) {
                $temp = new BigInteger(Strings::shift($chunk, 8), 256);
                $temp->setPrecision(64);
                $w[] = $temp;
            }

            // Extend the sixteen 32-bit words into eighty 32-bit words
            for ($i = 16; $i < 80; $i++) {
                $temp = [
                          $w[$i - 15]->bitwise_rightRotate(1),
                          $w[$i - 15]->bitwise_rightRotate(8),
                          $w[$i - 15]->bitwise_rightShift(7)
                ];
                $s0 = $temp[0]->bitwise_xor($temp[1]);
                $s0 = $s0->bitwise_xor($temp[2]);
                $temp = [
                          $w[$i - 2]->bitwise_rightRotate(19),
                          $w[$i - 2]->bitwise_rightRotate(61),
                          $w[$i - 2]->bitwise_rightShift(6)
                ];
                $s1 = $temp[0]->bitwise_xor($temp[1]);
                $s1 = $s1->bitwise_xor($temp[2]);
                $w[$i] = clone $w[$i - 16];
                $w[$i] = $w[$i]->add($s0);
                $w[$i] = $w[$i]->add($w[$i - 7]);
                $w[$i] = $w[$i]->add($s1);
            }

            // Initialize hash value for this chunk
            $a = clone $hash[0];
            $b = clone $hash[1];
            $c = clone $hash[2];
            $d = clone $hash[3];
            $e = clone $hash[4];
            $f = clone $hash[5];
            $g = clone $hash[6];
            $h = clone $hash[7];

            // Main loop
            for ($i = 0; $i < 80; $i++) {
                $temp = [
                    $a->bitwise_rightRotate(28),
                    $a->bitwise_rightRotate(34),
                    $a->bitwise_rightRotate(39)
                ];
                $s0 = $temp[0]->bitwise_xor($temp[1]);
                $s0 = $s0->bitwise_xor($temp[2]);
                $temp = [
                    $a->bitwise_and($b),
                    $a->bitwise_and($c),
                    $b->bitwise_and($c)
                ];
                $maj = $temp[0]->bitwise_xor($temp[1]);
                $maj = $maj->bitwise_xor($temp[2]);
                $t2 = $s0->add($maj);

                $temp = [
                    $e->bitwise_rightRotate(14),
                    $e->bitwise_rightRotate(18),
                    $e->bitwise_rightRotate(41)
                ];
                $s1 = $temp[0]->bitwise_xor($temp[1]);
                $s1 = $s1->bitwise_xor($temp[2]);
                $temp = [
                    $e->bitwise_and($f),
                    $g->bitwise_and($e->bitwise_not())
                ];
                $ch = $temp[0]->bitwise_xor($temp[1]);
                $t1 = $h->add($s1);
                $t1 = $t1->add($ch);
                $t1 = $t1->add($k[$i]);
                $t1 = $t1->add($w[$i]);

                $h = clone $g;
                $g = clone $f;
                $f = clone $e;
                $e = $d->add($t1);
                $d = clone $c;
                $c = clone $b;
                $b = clone $a;
                $a = $t1->add($t2);
            }

            // Add this chunk's hash to result so far
            $hash = [
                $hash[0]->add($a),
                $hash[1]->add($b),
                $hash[2]->add($c),
                $hash[3]->add($d),
                $hash[4]->add($e),
                $hash[5]->add($f),
                $hash[6]->add($g),
                $hash[7]->add($h)
            ];
        }

        // Produce the final hash value (big-endian)
        // (\phpseclib3\Crypt\Hash::hash() trims the output for hashes but not for HMACs.  as such, we trim the output here)
        $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
                $hash[4]->toBytes() . $hash[5]->toBytes() . $hash[6]->toBytes() . $hash[7]->toBytes();

        return $temp;
    }

    /**
     * Pure-PHP implementation of SHA512
     *
     * @param string $m
     * @param array $hash
     * @return string
     */
    private static function sha512_64($m, $hash)
    {
        static $k;

        if (!isset($k)) {
            // Initialize table of round constants
            // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
            $k = [
                '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
                '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
                'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
                '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
                'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
                '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
                '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
                'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
                '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
                '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
                'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
                'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
                '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
                '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
                '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
                '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
                'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
                '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
                '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
                '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
            ];

            for ($i = 0; $i < 80; $i++) {
                list(, $k[$i]) = unpack('J', pack('H*', $k[$i]));
            }
        }

        // Pre-processing
        $length = strlen($m);
        // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
        $m .= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
        $m[$length] = chr(0x80);
        // we don't support hashing strings 512MB long
        $m .= pack('N4', 0, 0, 0, $length << 3);

        // Process the message in successive 1024-bit chunks
        $chunks = str_split($m, 128);
        foreach ($chunks as $chunk) {
            $w = [];
            for ($i = 0; $i < 16; $i++) {
                list(, $w[]) = unpack('J', Strings::shift($chunk, 8));
            }

            // Extend the sixteen 32-bit words into eighty 32-bit words
            for ($i = 16; $i < 80; $i++) {
                $temp = [
                    self::rotateRight64($w[$i - 15], 1),
                    self::rotateRight64($w[$i - 15], 8),
                    ($w[$i - 15] >> 7) & 0x01FFFFFFFFFFFFFF,
                ];
                $s0 = $temp[0] ^ $temp[1] ^ $temp[2];
                $temp = [
                    self::rotateRight64($w[$i - 2], 19),
                    self::rotateRight64($w[$i - 2], 61),
                    ($w[$i - 2] >> 6) & 0x03FFFFFFFFFFFFFF,
                ];
                $s1 = $temp[0] ^ $temp[1] ^ $temp[2];

                $w[$i] = $w[$i - 16];
                $w[$i] = self::add64($w[$i], $s0);
                $w[$i] = self::add64($w[$i], $w[$i - 7]);
                $w[$i] = self::add64($w[$i], $s1);
            }

            // Initialize hash value for this chunk
            list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;

            // Main loop
            for ($i = 0; $i < 80; $i++) {
                $temp = [
                    self::rotateRight64($a, 28),
                    self::rotateRight64($a, 34),
                    self::rotateRight64($a, 39),
                ];
                $s0 = $temp[0] ^ $temp[1] ^ $temp[2];
                $temp = [$a & $b, $a & $c, $b & $c];
                $maj = $temp[0] ^ $temp[1] ^ $temp[2];
                $t2 = self::add64($s0, $maj);

                $temp = [
                    self::rotateRight64($e, 14),
                    self::rotateRight64($e, 18),
                    self::rotateRight64($e, 41),
                ];
                $s1 = $temp[0] ^ $temp[1] ^ $temp[2];
                $ch = ($e & $f) ^ ($g & ~$e);
                $t1 = self::add64($h, $s1);
                $t1 = self::add64($t1, $ch);
                $t1 = self::add64($t1, $k[$i]);
                $t1 = self::add64($t1, $w[$i]);

                $h = $g;
                $g = $f;
                $f = $e;
                $e = self::add64($d, $t1);
                $d = $c;
                $c = $b;
                $b = $a;
                $a = self::add64($t1, $t2);
            }

            // Add this chunk's hash to result so far
            $hash = [
                self::add64($hash[0], $a),
                self::add64($hash[1], $b),
                self::add64($hash[2], $c),
                self::add64($hash[3], $d),
                self::add64($hash[4], $e),
                self::add64($hash[5], $f),
                self::add64($hash[6], $g),
                self::add64($hash[7], $h),
            ];
        }

        // Produce the final hash value (big-endian)
        // (\phpseclib3\Crypt\Hash::hash() trims the output for hashes but not for HMACs.  as such, we trim the output here)
        return pack('J*', ...$hash);
    }

    /**
     *  OMAC Padding
     *
     * @link https://www.rfc-editor.org/rfc/rfc4493.html#section-2.4
     */
    private static function OMAC_padding($m, $length)
    {
        $count = $length - strlen($m) - 1;
        return "$m\x80" . str_repeat("\0", $count);
    }

    /**
     *  __toString() magic method
     */
    public function __toString()
    {
        return $this->getHash();
    }
}
<?php

/**
 * Pure-PHP (EC)DH implementation
 *
 * PHP version 5
 *
 * Here's an example of how to compute a shared secret with this library:
 * <code>
 * <?php
 * include 'vendor/autoload.php';
 *
 * $ourPrivate = \phpseclib3\Crypt\DH::createKey();
 * $secret = DH::computeSecret($ourPrivate, $theirPublic);
 *
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Crypt\Common\AsymmetricKey;
use phpseclib3\Crypt\DH\Parameters;
use phpseclib3\Crypt\DH\PrivateKey;
use phpseclib3\Crypt\DH\PublicKey;
use phpseclib3\Crypt\EC\Curves\Curve25519;
use phpseclib3\Crypt\EC\Curves\Curve448;
use phpseclib3\Crypt\EC\Formats\Keys\PKCS1;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\NoKeyLoadedException;
use phpseclib3\Exception\UnsupportedOperationException;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * Pure-PHP (EC)DH implementation
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class DH extends AsymmetricKey
{
    /**
     * Algorithm Name
     *
     * @var string
     */
    const ALGORITHM = 'DH';

    /**
     * DH prime
     *
     * @var BigInteger
     */
    protected $prime;

    /**
     * DH Base
     *
     * Prime divisor of p-1
     *
     * @var BigInteger
     */
    protected $base;

    /**
     * Public Key
     *
     * @var BigInteger
     */
    protected $publicKey;

    /**
     * Create DH parameters
     *
     * This method is a bit polymorphic. It can take any of the following:
     *  - two BigInteger's (prime and base)
     *  - an integer representing the size of the prime in bits (the base is assumed to be 2)
     *  - a string (eg. diffie-hellman-group14-sha1)
     *
     * @return Parameters
     */
    public static function createParameters(...$args)
    {
        $class = new \ReflectionClass(static::class);
        if ($class->isFinal()) {
            throw new \RuntimeException('createParameters() should not be called from final classes (' . static::class . ')');
        }

        $params = new Parameters();
        if (count($args) == 2 && $args[0] instanceof BigInteger && $args[1] instanceof BigInteger) {
            //if (!$args[0]->isPrime()) {
            //    throw new \InvalidArgumentException('The first parameter should be a prime number');
            //}
            $params->prime = $args[0];
            $params->base = $args[1];
            return $params;
        } elseif (count($args) == 1 && is_numeric($args[0])) {
            $params->prime = BigInteger::randomPrime($args[0]);
            $params->base = new BigInteger(2);
            return $params;
        } elseif (count($args) != 1 || !is_string($args[0])) {
            throw new \InvalidArgumentException('Valid parameters are either: two BigInteger\'s (prime and base), a single integer (the length of the prime; base is assumed to be 2) or a string');
        }
        switch ($args[0]) {
            // see http://tools.ietf.org/html/rfc2409#section-6.2 and
            // http://tools.ietf.org/html/rfc2412, appendex E
            case 'diffie-hellman-group1-sha1':
                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
                break;
            // see http://tools.ietf.org/html/rfc3526#section-3
            case 'diffie-hellman-group14-sha1': // 2048-bit MODP Group
            case 'diffie-hellman-group14-sha256':
                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
                         '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
                         '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
                         'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
                         '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
                break;
            // see https://tools.ietf.org/html/rfc3526#section-4
            case 'diffie-hellman-group15-sha512': // 3072-bit MODP Group
                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
                         '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
                         '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
                         'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
                         '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
                         'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
                         'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
                         'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
                         '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF';
                break;
            // see https://tools.ietf.org/html/rfc3526#section-5
            case 'diffie-hellman-group16-sha512': // 4096-bit MODP Group
                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
                         '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
                         '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
                         'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
                         '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
                         'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
                         'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
                         'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
                         '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' .
                         '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' .
                         'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' .
                         '233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' .
                         '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF';
                break;
            // see https://tools.ietf.org/html/rfc3526#section-6
            case 'diffie-hellman-group17-sha512': // 6144-bit MODP Group
                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
                         '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
                         '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
                         'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
                         '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
                         'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
                         'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
                         'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
                         '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' .
                         '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' .
                         'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' .
                         '233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' .
                         '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026' .
                         'C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AE' .
                         'B06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B' .
                         'DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92EC' .
                         'F032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E' .
                         '59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA' .
                         'CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76' .
                         'F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468' .
                         '043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF';
                break;
            // see https://tools.ietf.org/html/rfc3526#section-7
            case 'diffie-hellman-group18-sha512': // 8192-bit MODP Group
                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
                         '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
                         '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
                         'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
                         '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
                         'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
                         'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
                         'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
                         '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' .
                         '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' .
                         'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' .
                         '233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' .
                         '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026' .
                         'C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AE' .
                         'B06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B' .
                         'DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92EC' .
                         'F032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E' .
                         '59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA' .
                         'CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76' .
                         'F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468' .
                         '043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4' .
                         '38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED' .
                         '2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652D' .
                         'E3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B' .
                         '4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6' .
                         '6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851D' .
                         'F9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92' .
                         '4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA' .
                         '9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF';
                break;
            default:
                throw new \InvalidArgumentException('Invalid named prime provided');
        }

        $params->prime = new BigInteger($prime, 16);
        $params->base = new BigInteger(2);

        return $params;
    }

    /**
     * Create public / private key pair.
     *
     * The rationale for the second parameter is described in http://tools.ietf.org/html/rfc4419#section-6.2 :
     *
     * "To increase the speed of the key exchange, both client and server may
     *  reduce the size of their private exponents.  It should be at least
     *  twice as long as the key material that is generated from the shared
     *  secret.  For more details, see the paper by van Oorschot and Wiener
     *  [VAN-OORSCHOT]."
     *
     * $length is in bits
     *
     * @param Parameters $params
     * @param int $length optional
     * @return PrivateKey
     */
    public static function createKey(Parameters $params, $length = 0)
    {
        $class = new \ReflectionClass(static::class);
        if ($class->isFinal()) {
            throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
        }

        $one = new BigInteger(1);
        if ($length) {
            $max = $one->bitwise_leftShift($length);
            $max = $max->subtract($one);
        } else {
            $max = $params->prime->subtract($one);
        }

        $key = new PrivateKey();
        $key->prime = $params->prime;
        $key->base = $params->base;
        $key->privateKey = BigInteger::randomRange($one, $max);
        $key->publicKey = $key->base->powMod($key->privateKey, $key->prime);
        return $key;
    }

    /**
     * Compute Shared Secret
     *
     * @param PrivateKey|EC $private
     * @param PublicKey|BigInteger|string $public
     * @return mixed
     */
    public static function computeSecret($private, $public)
    {
        if ($private instanceof PrivateKey) { // DH\PrivateKey
            switch (true) {
                case $public instanceof PublicKey:
                    if (!$private->prime->equals($public->prime) || !$private->base->equals($public->base)) {
                        throw new \InvalidArgumentException('The public and private key do not share the same prime and / or base numbers');
                    }
                    return $public->publicKey->powMod($private->privateKey, $private->prime)->toBytes(true);
                case is_string($public):
                    $public = new BigInteger($public, -256);
                    // fall-through
                case $public instanceof BigInteger:
                    return $public->powMod($private->privateKey, $private->prime)->toBytes(true);
                default:
                    throw new \InvalidArgumentException('$public needs to be an instance of DH\PublicKey, a BigInteger or a string');
            }
        }

        if ($private instanceof EC\PrivateKey) {
            $privateCurve = $private->getCurve();
            switch (true) {
                case $public instanceof EC\PublicKey:
                    if ($privateCurve !== $public->getCurve()) {
                        throw new \InvalidArgumentException("The public key curve (" . $public->getCurve() . ") and private key curve ($privateCurve) need to match");
                    }
                    $orig = $public;
                    $public = $public->getEncodedCoordinates();
                    // fall-through
                case is_string($public):
                    $forcedEngine = EC::getForcedEngine();
                    if ($forcedEngine === 'libsodium' && $privateCurve !== 'Curve25519') {
                        throw new BadConfigurationException('Engine libsodium is forced but can only used with Curve25519 for ECDH');
                    }
                    if (!isset($forcedEngine) || $forcedEngine === 'OpenSSL') {
                        // PHP 7.3.0 introduced the openssl_pkey_derive() function
                        // openssl_dh_computee_key() has been around since PHP 5.3.0+ BUT it did not support ECDH
                        // until PHP 8.1.0 / OpenSSL 3.0.0
                        if ($forcedEngine === 'OpenSSL' && !function_exists('openssl_pkey_derive')) {
                            throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDH');
                        }
                        if (function_exists('openssl_pkey_derive')) {
                            $privateStr = (string) $private->withPassword();
                            $publicStr = (string) (isset($orig) ? $orig : EC::convertPointToPublicKey($private->getCurve(), $public));
                            $result = openssl_pkey_derive($publicStr, $privateStr);
                            if ($result) {
                                return $result;
                            }
                            if ($forcedEngine === 'OpenSSL') {
                                // i suppose we _could_ try openssl_dh_compute_key() at this point
                                // quoting https://www.php.net/openssl-dh-compute-key "ECDH is only supported as of PHP 8.1.0 and OpenSSL 3.0.0". ie.
                                // PHP_VERSION_ID >= 80100 && OPENSSL_VERSION_NUMBER >= 0x3000000f
                                // but i think that's overkill. if openssl_pkey_derive() doesn't work it seems doubtful to me that openssl_dh_compute_key() would
                                throw new BadConfigurationException('Engine OpenSSL is forced but was unable to perform ECDH because of ' . openssl_error_string());
                            }
                        }
                    }
                    $curveName = $private->getCurve();
                    $isMontgomeryCurve = $curveName == 'Curve25519' || $curveName == 'Curve448';
                    if (!$isMontgomeryCurve) {
                        $public = EC::convertPointToPublicKey($curveName, $public, false);
                    }
                    $point = $private->multiply($public);
                    // according to https://www.secg.org/sec1-v2.pdf#page=33 only X is returned
                    $secret = $isMontgomeryCurve ? $point : substr($point, 1, (strlen($point) - 1) >> 1);
                    /*
                    if (($secret[0] & "\x80") === "\x80") {
                        $secret = "\0$secret";
                    }
                    */
                    return $secret;
                default:
                    throw new \InvalidArgumentException('$public needs to be an instance of EC\PublicKey or a string (an encoded coordinate)');
            }
        }
    }

    /**
     * Load the key
     *
     * @param string $key
     * @param string $password optional
     * @return AsymmetricKey
     */
    public static function load($key, $password = false)
    {
        try {
            return EC::load($key, $password);
        } catch (NoKeyLoadedException $e) {
        }

        return parent::load($key, $password);
    }

    /**
     * OnLoad Handler
     *
     * @return bool
     */
    protected static function onLoad(array $components)
    {
        if (!isset($components['privateKey']) && !isset($components['publicKey'])) {
            $new = new Parameters();
        } else {
            $new = isset($components['privateKey']) ?
                new PrivateKey() :
                new PublicKey();
        }

        $new->prime = $components['prime'];
        $new->base = $components['base'];

        if (isset($components['privateKey'])) {
            $new->privateKey = $components['privateKey'];
        }
        if (isset($components['publicKey'])) {
            $new->publicKey = $components['publicKey'];
        }

        return $new;
    }

    /**
     * Determines which hashing function should be used
     *
     * @param string $hash
     */
    public function withHash($hash)
    {
        throw new UnsupportedOperationException('DH does not use a hash algorithm');
    }

    /**
     * Returns the hash algorithm currently being used
     *
     */
    public function getHash()
    {
        throw new UnsupportedOperationException('DH does not use a hash algorithm');
    }

    /**
     * Returns the parameters
     *
     * A public / private key is only returned if the currently loaded "key" contains an x or y
     * value.
     *
     * @see self::getPublicKey()
     * @return mixed
     */
    public function getParameters()
    {
        $type = DH::validatePlugin('Keys', 'PKCS1', 'saveParameters');

        $key = $type::saveParameters($this->prime, $this->base);
        return DH::load($key, 'PKCS1');
    }
}
<?php

/**
 * Random Number Generator
 *
 * PHP version 5
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    echo bin2hex(\phpseclib3\Crypt\Random::string(8));
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

/**
 * Pure-PHP Random Number Generator
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Random
{
    /**
     * Generate a random string.
     *
     * Although microoptimizations are generally discouraged as they impair readability this function is ripe with
     * microoptimizations because this function has the potential of being called a huge number of times.
     * eg. for RSA key generation.
     *
     * @param int $length
     * @throws \RuntimeException if a symmetric cipher is needed but not loaded
     * @return string
     */
    public static function string($length)
    {
        if (!$length) {
            return '';
        }

        try {
            return random_bytes($length);
        } catch (\Exception $e) {
            // random_compat will throw an Exception, which in PHP 5 does not implement Throwable
        } catch (\Throwable $e) {
            // If a sufficient source of randomness is unavailable, random_bytes() will throw an
            // object that implements the Throwable interface (Exception, TypeError, Error).
            // We don't actually need to do anything here. The string() method should just continue
            // as normal. Note, however, that if we don't have a sufficient source of randomness for
            // random_bytes(), most of the other calls here will fail too, so we'll end up using
            // the PHP implementation.
        }
        // at this point we have no choice but to use a pure-PHP CSPRNG

        // cascade entropy across multiple PHP instances by fixing the session and collecting all
        // environmental variables, including the previous session data and the current session
        // data.
        //
        // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively)
        // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but
        // PHP isn't low level to be able to use those as sources and on a web server there's not likely
        // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use
        // however, a ton of people visiting the website. obviously you don't want to base your seeding
        // solely on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled
        // by the user and (2) this isn't just looking at the data sent by the current user - it's based
        // on the data sent by all users. one user requests the page and a hash of their info is saved.
        // another user visits the page and the serialization of their data is utilized along with the
        // server environment stuff and a hash of the previous http request data (which itself utilizes
        // a hash of the session data before that). certainly an attacker should be assumed to have
        // full control over his own http requests. he, however, is not going to have control over
        // everyone's http requests.
        static $crypto = false, $v;
        if ($crypto === false) {
            // save old session data
            $old_session_id = session_id();
            $old_use_cookies = ini_get('session.use_cookies');
            $old_session_cache_limiter = session_cache_limiter();
            $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false;
            if ($old_session_id != '') {
                session_write_close();
            }

            session_id(1);
            ini_set('session.use_cookies', 0);
            session_cache_limiter('');
            session_start();

            $v = (isset($_SERVER) ? self::safe_serialize($_SERVER) : '') .
                 (isset($_POST) ? self::safe_serialize($_POST) : '') .
                 (isset($_GET) ? self::safe_serialize($_GET) : '') .
                 (isset($_COOKIE) ? self::safe_serialize($_COOKIE) : '') .
                 // as of PHP 8.1 $GLOBALS can't be accessed by reference, which eliminates
                 // the need for phpseclib_safe_serialize. see https://wiki.php.net/rfc/restrict_globals_usage
                 // for more info
                 (version_compare(PHP_VERSION, '8.1.0', '>=') ? serialize($GLOBALS) : self::safe_serialize($GLOBALS)) .
                 self::safe_serialize($_SESSION) .
                 self::safe_serialize($_OLD_SESSION);
            $v = $seed = $_SESSION['seed'] = sha1($v, true);
            if (!isset($_SESSION['count'])) {
                $_SESSION['count'] = 0;
            }
            $_SESSION['count']++;

            session_write_close();

            // restore old session data
            if ($old_session_id != '') {
                session_id($old_session_id);
                session_start();
                ini_set('session.use_cookies', $old_use_cookies);
                session_cache_limiter($old_session_cache_limiter);
            } else {
                if ($_OLD_SESSION !== false) {
                    $_SESSION = $_OLD_SESSION;
                    unset($_OLD_SESSION);
                } else {
                    unset($_SESSION);
                }
            }

            // in SSH2 a shared secret and an exchange hash are generated through the key exchange process.
            // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C.
            // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the
            // original hash and the current hash. we'll be emulating that. for more info see the following URL:
            //
            // http://tools.ietf.org/html/rfc4253#section-7.2
            //
            // see the is_string($crypto) part for an example of how to expand the keys
            $key = sha1($seed . 'A', true);
            $iv = sha1($seed . 'C', true);

            // ciphers are used as per the nist.gov link below. also, see this link:
            //
            // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives
            switch (true) {
                case class_exists('\phpseclib3\Crypt\AES'):
                    $crypto = new AES('ctr');
                    break;
                case class_exists('\phpseclib3\Crypt\Twofish'):
                    $crypto = new Twofish('ctr');
                    break;
                case class_exists('\phpseclib3\Crypt\Blowfish'):
                    $crypto = new Blowfish('ctr');
                    break;
                case class_exists('\phpseclib3\Crypt\TripleDES'):
                    $crypto = new TripleDES('ctr');
                    break;
                case class_exists('\phpseclib3\Crypt\DES'):
                    $crypto = new DES('ctr');
                    break;
                case class_exists('\phpseclib3\Crypt\RC4'):
                    $crypto = new RC4();
                    break;
                default:
                    throw new \RuntimeException(__CLASS__ . ' requires at least one symmetric cipher be loaded');
            }

            $crypto->setKey(substr($key, 0, $crypto->getKeyLength() >> 3));
            $crypto->setIV(substr($iv, 0, $crypto->getBlockLength() >> 3));
            $crypto->enableContinuousBuffer();
        }

        //return $crypto->encrypt(str_repeat("\0", $length));

        // the following is based off of ANSI X9.31:
        //
        // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf
        //
        // OpenSSL uses that same standard for it's random numbers:
        //
        // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c
        // (do a search for "ANS X9.31 A.2.4")
        $result = '';
        while (strlen($result) < $length) {
            $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21
            $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20
            $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
            $result .= $r;
        }

        return substr($result, 0, $length);
    }

    /**
     * Safely serialize variables
     *
     * If a class has a private __sleep() it'll emit a warning
     * @return mixed
     * @param mixed $arr
     */
    private static function safe_serialize(&$arr)
    {
        if (is_object($arr)) {
            return '';
        }
        if (!is_array($arr)) {
            return serialize($arr);
        }
        // prevent circular array recursion
        if (isset($arr['__phpseclib_marker'])) {
            return '';
        }
        $safearr = [];
        $arr['__phpseclib_marker'] = true;
        foreach (array_keys($arr) as $key) {
            // do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
            if ($key !== '__phpseclib_marker') {
                $safearr[$key] = self::safe_serialize($arr[$key]);
            }
        }
        unset($arr['__phpseclib_marker']);
        return serialize($safearr);
    }
}
<?php

/**
 * Miccrosoft BLOB Formatted RSA Key Handler
 *
 * More info:
 *
 * https://msdn.microsoft.com/en-us/library/windows/desktop/aa375601(v=vs.85).aspx
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\RSA\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Exception\UnsupportedFormatException;
use phpseclib3\Math\BigInteger;

/**
 * Microsoft BLOB Formatted RSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class MSBLOB
{
    /**
     * Public/Private Key Pair
     *
     */
    const PRIVATEKEYBLOB = 0x7;
    /**
     * Public Key
     *
     */
    const PUBLICKEYBLOB = 0x6;
    /**
     * Public Key
     *
     */
    const PUBLICKEYBLOBEX = 0xA;
    /**
     * RSA public key exchange algorithm
     *
     */
    const CALG_RSA_KEYX = 0x0000A400;
    /**
     * RSA public key exchange algorithm
     *
     */
    const CALG_RSA_SIGN = 0x00002400;
    /**
     * Public Key
     *
     */
    const RSA1 = 0x31415352;
    /**
     * Private Key
     *
     */
    const RSA2 = 0x32415352;

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        $key = Strings::base64_decode($key);

        if (!is_string($key)) {
            throw new \UnexpectedValueException('Base64 decoding produced an error');
        }
        if (strlen($key) < 20) {
            throw new \UnexpectedValueException('Key appears to be malformed');
        }

        // PUBLICKEYSTRUC  publickeystruc
        // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387453(v=vs.85).aspx
        $unpacked = unpack('atype/aversion/vreserved/Valgo', Strings::shift($key, 8));
        $type = $unpacked['type'];
        $version = $unpacked['version'];
        $reserved = $unpacked['reserved'];
        $algo = $unpacked['algo'];
        switch (ord($type)) {
            case self::PUBLICKEYBLOB:
            case self::PUBLICKEYBLOBEX:
                $publickey = true;
                break;
            case self::PRIVATEKEYBLOB:
                $publickey = false;
                break;
            default:
                throw new \UnexpectedValueException('Key appears to be malformed');
        }

        $components = ['isPublicKey' => $publickey];

        // https://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx
        switch ($algo) {
            case self::CALG_RSA_KEYX:
            case self::CALG_RSA_SIGN:
                break;
            default:
                throw new \UnexpectedValueException('Key appears to be malformed');
        }

        // RSAPUBKEY rsapubkey
        // https://msdn.microsoft.com/en-us/library/windows/desktop/aa387685(v=vs.85).aspx
        // could do V for pubexp but that's unsigned 32-bit whereas some PHP installs only do signed 32-bit
        $unpacked = unpack('Vmagic/Vbitlen/a4pubexp', Strings::shift($key, 12));
        $magic = $unpacked['magic'];
        $bitlen = $unpacked['bitlen'];
        $pubexp = $unpacked['pubexp'];
        switch ($magic) {
            case self::RSA2:
                $components['isPublicKey'] = false;
                // fall-through
            case self::RSA1:
                break;
            default:
                throw new \UnexpectedValueException('Key appears to be malformed');
        }

        $baseLength = $bitlen / 16;
        if (strlen($key) != 2 * $baseLength && strlen($key) != 9 * $baseLength) {
            throw new \UnexpectedValueException('Key appears to be malformed');
        }

        $components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(strrev($pubexp), 256);
        // BYTE modulus[rsapubkey.bitlen/8]
        $components['modulus'] = new BigInteger(strrev(Strings::shift($key, $bitlen / 8)), 256);

        if ($publickey) {
            return $components;
        }

        $components['isPublicKey'] = false;

        // BYTE prime1[rsapubkey.bitlen/16]
        $components['primes'] = [1 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256)];
        // BYTE prime2[rsapubkey.bitlen/16]
        $components['primes'][] = new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256);
        // BYTE exponent1[rsapubkey.bitlen/16]
        $components['exponents'] = [1 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256)];
        // BYTE exponent2[rsapubkey.bitlen/16]
        $components['exponents'][] = new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256);
        // BYTE coefficient[rsapubkey.bitlen/16]
        $components['coefficients'] = [2 => new BigInteger(strrev(Strings::shift($key, $bitlen / 16)), 256)];
        if (isset($components['privateExponent'])) {
            $components['publicExponent'] = $components['privateExponent'];
        }
        // BYTE privateExponent[rsapubkey.bitlen/8]
        $components['privateExponent'] = new BigInteger(strrev(Strings::shift($key, $bitlen / 8)), 256);

        return $components;
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param BigInteger $d
     * @param array $primes
     * @param array $exponents
     * @param array $coefficients
     * @param string $password optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '')
    {
        if (count($primes) != 2) {
            throw new \InvalidArgumentException('MSBLOB does not support multi-prime RSA keys');
        }

        if (!empty($password) && is_string($password)) {
            throw new UnsupportedFormatException('MSBLOB private keys do not support encryption');
        }

        $n = strrev($n->toBytes());
        $e = str_pad(strrev($e->toBytes()), 4, "\0");
        $key = pack('aavV', chr(self::PRIVATEKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX);
        $key .= pack('VVa*', self::RSA2, 8 * strlen($n), $e);
        $key .= $n;
        $key .= strrev($primes[1]->toBytes());
        $key .= strrev($primes[2]->toBytes());
        $key .= strrev($exponents[1]->toBytes());
        $key .= strrev($exponents[2]->toBytes());
        $key .= strrev($coefficients[2]->toBytes());
        $key .= strrev($d->toBytes());

        return Strings::base64_encode($key);
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @return string
     */
    public static function savePublicKey(BigInteger $n, BigInteger $e)
    {
        $n = strrev($n->toBytes());
        $e = str_pad(strrev($e->toBytes()), 4, "\0");
        $key = pack('aavV', chr(self::PUBLICKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX);
        $key .= pack('VVa*', self::RSA1, 8 * strlen($n), $e);
        $key .= $n;

        return Strings::base64_encode($key);
    }
}
<?php

/**
 * Raw RSA Key Handler
 *
 * PHP version 5
 *
 * An array containing two \phpseclib3\Math\BigInteger objects.
 *
 * The exponent can be indexed with any of the following:
 *
 * 0, e, exponent, publicExponent
 *
 * The modulus can be indexed with any of the following:
 *
 * 1, n, modulo, modulus
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\RSA\Formats\Keys;

use phpseclib3\Math\BigInteger;

/**
 * Raw RSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class Raw
{
    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        if (!is_array($key)) {
            throw new \UnexpectedValueException('Key should be a array - not a ' . gettype($key));
        }

        $key = array_change_key_case($key, CASE_LOWER);

        $components = ['isPublicKey' => false];

        foreach (['e', 'exponent', 'publicexponent', 0, 'privateexponent', 'd'] as $index) {
            if (isset($key[$index])) {
                $components['publicExponent'] = $key[$index];
                break;
            }
        }

        foreach (['n', 'modulo', 'modulus', 1] as $index) {
            if (isset($key[$index])) {
                $components['modulus'] = $key[$index];
                break;
            }
        }

        if (!isset($components['publicExponent']) || !isset($components['modulus'])) {
            throw new \UnexpectedValueException('Modulus / exponent not present');
        }

        if (isset($key['primes'])) {
            $components['primes'] = $key['primes'];
        } elseif (isset($key['p']) && isset($key['q'])) {
            $indices = [
                ['p', 'q'],
                ['prime1', 'prime2']
            ];
            foreach ($indices as $index) {
                list($i0, $i1) = $index;
                if (isset($key[$i0]) && isset($key[$i1])) {
                    $components['primes'] = [1 => $key[$i0], $key[$i1]];
                }
            }
        }

        if (isset($key['exponents'])) {
            $components['exponents'] = $key['exponents'];
        } else {
            $indices = [
                ['dp', 'dq'],
                ['exponent1', 'exponent2']
            ];
            foreach ($indices as $index) {
                list($i0, $i1) = $index;
                if (isset($key[$i0]) && isset($key[$i1])) {
                    $components['exponents'] = [1 => $key[$i0], $key[$i1]];
                }
            }
        }

        if (isset($key['coefficients'])) {
            $components['coefficients'] = $key['coefficients'];
        } else {
            foreach (['inverseq', 'q\'', 'coefficient'] as $index) {
                if (isset($key[$index])) {
                    $components['coefficients'] = [2 => $key[$index]];
                }
            }
        }

        if (!isset($components['primes'])) {
            $components['isPublicKey'] = true;
            return $components;
        }

        if (!isset($components['exponents'])) {
            $one = new BigInteger(1);
            $temp = $components['primes'][1]->subtract($one);
            $exponents = [1 => $components['publicExponent']->modInverse($temp)];
            $temp = $components['primes'][2]->subtract($one);
            $exponents[] = $components['publicExponent']->modInverse($temp);
            $components['exponents'] = $exponents;
        }

        if (!isset($components['coefficients'])) {
            $components['coefficients'] = [2 => $components['primes'][2]->modInverse($components['primes'][1])];
        }

        foreach (['privateexponent', 'd'] as $index) {
            if (isset($key[$index])) {
                $components['privateExponent'] = $key[$index];
                break;
            }
        }

        return $components;
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param BigInteger $d
     * @param array $primes
     * @param array $exponents
     * @param array $coefficients
     * @param string $password optional
     * @param array $options optional
     * @return array
     */
    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
    {
        if (!empty($password) && is_string($password)) {
            throw new UnsupportedFormatException('Raw private keys do not support encryption');
        }

        return [
            'e' => clone $e,
            'n' => clone $n,
            'd' => clone $d,
            'primes' => array_map(function ($var) {
                return clone $var;
            }, $primes),
            'exponents' => array_map(function ($var) {
                return clone $var;
            }, $exponents),
            'coefficients' => array_map(function ($var) {
                return clone $var;
            }, $coefficients)
        ];
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @return array
     */
    public static function savePublicKey(BigInteger $n, BigInteger $e)
    {
        return ['e' => clone $e, 'n' => clone $n];
    }
}
<?php

/**
 * OpenSSH Formatted RSA Key Handler
 *
 * PHP version 5
 *
 * Place in $HOME/.ssh/authorized_keys
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\RSA\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\OpenSSH as Progenitor;
use phpseclib3\Math\BigInteger;

/**
 * OpenSSH Formatted RSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class OpenSSH extends Progenitor
{
    /**
     * Supported Key Types
     *
     * @var array
     */
    protected static $types = ['ssh-rsa'];

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        static $one;
        if (!isset($one)) {
            $one = new BigInteger(1);
        }

        $parsed = parent::load($key, $password);

        if (isset($parsed['paddedKey'])) {
            list($type) = Strings::unpackSSH2('s', $parsed['paddedKey']);
            if ($type != $parsed['type']) {
                throw new \RuntimeException("The public and private keys are not of the same type ($type vs $parsed[type])");
            }

            $primes = $coefficients = [];

            list(
                $modulus,
                $publicExponent,
                $privateExponent,
                $coefficients[2],
                $primes[1],
                $primes[2],
                $comment,
            ) = Strings::unpackSSH2('i6s', $parsed['paddedKey']);

            $temp = $primes[1]->subtract($one);
            $exponents = [1 => $publicExponent->modInverse($temp)];
            $temp = $primes[2]->subtract($one);
            $exponents[] = $publicExponent->modInverse($temp);

            $isPublicKey = false;

            return compact('publicExponent', 'modulus', 'privateExponent', 'primes', 'coefficients', 'exponents', 'comment', 'isPublicKey');
        }

        list($publicExponent, $modulus) = Strings::unpackSSH2('ii', $parsed['publicKey']);

        return [
            'isPublicKey' => true,
            'modulus' => $modulus,
            'publicExponent' => $publicExponent,
            'comment' => $parsed['comment']
        ];
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param array $options optional
     * @return string
     */
    public static function savePublicKey(BigInteger $n, BigInteger $e, array $options = [])
    {
        $RSAPublicKey = Strings::packSSH2('sii', 'ssh-rsa', $e, $n);

        if (isset($options['binary']) ? $options['binary'] : self::$binary) {
            return $RSAPublicKey;
        }

        $comment = isset($options['comment']) ? $options['comment'] : self::$comment;
        $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $comment;

        return $RSAPublicKey;
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param BigInteger $d
     * @param array $primes
     * @param array $exponents
     * @param array $coefficients
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
    {
        $publicKey = self::savePublicKey($n, $e, ['binary' => true]);
        $privateKey = Strings::packSSH2('si6', 'ssh-rsa', $n, $e, $d, $coefficients[2], $primes[1], $primes[2]);

        return self::wrapPrivateKey($publicKey, $privateKey, $password, $options);
    }
}
<?php

/**
 * XML Formatted RSA Key Handler
 *
 * More info:
 *
 * http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
 * http://www.w3.org/TR/xkms2/#XKMS_2_0_Paragraph_269
 * http://en.wikipedia.org/wiki/XML_Signature
 * http://en.wikipedia.org/wiki/XKMS
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\RSA\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\UnsupportedFormatException;
use phpseclib3\Math\BigInteger;

/**
 * XML Formatted RSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class XML
{
    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        if (!class_exists('DOMDocument')) {
            throw new BadConfigurationException('The dom extension is not setup correctly on this system');
        }

        $components = [
            'isPublicKey' => false,
            'primes' => [],
            'exponents' => [],
            'coefficients' => []
        ];

        $use_errors = libxml_use_internal_errors(true);

        $dom = new \DOMDocument();
        if (substr($key, 0, 5) != '<?xml') {
            $key = '<xml>' . $key . '</xml>';
        }
        if (!$dom->loadXML($key)) {
            libxml_use_internal_errors($use_errors);
            throw new \UnexpectedValueException('Key does not appear to contain XML');
        }
        $xpath = new \DOMXPath($dom);
        $keys = ['modulus', 'exponent', 'p', 'q', 'dp', 'dq', 'inverseq', 'd'];
        foreach ($keys as $key) {
            // $dom->getElementsByTagName($key) is case-sensitive
            $temp = $xpath->query("//*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$key']");
            if (!$temp->length) {
                continue;
            }
            $value = new BigInteger(Strings::base64_decode($temp->item(0)->nodeValue), 256);
            switch ($key) {
                case 'modulus':
                    $components['modulus'] = $value;
                    break;
                case 'exponent':
                    $components['publicExponent'] = $value;
                    break;
                case 'p':
                    $components['primes'][1] = $value;
                    break;
                case 'q':
                    $components['primes'][2] = $value;
                    break;
                case 'dp':
                    $components['exponents'][1] = $value;
                    break;
                case 'dq':
                    $components['exponents'][2] = $value;
                    break;
                case 'inverseq':
                    $components['coefficients'][2] = $value;
                    break;
                case 'd':
                    $components['privateExponent'] = $value;
            }
        }

        libxml_use_internal_errors($use_errors);

        foreach ($components as $key => $value) {
            if (is_array($value) && !count($value)) {
                unset($components[$key]);
            }
        }

        if (isset($components['modulus']) && isset($components['publicExponent'])) {
            if (count($components) == 3) {
                $components['isPublicKey'] = true;
            }
            return $components;
        }

        throw new \UnexpectedValueException('Modulus / exponent not present');
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param BigInteger $d
     * @param array $primes
     * @param array $exponents
     * @param array $coefficients
     * @param string $password optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '')
    {
        if (count($primes) != 2) {
            throw new \InvalidArgumentException('XML does not support multi-prime RSA keys');
        }

        if (!empty($password) && is_string($password)) {
            throw new UnsupportedFormatException('XML private keys do not support encryption');
        }

        return "<RSAKeyPair>\r\n" .
               '  <Modulus>' . Strings::base64_encode($n->toBytes()) . "</Modulus>\r\n" .
               '  <Exponent>' . Strings::base64_encode($e->toBytes()) . "</Exponent>\r\n" .
               '  <P>' . Strings::base64_encode($primes[1]->toBytes()) . "</P>\r\n" .
               '  <Q>' . Strings::base64_encode($primes[2]->toBytes()) . "</Q>\r\n" .
               '  <DP>' . Strings::base64_encode($exponents[1]->toBytes()) . "</DP>\r\n" .
               '  <DQ>' . Strings::base64_encode($exponents[2]->toBytes()) . "</DQ>\r\n" .
               '  <InverseQ>' . Strings::base64_encode($coefficients[2]->toBytes()) . "</InverseQ>\r\n" .
               '  <D>' . Strings::base64_encode($d->toBytes()) . "</D>\r\n" .
               '</RSAKeyPair>';
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @return string
     */
    public static function savePublicKey(BigInteger $n, BigInteger $e)
    {
        return "<RSAKeyValue>\r\n" .
               '  <Modulus>' . Strings::base64_encode($n->toBytes()) . "</Modulus>\r\n" .
               '  <Exponent>' . Strings::base64_encode($e->toBytes()) . "</Exponent>\r\n" .
               '</RSAKeyValue>';
    }
}
<?php

/**
 * PuTTY Formatted RSA Key Handler
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\RSA\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\PuTTY as Progenitor;
use phpseclib3\Math\BigInteger;

/**
 * PuTTY Formatted RSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PuTTY extends Progenitor
{
    /**
     * Public Handler
     *
     * @var string
     */
    const PUBLIC_HANDLER = 'phpseclib3\Crypt\RSA\Formats\Keys\OpenSSH';

    /**
     * Algorithm Identifier
     *
     * @var array
     */
    protected static $types = ['ssh-rsa'];

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        static $one;
        if (!isset($one)) {
            $one = new BigInteger(1);
        }

        $components = parent::load($key, $password);
        if (!isset($components['private'])) {
            return $components;
        }
        $type = $components['type'];
        $comment = $components['comment'];
        $public = $components['public'];
        $private = $components['private'];
        unset($components['public'], $components['private']);

        $isPublicKey = false;

        $result = Strings::unpackSSH2('ii', $public);
        if ($result === false) {
            throw new \UnexpectedValueException('Key appears to be malformed');
        }
        list($publicExponent, $modulus) = $result;

        $result = Strings::unpackSSH2('iiii', $private);
        if ($result === false) {
            throw new \UnexpectedValueException('Key appears to be malformed');
        }
        $primes = $coefficients = [];
        list($privateExponent, $primes[1], $primes[2], $coefficients[2]) = $result;

        $temp = $primes[1]->subtract($one);
        $exponents = [1 => $publicExponent->modInverse($temp)];
        $temp = $primes[2]->subtract($one);
        $exponents[] = $publicExponent->modInverse($temp);

        return compact('publicExponent', 'modulus', 'privateExponent', 'primes', 'coefficients', 'exponents', 'comment', 'isPublicKey');
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param BigInteger $d
     * @param array $primes
     * @param array $exponents
     * @param array $coefficients
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
    {
        if (count($primes) != 2) {
            throw new \InvalidArgumentException('PuTTY does not support multi-prime RSA keys');
        }

        $public =  Strings::packSSH2('ii', $e, $n);
        $private = Strings::packSSH2('iiii', $d, $primes[1], $primes[2], $coefficients[2]);

        return self::wrapPrivateKey($public, $private, 'ssh-rsa', $password, $options);
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @return string
     */
    public static function savePublicKey(BigInteger $n, BigInteger $e)
    {
        return self::wrapPublicKey(Strings::packSSH2('ii', $e, $n), 'ssh-rsa');
    }
}
<?php

/**
 * PKCS#1 Formatted RSA Key Handler
 *
 * PHP version 5
 *
 * Used by File/X509.php
 *
 * Processes keys with the following headers:
 *
 * -----BEGIN RSA PRIVATE KEY-----
 * -----BEGIN RSA PUBLIC KEY-----
 *
 * Analogous to ssh-keygen's pem format (as specified by -m)
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\RSA\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * PKCS#1 Formatted RSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS1 extends Progenitor
{
    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        if (strpos($key, 'PUBLIC') !== false) {
            $components = ['isPublicKey' => true];
        } elseif (strpos($key, 'PRIVATE') !== false) {
            $components = ['isPublicKey' => false];
        } else {
            $components = [];
        }

        $key = parent::load($key, $password);

        $decoded = ASN1::decodeBER($key);
        if (!$decoded) {
            throw new \RuntimeException('Unable to decode BER');
        }

        $key = ASN1::asn1map($decoded[0], Maps\RSAPrivateKey::MAP);
        if (is_array($key)) {
            if ($key['version'] === false) {
                throw new \UnexpectedValueException('Version number is not valid');
            }
            $components += [
                'modulus' => $key['modulus'],
                'publicExponent' => $key['publicExponent'],
                'privateExponent' => $key['privateExponent'],
                'primes' => [1 => $key['prime1'], $key['prime2']],
                'exponents' => [1 => $key['exponent1'], $key['exponent2']],
                'coefficients' => [2 => $key['coefficient']]
            ];
            if ($key['version'] == 'multi') {
                foreach ($key['otherPrimeInfos'] as $primeInfo) {
                    $components['primes'][] = $primeInfo['prime'];
                    $components['exponents'][] = $primeInfo['exponent'];
                    $components['coefficients'][] = $primeInfo['coefficient'];
                }
            }
            if (!isset($components['isPublicKey'])) {
                $components['isPublicKey'] = false;
            }
            return $components;
        }

        $key = ASN1::asn1map($decoded[0], Maps\RSAPublicKey::MAP);

        if (!is_array($key)) {
            throw new \RuntimeException('Unable to perform ASN1 mapping');
        }

        if (!isset($components['isPublicKey'])) {
            $components['isPublicKey'] = true;
        }

        $components = $components + $key;
        foreach ($components as &$val) {
            if ($val instanceof BigInteger) {
                $val = self::makePositive($val);
            }
            if (is_array($val)) {
                foreach ($val as &$subval) {
                    if ($subval instanceof BigInteger) {
                        $subval = self::makePositive($subval);
                    }
                }
            }
        }

        return $components + $key;
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param BigInteger $d
     * @param array $primes
     * @param array $exponents
     * @param array $coefficients
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
    {
        $num_primes = count($primes);
        $key = [
            'version' => $num_primes == 2 ? 'two-prime' : 'multi',
            'modulus' => $n,
            'publicExponent' => $e,
            'privateExponent' => $d,
            'prime1' => $primes[1],
            'prime2' => $primes[2],
            'exponent1' => $exponents[1],
            'exponent2' => $exponents[2],
            'coefficient' => $coefficients[2]
        ];
        for ($i = 3; $i <= $num_primes; $i++) {
            $key['otherPrimeInfos'][] = [
                'prime' => $primes[$i],
                'exponent' => $exponents[$i],
                'coefficient' => $coefficients[$i]
            ];
        }

        $key = ASN1::encodeDER($key, Maps\RSAPrivateKey::MAP);

        return self::wrapPrivateKey($key, 'RSA', $password, $options);
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @return string
     */
    public static function savePublicKey(BigInteger $n, BigInteger $e)
    {
        $key = [
            'modulus' => $n,
            'publicExponent' => $e
        ];

        $key = ASN1::encodeDER($key, Maps\RSAPublicKey::MAP);

        return self::wrapPublicKey($key, 'RSA');
    }

    /**
     * Negative numbers make no sense in RSA so convert them to positive
     *
     * @param BigInteger $x
     * @return string
     */
    private static function makePositive(BigInteger $x)
    {
        return $x->isNegative() ?
            new BigInteger($x->toBytes(true), 256) :
            $x;
    }
}
<?php

/**
 * PKCS#8 Formatted RSA Key Handler
 *
 * PHP version 5
 *
 * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
 *
 * Processes keys with the following headers:
 *
 * -----BEGIN ENCRYPTED PRIVATE KEY-----
 * -----BEGIN PRIVATE KEY-----
 * -----BEGIN PUBLIC KEY-----
 *
 * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
 * is specific to private keys it's basically creating a DER-encoded wrapper
 * for keys. This just extends that same concept to public keys (much like ssh-keygen)
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\RSA\Formats\Keys;

use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
use phpseclib3\File\ASN1;
use phpseclib3\Math\BigInteger;

/**
 * PKCS#8 Formatted RSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS8 extends Progenitor
{
    /**
     * OID Name
     *
     * @var string
     */
    const OID_NAME = 'rsaEncryption';

    /**
     * OID Value
     *
     * @var string
     */
    const OID_VALUE = '1.2.840.113549.1.1.1';

    /**
     * Child OIDs loaded
     *
     * @var bool
     */
    protected static $childOIDsLoaded = false;

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        $key = parent::load($key, $password);

        if (isset($key['privateKey'])) {
            $components['isPublicKey'] = false;
            $type = 'private';
        } else {
            $components['isPublicKey'] = true;
            $type = 'public';
        }

        $result = $components + PKCS1::load($key[$type . 'Key']);

        if (isset($key['meta'])) {
            $result['meta'] = $key['meta'];
        }

        return $result;
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param BigInteger $d
     * @param array $primes
     * @param array $exponents
     * @param array $coefficients
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
    {
        $key = PKCS1::savePrivateKey($n, $e, $d, $primes, $exponents, $coefficients);
        $key = ASN1::extractBER($key);
        return self::wrapPrivateKey($key, [], null, $password, null, '', $options);
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param array $options optional
     * @return string
     */
    public static function savePublicKey(BigInteger $n, BigInteger $e, array $options = [])
    {
        $key = PKCS1::savePublicKey($n, $e);
        $key = ASN1::extractBER($key);
        return self::wrapPublicKey($key, null, null, $options);
    }
}
<?php

/**
 * JSON Web Key (RFC7517) Formatted RSA Handler
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\RSA\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\JWK as Progenitor;
use phpseclib3\Math\BigInteger;

/**
 * JWK Formatted RSA Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class JWK extends Progenitor
{
    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        $key = parent::load($key, $password);

        if ($key->kty != 'RSA') {
            throw new \RuntimeException('Only RSA JWK keys are supported');
        }

        $count = $publicCount = 0;
        $vars = ['n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi'];
        foreach ($vars as $var) {
            if (!isset($key->$var) || !is_string($key->$var)) {
                continue;
            }
            $count++;
            $value = new BigInteger(Strings::base64url_decode($key->$var), 256);
            switch ($var) {
                case 'n':
                    $publicCount++;
                    $components['modulus'] = $value;
                    break;
                case 'e':
                    $publicCount++;
                    $components['publicExponent'] = $value;
                    break;
                case 'd':
                    $components['privateExponent'] = $value;
                    break;
                case 'p':
                    $components['primes'][1] = $value;
                    break;
                case 'q':
                    $components['primes'][2] = $value;
                    break;
                case 'dp':
                    $components['exponents'][1] = $value;
                    break;
                case 'dq':
                    $components['exponents'][2] = $value;
                    break;
                case 'qi':
                    $components['coefficients'][2] = $value;
            }
        }

        if ($count == count($vars)) {
            return $components + ['isPublicKey' => false];
        }

        if ($count == 2 && $publicCount == 2) {
            return $components + ['isPublicKey' => true];
        }

        throw new \UnexpectedValueException('Key does not have an appropriate number of RSA parameters');
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param BigInteger $d
     * @param array $primes
     * @param array $exponents
     * @param array $coefficients
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
    {
        if (count($primes) != 2) {
            throw new \InvalidArgumentException('JWK does not support multi-prime RSA keys');
        }

        $key = [
            'kty' => 'RSA',
            'n' => Strings::base64url_encode($n->toBytes()),
            'e' => Strings::base64url_encode($e->toBytes()),
            'd' => Strings::base64url_encode($d->toBytes()),
            'p' => Strings::base64url_encode($primes[1]->toBytes()),
            'q' => Strings::base64url_encode($primes[2]->toBytes()),
            'dp' => Strings::base64url_encode($exponents[1]->toBytes()),
            'dq' => Strings::base64url_encode($exponents[2]->toBytes()),
            'qi' => Strings::base64url_encode($coefficients[2]->toBytes())
        ];

        return self::wrapKey($key, $options);
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param array $options optional
     * @return string
     */
    public static function savePublicKey(BigInteger $n, BigInteger $e, array $options = [])
    {
        $key = [
            'kty' => 'RSA',
            'n' => Strings::base64url_encode($n->toBytes()),
            'e' => Strings::base64url_encode($e->toBytes())
        ];

        return self::wrapKey($key, $options);
    }
}
<?php

/**
 * PKCS#8 Formatted RSA-PSS Key Handler
 *
 * PHP version 5
 *
 * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
 *
 * Processes keys with the following headers:
 *
 * -----BEGIN ENCRYPTED PRIVATE KEY-----
 * -----BEGIN PRIVATE KEY-----
 * -----BEGIN PUBLIC KEY-----
 *
 * Analogous to "openssl genpkey -algorithm rsa-pss".
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\RSA\Formats\Keys;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * PKCS#8 Formatted RSA-PSS Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PSS extends Progenitor
{
    /**
     * OID Name
     *
     * @var string
     */
    const OID_NAME = 'id-RSASSA-PSS';

    /**
     * OID Value
     *
     * @var string
     */
    const OID_VALUE = '1.2.840.113549.1.1.10';

    /**
     * OIDs loaded
     *
     * @var bool
     */
    private static $oidsLoaded = false;

    /**
     * Child OIDs loaded
     *
     * @var bool
     */
    protected static $childOIDsLoaded = false;

    /**
     * Initialize static variables
     */
    private static function initialize_static_variables()
    {
        if (!self::$oidsLoaded) {
            ASN1::loadOIDs([
                'md2' => '1.2.840.113549.2.2',
                'md4' => '1.2.840.113549.2.4',
                'md5' => '1.2.840.113549.2.5',
                'id-sha1' => '1.3.14.3.2.26',
                'id-sha256' => '2.16.840.1.101.3.4.2.1',
                'id-sha384' => '2.16.840.1.101.3.4.2.2',
                'id-sha512' => '2.16.840.1.101.3.4.2.3',
                'id-sha224' => '2.16.840.1.101.3.4.2.4',
                'id-sha512/224' => '2.16.840.1.101.3.4.2.5',
                'id-sha512/256' => '2.16.840.1.101.3.4.2.6',

                'id-mgf1' => '1.2.840.113549.1.1.8'
            ]);
            self::$oidsLoaded = true;
        }
    }

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        self::initialize_static_variables();

        if (!Strings::is_stringable($key)) {
            throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
        }

        $components = ['isPublicKey' => strpos($key, 'PUBLIC') !== false];

        $key = parent::load($key, $password);

        $type = isset($key['privateKey']) ? 'private' : 'public';

        $result = $components + PKCS1::load($key[$type . 'Key']);

        if (isset($key[$type . 'KeyAlgorithm']['parameters'])) {
            $decoded = ASN1::decodeBER($key[$type . 'KeyAlgorithm']['parameters']);
            if ($decoded === false) {
                throw new \UnexpectedValueException('Unable to decode parameters');
            }
            $params = ASN1::asn1map($decoded[0], Maps\RSASSA_PSS_params::MAP);
        } else {
            $params = [];
        }

        if (isset($params['maskGenAlgorithm']['parameters'])) {
            $decoded = ASN1::decodeBER($params['maskGenAlgorithm']['parameters']);
            if ($decoded === false) {
                throw new \UnexpectedValueException('Unable to decode parameters');
            }
            $params['maskGenAlgorithm']['parameters'] = ASN1::asn1map($decoded[0], Maps\HashAlgorithm::MAP);
        } else {
            $params['maskGenAlgorithm'] = [
                'algorithm' => 'id-mgf1',
                'parameters' => ['algorithm' => 'id-sha1']
            ];
        }

        if (!isset($params['hashAlgorithm']['algorithm'])) {
            $params['hashAlgorithm']['algorithm'] = 'id-sha1';
        }

        $result['hash'] = str_replace('id-', '', $params['hashAlgorithm']['algorithm']);
        $result['MGFHash'] = str_replace('id-', '', $params['maskGenAlgorithm']['parameters']['algorithm']);
        if (isset($params['saltLength'])) {
            $result['saltLength'] = (int) "$params[saltLength]";
        }

        if (isset($key['meta'])) {
            $result['meta'] = $key['meta'];
        }

        return $result;
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param BigInteger $d
     * @param array $primes
     * @param array $exponents
     * @param array $coefficients
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
    {
        self::initialize_static_variables();

        $key = PKCS1::savePrivateKey($n, $e, $d, $primes, $exponents, $coefficients);
        $key = ASN1::extractBER($key);
        $params = self::savePSSParams($options);
        return self::wrapPrivateKey($key, [], $params, $password, null, '', $options);
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $n
     * @param BigInteger $e
     * @param array $options optional
     * @return string
     */
    public static function savePublicKey(BigInteger $n, BigInteger $e, array $options = [])
    {
        self::initialize_static_variables();

        $key = PKCS1::savePublicKey($n, $e);
        $key = ASN1::extractBER($key);
        $params = self::savePSSParams($options);
        return self::wrapPublicKey($key, $params);
    }

    /**
     * Encodes PSS parameters
     *
     * @param array $options
     * @return string
     */
    public static function savePSSParams(array $options)
    {
        /*
         The trailerField field is an integer.  It provides
         compatibility with IEEE Std 1363a-2004 [P1363A].  The value
         MUST be 1, which represents the trailer field with hexadecimal
         value 0xBC.  Other trailer fields, including the trailer field
         composed of HashID concatenated with 0xCC that is specified in
         IEEE Std 1363a, are not supported.  Implementations that
         perform signature generation MUST omit the trailerField field,
         indicating that the default trailer field value was used.
         Implementations that perform signature validation MUST
         recognize both a present trailerField field with value 1 and an
         absent trailerField field.

         source: https://tools.ietf.org/html/rfc4055#page-9
        */
        $params = [
            'trailerField' => new BigInteger(1)
        ];
        if (isset($options['hash'])) {
            $params['hashAlgorithm']['algorithm'] = 'id-' . $options['hash'];
        }
        if (isset($options['MGFHash'])) {
            $temp = ['algorithm' => 'id-' . $options['MGFHash']];
            $temp = ASN1::encodeDER($temp, Maps\HashAlgorithm::MAP);
            $params['maskGenAlgorithm'] = [
                'algorithm' => 'id-mgf1',
                'parameters' => new ASN1\Element($temp)
            ];
        }
        if (isset($options['saltLength'])) {
            $params['saltLength'] = new BigInteger($options['saltLength']);
        }

        return new ASN1\Element(ASN1::encodeDER($params, Maps\RSASSA_PSS_params::MAP));
    }
}
<?php

/**
 * RSA Private Key
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\RSA;

use phpseclib3\Crypt\Common;
use phpseclib3\Crypt\Random;
use phpseclib3\Crypt\RSA;
use phpseclib3\Crypt\RSA\Formats\Keys\PSS;
use phpseclib3\Exception\UnsupportedFormatException;
use phpseclib3\Math\BigInteger;

/**
 * Raw RSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
final class PrivateKey extends RSA implements Common\PrivateKey
{
    use Common\Traits\PasswordProtected;

    /**
     * Primes for Chinese Remainder Theorem (ie. p and q)
     *
     * @var array
     */
    protected $primes;

    /**
     * Exponents for Chinese Remainder Theorem (ie. dP and dQ)
     *
     * @var array
     */
    protected $exponents;

    /**
     * Coefficients for Chinese Remainder Theorem (ie. qInv)
     *
     * @var array
     */
    protected $coefficients;

    /**
     * Private Exponent
     *
     * @var BigInteger
     */
    protected $privateExponent;

    /**
     * RSADP
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
     *
     * @return bool|BigInteger
     */
    private function rsadp(BigInteger $c)
    {
        if ($c->compare(self::$zero) < 0 || $c->compare($this->modulus) > 0) {
            throw new \OutOfRangeException('Ciphertext representative out of range');
        }
        return $this->exponentiate($c);
    }

    /**
     * RSASP1
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
     *
     * @return bool|BigInteger
     */
    private function rsasp1(BigInteger $m)
    {
        if ($m->compare(self::$zero) < 0 || $m->compare($this->modulus) > 0) {
            throw new \OutOfRangeException('Signature representative out of range');
        }
        return $this->exponentiate($m);
    }

    /**
     * Exponentiate
     *
     * @param BigInteger $x
     * @return BigInteger
     */
    protected function exponentiate(BigInteger $x)
    {
        switch (true) {
            case empty($this->primes):
            case $this->primes[1]->equals(self::$zero):
            case empty($this->coefficients):
            case $this->coefficients[2]->equals(self::$zero):
            case empty($this->exponents):
            case $this->exponents[1]->equals(self::$zero):
                return $x->modPow($this->exponent, $this->modulus);
        }

        $num_primes = count($this->primes);

        if (!static::$enableBlinding) {
            $m_i = [
                1 => $x->modPow($this->exponents[1], $this->primes[1]),
                2 => $x->modPow($this->exponents[2], $this->primes[2])
            ];
            $h = $m_i[1]->subtract($m_i[2]);
            $h = $h->multiply($this->coefficients[2]);
            list(, $h) = $h->divide($this->primes[1]);
            $m = $m_i[2]->add($h->multiply($this->primes[2]));

            $r = $this->primes[1];
            for ($i = 3; $i <= $num_primes; $i++) {
                $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);

                $r = $r->multiply($this->primes[$i - 1]);

                $h = $m_i->subtract($m);
                $h = $h->multiply($this->coefficients[$i]);
                list(, $h) = $h->divide($this->primes[$i]);

                $m = $m->add($r->multiply($h));
            }
        } else {
            $smallest = $this->primes[1];
            for ($i = 2; $i <= $num_primes; $i++) {
                if ($smallest->compare($this->primes[$i]) > 0) {
                    $smallest = $this->primes[$i];
                }
            }

            $r = BigInteger::randomRange(self::$one, $smallest->subtract(self::$one));

            $m_i = [
                1 => $this->blind($x, $r, 1),
                2 => $this->blind($x, $r, 2)
            ];
            $h = $m_i[1]->subtract($m_i[2]);
            $h = $h->multiply($this->coefficients[2]);
            list(, $h) = $h->divide($this->primes[1]);
            $m = $m_i[2]->add($h->multiply($this->primes[2]));

            $r = $this->primes[1];
            for ($i = 3; $i <= $num_primes; $i++) {
                $m_i = $this->blind($x, $r, $i);

                $r = $r->multiply($this->primes[$i - 1]);

                $h = $m_i->subtract($m);
                $h = $h->multiply($this->coefficients[$i]);
                list(, $h) = $h->divide($this->primes[$i]);

                $m = $m->add($r->multiply($h));
            }
        }

        return $m;
    }

    /**
     * Performs RSA Blinding
     *
     * Protects against timing attacks by employing RSA Blinding.
     * Returns $x->modPow($this->exponents[$i], $this->primes[$i])
     *
     * @param BigInteger $x
     * @param BigInteger $r
     * @param int $i
     * @return BigInteger
     */
    private function blind(BigInteger $x, BigInteger $r, $i)
    {
        $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
        $x = $x->modPow($this->exponents[$i], $this->primes[$i]);

        $r = $r->modInverse($this->primes[$i]);
        $x = $x->multiply($r);
        list(, $x) = $x->divide($this->primes[$i]);

        return $x;
    }

    /**
     * EMSA-PSS-ENCODE
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
     *
     * @return string
     * @param string $m
     * @throws \RuntimeException on encoding error
     * @param int $emBits
     */
    private function emsa_pss_encode($m, $emBits)
    {
        // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
        // be output.

        $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
        $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;

        $mHash = $this->hash->hash($m);
        if ($emLen < $this->hLen + $sLen + 2) {
            throw new \LengthException('RSA modulus too short');
        }

        $salt = Random::string($sLen);
        $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
        $h = $this->hash->hash($m2);
        $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
        $db = $ps . chr(1) . $salt;
        $dbMask = $this->mgf1($h, $emLen - $this->hLen - 1); // ie. stlren($db)
        $maskedDB = $db ^ $dbMask;
        $maskedDB[0] = ~chr(256 - (1 << ($emBits & 7))) & $maskedDB[0];
        $em = $maskedDB . $h . chr(0xBC);

        return $em;
    }

    /**
     * RSASSA-PSS-SIGN
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
     *
     * @param string $m
     * @return bool|string
     */
    private function rsassa_pss_sign($m)
    {
        // EMSA-PSS encoding

        $em = $this->emsa_pss_encode($m, 8 * $this->k - 1);

        // RSA signature

        $m = $this->os2ip($em);
        $s = $this->rsasp1($m);
        $s = $this->i2osp($s, $this->k);

        // Output the signature S

        return $s;
    }

    /**
     * RSASSA-PKCS1-V1_5-SIGN
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
     *
     * @param string $m
     * @throws \LengthException if the RSA modulus is too short
     * @return bool|string
     */
    private function rsassa_pkcs1_v1_5_sign($m)
    {
        // EMSA-PKCS1-v1_5 encoding

        // If the encoding operation outputs "intended encoded message length too short," output "RSA modulus
        // too short" and stop.
        try {
            $em = $this->emsa_pkcs1_v1_5_encode($m, $this->k);
        } catch (\LengthException $e) {
            throw new \LengthException('RSA modulus too short');
        }

        // RSA signature

        $m = $this->os2ip($em);
        $s = $this->rsasp1($m);
        $s = $this->i2osp($s, $this->k);

        // Output the signature S

        return $s;
    }

    /**
     * Create a signature
     *
     * @see self::verify()
     * @param string $message
     * @return string
     */
    public function sign($message)
    {
        $result = $this->handleOpenSSL('openssl_sign', $message);
        if ($result !== null) {
            return $result;
        }

        switch ($this->signaturePadding) {
            case self::SIGNATURE_PKCS1:
            case self::SIGNATURE_RELAXED_PKCS1:
                return $this->rsassa_pkcs1_v1_5_sign($message);
            //case self::SIGNATURE_PSS:
            default:
                return $this->rsassa_pss_sign($message);
        }
    }

    /**
     * RSAES-PKCS1-V1_5-DECRYPT
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
     *
     * @param string $c
     * @return bool|string
     */
    private function rsaes_pkcs1_v1_5_decrypt($c)
    {
        // Length checking

        if (strlen($c) != $this->k) { // or if k < 11
            throw new \LengthException('Ciphertext representative too long');
        }

        // RSA decryption

        $c = $this->os2ip($c);
        $m = $this->rsadp($c);
        $em = $this->i2osp($m, $this->k);

        // EME-PKCS1-v1_5 decoding

        if (ord($em[0]) != 0 || ord($em[1]) > 2) {
            throw new \RuntimeException('Decryption error');
        }

        $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
        $m = substr($em, strlen($ps) + 3);

        if (strlen($ps) < 8) {
            throw new \RuntimeException('Decryption error');
        }

        // Output M

        return $m;
    }

    /**
     * RSAES-OAEP-DECRYPT
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}.  The fact that the error
     * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
     *
     *    Note.  Care must be taken to ensure that an opponent cannot
     *    distinguish the different error conditions in Step 3.g, whether by
     *    error message or timing, or, more generally, learn partial
     *    information about the encoded message EM.  Otherwise an opponent may
     *    be able to obtain useful information about the decryption of the
     *    ciphertext C, leading to a chosen-ciphertext attack such as the one
     *    observed by Manger [36].
     *
     * @param string $c
     * @return bool|string
     */
    private function rsaes_oaep_decrypt($c)
    {
        // Length checking

        // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
        // be output.

        if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
            throw new \LengthException('Ciphertext representative too long');
        }

        // RSA decryption

        $c = $this->os2ip($c);
        $m = $this->rsadp($c);
        $em = $this->i2osp($m, $this->k);

        // EME-OAEP decoding

        $lHash = $this->hash->hash($this->label);
        $y = ord($em[0]);
        $maskedSeed = substr($em, 1, $this->hLen);
        $maskedDB = substr($em, $this->hLen + 1);
        $seedMask = $this->mgf1($maskedDB, $this->hLen);
        $seed = $maskedSeed ^ $seedMask;
        $dbMask = $this->mgf1($seed, $this->k - $this->hLen - 1);
        $db = $maskedDB ^ $dbMask;
        $lHash2 = substr($db, 0, $this->hLen);
        $m = substr($db, $this->hLen);
        $hashesMatch = hash_equals($lHash, $lHash2);
        $leadingZeros = 1;
        $patternMatch = 0;
        $offset = 0;
        for ($i = 0; $i < strlen($m); $i++) {
            $patternMatch |= $leadingZeros & ($m[$i] === "\1");
            $leadingZeros &= $m[$i] === "\0";
            $offset += $patternMatch ? 0 : 1;
        }

        // we do | instead of || to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation
        // to protect against timing attacks
        if (!$hashesMatch | !$patternMatch) {
            throw new \RuntimeException('Decryption error');
        }

        // Output the message M

        return substr($m, $offset + 1);
    }

    /**
     * Raw Encryption / Decryption
     *
     * Doesn't use padding and is not recommended.
     *
     * @param string $m
     * @return bool|string
     * @throws \LengthException if strlen($m) > $this->k
     */
    private function raw_encrypt($m)
    {
        if (strlen($m) > $this->k) {
            throw new \LengthException('Ciphertext representative too long');
        }

        $temp = $this->os2ip($m);
        $temp = $this->rsadp($temp);
        return  $this->i2osp($temp, $this->k);
    }

    /**
     * Decryption
     *
     * @see self::encrypt()
     * @param string $ciphertext
     * @return bool|string
     */
    public function decrypt($ciphertext)
    {
        $result = $this->handleOpenSSL('openssl_private_decrypt', $ciphertext);
        if ($result !== null) {
            return $result;
        }

        switch ($this->encryptionPadding) {
            case self::ENCRYPTION_NONE:
                return $this->raw_encrypt($ciphertext);
            case self::ENCRYPTION_PKCS1:
                return $this->rsaes_pkcs1_v1_5_decrypt($ciphertext);
            //case self::ENCRYPTION_OAEP:
            default:
                return $this->rsaes_oaep_decrypt($ciphertext);
        }
    }

    /**
     * Returns the public key
     *
     * @return mixed
     */
    public function getPublicKey()
    {
        $type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey');
        if (empty($this->modulus) || empty($this->publicExponent)) {
            throw new \RuntimeException('Public key components not found');
        }

        $key = $type::savePublicKey($this->modulus, $this->publicExponent);
        return RSA::loadFormat('PKCS8', $key)
            ->withHash($this->hash->getHash())
            ->withMGFHash($this->mgfHash->getHash())
            ->withSaltLength($this->sLen)
            ->withLabel($this->label)
            ->withPadding($this->signaturePadding | $this->encryptionPadding);
    }

    /**
     * Returns the private key
     *
     * @param string $type
     * @param array $options optional
     * @return string
     */
    public function toString($type, array $options = [])
    {
        $type = self::validatePlugin(
            'Keys',
            $type,
            empty($this->primes) ? 'savePublicKey' : 'savePrivateKey'
        );

        if ($type == PSS::class) {
            if ($this->signaturePadding == self::SIGNATURE_PSS) {
                $options += [
                    'hash' => $this->hash->getHash(),
                    'MGFHash' => $this->mgfHash->getHash(),
                    'saltLength' => $this->getSaltLength()
                ];
            } else {
                throw new UnsupportedFormatException('The PSS format can only be used when the signature method has been explicitly set to PSS');
            }
        }

        if (empty($this->primes)) {
            return $type::savePublicKey($this->modulus, $this->exponent, $options);
        }

        return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password, $options);

        /*
        $key = $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password, $options);
        if ($key !== false || count($this->primes) == 2) {
            return $key;
        }

        $nSize = $this->getSize() >> 1;

        $primes = [1 => clone self::$one, clone self::$one];
        $i = 1;
        foreach ($this->primes as $prime) {
            $primes[$i] = $primes[$i]->multiply($prime);
            if ($primes[$i]->getLength() >= $nSize) {
                $i++;
            }
        }

        $exponents = [];
        $coefficients = [2 => $primes[2]->modInverse($primes[1])];

        foreach ($primes as $i => $prime) {
            $temp = $prime->subtract(self::$one);
            $exponents[$i] = $this->modulus->modInverse($temp);
        }

        return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $primes, $exponents, $coefficients, $this->password, $options);
        */
    }
}
<?php

/**
 * RSA Public Key
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\RSA;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common;
use phpseclib3\Crypt\Hash;
use phpseclib3\Crypt\Random;
use phpseclib3\Crypt\RSA;
use phpseclib3\Crypt\RSA\Formats\Keys\PSS;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\Exception\UnsupportedFormatException;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps\DigestInfo;
use phpseclib3\Math\BigInteger;

/**
 * Raw RSA Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
final class PublicKey extends RSA implements Common\PublicKey
{
    use Common\Traits\Fingerprint;

    /**
     * Exponentiate
     *
     * @param BigInteger $x
     * @return BigInteger
     */
    private function exponentiate(BigInteger $x)
    {
        return $x->modPow($this->exponent, $this->modulus);
    }

    /**
     * RSAVP1
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
     *
     * @param BigInteger $s
     * @return bool|BigInteger
     */
    private function rsavp1($s)
    {
        if ($s->compare(self::$zero) < 0 || $s->compare($this->modulus) > 0) {
            return false;
        }
        return $this->exponentiate($s);
    }

    /**
     * RSASSA-PKCS1-V1_5-VERIFY
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
     *
     * @param string $m
     * @param string $s
     * @throws \LengthException if the RSA modulus is too short
     * @return bool
     */
    private function rsassa_pkcs1_v1_5_verify($m, $s)
    {
        // Length checking

        if (strlen($s) != $this->k) {
            return false;
        }

        // RSA verification

        $s = $this->os2ip($s);
        $m2 = $this->rsavp1($s);
        if ($m2 === false) {
            return false;
        }
        $em = $this->i2osp($m2, $this->k);
        if ($em === false) {
            return false;
        }

        // EMSA-PKCS1-v1_5 encoding

        $exception = false;

        // If the encoding operation outputs "intended encoded message length too short," output "RSA modulus
        // too short" and stop.
        try {
            $em2 = $this->emsa_pkcs1_v1_5_encode($m, $this->k);
            $r1 = hash_equals($em, $em2);
        } catch (\LengthException $e) {
            $exception = true;
        }

        try {
            $em3 = $this->emsa_pkcs1_v1_5_encode_without_null($m, $this->k);
            $r2 = hash_equals($em, $em3);
        } catch (\LengthException $e) {
            $exception = true;
        } catch (UnsupportedAlgorithmException $e) {
            $r2 = false;
        }

        if ($exception) {
            throw new \LengthException('RSA modulus too short');
        }

        // Compare
        return boolval($r1 | $r2);
    }

    /**
     * RSASSA-PKCS1-V1_5-VERIFY (relaxed matching)
     *
     * Per {@link http://tools.ietf.org/html/rfc3447#page-43 RFC3447#page-43} PKCS1 v1.5
     * specified the use BER encoding rather than DER encoding that PKCS1 v2.0 specified.
     * This means that under rare conditions you can have a perfectly valid v1.5 signature
     * that fails to validate with _rsassa_pkcs1_v1_5_verify(). PKCS1 v2.1 also recommends
     * that if you're going to validate these types of signatures you "should indicate
     * whether the underlying BER encoding is a DER encoding and hence whether the signature
     * is valid with respect to the specification given in [PKCS1 v2.0+]". so if you do
     * $rsa->getLastPadding() and get RSA::PADDING_RELAXED_PKCS1 back instead of
     * RSA::PADDING_PKCS1... that means BER encoding was used.
     *
     * @param string $m
     * @param string $s
     * @return bool
     */
    private function rsassa_pkcs1_v1_5_relaxed_verify($m, $s)
    {
        // Length checking

        if (strlen($s) != $this->k) {
            return false;
        }

        // RSA verification

        $s = $this->os2ip($s);
        $m2 = $this->rsavp1($s);
        if ($m2 === false) {
            return false;
        }
        $em = $this->i2osp($m2, $this->k);
        if ($em === false) {
            return false;
        }

        if (Strings::shift($em, 2) != "\0\1") {
            return false;
        }

        $em = ltrim($em, "\xFF");
        if (Strings::shift($em) != "\0") {
            return false;
        }

        $decoded = ASN1::decodeBER($em);
        if (!is_array($decoded) || empty($decoded[0]) || strlen($em) > $decoded[0]['length']) {
            return false;
        }

        static $oids;
        if (!isset($oids)) {
            $oids = [
                'md2' => '1.2.840.113549.2.2',
                'md4' => '1.2.840.113549.2.4', // from PKCS1 v1.5
                'md5' => '1.2.840.113549.2.5',
                'id-sha1' => '1.3.14.3.2.26',
                'id-sha256' => '2.16.840.1.101.3.4.2.1',
                'id-sha384' => '2.16.840.1.101.3.4.2.2',
                'id-sha512' => '2.16.840.1.101.3.4.2.3',
                // from PKCS1 v2.2
                'id-sha224' => '2.16.840.1.101.3.4.2.4',
                'id-sha512/224' => '2.16.840.1.101.3.4.2.5',
                'id-sha512/256' => '2.16.840.1.101.3.4.2.6',
            ];
            ASN1::loadOIDs($oids);
        }

        $decoded = ASN1::asn1map($decoded[0], DigestInfo::MAP);
        if (!isset($decoded) || $decoded === false) {
            return false;
        }

        if (!isset($oids[$decoded['digestAlgorithm']['algorithm']])) {
            return false;
        }

        if (isset($decoded['digestAlgorithm']['parameters']) && $decoded['digestAlgorithm']['parameters'] !== ['null' => '']) {
            return false;
        }

        $hash = $decoded['digestAlgorithm']['algorithm'];
        $hash = substr($hash, 0, 3) == 'id-' ?
            substr($hash, 3) :
            $hash;
        $hash = new Hash($hash);
        $em = $hash->hash($m);
        $em2 = $decoded['digest'];

        return hash_equals($em, $em2);
    }

    /**
     * EMSA-PSS-VERIFY
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
     *
     * @param string $m
     * @param string $em
     * @param int $emBits
     * @return string
     */
    private function emsa_pss_verify($m, $em, $emBits)
    {
        // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
        // be output.

        $emLen = ($emBits + 7) >> 3; // ie. ceil($emBits / 8);
        $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;

        $mHash = $this->hash->hash($m);
        if ($emLen < $this->hLen + $sLen + 2) {
            return false;
        }

        if ($em[strlen($em) - 1] != chr(0xBC)) {
            return false;
        }

        $maskedDB = substr($em, 0, -$this->hLen - 1);
        $h = substr($em, -$this->hLen - 1, $this->hLen);
        $temp = chr(256 - (1 << ($emBits & 7)));
        if ((~$maskedDB[0] & $temp) != $temp) {
            return false;
        }
        $dbMask = $this->mgf1($h, $emLen - $this->hLen - 1);
        $db = $maskedDB ^ $dbMask;
        $db[0] = ~chr(256 - (1 << ($emBits & 7))) & $db[0];
        $temp = $emLen - $this->hLen - $sLen - 2;
        if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
            return false;
        }
        $salt = substr($db, $temp + 1); // should be $sLen long
        $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
        $h2 = $this->hash->hash($m2);
        return hash_equals($h, $h2);
    }

    /**
     * RSASSA-PSS-VERIFY
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
     *
     * @param string $m
     * @param string $s
     * @return bool|string
     */
    private function rsassa_pss_verify($m, $s)
    {
        // Length checking

        if (strlen($s) != $this->k) {
            return false;
        }

        // RSA verification

        $modBits = strlen($this->modulus->toBits());

        $s2 = $this->os2ip($s);
        $m2 = $this->rsavp1($s2);
        $em = $this->i2osp($m2, $this->k);
        if ($em === false) {
            return false;
        }

        // EMSA-PSS verification

        return $this->emsa_pss_verify($m, $em, $modBits - 1);
    }

    /**
     * Verifies a signature
     *
     * @see self::sign()
     * @param string $message
     * @param string $signature
     * @return bool
     */
    public function verify($message, $signature)
    {
        $result = $this->handleOpenSSL('openssl_verify', $message, $signature);
        if ($result !== null) {
            return $result;
        }

        switch ($this->signaturePadding) {
            case self::SIGNATURE_RELAXED_PKCS1:
                return $this->rsassa_pkcs1_v1_5_relaxed_verify($message, $signature);
            case self::SIGNATURE_PKCS1:
                return $this->rsassa_pkcs1_v1_5_verify($message, $signature);
            //case self::SIGNATURE_PSS:
            default:
                return $this->rsassa_pss_verify($message, $signature);
        }
    }

    /**
     * RSAES-PKCS1-V1_5-ENCRYPT
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
     *
     * @param string $m
     * @param bool $pkcs15_compat optional
     * @throws \LengthException if strlen($m) > $this->k - 11
     * @return bool|string
     */
    private function rsaes_pkcs1_v1_5_encrypt($m, $pkcs15_compat = false)
    {
        $mLen = strlen($m);

        // Length checking

        if ($mLen > $this->k - 11) {
            throw new \LengthException('Message too long');
        }

        // EME-PKCS1-v1_5 encoding

        $psLen = $this->k - $mLen - 3;
        $ps = '';
        while (strlen($ps) != $psLen) {
            $temp = Random::string($psLen - strlen($ps));
            $temp = str_replace("\x00", '', $temp);
            $ps .= $temp;
        }
        $type = 2;
        $em = chr(0) . chr($type) . $ps . chr(0) . $m;

        // RSA encryption
        $m = $this->os2ip($em);
        $c = $this->rsaep($m);
        $c = $this->i2osp($c, $this->k);

        // Output the ciphertext C

        return $c;
    }

    /**
     * RSAES-OAEP-ENCRYPT
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
     * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
     *
     * @param string $m
     * @throws \LengthException if strlen($m) > $this->k - 2 * $this->hLen - 2
     * @return string
     */
    private function rsaes_oaep_encrypt($m)
    {
        $mLen = strlen($m);

        // Length checking

        // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
        // be output.

        if ($mLen > $this->k - 2 * $this->hLen - 2) {
            throw new \LengthException('Message too long');
        }

        // EME-OAEP encoding

        $lHash = $this->hash->hash($this->label);
        $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
        $db = $lHash . $ps . chr(1) . $m;
        $seed = Random::string($this->hLen);
        $dbMask = $this->mgf1($seed, $this->k - $this->hLen - 1);
        $maskedDB = $db ^ $dbMask;
        $seedMask = $this->mgf1($maskedDB, $this->hLen);
        $maskedSeed = $seed ^ $seedMask;
        $em = chr(0) . $maskedSeed . $maskedDB;

        // RSA encryption

        $m = $this->os2ip($em);
        $c = $this->rsaep($m);
        $c = $this->i2osp($c, $this->k);

        // Output the ciphertext C

        return $c;
    }

    /**
     * RSAEP
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
     *
     * @param BigInteger $m
     * @return bool|BigInteger
     */
    private function rsaep($m)
    {
        if ($m->compare(self::$zero) < 0 || $m->compare($this->modulus) > 0) {
            throw new \OutOfRangeException('Message representative out of range');
        }
        return $this->exponentiate($m);
    }

    /**
     * Raw Encryption / Decryption
     *
     * Doesn't use padding and is not recommended.
     *
     * @param string $m
     * @return bool|string
     * @throws \LengthException if strlen($m) > $this->k
     */
    private function raw_encrypt($m)
    {
        if (strlen($m) > $this->k) {
            throw new \LengthException('Message too long');
        }

        $temp = $this->os2ip($m);
        $temp = $this->rsaep($temp);
        return  $this->i2osp($temp, $this->k);
    }

    /**
     * Encryption
     *
     * Both self::PADDING_OAEP and self::PADDING_PKCS1 both place limits on how long $plaintext can be.
     * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
     * be concatenated together.
     *
     * @see self::decrypt()
     * @param string $plaintext
     * @return bool|string
     * @throws \LengthException if the RSA modulus is too short
     */
    public function encrypt($plaintext)
    {
        $result = $this->handleOpenSSL('openssl_public_encrypt', $plaintext);
        if ($result !== null) {
            return $result;
        }

        switch ($this->encryptionPadding) {
            case self::ENCRYPTION_NONE:
                return $this->raw_encrypt($plaintext);
            case self::ENCRYPTION_PKCS1:
                return $this->rsaes_pkcs1_v1_5_encrypt($plaintext);
            //case self::ENCRYPTION_OAEP:
            default:
                return $this->rsaes_oaep_encrypt($plaintext);
        }
    }

    /**
     * Returns the public key
     *
     * The public key is only returned under two circumstances - if the private key had the public key embedded within it
     * or if the public key was set via setPublicKey().  If the currently loaded key is supposed to be the public key this
     * function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
     *
     * @param string $type
     * @param array $options optional
     * @return mixed
     */
    public function toString($type, array $options = [])
    {
        $type = self::validatePlugin('Keys', $type, 'savePublicKey');

        if ($type == PSS::class) {
            if ($this->signaturePadding == self::SIGNATURE_PSS) {
                $options += [
                    'hash' => $this->hash->getHash(),
                    'MGFHash' => $this->mgfHash->getHash(),
                    'saltLength' => $this->getSaltLength()
                ];
            } else {
                throw new UnsupportedFormatException('The PSS format can only be used when the signature method has been explicitly set to PSS');
            }
        }

        return $type::savePublicKey($this->modulus, $this->publicExponent, $options);
    }

    /**
     * Converts a public key to a private key
     *
     * @return RSA
     */
    public function asPrivateKey()
    {
        $new = new PrivateKey();
        $new->exponent = $this->exponent;
        $new->modulus = $this->modulus;
        $new->k = $this->k;
        $new->format = $this->format;
        return $new
            ->withHash($this->hash->getHash())
            ->withMGFHash($this->mgfHash->getHash())
            ->withSaltLength($this->sLen)
            ->withLabel($this->label)
            ->withPadding($this->signaturePadding | $this->encryptionPadding);
    }
}
<?php

/**
 * Pure-PHP implementation of EC.
 *
 * PHP version 5
 *
 * Here's an example of how to create signatures and verify signatures with this library:
 * <code>
 * <?php
 * include 'vendor/autoload.php';
 *
 * $private = \phpseclib3\Crypt\EC::createKey('secp256k1');
 * $public = $private->getPublicKey();
 *
 * $plaintext = 'terrafrost';
 *
 * $signature = $private->sign($plaintext);
 *
 * echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified';
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2016 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Crypt\Common\AsymmetricKey;
use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib3\Crypt\EC\Curves\Curve25519;
use phpseclib3\Crypt\EC\Curves\Curve448;
use phpseclib3\Crypt\EC\Curves\Ed25519;
use phpseclib3\Crypt\EC\Curves\Ed448;
use phpseclib3\Crypt\EC\Formats\Keys\PKCS1;
use phpseclib3\Crypt\EC\Formats\Keys\PKCS8;
use phpseclib3\Crypt\EC\Parameters;
use phpseclib3\Crypt\EC\PrivateKey;
use phpseclib3\Crypt\EC\PublicKey;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\Exception\UnsupportedCurveException;
use phpseclib3\Exception\UnsupportedOperationException;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps\ECParameters;
use phpseclib3\Math\BigInteger;

/**
 * Pure-PHP implementation of EC.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class EC extends AsymmetricKey
{
    /**
     * Algorithm Name
     *
     * @var string
     */
    const ALGORITHM = 'EC';

    /**
     * Public Key QA
     *
     * @var object[]
     */
    protected $QA;

    /**
     * Curve
     *
     * @var EC\BaseCurves\Base
     */
    protected $curve;

    /**
     * Signature Format (Short)
     *
     * @var string
     */
    protected $shortFormat;

    /**
     * Curve Name
     *
     * @var string
     */
    private $curveName;

    /**
     * Curve Order
     *
     * Used for deterministic ECDSA
     *
     * @var BigInteger
     */
    protected $q;

    /**
     * Alias for the private key
     *
     * Used for deterministic ECDSA. AsymmetricKey expects $x. I don't like x because
     * with x you have x * the base point yielding an (x, y)-coordinate that is the
     * public key. But the x is different depending on which side of the equal sign
     * you're on. It's less ambiguous if you do dA * base point = (x, y)-coordinate.
     *
     * @var BigInteger
     */
    protected $x;

    /**
     * Context
     *
     * @var string
     */
    protected $context;

    /**
     * Signature Format
     *
     * @var string
     */
    protected $sigFormat;

    /**
     * Forced Engine
     *
     * @var ?string
     * @see parent::forceEngine()
     */
    protected static $forcedEngine = null;

    /**
     * Create public / private key pair.
     *
     * @param string $curve
     * @return PrivateKey
     */
    public static function createKey($curve)
    {
        self::initialize_static_variables();

        $class = new \ReflectionClass(static::class);
        if ($class->isFinal()) {
            throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
        }

        $curveName = self::getCurveCase($curve);
        $curve = '\phpseclib3\Crypt\EC\Curves\\' . $curveName;

        if (!class_exists($curve)) {
            throw new UnsupportedCurveException('Named Curve of ' . $curveName . ' is not supported');
        }

        $reflect = new \ReflectionClass($curve);
        $curveName = $reflect->isFinal() ?
            $reflect->getParentClass()->getShortName() :
            $reflect->getShortName();
        $curveEngineName = self::getOpenSSLCurveName(strtolower($curveName));

        switch ($curveName) {
            case 'Ed25519':
                $providers = [
                    'libsodium' => function_exists('sodium_crypto_sign_keypair'),
                    // OPENSSL_KEYTYPE_ED25519 introduced in PHP 8.4.0
                    'OpenSSL'   => defined('OPENSSL_KEYTYPE_ED25519'),
                ];
                break;
            case 'Ed448':
                // OPENSSL_KEYTYPE_ED448 introduced in PHP 8.4.0
                $providers = ['OpenSSL' => defined('OPENSSL_KEYTYPE_ED448')];
                break;
            case 'Curve25519':
                $providers = [
                    'libsodium' => function_exists('sodium_crypto_box_publickey_from_secretkey'),
                    // OPENSSL_KEYTYPE_X25519 introduced in PHP 8.4.0
                    'OpenSSL'   => defined('OPENSSL_KEYTYPE_X25519'),
                ];
                break;
            // OPENSSL_KEYTYPE_X448 introduced in PHP 8.4.0
            case 'Curve448':
                $providers = ['OpenSSL' => defined('OPENSSL_KEYTYPE_X448')];
                break;
            default:
                // openssl_get_curve_names() was introduced in PHP 7.1.0
                // exclude curve25519 and curve448 from testing
                $providers = ['OpenSSL' => function_exists('openssl_get_curve_names') && substr($curveEngineName, 0, 5) != 'curve' && in_array($curveEngineName, openssl_get_curve_names())];
        };

        foreach ($providers as $engine => $isSupported) {
            // if an engine is being forced and the forced engine doesn't match $engine, skip it
            if (isset(self::$forcedEngine) && self::$forcedEngine !== $engine) {
                continue;
            }
            if ($isSupported) {
                $result = self::generateWithEngine($engine, $curveEngineName);
                if (isset($result)) {
                    return $result;
                }
            }
            if (self::$forcedEngine === $engine) {
                throw new BadConfigurationException("EC::createKey: Engine $engine is forced but unsupported for $curve");
            }
        }

        $privatekey = new PrivateKey();

        $curve = new $curve();
        if ($curve instanceof TwistedEdwardsCurve) {
            $arr = $curve->extractSecret(Random::string($curve instanceof Ed448 ? 57 : 32));
            $privatekey->dA = $dA = $arr['dA'];
            $privatekey->secret = $arr['secret'];
        } else {
            $privatekey->dA = $dA = $curve->createRandomMultiplier();
        }
        $privatekey->curve = $curve;
        $privatekey->curveName = $curveName;
        $privatekey->QA = $curve->multiplyPoint($curve->getBasePoint(), $dA);

        //$publickey = clone $privatekey;
        //unset($publickey->dA);
        //unset($publickey->x);

        //$publickey->curveName = $curveName;

        if ($privatekey->curve instanceof TwistedEdwardsCurve) {
            return $privatekey->withHash($curve::HASH);
        }

        return $privatekey;
    }

    /**
     * Returns the actual case of the curve
     *
     * Useful for initializing the curve class
     *
     * @param string $curveName
     * @return string
     */
    private static function getCurveCase($curveName)
    {
        $curveName = strtolower($curveName);
        if (preg_match('#(?:^curve|^ed)\d+$#', $curveName)) {
            return ucfirst($curveName);
        }
        if (substr($curveName, 0, 10) == 'brainpoolp') {
            return 'brainpoolP' . substr($curveName, 10);
        }
        return $curveName;
    }

    /**
     * Return the OpenSSL name for a curve
     *
     * @param string $curve
     * @return string
     */
    private static function getOpenSSLCurveName($curve)
    {
        switch ($curve) {
            case 'secp256r1':
                return 'prime256v1';
            case 'secp192r1':
                return 'prime192v1';
        }
        return $curve;
    }

    /**
     * Generate the key for a given curve / engine combo
     *
     * @param string $engine
     * @param string $curve
     * @return ?PrivateKey
     */
    private static function generateWithEngine($engine, $curve)
    {
        if ($engine == 'libsodium') {
            if ($curve == 'ed25519') {
                $kp = sodium_crypto_sign_keypair();

                $privatekey = EC::loadFormat('libsodium', sodium_crypto_sign_secretkey($kp));
                //$publickey = EC::loadFormat('libsodium', sodium_crypto_sign_publickey($kp));

                $privatekey->curveName = 'Ed25519';
                //$publickey->curveName = $curve;

                return $privatekey;
            } else { // $curve == 'curve25519
                $privatekey = new PrivateKey();
                $privatekey->curve = new Curve25519();
                $privatekey->curveName = 'Curve25519';
                $privatekey->dA = $privatekey->curve->createRandomMultiplier();
                $dA = str_pad($privatekey->dA->toBytes(), 32, "\0", STR_PAD_LEFT);
                //$r = pack('H*', '0900000000000000000000000000000000000000000000000000000000000000');
                //$QA = sodium_crypto_scalarmult($dA, $r);
                $QA = sodium_crypto_box_publickey_from_secretkey($dA);
                $privatekey->QA = [$privatekey->curve->convertInteger(new BigInteger(strrev($QA), 256))];
                return $privatekey;
            }
        }

        // at this point $engine == 'OpenSSL'

        $curveName = self::getCurveCase($curve);

        $config = [];
        if (self::$configFile) {
            $config['config'] = self::$configFile;
        }
        $params = $config;
        switch ($curve) {
            case 'ed25519':
                $params['private_key_type'] = OPENSSL_KEYTYPE_ED25519;
                break;
            case 'ed448':
                $params['private_key_type'] = OPENSSL_KEYTYPE_ED448;
                break;
            case 'curve25519':
                $params['private_key_type'] = OPENSSL_KEYTYPE_X25519;
                break;
            case 'curve448':
                $params['private_key_type'] = OPENSSL_KEYTYPE_X448;
                break;
            default:
                $params['private_key_type'] = OPENSSL_KEYTYPE_EC;
                $params['curve_name'] = $curveName;
        }

        $key = openssl_pkey_new($params);
        if (!$key) {
            return null;
        }
        $privateKeyStr = '';
        if (!openssl_pkey_export($key, $privateKeyStr, null, $config)) {
            return null;
        }
        // clear the buffer of error strings
        while (openssl_error_string() !== false) {
        }
        // some versions of OpenSSL / PHP return PKCS1 keys, others return PKCS8 keys
        $privatekey = EC::load($privateKeyStr);
        switch ($curveName) {
            case 'prime256v1':
                $privatekey->curveName = 'secp256r1';
                break;
            case 'prime192v1':
                $privatekey->curveName = 'secp192r1';
                break;
            default:
                $privatekey->curveName = $curveName;
        }
        return $privatekey;
    }

    /**
     * OnLoad Handler
     *
     * @return bool
     */
    protected static function onLoad(array $components)
    {
        if (!isset($components['dA']) && !isset($components['QA'])) {
            $new = new Parameters();
            $new->curve = $components['curve'];
            return $new;
        }

        $new = isset($components['dA']) ?
            new PrivateKey() :
            new PublicKey();
        $new->curve = $components['curve'];
        $new->QA = $components['QA'];

        if (isset($components['dA'])) {
            $new->dA = $components['dA'];
            $new->secret = $components['secret'];
        }

        if ($new->curve instanceof TwistedEdwardsCurve) {
            return $new->withHash($components['curve']::HASH);
        }

        return $new;
    }

    /**
     * Constructor
     *
     * PublicKey and PrivateKey objects can only be created from abstract RSA class
     */
    protected function __construct()
    {
        $this->sigFormat = self::validatePlugin('Signature', 'ASN1');
        $this->shortFormat = 'ASN1';

        parent::__construct();
    }

    /**
     * Returns the curve
     *
     * Returns a string if it's a named curve, an array if not
     *
     * @return string|array
     */
    public function getCurve()
    {
        if ($this->curveName) {
            return $this->curveName;
        }

        if ($this->curve instanceof MontgomeryCurve) {
            $this->curveName = $this->curve instanceof Curve25519 ? 'Curve25519' : 'Curve448';
            return $this->curveName;
        }

        if ($this->curve instanceof TwistedEdwardsCurve) {
            $this->curveName = $this->curve instanceof Ed25519 ? 'Ed25519' : 'Ed448';
            return $this->curveName;
        }

        $params = $this->getParameters()->toString('PKCS8', ['namedCurve' => true]);
        $decoded = ASN1::extractBER($params);
        $decoded = ASN1::decodeBER($decoded);
        $decoded = ASN1::asn1map($decoded[0], ECParameters::MAP);
        if (isset($decoded['namedCurve'])) {
            $this->curveName = $decoded['namedCurve'];
            return $decoded['namedCurve'];
        }

        if (!$namedCurves) {
            PKCS1::useSpecifiedCurve();
        }

        return $decoded;
    }

    /**
     * Returns the key size
     *
     * Quoting https://tools.ietf.org/html/rfc5656#section-2,
     *
     * "The size of a set of elliptic curve domain parameters on a prime
     *  curve is defined as the number of bits in the binary representation
     *  of the field order, commonly denoted by p.  Size on a
     *  characteristic-2 curve is defined as the number of bits in the binary
     *  representation of the field, commonly denoted by m.  A set of
     *  elliptic curve domain parameters defines a group of order n generated
     *  by a base point P"
     *
     * @return int
     */
    public function getLength()
    {
        return $this->curve->getLength();
    }

    /**
     * Returns the public key coordinates as a string
     *
     * Used by ECDH
     *
     * @return string
     */
    public function getEncodedCoordinates()
    {
        if ($this->curve instanceof MontgomeryCurve) {
            return strrev($this->QA[0]->toBytes(true));
        }
        if ($this->curve instanceof TwistedEdwardsCurve) {
            return $this->curve->encodePoint($this->QA);
        }
        return "\4" . $this->QA[0]->toBytes(true) . $this->QA[1]->toBytes(true);
    }

    /**
     * Convert point to public key
     *
     * For Weierstrass curves, if only the x coordinate is present (as is the case after doing a round of ECDH)
     * then we'll guess at the y coordinate. There are only two possible y values and, atleast in-so-far as
     * multiplication is concerned, neither value affects the resultant x value
     *
     * If $toPublicKey is set to false then a string will be returned - a kind of public key precursor
     *
     * @param string $curveName
     * @param string $secret
     * @param bool $toPublicKey optional
     * @return PublicKey|string
     */
    public static function convertPointToPublicKey($curveName, $secret, $toPublicKey = true)
    {
        $curveName = self::getCurveCase($curveName);
        $curve = '\phpseclib3\Crypt\EC\Curves\\' . $curveName;

        if (!class_exists($curve)) {
            throw new UnsupportedCurveException('Named Curve of ' . $curveName . ' is not supported');
        }

        $curve = new $curve();
        if (!$curve instanceof TwistedEdwardsCurve) {
            if ($curve instanceof MontgomeryCurve) {
                $secret = strrev($secret);
            } elseif ($curve->getLengthInBytes() == strlen($secret)) {
                $secret = "\3$secret";
            }
            if (!$toPublicKey) {
                return $secret;
            }
            $secret = "\0$secret";
        } elseif (!$toPublicKey) {
            return $secret;
        }
        $QA = PKCS8::extractPoint($secret, $curve);
        $key = PKCS8::savePublicKey($curve, $QA);
        return EC::loadFormat('PKCS8', $key);
    }

    /**
     * Returns the parameters
     *
     * @see self::getPublicKey()
     * @param string $type optional
     * @return mixed
     */
    public function getParameters($type = 'PKCS1')
    {
        $type = self::validatePlugin('Keys', $type, 'saveParameters');

        $key = $type::saveParameters($this->curve);

        return EC::load($key, 'PKCS1')
            ->withHash($this->hash->getHash())
            ->withSignatureFormat($this->shortFormat);
    }

    /**
     * Determines the signature padding mode
     *
     * Valid values are: ASN1, SSH2, Raw
     *
     * @param string $format
     */
    public function withSignatureFormat($format)
    {
        if ($this->curve instanceof MontgomeryCurve) {
            throw new UnsupportedOperationException('Montgomery Curves cannot be used to create signatures');
        }

        $new = clone $this;
        $new->shortFormat = $format;
        $new->sigFormat = self::validatePlugin('Signature', $format);
        return $new;
    }

    /**
     * Returns the signature format currently being used
     *
     */
    public function getSignatureFormat()
    {
        return $this->shortFormat;
    }

    /**
     * Sets the context
     *
     * Used by Ed25519 / Ed448.
     *
     * @see self::sign()
     * @see self::verify()
     * @param string $context optional
     */
    public function withContext($context = null)
    {
        if (!$this->curve instanceof TwistedEdwardsCurve) {
            throw new UnsupportedCurveException('Only Ed25519 and Ed448 support contexts');
        }

        $new = clone $this;
        if (!isset($context)) {
            $new->context = null;
            return $new;
        }
        if (!is_string($context)) {
            throw new \InvalidArgumentException('setContext expects a string');
        }
        if (strlen($context) > 255) {
            throw new \LengthException('The context is supposed to be, at most, 255 bytes long');
        }
        $new->context = $context;
        return $new;
    }

    /**
     * Returns the signature format currently being used
     *
     */
    public function getContext()
    {
        return $this->context;
    }

    /**
     * Determines which hashing function should be used
     *
     * @param string $hash
     */
    public function withHash($hash)
    {
        if ($this->curve instanceof MontgomeryCurve) {
            throw new UnsupportedOperationException('Montgomery Curves cannot be used to create signatures');
        }
        if ($this->curve instanceof Ed25519 && $hash != 'sha512') {
            throw new UnsupportedAlgorithmException('Ed25519 only supports sha512 as a hash');
        }
        if ($this->curve instanceof Ed448 && $hash != 'shake256-912') {
            throw new UnsupportedAlgorithmException('Ed448 only supports shake256 with a length of 114 bytes');
        }

        return parent::withHash($hash);
    }
}
<?php

/**
 * Pure-PHP implementation of AES.
 *
 * Uses mcrypt, if available/possible, and an internal implementation, otherwise.
 *
 * PHP version 5
 *
 * NOTE: Since AES.php is (for compatibility and phpseclib-historical reasons) virtually
 * just a wrapper to Rijndael.php you may consider using Rijndael.php instead of
 * to save one include_once().
 *
 * If {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
 * {@link self::setKey() setKey()}.  ie. if the key is 128-bits, the key length will be 128-bits.  If it's 136-bits
 * it'll be null-padded to 192-bits and 192 bits will be the key length until {@link self::setKey() setKey()}
 * is called, again, at which point, it'll be recalculated.
 *
 * Since \phpseclib3\Crypt\AES extends \phpseclib3\Crypt\Rijndael, some functions are available to be called that, in the context of AES, don't
 * make a whole lot of sense.  {@link self::setBlockLength() setBlockLength()}, for instance.  Calling that function,
 * however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $aes = new \phpseclib3\Crypt\AES('ctr');
 *
 *    $aes->setKey('abcdefghijklmnop');
 *
 *    $size = 10 * 1024;
 *    $plaintext = '';
 *    for ($i = 0; $i < $size; $i++) {
 *        $plaintext.= 'a';
 *    }
 *
 *    echo $aes->decrypt($aes->encrypt($plaintext));
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2008 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

/**
 * Pure-PHP implementation of AES.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class AES extends Rijndael
{
    /**
     * Dummy function
     *
     * Since \phpseclib3\Crypt\AES extends \phpseclib3\Crypt\Rijndael, this function is, technically, available, but it doesn't do anything.
     *
     * @see \phpseclib3\Crypt\Rijndael::setBlockLength()
     * @param int $length
     * @throws \BadMethodCallException anytime it's called
     */
    public function setBlockLength($length)
    {
        throw new \BadMethodCallException('The block length cannot be set for AES.');
    }

    /**
     * Sets the key length
     *
     * Valid key lengths are 128, 192, and 256.  Set the link to bool(false) to disable a fixed key length
     *
     * @see \phpseclib3\Crypt\Rijndael:setKeyLength()
     * @param int $length
     * @throws \LengthException if the key length isn't supported
     */
    public function setKeyLength($length)
    {
        switch ($length) {
            case 128:
            case 192:
            case 256:
                break;
            default:
                throw new \LengthException('Key of size ' . $length . ' not supported by this algorithm. Only keys of sizes 128, 192 or 256 supported');
        }
        parent::setKeyLength($length);
    }

    /**
     * Sets the key.
     *
     * Rijndael supports five different key lengths, AES only supports three.
     *
     * @see \phpseclib3\Crypt\Rijndael:setKey()
     * @see setKeyLength()
     * @param string $key
     * @throws \LengthException if the key length isn't supported
     */
    public function setKey($key)
    {
        switch (strlen($key)) {
            case 16:
            case 24:
            case 32:
                break;
            default:
                throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
        }

        parent::setKey($key);
    }
}
<?php

/**
 * Pure-PHP implementation of Triple DES.
 *
 * Uses mcrypt, if available, and an internal implementation, otherwise.  Operates in the EDE3 mode (encrypt-decrypt-encrypt).
 *
 * PHP version 5
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $des = new \phpseclib3\Crypt\TripleDES('ctr');
 *
 *    $des->setKey('abcdefghijklmnopqrstuvwx');
 *
 *    $size = 10 * 1024;
 *    $plaintext = '';
 *    for ($i = 0; $i < $size; $i++) {
 *        $plaintext.= 'a';
 *    }
 *
 *    echo $des->decrypt($des->encrypt($plaintext));
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

/**
 * Pure-PHP implementation of Triple DES.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class TripleDES extends DES
{
    /**
     * Encrypt / decrypt using inner chaining
     *
     * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (self::MODE_CBC3).
     */
    const MODE_3CBC = -2;

    /**
     * Encrypt / decrypt using outer chaining
     *
     * Outer chaining is used by SSH-2 and when the mode is set to \phpseclib3\Crypt\Common\BlockCipher::MODE_CBC.
     */
    const MODE_CBC3 = self::MODE_CBC;

    /**
     * Key Length (in bytes)
     *
     * @see \phpseclib3\Crypt\TripleDES::setKeyLength()
     * @var int
     */
    protected $key_length = 24;

    /**
     * The mcrypt specific name of the cipher
     *
     * @see DES::cipher_name_mcrypt
     * @see Common\SymmetricKey::cipher_name_mcrypt
     * @var string
     */
    protected $cipher_name_mcrypt = 'tripledes';

    /**
     * Optimizing value while CFB-encrypting
     *
     * @see Common\SymmetricKey::cfb_init_len
     * @var int
     */
    protected $cfb_init_len = 750;

    /**
     * max possible size of $key
     *
     * @see self::setKey()
     * @see DES::setKey()
     * @var string
     */
    protected $key_length_max = 24;

    /**
     * Internal flag whether using self::MODE_3CBC or not
     *
     * @var bool
     */
    private $mode_3cbc;

    /**
     * The \phpseclib3\Crypt\DES objects
     *
     * Used only if $mode_3cbc === true
     *
     * @var array
     */
    private $des;

    /**
     * Default Constructor.
     *
     * Determines whether or not the mcrypt or OpenSSL extensions should be used.
     *
     * $mode could be:
     *
     * - ecb
     *
     * - cbc
     *
     * - ctr
     *
     * - cfb
     *
     * - ofb
     *
     * - 3cbc
     *
     * - cbc3 (same as cbc)
     *
     * @see Crypt\DES::__construct()
     * @see Common\SymmetricKey::__construct()
     * @param string $mode
     */
    public function __construct($mode)
    {
        switch (strtolower($mode)) {
            // In case of self::MODE_3CBC, we init as CRYPT_DES_MODE_CBC
            // and additional flag us internally as 3CBC
            case '3cbc':
                parent::__construct('cbc');
                $this->mode_3cbc = true;

                // This three $des'es will do the 3CBC work (if $key > 64bits)
                $this->des = [
                    new DES('cbc'),
                    new DES('cbc'),
                    new DES('cbc'),
                ];

                // we're going to be doing the padding, ourselves, so disable it in the \phpseclib3\Crypt\DES objects
                $this->des[0]->disablePadding();
                $this->des[1]->disablePadding();
                $this->des[2]->disablePadding();
                break;
            case 'cbc3':
                $mode = 'cbc';
                // fall-through
            // If not 3CBC, we init as usual
            default:
                parent::__construct($mode);

                if ($this->mode == self::MODE_STREAM) {
                    throw new BadModeException('Block ciphers cannot be ran in stream mode');
                }
        }
    }

    /**
     * Test for engine validity
     *
     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
     *
     * @see Common\SymmetricKey::__construct()
     * @param int $engine
     * @return bool
     */
    protected function isValidEngineHelper($engine)
    {
        if ($engine == self::ENGINE_OPENSSL) {
            $this->cipher_name_openssl_ecb = 'des-ede3';
            $mode = $this->openssl_translate_mode();
            $this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode;
        }

        return parent::isValidEngineHelper($engine);
    }

    /**
     * Sets the initialization vector.
     *
     * SetIV is not required when \phpseclib3\Crypt\Common\SymmetricKey::MODE_ECB is being used.
     *
     * @see Common\SymmetricKey::setIV()
     * @param string $iv
     */
    public function setIV($iv)
    {
        parent::setIV($iv);
        if ($this->mode_3cbc) {
            $this->des[0]->setIV($iv);
            $this->des[1]->setIV($iv);
            $this->des[2]->setIV($iv);
        }
    }

    /**
     * Sets the key length.
     *
     * Valid key lengths are 128 and 192 bits.
     *
     * If you want to use a 64-bit key use DES.php
     *
     * @see Common\SymmetricKey:setKeyLength()
     * @throws \LengthException if the key length is invalid
     * @param int $length
     */
    public function setKeyLength($length)
    {
        switch ($length) {
            case 128:
            case 192:
                break;
            default:
                throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128 or 192 bits are supported');
        }

        parent::setKeyLength($length);
    }

    /**
     * Sets the key.
     *
     * Triple DES can use 128-bit (eg. strlen($key) == 16) or 192-bit (eg. strlen($key) == 24) keys.
     *
     * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
     *
     * @see DES::setKey()
     * @see Common\SymmetricKey::setKey()
     * @throws \LengthException if the key length is invalid
     * @param string $key
     */
    public function setKey($key)
    {
        if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
            throw new \LengthException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
        }

        switch (strlen($key)) {
            case 16:
                $key .= substr($key, 0, 8);
                break;
            case 24:
                break;
            default:
                throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16 or 24 are supported');
        }

        // copied from self::setKey()
        $this->key = $key;
        $this->key_length = strlen($key);
        $this->changed = $this->nonIVChanged = true;
        $this->setEngine();

        if ($this->mode_3cbc) {
            $this->des[0]->setKey(substr($key, 0, 8));
            $this->des[1]->setKey(substr($key, 8, 8));
            $this->des[2]->setKey(substr($key, 16, 8));
        }
    }

    /**
     * Encrypts a message.
     *
     * @see Common\SymmetricKey::encrypt()
     * @param string $plaintext
     * @return string $cipertext
     */
    public function encrypt($plaintext)
    {
        // parent::en/decrypt() is able to do all the work for all modes and keylengths,
        // except for: self::MODE_3CBC (inner chaining CBC) with a key > 64bits

        // if the key is smaller then 8, do what we'd normally do
        if ($this->mode_3cbc && strlen($this->key) > 8) {
            return $this->des[2]->encrypt(
                $this->des[1]->decrypt(
                    $this->des[0]->encrypt(
                        $this->pad($plaintext)
                    )
                )
            );
        }

        return parent::encrypt($plaintext);
    }

    /**
     * Decrypts a message.
     *
     * @see Common\SymmetricKey::decrypt()
     * @param string $ciphertext
     * @return string $plaintext
     */
    public function decrypt($ciphertext)
    {
        if ($this->mode_3cbc && strlen($this->key) > 8) {
            return $this->unpad(
                $this->des[0]->decrypt(
                    $this->des[1]->encrypt(
                        $this->des[2]->decrypt(
                            str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
                        )
                    )
                )
            );
        }

        return parent::decrypt($ciphertext);
    }

    /**
     * Treat consecutive "packets" as if they are a continuous buffer.
     *
     * Say you have a 16-byte plaintext $plaintext.  Using the default behavior, the two following code snippets
     * will yield different outputs:
     *
     * <code>
     *    echo $des->encrypt(substr($plaintext, 0, 8));
     *    echo $des->encrypt(substr($plaintext, 8, 8));
     * </code>
     * <code>
     *    echo $des->encrypt($plaintext);
     * </code>
     *
     * The solution is to enable the continuous buffer.  Although this will resolve the above discrepancy, it creates
     * another, as demonstrated with the following:
     *
     * <code>
     *    $des->encrypt(substr($plaintext, 0, 8));
     *    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
     * </code>
     * <code>
     *    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
     * </code>
     *
     * With the continuous buffer disabled, these would yield the same output.  With it enabled, they yield different
     * outputs.  The reason is due to the fact that the initialization vector's change after every encryption /
     * decryption round when the continuous buffer is enabled.  When it's disabled, they remain constant.
     *
     * Put another way, when the continuous buffer is enabled, the state of the \phpseclib3\Crypt\DES() object changes after each
     * encryption / decryption round, whereas otherwise, it'd remain constant.  For this reason, it's recommended that
     * continuous buffers not be used.  They do offer better security and are, in fact, sometimes required (SSH uses them),
     * however, they are also less intuitive and more likely to cause you problems.
     *
     * @see Common\SymmetricKey::enableContinuousBuffer()
     * @see self::disableContinuousBuffer()
     */
    public function enableContinuousBuffer()
    {
        parent::enableContinuousBuffer();
        if ($this->mode_3cbc) {
            $this->des[0]->enableContinuousBuffer();
            $this->des[1]->enableContinuousBuffer();
            $this->des[2]->enableContinuousBuffer();
        }
    }

    /**
     * Treat consecutive packets as if they are a discontinuous buffer.
     *
     * The default behavior.
     *
     * @see Common\SymmetricKey::disableContinuousBuffer()
     * @see self::enableContinuousBuffer()
     */
    public function disableContinuousBuffer()
    {
        parent::disableContinuousBuffer();
        if ($this->mode_3cbc) {
            $this->des[0]->disableContinuousBuffer();
            $this->des[1]->disableContinuousBuffer();
            $this->des[2]->disableContinuousBuffer();
        }
    }

    /**
     * Creates the key schedule
     *
     * @see DES::setupKey()
     * @see Common\SymmetricKey::setupKey()
     */
    protected function setupKey()
    {
        switch (true) {
            // if $key <= 64bits we configure our internal pure-php cipher engine
            // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same.
            case strlen($this->key) <= 8:
                $this->des_rounds = 1;
                break;

            // otherwise, if $key > 64bits, we configure our engine to work as 3DES.
            default:
                $this->des_rounds = 3;

                // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately.
                if ($this->mode_3cbc) {
                    $this->des[0]->setupKey();
                    $this->des[1]->setupKey();
                    $this->des[2]->setupKey();

                    // because $des[0-2] will, now, do all the work we can return here
                    // not need unnecessary stress parent::setupKey() with our, now unused, $key.
                    return;
                }
        }
        // setup our key
        parent::setupKey();
    }

    /**
     * Sets the internal crypt engine
     *
     * @see Common\SymmetricKey::__construct()
     * @see Common\SymmetricKey::setPreferredEngine()
     * @param int $engine
     */
    public function setPreferredEngine($engine)
    {
        if ($this->mode_3cbc) {
            $this->des[0]->setPreferredEngine($engine);
            $this->des[1]->setPreferredEngine($engine);
            $this->des[2]->setPreferredEngine($engine);
        }

        parent::setPreferredEngine($engine);
    }
}
<?php

/**
 * Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
 *
 * PHP version 5
 *
 * Here's an example of how to encrypt and decrypt text with this library:
 * <code>
 * <?php
 * include 'vendor/autoload.php';
 *
 * $private = Crypt\RSA::createKey();
 * $public = $private->getPublicKey();
 *
 * $plaintext = 'terrafrost';
 *
 * $ciphertext = $public->encrypt($plaintext);
 *
 * echo $private->decrypt($ciphertext);
 * ?>
 * </code>
 *
 * Here's an example of how to create signatures and verify signatures with this library:
 * <code>
 * <?php
 * include 'vendor/autoload.php';
 *
 * $private = Crypt\RSA::createKey();
 * $public = $private->getPublicKey();
 *
 * $plaintext = 'terrafrost';
 *
 * $signature = $private->sign($plaintext);
 *
 * echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified';
 * ?>
 * </code>
 *
 * One thing to consider when using this: so phpseclib uses PSS mode by default.
 * Technically, id-RSASSA-PSS has a different key format than rsaEncryption. So
 * should phpseclib save to the id-RSASSA-PSS format by default or the
 * rsaEncryption format? For stand-alone keys I figure rsaEncryption is better
 * because SSH doesn't use PSS and idk how many SSH servers would be able to
 * decode an id-RSASSA-PSS key. For X.509 certificates the id-RSASSA-PSS
 * format is used by default (unless you change it up to use PKCS1 instead)
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2009 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Crypt\Common\AsymmetricKey;
use phpseclib3\Crypt\RSA\Formats\Keys\PSS;
use phpseclib3\Crypt\RSA\PrivateKey;
use phpseclib3\Crypt\RSA\PublicKey;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Exception\InconsistentSetupException;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\Math\BigInteger;

/**
 * Pure-PHP PKCS#1 compliant implementation of RSA.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class RSA extends AsymmetricKey
{
    /**
     * Algorithm Name
     *
     * @var string
     */
    const ALGORITHM = 'RSA';

    /**
     * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
     * (OAEP) for encryption / decryption.
     *
     * Uses sha256 by default
     *
     * @see self::setHash()
     * @see self::setMGFHash()
     * @see self::encrypt()
     * @see self::decrypt()
     */
    const ENCRYPTION_OAEP = 1;

    /**
     * Use PKCS#1 padding.
     *
     * Although self::PADDING_OAEP / self::PADDING_PSS  offers more security, including PKCS#1 padding is necessary for purposes of backwards
     * compatibility with protocols (like SSH-1) written before OAEP's introduction.
     *
     * @see self::encrypt()
     * @see self::decrypt()
     */
    const ENCRYPTION_PKCS1 = 2;

    /**
     * Do not use any padding
     *
     * Although this method is not recommended it can none-the-less sometimes be useful if you're trying to decrypt some legacy
     * stuff, if you're trying to diagnose why an encrypted message isn't decrypting, etc.
     *
     * @see self::encrypt()
     * @see self::decrypt()
     */
    const ENCRYPTION_NONE = 4;

    /**
     * Use the Probabilistic Signature Scheme for signing
     *
     * Uses sha256 and 0 as the salt length
     *
     * @see self::setSaltLength()
     * @see self::setMGFHash()
     * @see self::setHash()
     * @see self::sign()
     * @see self::verify()
     * @see self::setHash()
     */
    const SIGNATURE_PSS = 16;

    /**
     * Use a relaxed version of PKCS#1 padding for signature verification
     *
     * @see self::sign()
     * @see self::verify()
     * @see self::setHash()
     */
    const SIGNATURE_RELAXED_PKCS1 = 32;

    /**
     * Use PKCS#1 padding for signature verification
     *
     * @see self::sign()
     * @see self::verify()
     * @see self::setHash()
     */
    const SIGNATURE_PKCS1 = 64;

    /**
     * Encryption padding mode
     *
     * @var int
     */
    protected $encryptionPadding = self::ENCRYPTION_OAEP;

    /**
     * Signature padding mode
     *
     * @var int
     */
    protected $signaturePadding = self::SIGNATURE_PSS;

    /**
     * Length of hash function output
     *
     * @var int
     */
    protected $hLen;

    /**
     * Length of salt
     *
     * @var int
     */
    protected $sLen;

    /**
     * Label
     *
     * @var string
     */
    protected $label = '';

    /**
     * Hash function for the Mask Generation Function
     *
     * @var Hash
     */
    protected $mgfHash;

    /**
     * Length of MGF hash function output
     *
     * @var int
     */
    protected $mgfHLen;

    /**
     * Modulus (ie. n)
     *
     * @var Math\BigInteger
     */
    protected $modulus;

    /**
     * Modulus length
     *
     * @var Math\BigInteger
     */
    protected $k;

    /**
     * Exponent (ie. e or d)
     *
     * @var Math\BigInteger
     */
    protected $exponent;

    /**
     * Default public exponent
     *
     * @var int
     * @link http://en.wikipedia.org/wiki/65537_%28number%29
     */
    private static $defaultExponent = 65537;

    /**
     * Enable Blinding?
     *
     * @var bool
     */
    protected static $enableBlinding = true;

    /**
     * Smallest Prime
     *
     * Per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
     * than 256 bits. As a consequence if the key you're trying to create is 1024 bits and you've set smallestPrime
     * to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). At least if
     * engine is set to self::ENGINE_INTERNAL. If Engine is set to self::ENGINE_OPENSSL then smallest Prime is
     * ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key generation when there's
     * a chance neither gmp nor OpenSSL are installed)
     *
     * @var int
     */
    private static $smallestPrime = 4096;

    /**
     * Public Exponent
     *
     * @var Math\BigInteger
     */
    protected $publicExponent;

    /**
     * Forced Engine
     *
     * @var ?string
     * @see parent::forceEngine()
     */
    protected static $forcedEngine = null;

    /**
     * Sets the public exponent for key generation
     *
     * This will be 65537 unless changed.
     *
     * @param int $val
     */
    public static function setExponent($val)
    {
        self::$defaultExponent = $val;
    }

    /**
     * Sets the smallest prime number in bits. Used for key generation
     *
     * This will be 4096 unless changed.
     *
     * @param int $val
     */
    public static function setSmallestPrime($val)
    {
        self::$smallestPrime = $val;
    }

    /**
     * Create a private key
     *
     * The public key can be extracted from the private key
     *
     * @return PrivateKey
     * @param int $bits
     */
    public static function createKey($bits = 2048)
    {
        self::initialize_static_variables();

        $class = new \ReflectionClass(static::class);
        if ($class->isFinal()) {
            throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
        }

        if (self::$forcedEngine == 'libsodium' || (self::$forcedEngine == 'OpenSSL' && !function_exists('openssl_pkey_new'))) {
            throw new BadConfigurationException('Engine ' . self::$forcedEngine . ' is forced but unsupported for RSA');
        }

        $regSize = $bits >> 1; // divide by two to see how many bits P and Q would be
        if ($regSize > self::$smallestPrime) {
            $num_primes = floor($bits / self::$smallestPrime);
            $regSize = self::$smallestPrime;
        } else {
            $num_primes = 2;
        }

        if ($num_primes == 2 && $bits >= 384 && self::$defaultExponent == 65537) {
            // at this point the only two supported values for self::$forcedEngine are OpenSSL, PHP and null
            // if it's either OpenSSL or null we'll use OpenSSL (if it's available)
            if (self::$forcedEngine !== 'PHP' && function_exists('openssl_pkey_new')) {
                $config = [];
                if (self::$configFile) {
                    $config['config'] = self::$configFile;
                }
                // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
                $rsa = openssl_pkey_new(['private_key_bits' => $bits] + $config);
                if (!$rsa || !openssl_pkey_export($rsa, $privatekeystr, null, $config)) {
                    if (isset(self::$forcedEngine)) {
                        throw new BadConfigurationException('Engine OpenSSL is forced but produced an error - ' . openssl_error_string());
                    }
                } else {
                    // clear the buffer of error strings stemming from a minimalistic openssl.cnf
                    // https://github.com/php/php-src/issues/11054 talks about other errors this'll pick up
                    while (openssl_error_string() !== false) {
                    }

                    return RSA::load($privatekeystr);
                }
            }
        }

        static $e;
        if (!isset($e)) {
            $e = new BigInteger(self::$defaultExponent);
        }

        $n = clone self::$one;
        $exponents = $coefficients = $primes = [];
        $lcm = [
            'top' => clone self::$one,
            'bottom' => false
        ];

        do {
            for ($i = 1; $i <= $num_primes; $i++) {
                if ($i != $num_primes) {
                    $primes[$i] = BigInteger::randomPrime($regSize);
                } else {
                    $minMax = BigInteger::minMaxBits($bits);
                    $min = $minMax['min'];
                    $max = $minMax['max'];
                    list($min) = $min->divide($n);
                    $min = $min->add(self::$one);
                    list($max) = $max->divide($n);
                    $primes[$i] = BigInteger::randomRangePrime($min, $max);
                }

                // the first coefficient is calculated differently from the rest
                // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
                if ($i > 2) {
                    $coefficients[$i] = $n->modInverse($primes[$i]);
                }

                $n = $n->multiply($primes[$i]);

                $temp = $primes[$i]->subtract(self::$one);

                // textbook RSA implementations use Euler's totient function instead of the least common multiple.
                // see http://en.wikipedia.org/wiki/Euler%27s_totient_function
                $lcm['top'] = $lcm['top']->multiply($temp);
                $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
            }

            list($temp) = $lcm['top']->divide($lcm['bottom']);
            $gcd = $temp->gcd($e);
            $i0 = 1;
        } while (!$gcd->equals(self::$one));

        $coefficients[2] = $primes[2]->modInverse($primes[1]);

        $d = $e->modInverse($temp);

        foreach ($primes as $i => $prime) {
            $temp = $prime->subtract(self::$one);
            $exponents[$i] = $e->modInverse($temp);
        }

        // from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
        // RSAPrivateKey ::= SEQUENCE {
        //     version           Version,
        //     modulus           INTEGER,  -- n
        //     publicExponent    INTEGER,  -- e
        //     privateExponent   INTEGER,  -- d
        //     prime1            INTEGER,  -- p
        //     prime2            INTEGER,  -- q
        //     exponent1         INTEGER,  -- d mod (p-1)
        //     exponent2         INTEGER,  -- d mod (q-1)
        //     coefficient       INTEGER,  -- (inverse of q) mod p
        //     otherPrimeInfos   OtherPrimeInfos OPTIONAL
        // }
        $privatekey = new PrivateKey();
        $privatekey->modulus = $n;
        $privatekey->k = $bits >> 3;
        $privatekey->publicExponent = $e;
        $privatekey->exponent = $d;
        $privatekey->primes = $primes;
        $privatekey->exponents = $exponents;
        $privatekey->coefficients = $coefficients;

        /*
        $publickey = new PublicKey;
        $publickey->modulus = $n;
        $publickey->k = $bits >> 3;
        $publickey->exponent = $e;
        $publickey->publicExponent = $e;
        $publickey->isPublic = true;
        */

        return $privatekey;
    }

    /**
     * OnLoad Handler
     *
     * @return bool
     */
    protected static function onLoad(array $components)
    {
        $key = $components['isPublicKey'] ?
            new PublicKey() :
            new PrivateKey();

        $key->modulus = $components['modulus'];
        $key->publicExponent = $components['publicExponent'];
        $key->k = $key->modulus->getLengthInBytes();

        if ($components['isPublicKey'] || !isset($components['privateExponent'])) {
            $key->exponent = $key->publicExponent;
        } else {
            $key->privateExponent = $components['privateExponent'];
            $key->exponent = $key->privateExponent;
            $key->primes = $components['primes'];
            $key->exponents = $components['exponents'];
            $key->coefficients = $components['coefficients'];
        }

        if ($components['format'] == PSS::class) {
            // in the X509 world RSA keys are assumed to use PKCS1 padding by default. only if the key is
            // explicitly a PSS key is the use of PSS assumed. phpseclib does not work like this. phpseclib
            // uses PSS padding by default. it assumes the more secure method by default and altho it provides
            // for the less secure PKCS1 method you have to go out of your way to use it. this is consistent
            // with the latest trends in crypto. libsodium (NaCl) is actually a little more extreme in that
            // not only does it defaults to the most secure methods - it doesn't even let you choose less
            // secure methods
            //$key = $key->withPadding(self::SIGNATURE_PSS);
            if (isset($components['hash'])) {
                $key = $key->withHash($components['hash']);
            }
            if (isset($components['MGFHash'])) {
                $key = $key->withMGFHash($components['MGFHash']);
            }
            if (isset($components['saltLength'])) {
                $key = $key->withSaltLength($components['saltLength']);
            }
        }

        return $key;
    }

    /**
     * Constructor
     *
     * PublicKey and PrivateKey objects can only be created from abstract RSA class
     */
    protected function __construct()
    {
        parent::__construct();

        $this->hLen = $this->hash->getLengthInBytes();
        $this->mgfHash = new Hash('sha256');
        $this->mgfHLen = $this->mgfHash->getLengthInBytes();
    }

    /**
     * Integer-to-Octet-String primitive
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
     *
     * @param bool|Math\BigInteger $x
     * @param int $xLen
     * @return bool|string
     */
    protected function i2osp($x, $xLen)
    {
        if ($x === false) {
            return false;
        }
        $x = $x->toBytes();
        if (strlen($x) > $xLen) {
            throw new \OutOfRangeException('Resultant string length out of range');
        }
        return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
    }

    /**
     * Octet-String-to-Integer primitive
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
     *
     * @param string $x
     * @return Math\BigInteger
     */
    protected function os2ip($x)
    {
        return new BigInteger($x, 256);
    }

    /**
     * EMSA-PKCS1-V1_5-ENCODE
     *
     * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
     *
     * @param string $m
     * @param int $emLen
     * @throws \LengthException if the intended encoded message length is too short
     * @return string
     */
    protected function emsa_pkcs1_v1_5_encode($m, $emLen)
    {
        $h = $this->hash->hash($m);

        // see http://tools.ietf.org/html/rfc3447#page-43
        switch ($this->hash->getHash()) {
            case 'md2':
                $t = "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x02\x05\x00\x04\x10";
                break;
            case 'md5':
                $t = "\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10";
                break;
            case 'sha1':
                $t = "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14";
                break;
            case 'sha256':
                $t = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20";
                break;
            case 'sha384':
                $t = "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30";
                break;
            case 'sha512':
                $t = "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40";
                break;
            // from https://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptography-standard-wp.pdf#page=40
            case 'sha224':
                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04\x05\x00\x04\x1c";
                break;
            case 'sha512/224':
                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x05\x05\x00\x04\x1c";
                break;
            case 'sha512/256':
                $t = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x06\x05\x00\x04\x20";
                break;
            // the following 3x algorithms are not specified in PKCS1 v2.2, however, some standards none-the-less do use them:
            // https://sk-eid.github.io/smart-id-documentation/rp-api/changes.html#_security_enhancements
            // the OIDs are from this URL:
            // https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration#Hash
            case 'sha3/224':
                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x07\x05\x00\x04\x1c";
                break;
            case 'sha3/256':
                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x05\x00\x04\x20";
                break;
            case 'sha3/384':
                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x05\x00\x04\x30";
                break;
            case 'sha3/512':
                $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0A\x05\x00\x04\x40";
        }
        $t .= $h;
        $tLen = strlen($t);

        if ($emLen < $tLen + 11) {
            throw new \LengthException('Intended encoded message length too short');
        }

        $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);

        $em = "\0\1$ps\0$t";

        return $em;
    }

    /**
     * EMSA-PKCS1-V1_5-ENCODE (without NULL)
     *
     * Quoting https://tools.ietf.org/html/rfc8017#page-65,
     *
     * "The parameters field associated with id-sha1, id-sha224, id-sha256,
     *  id-sha384, id-sha512, id-sha512/224, and id-sha512/256 should
     *  generally be omitted, but if present, it shall have a value of type
     *  NULL"
     *
     * @param string $m
     * @param int $emLen
     * @return string
     */
    protected function emsa_pkcs1_v1_5_encode_without_null($m, $emLen)
    {
        $h = $this->hash->hash($m);

        // see http://tools.ietf.org/html/rfc3447#page-43
        switch ($this->hash->getHash()) {
            case 'sha1':
                $t = "\x30\x1f\x30\x07\x06\x05\x2b\x0e\x03\x02\x1a\x04\x14";
                break;
            case 'sha256':
                $t = "\x30\x2f\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x04\x20";
                break;
            case 'sha384':
                $t = "\x30\x3f\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x04\x30";
                break;
            case 'sha512':
                $t = "\x30\x4f\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x04\x40";
                break;
            // from https://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptography-standard-wp.pdf#page=40
            case 'sha224':
                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04\x04\x1c";
                break;
            case 'sha512/224':
                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x05\x04\x1c";
                break;
            case 'sha512/256':
                $t = "\x30\x2f\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x06\x04\x20";
                break;
            // the following 3x algorithms are not specified in PKCS1 v2.2, however, some standards none-the-less do use them:
            // https://sk-eid.github.io/smart-id-documentation/rp-api/changes.html#_security_enhancements
            // the OIDs are from this URL:
            // https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration#Hash
            case 'sha3/224':
                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x07\x04\x1c";
                break;
            case 'sha3/256':
                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x04\x20";
                break;
            case 'sha3/384':
                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x04\x30";
                break;
            case 'sha3/512':
                $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0A\x04\x40";
                break;
            default:
                throw new UnsupportedAlgorithmException('md2 and md5 require NULLs');
        }
        $t .= $h;
        $tLen = strlen($t);

        if ($emLen < $tLen + 11) {
            throw new \LengthException('Intended encoded message length too short');
        }

        $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);

        $em = "\0\1$ps\0$t";

        return $em;
    }

    /**
     * MGF1
     *
     * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
     *
     * @param string $mgfSeed
     * @param int $maskLen
     * @return string
     */
    protected function mgf1($mgfSeed, $maskLen)
    {
        // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.

        $t = '';
        $count = ceil($maskLen / $this->mgfHLen);
        for ($i = 0; $i < $count; $i++) {
            $c = pack('N', $i);
            $t .= $this->mgfHash->hash($mgfSeed . $c);
        }

        return substr($t, 0, $maskLen);
    }

    /**
     * Returns the key size
     *
     * More specifically, this returns the size of the modulo in bits.
     *
     * @return int
     */
    public function getLength()
    {
        return !isset($this->modulus) ? 0 : $this->modulus->getLength();
    }

    /**
     * Determines which hashing function should be used
     *
     * Used with signature production / verification and (if the encryption mode is self::PADDING_OAEP) encryption and
     * decryption.
     *
     * @param string $hash
     */
    public function withHash($hash)
    {
        $new = clone $this;

        // Crypt\Hash supports algorithms that PKCS#1 doesn't support.  md5-96 and sha1-96, for example.
        switch (strtolower($hash)) {
            case 'md2':
            case 'md5':
            case 'sha1':
            case 'sha256':
            case 'sha384':
            case 'sha512':
            case 'sha224':
            case 'sha512/224':
            case 'sha512/256':
            case 'sha3/224':
            case 'sha3/256':
            case 'sha3/384':
            case 'sha3/512':
                $new->hash = new Hash($hash);
                break;
            default:
                throw new UnsupportedAlgorithmException(
                    "The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256 - $hash provided"
                );
        }
        $new->hLen = $new->hash->getLengthInBytes();

        return $new;
    }

    /**
     * Determines which hashing function should be used for the mask generation function
     *
     * The mask generation function is used by self::PADDING_OAEP and self::PADDING_PSS and although it's
     * best if Hash and MGFHash are set to the same thing this is not a requirement.
     *
     * @param string $hash
     */
    public function withMGFHash($hash)
    {
        $new = clone $this;

        // Crypt\Hash supports algorithms that PKCS#1 doesn't support.  md5-96 and sha1-96, for example.
        switch (strtolower($hash)) {
            case 'md2':
            case 'md5':
            case 'sha1':
            case 'sha256':
            case 'sha384':
            case 'sha512':
            case 'sha224':
            case 'sha512/224':
            case 'sha512/256':
            case 'sha3/224':
            case 'sha3/256':
            case 'sha3/384':
            case 'sha3/512':
                $new->mgfHash = new Hash($hash);
                break;
            default:
                throw new UnsupportedAlgorithmException(
                    "The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256 - $hash provided"
                );
        }
        $new->mgfHLen = $new->mgfHash->getLengthInBytes();

        return $new;
    }

    /**
     * Returns the MGF hash algorithm currently being used
     *
     */
    public function getMGFHash()
    {
        return clone $this->mgfHash;
    }

    /**
     * Determines the salt length
     *
     * Used by RSA::PADDING_PSS
     *
     * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
     *
     *    Typical salt lengths in octets are hLen (the length of the output
     *    of the hash function Hash) and 0.
     *
     * @param int $sLen
     */
    public function withSaltLength($sLen)
    {
        $new = clone $this;
        $new->sLen = $sLen;
        return $new;
    }

    /**
     * Returns the salt length currently being used
     *
     */
    public function getSaltLength()
    {
        return $this->sLen !== null ? $this->sLen : $this->hLen;
    }

    /**
     * Determines the label
     *
     * Used by RSA::PADDING_OAEP
     *
     * To quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
     *
     *    Both the encryption and the decryption operations of RSAES-OAEP take
     *    the value of a label L as input.  In this version of PKCS #1, L is
     *    the empty string; other uses of the label are outside the scope of
     *    this document.
     *
     * @param string $label
     */
    public function withLabel($label)
    {
        $new = clone $this;
        $new->label = $label;
        return $new;
    }

    /**
     * Returns the label currently being used
     *
     */
    public function getLabel()
    {
        return $this->label;
    }

    /**
     * Determines the padding modes
     *
     * Example: $key->withPadding(RSA::ENCRYPTION_PKCS1 | RSA::SIGNATURE_PKCS1);
     *
     * @param int $padding
     */
    public function withPadding($padding)
    {
        $masks = [
            self::ENCRYPTION_OAEP,
            self::ENCRYPTION_PKCS1,
            self::ENCRYPTION_NONE
        ];
        $encryptedCount = 0;
        $selected = 0;
        foreach ($masks as $mask) {
            if ($padding & $mask) {
                $selected = $mask;
                $encryptedCount++;
            }
        }
        if ($encryptedCount > 1) {
            throw new InconsistentSetupException('Multiple encryption padding modes have been selected; at most only one should be selected');
        }
        $encryptionPadding = $selected;

        $masks = [
            self::SIGNATURE_PSS,
            self::SIGNATURE_RELAXED_PKCS1,
            self::SIGNATURE_PKCS1
        ];
        $signatureCount = 0;
        $selected = 0;
        foreach ($masks as $mask) {
            if ($padding & $mask) {
                $selected = $mask;
                $signatureCount++;
            }
        }
        if ($signatureCount > 1) {
            throw new InconsistentSetupException('Multiple signature padding modes have been selected; at most only one should be selected');
        }
        $signaturePadding = $selected;

        $new = clone $this;
        if ($encryptedCount) {
            $new->encryptionPadding = $encryptionPadding;
        }
        if ($signatureCount) {
            $new->signaturePadding = $signaturePadding;
        }
        return $new;
    }

    /**
     * Returns the padding currently being used
     *
     */
    public function getPadding()
    {
        return $this->signaturePadding | $this->encryptionPadding;
    }

    /**
     * Enable RSA Blinding
     *
     */
    public static function enableBlinding()
    {
        static::$enableBlinding = true;
    }

    /**
     * Disable RSA Blinding
     *
     */
    public static function disableBlinding()
    {
        static::$enableBlinding = false;
    }

    /**
     * Handles OpenSSL encryption / decryption / signature creation / verification
     *
     * @param string $func
     * @param string $message
     * @param ?string $signature
     * @return bool|string|null
     */
    protected function handleOpenSSL($func, $message, $signature = null)
    {
        switch ($func) {
            case 'openssl_verify':
            case 'openssl_sign':
                $paddingType = 'signaturePadding';
                break;
            case 'openssl_public_encrypt':
            case 'openssl_private_decrypt':
                $paddingType = 'encryptionPadding';
        }

        if (self::$forcedEngine === 'libsodium') {
            throw new BadConfigurationException('Engine libsodium is not supported for RSA');
        }

        if ((isset(self::$forcedEngine) && self::$forcedEngine !== 'PHP') && $this->$paddingType === self::SIGNATURE_RELAXED_PKCS1) {
            throw new BadConfigurationException('Only the PHP engine can be used with relaxed PKCS1 padding');
        }

        if (self::$forcedEngine !== 'PHP') {
            if (self::$forcedEngine === 'OpenSSL' && !function_exists($func)) {
                throw new BadConfigurationException('Engine OpenSSL is forced but unavailable for RSA');
            }
            if ($this->$paddingType === self::SIGNATURE_PSS) {
                switch (true) {
                    case !defined('OPENSSL_PKCS1_PSS_PADDING'):
                        $error = 'Engine OpenSSL is forced but PSS encryption requires PHP >= 8.5.0';
                        break;
                    case $this->hash->getHash() !== $this->mgfHash->getHash():
                        $error = 'Engine OpenSSL is forced but can\'t be used because the Hash and MGF Hash do not match';
                        break;
                    case $this->getSaltLength() !== $this->hLen:
                        $error = 'Engine OpenSSL is forced but can\'t be used because the salt length doesn\'t match the hash length';
                }
            }
            /*
            https://datatracker.ietf.org/doc/html/rfc4055#page-6 says the following:

               There are two possible encodings for the AlgorithmIdentifier
               parameters field associated with these object identifiers.  The two
               alternatives arise from the loss of the OPTIONAL associated with the
               algorithm identifier parameters when the 1988 syntax for
               AlgorithmIdentifier was translated into the 1997 syntax.  Later the
               OPTIONAL was recovered via a defect report, but by then many people
               thought that algorithm parameters were mandatory.  Because of this
               history some implementations encode parameters as a NULL element
               while others omit them entirely.  The correct encoding is to omit the
               parameters field; however, when RSASSA-PSS and RSAES-OAEP were
               defined, it was done using the NULL parameters rather than absent
               parameters.

               All implementations MUST accept both NULL and absent parameters as
               legal and equivalent encodings.

            OpenSSL does NOT accept both - it REQUIRES NULL be present. phpseclib, however,
            DOES accept both. at first, it didn't. at first, not knowing why some small number
            of PKCS1 signatures omitted NULL, i added the SIGNATURE_RELAXED_PKCS1 mode on
            2015-08-26. https://phpseclib.com/docs/rsa#rsasignature_relaxed_pkcs1 talks more
            about that mode. later, on 2021-04-05, there was CVE-2021-30130. consequently,
            the SIGNATURE_PKCS1 mode was updated to accept either NULL or non-NULL.

            because phpseclib accepts PKCS1 signatures that OpenSSL doesn't, OpenSSL isn't
            used for PKCS1. if the OpenSSL extension is installed then it'll be used to perform
            unpadded RSA (ie. modular exponentiation), however, the actual PKCS1 construction
            takes place in PHP code vs OpenSSL.

            see https://security.stackexchange.com/questions/110330/encoding-of-optional-null-in-der
            for an additional reference
            */
            if ($this->$paddingType === self::SIGNATURE_PKCS1 && $func === 'openssl_verify') {
                $error = 'Engine OpenSSL is forced but can\'t be used with PKCS1 signature verification because OpenSSL requires NULL be present whereas phpseclib doesn\'t';
            }
            if ($this->$paddingType === self::ENCRYPTION_OAEP) {
                switch (true) {
                    case $this->hash->getHash() !== $this->mgfHash->getHash():
                        $error = 'Engine OpenSSL is forced but can\'t be used because the Hash and MGF Hash do not match';
                        break;
                    case $this->hash->getHash() !== 'sha1' && PHP_VERSION_ID < 80500:
                        $error = 'Engine OpenSSL is forced but non-sha1 hashes are only supported on PHP 8.5.0+';
                        break;
                    case strlen($this->label):
                        $error = 'Engine OpenSSL is forced but can\'t be used because the label is not the empty string';
                }
            }
            if (isset($error)) {
                if (self::$forcedEngine === 'OpenSSL') {
                    throw new BadConfigurationException($error);
                }
            } elseif ($paddingType === 'signaturePadding') {
                switch (true) {
                    case $this->signaturePadding === self::SIGNATURE_PSS && defined('OPENSSL_PKCS1_PSS_PADDING'):
                    case $this->signaturePadding !== self::SIGNATURE_PSS && function_exists($func):
                        $key = $this instanceof PrivateKey ?
                            $this->withPassword()->toString('PKCS8') :
                            $this->toString('PKCS8');
                        if ($func === 'openssl_sign' && strpos($key, 'PUBLIC') !== false) {
                            if (self::$forcedEngine === 'OpenSSL') {
                                throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used because the private key does not have the prime components within it');
                            }
                            break;
                        }
                        $hash = $this->hash->getHash();

                        // on github actions, php 7.0 and 7.1 on windows emit the following warning:
                        // openssl_sign(): supplied key param cannot be coerced into a private key
                        set_error_handler(function ($errno, $errstr) {
                            throw new BadConfigurationException("Engine OpenSSL is forced but got error: $errstr");
                        });
                        try {
                            $result = $this->signaturePadding === self::SIGNATURE_PSS ?
                                $func($message, $signature, $key, $hash, OPENSSL_PKCS1_PSS_PADDING) :
                                $func($message, $signature, $key, $hash);
                        } catch (BadConfigurationException $e) {
                            if (self::$forcedEngine === 'OpenSSL') {
                                throw $e;
                            }
                            $result = false;
                        } finally {
                            restore_error_handler();
                        }

                        if ($func === 'openssl_verify' && $result !== -1 && $result !== false) {
                            return (bool) $result;
                        }
                        if ($result) {
                            return $signature;
                        }
                        if (self::$forcedEngine === 'OpenSSL') {
                            throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string());
                        }
                }
            } else {
                if ($this->encryptionPadding !== self::ENCRYPTION_OAEP || PHP_VERSION_ID >= 80500) {
                    $key = $this instanceof PrivateKey ?
                        $this->withPassword()->toString('PKCS8') :
                        $this->toString('PKCS8');
                    if ($func === 'openssl_private_decrypt' && strpos($key, 'PUBLIC') !== false) {
                        if ($this->encryptionPadding === self::ENCRYPTION_OAEP) {
                            if (self::$forcedEngine === 'OpenSSL') {
                                throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used because openssl_public_decrypt() doesn\'t have a hash parameter like openssl_private_decrypt() does');
                            }
                            return null;
                        }
                        $func = 'openssl_public_decrypt';
                    }
                    if ($this->encryptionPadding === self::ENCRYPTION_PKCS1 && OPENSSL_VERSION_NUMBER >= 0x30200000) {
                        // quoting https://docs.openssl.org/3.4/man3/RSA_public_encrypt/#return-values :
                        //
                        // "Since version 3.2.0, the default provider in OpenSSL does not return an error when padding checks fail.
                        //  Instead it generates a random message"
                        //
                        // the idea is that even a perfect implementation of PKCS1 padding can be used to conduct a Bleichenbacher
                        // padding oracle attack.
                        //
                        // so like if $rsa->decrypt() doesn't throw an exception it's liable to run additional code that'll take
                        // longer to run than it'd take if an exception would be thrown and in theory, with PKCS1, in particular,
                        // you can use that fact to guess at successive bits of the private key until you've figured it out. it's
                        // why you should use OAEP padding vs PKCS1 padding BUT if you need PKCS1 padding for interoperability then
                        // you're stuck with it.
                        //
                        // with the OpenSSL 3.2.0+ behavior they're making it harder to do the attack by making it harder to use PKCS1
                        // in the real world. this isn't a design philosophy i agree with. like phpseclib lets you DES encryption. you
                        // shouldn't use DES encryption but if you need to you need to and phpseclib isn't here to judge. that's a big
                        // difference between phpseclib and stuff like libsodium.
                        if (self::$forcedEngine === 'OpenSSL') {
                            throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used to decrypt PKCS1 encrypted strings with OpenSSL 3.2.0+');
                        }
                        return null;
                    }
                    $hash = $this->hash->getHash();
                    $output = '';
                    switch ($this->encryptionPadding) {
                        case self::ENCRYPTION_NONE:
                        case self::ENCRYPTION_PKCS1:
                            $padding = $this->encryptionPadding === self::ENCRYPTION_NONE ? OPENSSL_NO_PADDING : OPENSSL_PKCS1_PADDING;
                            // on github actions, php 7.0 and 7.1 on windows emit the following warning:
                            // openssl_private_decrypt(): key parameter is not a valid private key
                            set_error_handler(function ($errno, $errstr) {
                                throw new BadConfigurationException("Engine OpenSSL is forced but got error: $errstr");
                            });
                            try {
                                $result = $func($message, $output, $key, $padding);
                            } catch (BadConfigurationException $e) {
                                if (self::$forcedEngine === 'OpenSSL') {
                                    throw $e;
                                }
                                $result = false;
                            } finally {
                                restore_error_handler();
                            }
                            break;
                        //case self::ENCRYPTION_OAEP:
                        default:
                            $result = $func($message, $output, $key, OPENSSL_PKCS1_OAEP_PADDING, $hash);
                    }
                    if ($result) {
                        return $output;
                    }
                }
            }
            return null;
        }
    }
}
<?php

/**
 * Pure-PHP implementation of Salsa20.
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2019 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\StreamCipher;
use phpseclib3\Exception\BadDecryptionException;
use phpseclib3\Exception\InsufficientSetupException;

/**
 * Pure-PHP implementation of Salsa20.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Salsa20 extends StreamCipher
{
    /**
     * Part 1 of the state
     *
     * @var string|false
     */
    protected $p1 = false;

    /**
     * Part 2 of the state
     *
     * @var string|false
     */
    protected $p2 = false;

    /**
     * Key Length (in bytes)
     *
     * @var int
     */
    protected $key_length = 32; // = 256 bits

    /**
     * @see \phpseclib3\Crypt\Salsa20::crypt()
     */
    const ENCRYPT = 0;

    /**
     * @see \phpseclib3\Crypt\Salsa20::crypt()
     */
    const DECRYPT = 1;

    /**
     * Encryption buffer for continuous mode
     *
     * @var array
     */
    protected $enbuffer;

    /**
     * Decryption buffer for continuous mode
     *
     * @var array
     */
    protected $debuffer;

    /**
     * Counter
     *
     * @var int
     */
    protected $counter = 0;

    /**
     * Using Generated Poly1305 Key
     *
     * @var boolean
     */
    protected $usingGeneratedPoly1305Key = false;

    /**
     * Salsa20 uses a nonce
     *
     * @return bool
     */
    public function usesNonce()
    {
        return true;
    }

    /**
     * Sets the key.
     *
     * @param string $key
     * @throws \LengthException if the key length isn't supported
     */
    public function setKey($key)
    {
        switch (strlen($key)) {
            case 16:
            case 32:
                break;
            default:
                throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16 or 32 are supported');
        }

        parent::setKey($key);
    }

    /**
     * Sets the nonce.
     *
     * @param string $nonce
     */
    public function setNonce($nonce)
    {
        if (strlen($nonce) != 8) {
            throw new \LengthException('Nonce of size ' . strlen($key) . ' not supported by this algorithm. Only an 64-bit nonce is supported');
        }

        $this->nonce = $nonce;
        $this->changed = true;
        $this->setEngine();
    }

    /**
     * Sets the counter.
     *
     * @param int $counter
     */
    public function setCounter($counter)
    {
        $this->counter = $counter;
        $this->setEngine();
    }

    /**
     * Creates a Poly1305 key using the method discussed in RFC8439
     *
     * See https://tools.ietf.org/html/rfc8439#section-2.6.1
     */
    protected function createPoly1305Key()
    {
        if ($this->nonce === false) {
            throw new InsufficientSetupException('No nonce has been defined');
        }

        if ($this->key === false) {
            throw new InsufficientSetupException('No key has been defined');
        }

        $c = clone $this;
        $c->setCounter(0);
        $c->usePoly1305 = false;
        $block = $c->encrypt(str_repeat("\0", 256));
        $this->setPoly1305Key(substr($block, 0, 32));

        if ($this->counter == 0) {
            $this->counter++;
        }
    }

    /**
     * Setup the self::ENGINE_INTERNAL $engine
     *
     * (re)init, if necessary, the internal cipher $engine
     *
     * _setup() will be called each time if $changed === true
     * typically this happens when using one or more of following public methods:
     *
     * - setKey()
     *
     * - setNonce()
     *
     * - First run of encrypt() / decrypt() with no init-settings
     *
     * @see self::setKey()
     * @see self::setNonce()
     * @see self::disableContinuousBuffer()
     */
    protected function setup()
    {
        if (!$this->changed) {
            return;
        }

        $this->enbuffer = $this->debuffer = ['ciphertext' => '', 'counter' => $this->counter];

        $this->changed = $this->nonIVChanged = false;

        if ($this->nonce === false) {
            throw new InsufficientSetupException('No nonce has been defined');
        }

        if ($this->key === false) {
            throw new InsufficientSetupException('No key has been defined');
        }

        if ($this->usePoly1305 && !isset($this->poly1305Key)) {
            $this->usingGeneratedPoly1305Key = true;
            $this->createPoly1305Key();
        }

        $key = $this->key;
        if (strlen($key) == 16) {
            $constant = 'expand 16-byte k';
            $key .= $key;
        } else {
            $constant = 'expand 32-byte k';
        }

        $this->p1 = substr($constant, 0, 4) .
                    substr($key, 0, 16) .
                    substr($constant, 4, 4) .
                    $this->nonce .
                    "\0\0\0\0";
        $this->p2 = substr($constant, 8, 4) .
                    substr($key, 16, 16) .
                    substr($constant, 12, 4);
    }

    /**
     * Setup the key (expansion)
     */
    protected function setupKey()
    {
        // Salsa20 does not utilize this method
    }

    /**
     * Encrypts a message.
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
     * @see self::crypt()
     * @param string $plaintext
     * @return string $ciphertext
     */
    public function encrypt($plaintext)
    {
        $ciphertext = $this->crypt($plaintext, self::ENCRYPT);
        if (isset($this->poly1305Key)) {
            $this->newtag = $this->poly1305($ciphertext);
        }
        return $ciphertext;
    }

    /**
     * Decrypts a message.
     *
     * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
     * At least if the continuous buffer is disabled.
     *
     * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
     * @see self::crypt()
     * @param string $ciphertext
     * @return string $plaintext
     */
    public function decrypt($ciphertext)
    {
        if (isset($this->poly1305Key)) {
            if ($this->oldtag === false) {
                throw new InsufficientSetupException('Authentication Tag has not been set');
            }
            $newtag = $this->poly1305($ciphertext);
            if ($this->oldtag != substr($newtag, 0, strlen($this->oldtag))) {
                $this->oldtag = false;
                throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match');
            }
            $this->oldtag = false;
        }

        return $this->crypt($ciphertext, self::DECRYPT);
    }

    /**
     * Encrypts a block
     *
     * @param string $in
     */
    protected function encryptBlock($in)
    {
        // Salsa20 does not utilize this method
    }

    /**
     * Decrypts a block
     *
     * @param string $in
     */
    protected function decryptBlock($in)
    {
        // Salsa20 does not utilize this method
    }

    /**
     * Encrypts or decrypts a message.
     *
     * @see self::encrypt()
     * @see self::decrypt()
     * @param string $text
     * @param int $mode
     * @return string $text
     */
    private function crypt($text, $mode)
    {
        $this->setup();
        if (!$this->continuousBuffer) {
            if ($this->engine == self::ENGINE_OPENSSL) {
                $iv = pack('V', $this->counter) . $this->p2;
                return openssl_encrypt(
                    $text,
                    $this->cipher_name_openssl,
                    $this->key,
                    OPENSSL_RAW_DATA,
                    $iv
                );
            }
            $i = $this->counter;
            $blocks = str_split($text, 64);
            foreach ($blocks as &$block) {
                $block ^= static::salsa20($this->p1 . pack('V', $i++) . $this->p2);
            }
            unset($block);
            return implode('', $blocks);
        }

        if ($mode == self::ENCRYPT) {
            $buffer = &$this->enbuffer;
        } else {
            $buffer = &$this->debuffer;
        }
        if (!strlen($buffer['ciphertext'])) {
            $ciphertext = '';
        } else {
            $ciphertext = $text ^ Strings::shift($buffer['ciphertext'], strlen($text));
            $text = substr($text, strlen($ciphertext));
            if (!strlen($text)) {
                return $ciphertext;
            }
        }

        $overflow = strlen($text) % 64; // & 0x3F
        if ($overflow) {
            $text2 = Strings::pop($text, $overflow);
            if ($this->engine == self::ENGINE_OPENSSL) {
                $iv = pack('V', $buffer['counter']) . $this->p2;
                // at this point $text should be a multiple of 64
                $buffer['counter'] += (strlen($text) >> 6) + 1; // ie. divide by 64
                $encrypted = openssl_encrypt(
                    $text . str_repeat("\0", 64),
                    $this->cipher_name_openssl,
                    $this->key,
                    OPENSSL_RAW_DATA,
                    $iv
                );
                $temp = Strings::pop($encrypted, 64);
            } else {
                $blocks = str_split($text, 64);
                if (strlen($text)) {
                    foreach ($blocks as &$block) {
                        $block ^= static::salsa20($this->p1 . pack('V', $buffer['counter']++) . $this->p2);
                    }
                    unset($block);
                }
                $encrypted = implode('', $blocks);
                $temp = static::salsa20($this->p1 . pack('V', $buffer['counter']++) . $this->p2);
            }
            $ciphertext .= $encrypted . ($text2 ^ $temp);
            $buffer['ciphertext'] = substr($temp, $overflow);
        } elseif (!strlen($buffer['ciphertext'])) {
            if ($this->engine == self::ENGINE_OPENSSL) {
                $iv = pack('V', $buffer['counter']) . $this->p2;
                $buffer['counter'] += (strlen($text) >> 6);
                $ciphertext .= openssl_encrypt(
                    $text,
                    $this->cipher_name_openssl,
                    $this->key,
                    OPENSSL_RAW_DATA,
                    $iv
                );
            } else {
                $blocks = str_split($text, 64);
                foreach ($blocks as &$block) {
                    $block ^= static::salsa20($this->p1 . pack('V', $buffer['counter']++) . $this->p2);
                }
                unset($block);
                $ciphertext .= implode('', $blocks);
            }
        }

        return $ciphertext;
    }

    /**
     * Left Rotate
     *
     * @param int $x
     * @param int $n
     * @return int
     */
    protected static function leftRotate($x, $n)
    {
        if (PHP_INT_SIZE == 8) {
            $r1 = $x << $n;
            $r1 &= 0xFFFFFFFF;
            $r2 = ($x & 0xFFFFFFFF) >> (32 - $n);
        } else {
            $x = self::safe_intval($x);
            $r1 = $x << $n;
            $r2 = $x >> (32 - $n);
            $r2 &= (1 << $n) - 1;
        }
        return $r1 | $r2;
    }

    /**
     * The quarterround function
     *
     * @param int $a
     * @param int $b
     * @param int $c
     * @param int $d
     */
    protected static function quarterRound(&$a, &$b, &$c, &$d)
    {
        $b ^= self::leftRotate($a + $d, 7);
        $c ^= self::leftRotate($b + $a, 9);
        $d ^= self::leftRotate($c + $b, 13);
        $a ^= self::leftRotate($d + $c, 18);
    }

    /**
     * The doubleround function
     *
     * @param int $x0 (by reference)
     * @param int $x1 (by reference)
     * @param int $x2 (by reference)
     * @param int $x3 (by reference)
     * @param int $x4 (by reference)
     * @param int $x5 (by reference)
     * @param int $x6 (by reference)
     * @param int $x7 (by reference)
     * @param int $x8 (by reference)
     * @param int $x9 (by reference)
     * @param int $x10 (by reference)
     * @param int $x11 (by reference)
     * @param int $x12 (by reference)
     * @param int $x13 (by reference)
     * @param int $x14 (by reference)
     * @param int $x15 (by reference)
     */
    protected static function doubleRound(&$x0, &$x1, &$x2, &$x3, &$x4, &$x5, &$x6, &$x7, &$x8, &$x9, &$x10, &$x11, &$x12, &$x13, &$x14, &$x15)
    {
        // columnRound
        static::quarterRound($x0, $x4, $x8, $x12);
        static::quarterRound($x5, $x9, $x13, $x1);
        static::quarterRound($x10, $x14, $x2, $x6);
        static::quarterRound($x15, $x3, $x7, $x11);
        // rowRound
        static::quarterRound($x0, $x1, $x2, $x3);
        static::quarterRound($x5, $x6, $x7, $x4);
        static::quarterRound($x10, $x11, $x8, $x9);
        static::quarterRound($x15, $x12, $x13, $x14);
    }

    /**
     * The Salsa20 hash function function
     *
     * @param string $x
     */
    protected static function salsa20($x)
    {
        $z = $x = unpack('V*', $x);
        for ($i = 0; $i < 10; $i++) {
            static::doubleRound($z[1], $z[2], $z[3], $z[4], $z[5], $z[6], $z[7], $z[8], $z[9], $z[10], $z[11], $z[12], $z[13], $z[14], $z[15], $z[16]);
        }

        for ($i = 1; $i <= 16; $i++) {
            $x[$i] = self::safe_intval($x[$i] + $z[$i]);
        }

        return pack('V*', ...$x);
    }

    /**
     * Calculates Poly1305 MAC
     *
     * @see self::decrypt()
     * @see self::encrypt()
     * @param string $ciphertext
     * @return string
     */
    protected function poly1305($ciphertext)
    {
        if (!$this->usingGeneratedPoly1305Key) {
            return parent::poly1305($this->aad . $ciphertext);
        } else {
            /*
            sodium_crypto_aead_chacha20poly1305_encrypt does not calculate the poly1305 tag
            the same way sodium_crypto_aead_chacha20poly1305_ietf_encrypt does. you can see
            how the latter encrypts it in Salsa20::encrypt(). here's how the former encrypts
            it:

            $this->newtag = $this->poly1305(
                $this->aad .
                pack('V', strlen($this->aad)) . "\0\0\0\0" .
                $ciphertext .
                pack('V', strlen($ciphertext)) . "\0\0\0\0"
            );

            phpseclib opts to use the IETF construction, even when the nonce is 64-bits
            instead of 96-bits
            */
            return parent::poly1305(
                self::nullPad128($this->aad) .
                self::nullPad128($ciphertext) .
                pack('V', strlen($this->aad)) . "\0\0\0\0" .
                pack('V', strlen($ciphertext)) . "\0\0\0\0"
            );
        }
    }
}
<?php

/**
 * "PKCS1" Formatted EC Key Handler
 *
 * PHP version 5
 *
 * Processes keys with the following headers:
 *
 * -----BEGIN DH PARAMETERS-----
 *
 * Technically, PKCS1 is for RSA keys, only, but we're using PKCS1 to describe
 * DSA, whose format isn't really formally described anywhere, so might as well
 * use it to describe this, too.
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DH\Formats\Keys;

use phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * "PKCS1" Formatted DH Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS1 extends Progenitor
{
    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        $key = parent::load($key, $password);

        $decoded = ASN1::decodeBER($key);
        if (!$decoded) {
            throw new \RuntimeException('Unable to decode BER');
        }

        $components = ASN1::asn1map($decoded[0], Maps\DHParameter::MAP);
        if (!is_array($components)) {
            throw new \RuntimeException('Unable to perform ASN1 mapping on parameters');
        }

        return $components;
    }

    /**
     * Convert EC parameters to the appropriate format
     *
     * @return string
     */
    public static function saveParameters(BigInteger $prime, BigInteger $base, array $options = [])
    {
        $params = [
            'prime' => $prime,
            'base' => $base
        ];
        $params = ASN1::encodeDER($params, Maps\DHParameter::MAP);

        return "-----BEGIN DH PARAMETERS-----\r\n" .
               chunk_split(base64_encode($params), 64) .
               "-----END DH PARAMETERS-----\r\n";
    }
}
<?php

/**
 * PKCS#8 Formatted DH Key Handler
 *
 * PHP version 5
 *
 * Processes keys with the following headers:
 *
 * -----BEGIN ENCRYPTED PRIVATE KEY-----
 * -----BEGIN PRIVATE KEY-----
 * -----BEGIN PUBLIC KEY-----
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DH\Formats\Keys;

use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;

/**
 * PKCS#8 Formatted DH Key Handler
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
abstract class PKCS8 extends Progenitor
{
    /**
     * OID Name
     *
     * @var string
     */
    const OID_NAME = 'dhKeyAgreement';

    /**
     * OID Value
     *
     * @var string
     */
    const OID_VALUE = '1.2.840.113549.1.3.1';

    /**
     * Child OIDs loaded
     *
     * @var bool
     */
    protected static $childOIDsLoaded = false;

    /**
     * Break a public or private key down into its constituent components
     *
     * @param string $key
     * @param string $password optional
     * @return array
     */
    public static function load($key, $password = '')
    {
        $key = parent::load($key, $password);

        $type = isset($key['privateKey']) ? 'privateKey' : 'publicKey';

        $decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element);
        if (empty($decoded)) {
            throw new \RuntimeException('Unable to decode BER of parameters');
        }
        $components = ASN1::asn1map($decoded[0], Maps\DHParameter::MAP);
        if (!is_array($components)) {
            throw new \RuntimeException('Unable to perform ASN1 mapping on parameters');
        }

        $decoded = ASN1::decodeBER($key[$type]);
        switch (true) {
            case !isset($decoded):
            case !isset($decoded[0]['content']):
            case !$decoded[0]['content'] instanceof BigInteger:
                throw new \RuntimeException('Unable to decode BER of parameters');
        }
        $components[$type] = $decoded[0]['content'];

        return $components;
    }

    /**
     * Convert a private key to the appropriate format.
     *
     * @param BigInteger $prime
     * @param BigInteger $base
     * @param BigInteger $privateKey
     * @param BigInteger $publicKey
     * @param string $password optional
     * @param array $options optional
     * @return string
     */
    public static function savePrivateKey(BigInteger $prime, BigInteger $base, BigInteger $privateKey, BigInteger $publicKey, $password = '', array $options = [])
    {
        $params = [
            'prime' => $prime,
            'base' => $base
        ];
        $params = ASN1::encodeDER($params, Maps\DHParameter::MAP);
        $params = new ASN1\Element($params);
        $key = ASN1::encodeDER($privateKey, ['type' => ASN1::TYPE_INTEGER]);
        return self::wrapPrivateKey($key, [], $params, $password, null, '', $options);
    }

    /**
     * Convert a public key to the appropriate format
     *
     * @param BigInteger $prime
     * @param BigInteger $base
     * @param BigInteger $publicKey
     * @param array $options optional
     * @return string
     */
    public static function savePublicKey(BigInteger $prime, BigInteger $base, BigInteger $publicKey, array $options = [])
    {
        $params = [
            'prime' => $prime,
            'base' => $base
        ];
        $params = ASN1::encodeDER($params, Maps\DHParameter::MAP);
        $params = new ASN1\Element($params);
        $key = ASN1::encodeDER($publicKey, ['type' => ASN1::TYPE_INTEGER]);
        return self::wrapPublicKey($key, $params, null, $options);
    }
}
<?php

/**
 * DH Private Key
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DH;

use phpseclib3\Crypt\Common;
use phpseclib3\Crypt\DH;

/**
 * DH Private Key
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
final class PrivateKey extends DH
{
    use Common\Traits\PasswordProtected;

    /**
     * Private Key
     *
     * @var \phpseclib3\Math\BigInteger
     */
    protected $privateKey;

    /**
     * Public Key
     *
     * @var \phpseclib3\Math\BigInteger
     */
    protected $publicKey;

    /**
     * Returns the public key
     *
     * @return PublicKey
     */
    public function getPublicKey()
    {
        $type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey');

        if (!isset($this->publicKey)) {
            $this->publicKey = $this->base->powMod($this->privateKey, $this->prime);
        }

        $key = $type::savePublicKey($this->prime, $this->base, $this->publicKey);

        return DH::loadFormat('PKCS8', $key);
    }

    /**
     * Returns the private key
     *
     * @param string $type
     * @param array $options optional
     * @return string
     */
    public function toString($type, array $options = [])
    {
        $type = self::validatePlugin('Keys', $type, 'savePrivateKey');

        if (!isset($this->publicKey)) {
            $this->publicKey = $this->base->powMod($this->privateKey, $this->prime);
        }

        return $type::savePrivateKey($this->prime, $this->base, $this->privateKey, $this->publicKey, $this->password, $options);
    }
}
<?php

/**
 * DH Public Key
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DH;

use phpseclib3\Crypt\Common;
use phpseclib3\Crypt\DH;

/**
 * DH Public Key
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
final class PublicKey extends DH
{
    use Common\Traits\Fingerprint;

    /**
     * Returns the public key
     *
     * @param string $type
     * @param array $options optional
     * @return string
     */
    public function toString($type, array $options = [])
    {
        $type = self::validatePlugin('Keys', $type, 'savePublicKey');

        return $type::savePublicKey($this->prime, $this->base, $this->publicKey, $options);
    }

    /**
     * Returns the public key as a BigInteger
     *
     * @return \phpseclib3\Math\BigInteger
     */
    public function toBigInteger()
    {
        return $this->publicKey;
    }
}
<?php

/**
 * DH Parameters
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt\DH;

use phpseclib3\Crypt\DH;

/**
 * DH Parameters
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
final class Parameters extends DH
{
    /**
     * Returns the parameters
     *
     * @param string $type
     * @param array $options optional
     * @return string
     */
    public function toString($type = 'PKCS1', array $options = [])
    {
        $type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');

        return $type::saveParameters($this->prime, $this->base, $options);
    }
}
<?php

/**
 * Pure-PHP implementation of DES.
 *
 * Uses mcrypt, if available, and an internal implementation, otherwise.
 *
 * PHP version 5
 *
 * Useful resources are as follows:
 *
 *  - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
 *  - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
 *  - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
 *
 * Here's a short example of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $des = new \phpseclib3\Crypt\DES('ctr');
 *
 *    $des->setKey('abcdefgh');
 *
 *    $size = 10 * 1024;
 *    $plaintext = '';
 *    for ($i = 0; $i < $size; $i++) {
 *        $plaintext.= 'a';
 *    }
 *
 *    echo $des->decrypt($des->encrypt($plaintext));
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2007 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\Crypt;

use phpseclib3\Crypt\Common\BlockCipher;
use phpseclib3\Exception\BadModeException;

/**
 * Pure-PHP implementation of DES.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class DES extends BlockCipher
{
    /**
     * Contains $keys[self::ENCRYPT]
     *
     * @see \phpseclib3\Crypt\DES::setupKey()
     * @see \phpseclib3\Crypt\DES::processBlock()
     */
    const ENCRYPT = 0;
    /**
     * Contains $keys[self::DECRYPT]
     *
     * @see \phpseclib3\Crypt\DES::setupKey()
     * @see \phpseclib3\Crypt\DES::processBlock()
     */
    const DECRYPT = 1;

    /**
     * Block Length of the cipher
     *
     * @see Common\SymmetricKey::block_size
     * @var int
     */
    protected $block_size = 8;

    /**
     * Key Length (in bytes)
     *
     * @see Common\SymmetricKey::setKeyLength()
     * @var int
     */
    protected $key_length = 8;

    /**
     * The mcrypt specific name of the cipher
     *
     * @see Common\SymmetricKey::cipher_name_mcrypt
     * @var string
     */
    protected $cipher_name_mcrypt = 'des';

    /**
     * The OpenSSL names of the cipher / modes
     *
     * @see Common\SymmetricKey::openssl_mode_names
     * @var array
     */
    protected $openssl_mode_names = [
        self::MODE_ECB => 'des-ecb',
        self::MODE_CBC => 'des-cbc',
        self::MODE_CFB => 'des-cfb',
        self::MODE_OFB => 'des-ofb'
        // self::MODE_CTR is undefined for DES
    ];

    /**
     * Optimizing value while CFB-encrypting
     *
     * @see Common\SymmetricKey::cfb_init_len
     * @var int
     */
    protected $cfb_init_len = 500;

    /**
     * Switch for DES/3DES encryption
     *
     * Used only if $engine == self::ENGINE_INTERNAL
     *
     * @see self::setupKey()
     * @see self::processBlock()
     * @var int
     */
    protected $des_rounds = 1;

    /**
     * max possible size of $key
     *
     * @see self::setKey()
     * @var string
     */
    protected $key_length_max = 8;

    /**
     * The Key Schedule
     *
     * @see self::setupKey()
     * @var array
     */
    private $keys;

    /**
     * Key Cache "key"
     *
     * @see self::setupKey()
     * @var array
     */
    private $kl;

    /**
     * Shuffle table.
     *
     * For each byte value index, the entry holds an 8-byte string
     * with each byte containing all bits in the same state as the
     * corresponding bit in the index value.
     *
     * @see self::processBlock()
     * @see self::setupKey()
     * @var array
     */
    protected static $shuffle = [
        "\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF",
        "\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF",
        "\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF",
        "\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF",
        "\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF",
        "\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF",
        "\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF",
        "\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
        "\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF",
        "\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF",
        "\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF",
        "\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF",
        "\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF",
        "\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF",
        "\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF",
        "\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF",
        "\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF",
        "\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF",
        "\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF",
        "\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF",
        "\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF",
        "\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF",
        "\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF",
        "\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF",
        "\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF",
        "\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF",
        "\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF",
        "\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF",
        "\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF",
        "\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF",
        "\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF",
        "\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
        "\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF",
        "\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF",
        "\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF",
        "\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF",
        "\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF",
        "\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF",
        "\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF",
        "\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF",
        "\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF",
        "\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF",
        "\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF",
        "\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF",
        "\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF",
        "\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF",
        "\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF",
        "\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF",
        "\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF",
        "\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF",
        "\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF",
        "\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF",
        "\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF",
        "\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF",
        "\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF",
        "\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF",
        "\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF",
        "\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF",
        "\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF",
        "\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF",
        "\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF",
        "\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF",
        "\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF",
        "\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
        "\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF",
        "\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF",
        "\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF",
        "\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF",
        "\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF",
        "\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF",
        "\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF",
        "\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF",
        "\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF",
        "\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF",
        "\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF",
        "\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF",
        "\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF",
        "\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF",
        "\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF",
        "\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF",
        "\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF",
        "\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF",
        "\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF",
        "\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF",
        "\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF",
        "\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF",
        "\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF",
        "\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF",
        "\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF",
        "\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF",
        "\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF",
        "\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF",
        "\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF",
        "\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF",
        "\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF",
        "\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF",
        "\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF",
        "\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF",
        "\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF",
        "\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF",
        "\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF",
        "\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF",
        "\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF",
        "\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF",
        "\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF",
        "\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF",
        "\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF",
        "\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF",
        "\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF",
        "\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF",
        "\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF",
        "\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF",
        "\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF",
        "\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF",
        "\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF",
        "\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF",
        "\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF",
        "\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF",
        "\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF",
        "\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF",
        "\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF",
        "\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF",
        "\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF",
        "\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF",
        "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF",
        "\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF",
        "\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF",
        "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
    ];

    /**
     * IP mapping helper table.
     *
     * Indexing this table with each source byte performs the initial bit permutation.
     *
     * @var array
     */
    protected static $ipmap = [
        0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31,
        0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33,
        0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71,
        0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73,
        0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35,
        0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37,
        0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75,
        0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77,
        0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1,
        0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3,
        0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1,
        0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3,
        0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5,
        0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7,
        0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5,
        0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7,
        0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39,
        0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B,
        0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79,
        0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B,
        0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D,
        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
        0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D,
        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
        0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9,
        0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB,
        0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9,
        0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB,
        0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD,
        0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF,
        0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD,
        0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF
    ];

    /**
     * Inverse IP mapping helper table.
     * Indexing this table with a byte value reverses the bit order.
     *
     * @var array
     */
    protected static $invipmap = [
        0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
        0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
        0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
        0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
        0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
        0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
        0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
        0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
        0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
        0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
        0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
        0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
        0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
        0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
        0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
        0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
        0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
        0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
        0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
        0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
        0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
        0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
        0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
        0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
        0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
        0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
        0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
        0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
        0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
        0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
        0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
        0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
    ];

    /**
     * Pre-permuted S-box1
     *
     * Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the
     * P table: concatenation can then be replaced by exclusive ORs.
     *
     * @var array
     */
    protected static $sbox1 = [
        0x00808200, 0x00000000, 0x00008000, 0x00808202,
        0x00808002, 0x00008202, 0x00000002, 0x00008000,
        0x00000200, 0x00808200, 0x00808202, 0x00000200,
        0x00800202, 0x00808002, 0x00800000, 0x00000002,
        0x00000202, 0x00800200, 0x00800200, 0x00008200,
        0x00008200, 0x00808000, 0x00808000, 0x00800202,
        0x00008002, 0x00800002, 0x00800002, 0x00008002,
        0x00000000, 0x00000202, 0x00008202, 0x00800000,
        0x00008000, 0x00808202, 0x00000002, 0x00808000,
        0x00808200, 0x00800000, 0x00800000, 0x00000200,
        0x00808002, 0x00008000, 0x00008200, 0x00800002,
        0x00000200, 0x00000002, 0x00800202, 0x00008202,
        0x00808202, 0x00008002, 0x00808000, 0x00800202,
        0x00800002, 0x00000202, 0x00008202, 0x00808200,
        0x00000202, 0x00800200, 0x00800200, 0x00000000,
        0x00008002, 0x00008200, 0x00000000, 0x00808002
    ];

    /**
     * Pre-permuted S-box2
     *
     * @var array
     */
    protected static $sbox2 = [
        0x40084010, 0x40004000, 0x00004000, 0x00084010,
        0x00080000, 0x00000010, 0x40080010, 0x40004010,
        0x40000010, 0x40084010, 0x40084000, 0x40000000,
        0x40004000, 0x00080000, 0x00000010, 0x40080010,
        0x00084000, 0x00080010, 0x40004010, 0x00000000,
        0x40000000, 0x00004000, 0x00084010, 0x40080000,
        0x00080010, 0x40000010, 0x00000000, 0x00084000,
        0x00004010, 0x40084000, 0x40080000, 0x00004010,
        0x00000000, 0x00084010, 0x40080010, 0x00080000,
        0x40004010, 0x40080000, 0x40084000, 0x00004000,
        0x40080000, 0x40004000, 0x00000010, 0x40084010,
        0x00084010, 0x00000010, 0x00004000, 0x40000000,
        0x00004010, 0x40084000, 0x00080000, 0x40000010,
        0x00080010, 0x40004010, 0x40000010, 0x00080010,
        0x00084000, 0x00000000, 0x40004000, 0x00004010,
        0x40000000, 0x40080010, 0x40084010, 0x00084000
    ];

    /**
     * Pre-permuted S-box3
     *
     * @var array
     */
    protected static $sbox3 = [
        0x00000104, 0x04010100, 0x00000000, 0x04010004,
        0x04000100, 0x00000000, 0x00010104, 0x04000100,
        0x00010004, 0x04000004, 0x04000004, 0x00010000,
        0x04010104, 0x00010004, 0x04010000, 0x00000104,
        0x04000000, 0x00000004, 0x04010100, 0x00000100,
        0x00010100, 0x04010000, 0x04010004, 0x00010104,
        0x04000104, 0x00010100, 0x00010000, 0x04000104,
        0x00000004, 0x04010104, 0x00000100, 0x04000000,
        0x04010100, 0x04000000, 0x00010004, 0x00000104,
        0x00010000, 0x04010100, 0x04000100, 0x00000000,
        0x00000100, 0x00010004, 0x04010104, 0x04000100,
        0x04000004, 0x00000100, 0x00000000, 0x04010004,
        0x04000104, 0x00010000, 0x04000000, 0x04010104,
        0x00000004, 0x00010104, 0x00010100, 0x04000004,
        0x04010000, 0x04000104, 0x00000104, 0x04010000,
        0x00010104, 0x00000004, 0x04010004, 0x00010100
    ];

    /**
     * Pre-permuted S-box4
     *
     * @var array
     */
    protected static $sbox4 = [
        0x80401000, 0x80001040, 0x80001040, 0x00000040,
        0x00401040, 0x80400040, 0x80400000, 0x80001000,
        0x00000000, 0x00401000, 0x00401000, 0x80401040,
        0x80000040, 0x00000000, 0x00400040, 0x80400000,
        0x80000000, 0x00001000, 0x00400000, 0x80401000,
        0x00000040, 0x00400000, 0x80001000, 0x00001040,
        0x80400040, 0x80000000, 0x00001040, 0x00400040,
        0x00001000, 0x00401040, 0x80401040, 0x80000040,
        0x00400040, 0x80400000, 0x00401000, 0x80401040,
        0x80000040, 0x00000000, 0x00000000, 0x00401000,
        0x00001040, 0x00400040, 0x80400040, 0x80000000,
        0x80401000, 0x80001040, 0x80001040, 0x00000040,
        0x80401040, 0x80000040, 0x80000000, 0x00001000,
        0x80400000, 0x80001000, 0x00401040, 0x80400040,
        0x80001000, 0x00001040, 0x00400000, 0x80401000,
        0x00000040, 0x00400000, 0x00001000, 0x00401040
    ];

    /**
     * Pre-permuted S-box5
     *
     * @var array
     */
    protected static $sbox5 = [
        0x00000080, 0x01040080, 0x01040000, 0x21000080,
        0x00040000, 0x00000080, 0x20000000, 0x01040000,
        0x20040080, 0x00040000, 0x01000080, 0x20040080,
        0x21000080, 0x21040000, 0x00040080, 0x20000000,
        0x01000000, 0x20040000, 0x20040000, 0x00000000,
        0x20000080, 0x21040080, 0x21040080, 0x01000080,
        0x21040000, 0x20000080, 0x00000000, 0x21000000,
        0x01040080, 0x01000000, 0x21000000, 0x00040080,
        0x00040000, 0x21000080, 0x00000080, 0x01000000,
        0x20000000, 0x01040000, 0x21000080, 0x20040080,
        0x01000080, 0x20000000, 0x21040000, 0x01040080,
        0x20040080, 0x00000080, 0x01000000, 0x21040000,
        0x21040080, 0x00040080, 0x21000000, 0x21040080,
        0x01040000, 0x00000000, 0x20040000, 0x21000000,
        0x00040080, 0x01000080, 0x20000080, 0x00040000,
        0x00000000, 0x20040000, 0x01040080, 0x20000080
    ];

    /**
     * Pre-permuted S-box6
     *
     * @var array
     */
    protected static $sbox6 = [
        0x10000008, 0x10200000, 0x00002000, 0x10202008,
        0x10200000, 0x00000008, 0x10202008, 0x00200000,
        0x10002000, 0x00202008, 0x00200000, 0x10000008,
        0x00200008, 0x10002000, 0x10000000, 0x00002008,
        0x00000000, 0x00200008, 0x10002008, 0x00002000,
        0x00202000, 0x10002008, 0x00000008, 0x10200008,
        0x10200008, 0x00000000, 0x00202008, 0x10202000,
        0x00002008, 0x00202000, 0x10202000, 0x10000000,
        0x10002000, 0x00000008, 0x10200008, 0x00202000,
        0x10202008, 0x00200000, 0x00002008, 0x10000008,
        0x00200000, 0x10002000, 0x10000000, 0x00002008,
        0x10000008, 0x10202008, 0x00202000, 0x10200000,
        0x00202008, 0x10202000, 0x00000000, 0x10200008,
        0x00000008, 0x00002000, 0x10200000, 0x00202008,
        0x00002000, 0x00200008, 0x10002008, 0x00000000,
        0x10202000, 0x10000000, 0x00200008, 0x10002008
    ];

    /**
     * Pre-permuted S-box7
     *
     * @var array
     */
    protected static $sbox7 = [
        0x00100000, 0x02100001, 0x02000401, 0x00000000,
        0x00000400, 0x02000401, 0x00100401, 0x02100400,
        0x02100401, 0x00100000, 0x00000000, 0x02000001,
        0x00000001, 0x02000000, 0x02100001, 0x00000401,
        0x02000400, 0x00100401, 0x00100001, 0x02000400,
        0x02000001, 0x02100000, 0x02100400, 0x00100001,
        0x02100000, 0x00000400, 0x00000401, 0x02100401,
        0x00100400, 0x00000001, 0x02000000, 0x00100400,
        0x02000000, 0x00100400, 0x00100000, 0x02000401,
        0x02000401, 0x02100001, 0x02100001, 0x00000001,
        0x00100001, 0x02000000, 0x02000400, 0x00100000,
        0x02100400, 0x00000401, 0x00100401, 0x02100400,
        0x00000401, 0x02000001, 0x02100401, 0x02100000,
        0x00100400, 0x00000000, 0x00000001, 0x02100401,
        0x00000000, 0x00100401, 0x02100000, 0x00000400,
        0x02000001, 0x02000400, 0x00000400, 0x00100001
    ];

    /**
     * Pre-permuted S-box8
     *
     * @var array
     */
    protected static $sbox8 = [
        0x08000820, 0x00000800, 0x00020000, 0x08020820,
        0x08000000, 0x08000820, 0x00000020, 0x08000000,
        0x00020020, 0x08020000, 0x08020820, 0x00020800,
        0x08020800, 0x00020820, 0x00000800, 0x00000020,
        0x08020000, 0x08000020, 0x08000800, 0x00000820,
        0x00020800, 0x00020020, 0x08020020, 0x08020800,
        0x00000820, 0x00000000, 0x00000000, 0x08020020,
        0x08000020, 0x08000800, 0x00020820, 0x00020000,
        0x00020820, 0x00020000, 0x08020800, 0x00000800,
        0x00000020, 0x08020020, 0x00000800, 0x00020820,
        0x08000800, 0x00000020, 0x08000020, 0x08020000,
        0x08020020, 0x08000000, 0x00020000, 0x08000820,
        0x00000000, 0x08020820, 0x00020020, 0x08000020,
        0x08020000, 0x08000800, 0x08000820, 0x00000000,
        0x08020820, 0x00020800, 0x00020800, 0x00000820,
        0x00000820, 0x00020020, 0x08000000, 0x08020800
    ];

    /**
     * Default Constructor.
     *
     * @param string $mode
     * @throws BadModeException if an invalid / unsupported mode is provided
     */
    public function __construct($mode)
    {
        parent::__construct($mode);

        if ($this->mode == self::MODE_STREAM) {
            throw new BadModeException('Block ciphers cannot be ran in stream mode');
        }
    }

    /**
     * Test for engine validity
     *
     * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
     *
     * @see Common\SymmetricKey::isValidEngine()
     * @param int $engine
     * @return bool
     */
    protected function isValidEngineHelper($engine)
    {
        if ($this->key_length_max == 8) {
            if ($engine == self::ENGINE_OPENSSL) {
                // quoting https://www.openssl.org/news/openssl-3.0-notes.html, OpenSSL 3.0.1
                // "Moved all variations of the EVP ciphers CAST5, BF, IDEA, SEED, RC2, RC4, RC5, and DES to the legacy provider"
                // in theory openssl_get_cipher_methods() should catch this but, on GitHub Actions, at least, it does not
                if (defined('OPENSSL_VERSION_TEXT') && version_compare(preg_replace('#OpenSSL (\d+\.\d+\.\d+) .*#', '$1', OPENSSL_VERSION_TEXT), '3.0.1', '>=')) {
                    return false;
                }
                $this->cipher_name_openssl_ecb = 'des-ecb';
                $this->cipher_name_openssl = 'des-' . $this->openssl_translate_mode();
            }
        }

        return parent::isValidEngineHelper($engine);
    }

    /**
     * Sets the key.
     *
     * Keys must be 64-bits long or 8 bytes long.
     *
     * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
     *
     * @see Common\SymmetricKey::setKey()
     * @param string $key
     */
    public function setKey($key)
    {
        if (!($this instanceof TripleDES) && strlen($key) != 8) {
            throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of size 8 are supported');
        }

        // Sets the key
        parent::setKey($key);
    }

    /**
     * Encrypts a block
     *
     * @see Common\SymmetricKey::encryptBlock()
     * @see Common\SymmetricKey::encrypt()
     * @see self::encrypt()
     * @param string $in
     * @return string
     */
    protected function encryptBlock($in)
    {
        return $this->processBlock($in, self::ENCRYPT);
    }

    /**
     * Decrypts a block
     *
     * @see Common\SymmetricKey::decryptBlock()
     * @see Common\SymmetricKey::decrypt()
     * @see self::decrypt()
     * @param string $in
     * @return string
     */
    protected function decryptBlock($in)
    {
        return $this->processBlock($in, self::DECRYPT);
    }

    /**
     * Encrypts or decrypts a 64-bit block
     *
     * $mode should be either self::ENCRYPT or self::DECRYPT.  See
     * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
     * idea of what this function does.
     *
     * @see self::encryptBlock()
     * @see self::decryptBlock()
     * @param string $block
     * @param int $mode
     * @return string
     */
    private function processBlock($block, $mode)
    {
        static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
        if (!$sbox1) {
            $sbox1 = array_map([self::class, 'safe_intval'], self::$sbox1);
            $sbox2 = array_map([self::class, 'safe_intval'], self::$sbox2);
            $sbox3 = array_map([self::class, 'safe_intval'], self::$sbox3);
            $sbox4 = array_map([self::class, 'safe_intval'], self::$sbox4);
            $sbox5 = array_map([self::class, 'safe_intval'], self::$sbox5);
            $sbox6 = array_map([self::class, 'safe_intval'], self::$sbox6);
            $sbox7 = array_map([self::class, 'safe_intval'], self::$sbox7);
            $sbox8 = array_map([self::class, 'safe_intval'], self::$sbox8);
            /* Merge $shuffle with $[inv]ipmap */
            for ($i = 0; $i < 256; ++$i) {
                $shuffleip[]    =  self::$shuffle[self::$ipmap[$i]];
                $shuffleinvip[] =  self::$shuffle[self::$invipmap[$i]];
            }
        }

        $keys  = $this->keys[$mode];
        $ki    = -1;

        // Do the initial IP permutation.
        $t = unpack('Nl/Nr', $block);
        list($l, $r) = [$t['l'], $t['r']];
        $block = ($shuffleip[ $r        & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
                 ($shuffleip[($r >>  8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
                 ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
                 ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
                 ($shuffleip[ $l        & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
                 ($shuffleip[($l >>  8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
                 ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
                 ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");

        // Extract L0 and R0.
        $t = unpack('Nl/Nr', $block);
        list($l, $r) = [$t['l'], $t['r']];

        for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
            // Perform the 16 steps.
            for ($i = 0; $i < 16; $i++) {
                // start of "the Feistel (F) function" - see the following URL:
                // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
                // Merge key schedule.
                $b1 = (($r >>  3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki];
                $b2 = (($r >> 31) & 0x00000001) ^ ($r <<  1) ^ $keys[++$ki];

                // S-box indexing.
                $t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
                     $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
                     $sbox5[($b1 >>  8) & 0x3F] ^ $sbox6[($b2 >>  8) & 0x3F] ^
                     $sbox7[ $b1        & 0x3F] ^ $sbox8[ $b2        & 0x3F] ^ $l;
                // end of "the Feistel (F) function"

                $l = $r;
                $r = $t;
            }

            // Last step should not permute L & R.
            $t = $l;
            $l = $r;
            $r = $t;
        }

        // Perform the inverse IP permutation.
        return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
               ($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
               ($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
               ($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
               ($shuffleinvip[($r >>  8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
               ($shuffleinvip[($l >>  8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
               ($shuffleinvip[ $r        & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
               ($shuffleinvip[ $l        & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
    }

    /**
     * Creates the key schedule
     *
     * @see Common\SymmetricKey::setupKey()
     */
    protected function setupKey()
    {
        if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) {
            // already expanded
            return;
        }
        $this->kl = ['key' => $this->key, 'des_rounds' => $this->des_rounds];

        static $shifts = [ // number of key bits shifted per round
            1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
        ];

        static $pc1map = [
            0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C,
            0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E,
            0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C,
            0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E,
            0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C,
            0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E,
            0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C,
            0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E,
            0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C,
            0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E,
            0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C,
            0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E,
            0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C,
            0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E,
            0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C,
            0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E,
            0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C,
            0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E,
            0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C,
            0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E,
            0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC,
            0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE,
            0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC,
            0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE,
            0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC,
            0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE,
            0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC,
            0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE,
            0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC,
            0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE,
            0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC,
            0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE
        ];

        // Mapping tables for the PC-2 transformation.
        static $pc2mapc1 = [
            0x00000000, 0x00000400, 0x00200000, 0x00200400,
            0x00000001, 0x00000401, 0x00200001, 0x00200401,
            0x02000000, 0x02000400, 0x02200000, 0x02200400,
            0x02000001, 0x02000401, 0x02200001, 0x02200401
        ];
        static $pc2mapc2 = [
            0x00000000, 0x00000800, 0x08000000, 0x08000800,
            0x00010000, 0x00010800, 0x08010000, 0x08010800,
            0x00000000, 0x00000800, 0x08000000, 0x08000800,
            0x00010000, 0x00010800, 0x08010000, 0x08010800,
            0x00000100, 0x00000900, 0x08000100, 0x08000900,
            0x00010100, 0x00010900, 0x08010100, 0x08010900,
            0x00000100, 0x00000900, 0x08000100, 0x08000900,
            0x00010100, 0x00010900, 0x08010100, 0x08010900,
            0x00000010, 0x00000810, 0x08000010, 0x08000810,
            0x00010010, 0x00010810, 0x08010010, 0x08010810,
            0x00000010, 0x00000810, 0x08000010, 0x08000810,
            0x00010010, 0x00010810, 0x08010010, 0x08010810,
            0x00000110, 0x00000910, 0x08000110, 0x08000910,
            0x00010110, 0x00010910, 0x08010110, 0x08010910,
            0x00000110, 0x00000910, 0x08000110, 0x08000910,
            0x00010110, 0x00010910, 0x08010110, 0x08010910,
            0x00040000, 0x00040800, 0x08040000, 0x08040800,
            0x00050000, 0x00050800, 0x08050000, 0x08050800,
            0x00040000, 0x00040800, 0x08040000, 0x08040800,
            0x00050000, 0x00050800, 0x08050000, 0x08050800,
            0x00040100, 0x00040900, 0x08040100, 0x08040900,
            0x00050100, 0x00050900, 0x08050100, 0x08050900,
            0x00040100, 0x00040900, 0x08040100, 0x08040900,
            0x00050100, 0x00050900, 0x08050100, 0x08050900,
            0x00040010, 0x00040810, 0x08040010, 0x08040810,
            0x00050010, 0x00050810, 0x08050010, 0x08050810,
            0x00040010, 0x00040810, 0x08040010, 0x08040810,
            0x00050010, 0x00050810, 0x08050010, 0x08050810,
            0x00040110, 0x00040910, 0x08040110, 0x08040910,
            0x00050110, 0x00050910, 0x08050110, 0x08050910,
            0x00040110, 0x00040910, 0x08040110, 0x08040910,
            0x00050110, 0x00050910, 0x08050110, 0x08050910,
            0x01000000, 0x01000800, 0x09000000, 0x09000800,
            0x01010000, 0x01010800, 0x09010000, 0x09010800,
            0x01000000, 0x01000800, 0x09000000, 0x09000800,
            0x01010000, 0x01010800, 0x09010000, 0x09010800,
            0x01000100, 0x01000900, 0x09000100, 0x09000900,
            0x01010100, 0x01010900, 0x09010100, 0x09010900,
            0x01000100, 0x01000900, 0x09000100, 0x09000900,
            0x01010100, 0x01010900, 0x09010100, 0x09010900,
            0x01000010, 0x01000810, 0x09000010, 0x09000810,
            0x01010010, 0x01010810, 0x09010010, 0x09010810,
            0x01000010, 0x01000810, 0x09000010, 0x09000810,
            0x01010010, 0x01010810, 0x09010010, 0x09010810,
            0x01000110, 0x01000910, 0x09000110, 0x09000910,
            0x01010110, 0x01010910, 0x09010110, 0x09010910,
            0x01000110, 0x01000910, 0x09000110, 0x09000910,
            0x01010110, 0x01010910, 0x09010110, 0x09010910,
            0x01040000, 0x01040800, 0x09040000, 0x09040800,
            0x01050000, 0x01050800, 0x09050000, 0x09050800,
            0x01040000, 0x01040800, 0x09040000, 0x09040800,
            0x01050000, 0x01050800, 0x09050000, 0x09050800,
            0x01040100, 0x01040900, 0x09040100, 0x09040900,
            0x01050100, 0x01050900, 0x09050100, 0x09050900,
            0x01040100, 0x01040900, 0x09040100, 0x09040900,
            0x01050100, 0x01050900, 0x09050100, 0x09050900,
            0x01040010, 0x01040810, 0x09040010, 0x09040810,
            0x01050010, 0x01050810, 0x09050010, 0x09050810,
            0x01040010, 0x01040810, 0x09040010, 0x09040810,
            0x01050010, 0x01050810, 0x09050010, 0x09050810,
            0x01040110, 0x01040910, 0x09040110, 0x09040910,
            0x01050110, 0x01050910, 0x09050110, 0x09050910,
            0x01040110, 0x01040910, 0x09040110, 0x09040910,
            0x01050110, 0x01050910, 0x09050110, 0x09050910
        ];
        static $pc2mapc3 = [
            0x00000000, 0x00000004, 0x00001000, 0x00001004,
            0x00000000, 0x00000004, 0x00001000, 0x00001004,
            0x10000000, 0x10000004, 0x10001000, 0x10001004,
            0x10000000, 0x10000004, 0x10001000, 0x10001004,
            0x00000020, 0x00000024, 0x00001020, 0x00001024,
            0x00000020, 0x00000024, 0x00001020, 0x00001024,
            0x10000020, 0x10000024, 0x10001020, 0x10001024,
            0x10000020, 0x10000024, 0x10001020, 0x10001024,
            0x00080000, 0x00080004, 0x00081000, 0x00081004,
            0x00080000, 0x00080004, 0x00081000, 0x00081004,
            0x10080000, 0x10080004, 0x10081000, 0x10081004,
            0x10080000, 0x10080004, 0x10081000, 0x10081004,
            0x00080020, 0x00080024, 0x00081020, 0x00081024,
            0x00080020, 0x00080024, 0x00081020, 0x00081024,
            0x10080020, 0x10080024, 0x10081020, 0x10081024,
            0x10080020, 0x10080024, 0x10081020, 0x10081024,
            0x20000000, 0x20000004, 0x20001000, 0x20001004,
            0x20000000, 0x20000004, 0x20001000, 0x20001004,
            0x30000000, 0x30000004, 0x30001000, 0x30001004,
            0x30000000, 0x30000004, 0x30001000, 0x30001004,
            0x20000020, 0x20000024, 0x20001020, 0x20001024,
            0x20000020, 0x20000024, 0x20001020, 0x20001024,
            0x30000020, 0x30000024, 0x30001020, 0x30001024,
            0x30000020, 0x30000024, 0x30001020, 0x30001024,
            0x20080000, 0x20080004, 0x20081000, 0x20081004,
            0x20080000, 0x20080004, 0x20081000, 0x20081004,
            0x30080000, 0x30080004, 0x30081000, 0x30081004,
            0x30080000, 0x30080004, 0x30081000, 0x30081004,
            0x20080020, 0x20080024, 0x20081020, 0x20081024,
            0x20080020, 0x20080024, 0x20081020, 0x20081024,
            0x30080020, 0x30080024, 0x30081020, 0x30081024,
            0x30080020, 0x30080024, 0x30081020, 0x30081024,
            0x00000002, 0x00000006, 0x00001002, 0x00001006,
            0x00000002, 0x00000006, 0x00001002, 0x00001006,
            0x10000002, 0x10000006, 0x10001002, 0x10001006,
            0x10000002, 0x10000006, 0x10001002, 0x10001006,
            0x00000022, 0x00000026, 0x00001022, 0x00001026,
            0x00000022, 0x00000026, 0x00001022, 0x00001026,
            0x10000022, 0x10000026, 0x10001022, 0x10001026,
            0x10000022, 0x10000026, 0x10001022, 0x10001026,
            0x00080002, 0x00080006, 0x00081002, 0x00081006,
            0x00080002, 0x00080006, 0x00081002, 0x00081006,
            0x10080002, 0x10080006, 0x10081002, 0x10081006,
            0x10080002, 0x10080006, 0x10081002, 0x10081006,
            0x00080022, 0x00080026, 0x00081022, 0x00081026,
            0x00080022, 0x00080026, 0x00081022, 0x00081026,
            0x10080022, 0x10080026, 0x10081022, 0x10081026,
            0x10080022, 0x10080026, 0x10081022, 0x10081026,
            0x20000002, 0x20000006, 0x20001002, 0x20001006,
            0x20000002, 0x20000006, 0x20001002, 0x20001006,
            0x30000002, 0x30000006, 0x30001002, 0x30001006,
            0x30000002, 0x30000006, 0x30001002, 0x30001006,
            0x20000022, 0x20000026, 0x20001022, 0x20001026,
            0x20000022, 0x20000026, 0x20001022, 0x20001026,
            0x30000022, 0x30000026, 0x30001022, 0x30001026,
            0x30000022, 0x30000026, 0x30001022, 0x30001026,
            0x20080002, 0x20080006, 0x20081002, 0x20081006,
            0x20080002, 0x20080006, 0x20081002, 0x20081006,
            0x30080002, 0x30080006, 0x30081002, 0x30081006,
            0x30080002, 0x30080006, 0x30081002, 0x30081006,
            0x20080022, 0x20080026, 0x20081022, 0x20081026,
            0x20080022, 0x20080026, 0x20081022, 0x20081026,
            0x30080022, 0x30080026, 0x30081022, 0x30081026,
            0x30080022, 0x30080026, 0x30081022, 0x30081026
        ];
        static $pc2mapc4 = [
            0x00000000, 0x00100000, 0x00000008, 0x00100008,
            0x00000200, 0x00100200, 0x00000208, 0x00100208,
            0x00000000, 0x00100000, 0x00000008, 0x00100008,
            0x00000200, 0x00100200, 0x00000208, 0x00100208,
            0x04000000, 0x04100000, 0x04000008, 0x04100008,
            0x04000200, 0x04100200, 0x04000208, 0x04100208,
            0x04000000, 0x04100000, 0x04000008, 0x04100008,
            0x04000200, 0x04100200, 0x04000208, 0x04100208,
            0x00002000, 0x00102000, 0x00002008, 0x00102008,
            0x00002200, 0x00102200, 0x00002208, 0x00102208,
            0x00002000, 0x00102000, 0x00002008, 0x00102008,
            0x00002200, 0x00102200, 0x00002208, 0x00102208,
            0x04002000, 0x04102000, 0x04002008, 0x04102008,
            0x04002200, 0x04102200, 0x04002208, 0x04102208,
            0x04002000, 0x04102000, 0x04002008, 0x04102008,
            0x04002200, 0x04102200, 0x04002208, 0x04102208,
            0x00000000, 0x00100000, 0x00000008, 0x00100008,
            0x00000200, 0x00100200, 0x00000208, 0x00100208,
            0x00000000, 0x00100000, 0x00000008, 0x00100008,
            0x00000200, 0x00100200, 0x00000208, 0x00100208,
            0x04000000, 0x04100000, 0x04000008, 0x04100008,
            0x04000200, 0x04100200, 0x04000208, 0x04100208,
            0x04000000, 0x04100000, 0x04000008, 0x04100008,
            0x04000200, 0x04100200, 0x04000208, 0x04100208,
            0x00002000, 0x00102000, 0x00002008, 0x00102008,
            0x00002200, 0x00102200, 0x00002208, 0x00102208,
            0x00002000, 0x00102000, 0x00002008, 0x00102008,
            0x00002200, 0x00102200, 0x00002208, 0x00102208,
            0x04002000, 0x04102000, 0x04002008, 0x04102008,
            0x04002200, 0x04102200, 0x04002208, 0x04102208,
            0x04002000, 0x04102000, 0x04002008, 0x04102008,
            0x04002200, 0x04102200, 0x04002208, 0x04102208,
            0x00020000, 0x00120000, 0x00020008, 0x00120008,
            0x00020200, 0x00120200, 0x00020208, 0x00120208,
            0x00020000, 0x00120000, 0x00020008, 0x00120008,
            0x00020200, 0x00120200, 0x00020208, 0x00120208,
            0x04020000, 0x04120000, 0x04020008, 0x04120008,
            0x04020200, 0x04120200, 0x04020208, 0x04120208,
            0x04020000, 0x04120000, 0x04020008, 0x04120008,
            0x04020200, 0x04120200, 0x04020208, 0x04120208,
            0x00022000, 0x00122000, 0x00022008, 0x00122008,
            0x00022200, 0x00122200, 0x00022208, 0x00122208,
            0x00022000, 0x00122000, 0x00022008, 0x00122008,
            0x00022200, 0x00122200, 0x00022208, 0x00122208,
            0x04022000, 0x04122000, 0x04022008, 0x04122008,
            0x04022200, 0x04122200, 0x04022208, 0x04122208,
            0x04022000, 0x04122000, 0x04022008, 0x04122008,
            0x04022200, 0x04122200, 0x04022208, 0x04122208,
            0x00020000, 0x00120000, 0x00020008, 0x00120008,
            0x00020200, 0x00120200, 0x00020208, 0x00120208,
            0x00020000, 0x00120000, 0x00020008, 0x00120008,
            0x00020200, 0x00120200, 0x00020208, 0x00120208,
            0x04020000, 0x04120000, 0x04020008, 0x04120008,
            0x04020200, 0x04120200, 0x04020208, 0x04120208,
            0x04020000, 0x04120000, 0x04020008, 0x04120008,
            0x04020200, 0x04120200, 0x04020208, 0x04120208,
            0x00022000, 0x00122000, 0x00022008, 0x00122008,
            0x00022200, 0x00122200, 0x00022208, 0x00122208,
            0x00022000, 0x00122000, 0x00022008, 0x00122008,
            0x00022200, 0x00122200, 0x00022208, 0x00122208,
            0x04022000, 0x04122000, 0x04022008, 0x04122008,
            0x04022200, 0x04122200, 0x04022208, 0x04122208,
            0x04022000, 0x04122000, 0x04022008, 0x04122008,
            0x04022200, 0x04122200, 0x04022208, 0x04122208
        ];
        static $pc2mapd1 = [
            0x00000000, 0x00000001, 0x08000000, 0x08000001,
            0x00200000, 0x00200001, 0x08200000, 0x08200001,
            0x00000002, 0x00000003, 0x08000002, 0x08000003,
            0x00200002, 0x00200003, 0x08200002, 0x08200003
        ];
        static $pc2mapd2 = [
            0x00000000, 0x00100000, 0x00000800, 0x00100800,
            0x00000000, 0x00100000, 0x00000800, 0x00100800,
            0x04000000, 0x04100000, 0x04000800, 0x04100800,
            0x04000000, 0x04100000, 0x04000800, 0x04100800,
            0x00000004, 0x00100004, 0x00000804, 0x00100804,
            0x00000004, 0x00100004, 0x00000804, 0x00100804,
            0x04000004, 0x04100004, 0x04000804, 0x04100804,
            0x04000004, 0x04100004, 0x04000804, 0x04100804,
            0x00000000, 0x00100000, 0x00000800, 0x00100800,
            0x00000000, 0x00100000, 0x00000800, 0x00100800,
            0x04000000, 0x04100000, 0x04000800, 0x04100800,
            0x04000000, 0x04100000, 0x04000800, 0x04100800,
            0x00000004, 0x00100004, 0x00000804, 0x00100804,
            0x00000004, 0x00100004, 0x00000804, 0x00100804,
            0x04000004, 0x04100004, 0x04000804, 0x04100804,
            0x04000004, 0x04100004, 0x04000804, 0x04100804,
            0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
            0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
            0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
            0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
            0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
            0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
            0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
            0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
            0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
            0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
            0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
            0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
            0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
            0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
            0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
            0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
            0x00020000, 0x00120000, 0x00020800, 0x00120800,
            0x00020000, 0x00120000, 0x00020800, 0x00120800,
            0x04020000, 0x04120000, 0x04020800, 0x04120800,
            0x04020000, 0x04120000, 0x04020800, 0x04120800,
            0x00020004, 0x00120004, 0x00020804, 0x00120804,
            0x00020004, 0x00120004, 0x00020804, 0x00120804,
            0x04020004, 0x04120004, 0x04020804, 0x04120804,
            0x04020004, 0x04120004, 0x04020804, 0x04120804,
            0x00020000, 0x00120000, 0x00020800, 0x00120800,
            0x00020000, 0x00120000, 0x00020800, 0x00120800,
            0x04020000, 0x04120000, 0x04020800, 0x04120800,
            0x04020000, 0x04120000, 0x04020800, 0x04120800,
            0x00020004, 0x00120004, 0x00020804, 0x00120804,
            0x00020004, 0x00120004, 0x00020804, 0x00120804,
            0x04020004, 0x04120004, 0x04020804, 0x04120804,
            0x04020004, 0x04120004, 0x04020804, 0x04120804,
            0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
            0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
            0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
            0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
            0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
            0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
            0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
            0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
            0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
            0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
            0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
            0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
            0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
            0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
            0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
            0x04020204, 0x04120204, 0x04020A04, 0x04120A04
        ];
        static $pc2mapd3 = [
            0x00000000, 0x00010000, 0x02000000, 0x02010000,
            0x00000020, 0x00010020, 0x02000020, 0x02010020,
            0x00040000, 0x00050000, 0x02040000, 0x02050000,
            0x00040020, 0x00050020, 0x02040020, 0x02050020,
            0x00002000, 0x00012000, 0x02002000, 0x02012000,
            0x00002020, 0x00012020, 0x02002020, 0x02012020,
            0x00042000, 0x00052000, 0x02042000, 0x02052000,
            0x00042020, 0x00052020, 0x02042020, 0x02052020,
            0x00000000, 0x00010000, 0x02000000, 0x02010000,
            0x00000020, 0x00010020, 0x02000020, 0x02010020,
            0x00040000, 0x00050000, 0x02040000, 0x02050000,
            0x00040020, 0x00050020, 0x02040020, 0x02050020,
            0x00002000, 0x00012000, 0x02002000, 0x02012000,
            0x00002020, 0x00012020, 0x02002020, 0x02012020,
            0x00042000, 0x00052000, 0x02042000, 0x02052000,
            0x00042020, 0x00052020, 0x02042020, 0x02052020,
            0x00000010, 0x00010010, 0x02000010, 0x02010010,
            0x00000030, 0x00010030, 0x02000030, 0x02010030,
            0x00040010, 0x00050010, 0x02040010, 0x02050010,
            0x00040030, 0x00050030, 0x02040030, 0x02050030,
            0x00002010, 0x00012010, 0x02002010, 0x02012010,
            0x00002030, 0x00012030, 0x02002030, 0x02012030,
            0x00042010, 0x00052010, 0x02042010, 0x02052010,
            0x00042030, 0x00052030, 0x02042030, 0x02052030,
            0x00000010, 0x00010010, 0x02000010, 0x02010010,
            0x00000030, 0x00010030, 0x02000030, 0x02010030,
            0x00040010, 0x00050010, 0x02040010, 0x02050010,
            0x00040030, 0x00050030, 0x02040030, 0x02050030,
            0x00002010, 0x00012010, 0x02002010, 0x02012010,
            0x00002030, 0x00012030, 0x02002030, 0x02012030,
            0x00042010, 0x00052010, 0x02042010, 0x02052010,
            0x00042030, 0x00052030, 0x02042030, 0x02052030,
            0x20000000, 0x20010000, 0x22000000, 0x22010000,
            0x20000020, 0x20010020, 0x22000020, 0x22010020,
            0x20040000, 0x20050000, 0x22040000, 0x22050000,
            0x20040020, 0x20050020, 0x22040020, 0x22050020,
            0x20002000, 0x20012000, 0x22002000, 0x22012000,
            0x20002020, 0x20012020, 0x22002020, 0x22012020,
            0x20042000, 0x20052000, 0x22042000, 0x22052000,
            0x20042020, 0x20052020, 0x22042020, 0x22052020,
            0x20000000, 0x20010000, 0x22000000, 0x22010000,
            0x20000020, 0x20010020, 0x22000020, 0x22010020,
            0x20040000, 0x20050000, 0x22040000, 0x22050000,
            0x20040020, 0x20050020, 0x22040020, 0x22050020,
            0x20002000, 0x20012000, 0x22002000, 0x22012000,
            0x20002020, 0x20012020, 0x22002020, 0x22012020,
            0x20042000, 0x20052000, 0x22042000, 0x22052000,
            0x20042020, 0x20052020, 0x22042020, 0x22052020,
            0x20000010, 0x20010010, 0x22000010, 0x22010010,
            0x20000030, 0x20010030, 0x22000030, 0x22010030,
            0x20040010, 0x20050010, 0x22040010, 0x22050010,
            0x20040030, 0x20050030, 0x22040030, 0x22050030,
            0x20002010, 0x20012010, 0x22002010, 0x22012010,
            0x20002030, 0x20012030, 0x22002030, 0x22012030,
            0x20042010, 0x20052010, 0x22042010, 0x22052010,
            0x20042030, 0x20052030, 0x22042030, 0x22052030,
            0x20000010, 0x20010010, 0x22000010, 0x22010010,
            0x20000030, 0x20010030, 0x22000030, 0x22010030,
            0x20040010, 0x20050010, 0x22040010, 0x22050010,
            0x20040030, 0x20050030, 0x22040030, 0x22050030,
            0x20002010, 0x20012010, 0x22002010, 0x22012010,
            0x20002030, 0x20012030, 0x22002030, 0x22012030,
            0x20042010, 0x20052010, 0x22042010, 0x22052010,
            0x20042030, 0x20052030, 0x22042030, 0x22052030
        ];
        static $pc2mapd4 = [
            0x00000000, 0x00000400, 0x01000000, 0x01000400,
            0x00000000, 0x00000400, 0x01000000, 0x01000400,
            0x00000100, 0x00000500, 0x01000100, 0x01000500,
            0x00000100, 0x00000500, 0x01000100, 0x01000500,
            0x10000000, 0x10000400, 0x11000000, 0x11000400,
            0x10000000, 0x10000400, 0x11000000, 0x11000400,
            0x10000100, 0x10000500, 0x11000100, 0x11000500,
            0x10000100, 0x10000500, 0x11000100, 0x11000500,
            0x00080000, 0x00080400, 0x01080000, 0x01080400,
            0x00080000, 0x00080400, 0x01080000, 0x01080400,
            0x00080100, 0x00080500, 0x01080100, 0x01080500,
            0x00080100, 0x00080500, 0x01080100, 0x01080500,
            0x10080000, 0x10080400, 0x11080000, 0x11080400,
            0x10080000, 0x10080400, 0x11080000, 0x11080400,
            0x10080100, 0x10080500, 0x11080100, 0x11080500,
            0x10080100, 0x10080500, 0x11080100, 0x11080500,
            0x00000008, 0x00000408, 0x01000008, 0x01000408,
            0x00000008, 0x00000408, 0x01000008, 0x01000408,
            0x00000108, 0x00000508, 0x01000108, 0x01000508,
            0x00000108, 0x00000508, 0x01000108, 0x01000508,
            0x10000008, 0x10000408, 0x11000008, 0x11000408,
            0x10000008, 0x10000408, 0x11000008, 0x11000408,
            0x10000108, 0x10000508, 0x11000108, 0x11000508,
            0x10000108, 0x10000508, 0x11000108, 0x11000508,
            0x00080008, 0x00080408, 0x01080008, 0x01080408,
            0x00080008, 0x00080408, 0x01080008, 0x01080408,
            0x00080108, 0x00080508, 0x01080108, 0x01080508,
            0x00080108, 0x00080508, 0x01080108, 0x01080508,
            0x10080008, 0x10080408, 0x11080008, 0x11080408,
            0x10080008, 0x10080408, 0x11080008, 0x11080408,
            0x10080108, 0x10080508, 0x11080108, 0x11080508,
            0x10080108, 0x10080508, 0x11080108, 0x11080508,
            0x00001000, 0x00001400, 0x01001000, 0x01001400,
            0x00001000, 0x00001400, 0x01001000, 0x01001400,
            0x00001100, 0x00001500, 0x01001100, 0x01001500,
            0x00001100, 0x00001500, 0x01001100, 0x01001500,
            0x10001000, 0x10001400, 0x11001000, 0x11001400,
            0x10001000, 0x10001400, 0x11001000, 0x11001400,
            0x10001100, 0x10001500, 0x11001100, 0x11001500,
            0x10001100, 0x10001500, 0x11001100, 0x11001500,
            0x00081000, 0x00081400, 0x01081000, 0x01081400,
            0x00081000, 0x00081400, 0x01081000, 0x01081400,
            0x00081100, 0x00081500, 0x01081100, 0x01081500,
            0x00081100, 0x00081500, 0x01081100, 0x01081500,
            0x10081000, 0x10081400, 0x11081000, 0x11081400,
            0x10081000, 0x10081400, 0x11081000, 0x11081400,
            0x10081100, 0x10081500, 0x11081100, 0x11081500,
            0x10081100, 0x10081500, 0x11081100, 0x11081500,
            0x00001008, 0x00001408, 0x01001008, 0x01001408,
            0x00001008, 0x00001408, 0x01001008, 0x01001408,
            0x00001108, 0x00001508, 0x01001108, 0x01001508,
            0x00001108, 0x00001508, 0x01001108, 0x01001508,
            0x10001008, 0x10001408, 0x11001008, 0x11001408,
            0x10001008, 0x10001408, 0x11001008, 0x11001408,
            0x10001108, 0x10001508, 0x11001108, 0x11001508,
            0x10001108, 0x10001508, 0x11001108, 0x11001508,
            0x00081008, 0x00081408, 0x01081008, 0x01081408,
            0x00081008, 0x00081408, 0x01081008, 0x01081408,
            0x00081108, 0x00081508, 0x01081108, 0x01081508,
            0x00081108, 0x00081508, 0x01081108, 0x01081508,
            0x10081008, 0x10081408, 0x11081008, 0x11081408,
            0x10081008, 0x10081408, 0x11081008, 0x11081408,
            0x10081108, 0x10081508, 0x11081108, 0x11081508,
            0x10081108, 0x10081508, 0x11081108, 0x11081508
        ];

        $keys = [];
        for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
            // pad the key and remove extra characters as appropriate.
            $key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0");

            // Perform the PC/1 transformation and compute C and D.
            $t = unpack('Nl/Nr', $key);
            list($l, $r) = [$t['l'], $t['r']];
            $key = (self::$shuffle[$pc1map[ $r        & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") |
                   (self::$shuffle[$pc1map[($r >>  8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") |
                   (self::$shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") |
                   (self::$shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") |
                   (self::$shuffle[$pc1map[ $l        & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") |
                   (self::$shuffle[$pc1map[($l >>  8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") |
                   (self::$shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") |
                   (self::$shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00");
            $key = unpack('Nc/Nd', $key);
            $c = ( $key['c'] >> 4) & 0x0FFFFFFF;
            $d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F);

            $keys[$des_round] = [
                self::ENCRYPT => [],
                self::DECRYPT => array_fill(0, 32, 0)
            ];
            for ($i = 0, $ki = 31; $i < 16; ++$i, $ki -= 2) {
                $c <<= $shifts[$i];
                $c = ($c | ($c >> 28)) & 0x0FFFFFFF;
                $d <<= $shifts[$i];
                $d = ($d | ($d >> 28)) & 0x0FFFFFFF;

                // Perform the PC-2 transformation.
                $cp = $pc2mapc1[ $c >> 24        ] | $pc2mapc2[($c >> 16) & 0xFF] |
                      $pc2mapc3[($c >>  8) & 0xFF] | $pc2mapc4[ $c        & 0xFF];
                $dp = $pc2mapd1[ $d >> 24        ] | $pc2mapd2[($d >> 16) & 0xFF] |
                      $pc2mapd3[($d >>  8) & 0xFF] | $pc2mapd4[ $d        & 0xFF];

                // Reorder: odd bytes/even bytes. Push the result in key schedule.
                $val1 = ( $cp        & self::safe_intval(0xFF000000)) | (($cp <<  8) & 0x00FF0000) |
                        (($dp >> 16) & 0x0000FF00) | (($dp >>  8) & 0x000000FF);
                $val2 = (($cp <<  8) & self::safe_intval(0xFF000000)) | (($cp << 16) & 0x00FF0000) |
                        (($dp >>  8) & 0x0000FF00) | ( $dp        & 0x000000FF);
                $keys[$des_round][self::ENCRYPT][       ] = $val1;
                $keys[$des_round][self::DECRYPT][$ki - 1] = $val1;
                $keys[$des_round][self::ENCRYPT][       ] = $val2;
                $keys[$des_round][self::DECRYPT][$ki    ] = $val2;
            }
        }

        switch ($this->des_rounds) {
            case 3: // 3DES keys
                $this->keys = [
                    self::ENCRYPT => array_merge(
                        $keys[0][self::ENCRYPT],
                        $keys[1][self::DECRYPT],
                        $keys[2][self::ENCRYPT]
                    ),
                    self::DECRYPT => array_merge(
                        $keys[2][self::DECRYPT],
                        $keys[1][self::ENCRYPT],
                        $keys[0][self::DECRYPT]
                    )
                ];
                break;
            // case 1: // DES keys
            default:
                $this->keys = [
                    self::ENCRYPT => $keys[0][self::ENCRYPT],
                    self::DECRYPT => $keys[0][self::DECRYPT]
                ];
        }
    }

    /**
     * Setup the performance-optimized function for de/encrypt()
     *
     * @see Common\SymmetricKey::setupInlineCrypt()
     */
    protected function setupInlineCrypt()
    {
        // Engine configuration for:
        // -  DES ($des_rounds == 1) or
        // - 3DES ($des_rounds == 3)
        $des_rounds = $this->des_rounds;

        $init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
            if (!$sbox1) {
                $sbox1 = array_map(["' . self::class . '", "safe_intval"], self::$sbox1);
                $sbox2 = array_map(["' . self::class . '", "safe_intval"], self::$sbox2);
                $sbox3 = array_map(["' . self::class . '", "safe_intval"], self::$sbox3);
                $sbox4 = array_map(["' . self::class  .'", "safe_intval"], self::$sbox4);
                $sbox5 = array_map(["' . self::class . '", "safe_intval"], self::$sbox5);
                $sbox6 = array_map(["' . self::class . '", "safe_intval"], self::$sbox6);
                $sbox7 = array_map(["' . self::class . '", "safe_intval"], self::$sbox7);
                $sbox8 = array_map(["' . self::class . '", "safe_intval"], self::$sbox8);'
                /* Merge $shuffle with $[inv]ipmap */ . '
                for ($i = 0; $i < 256; ++$i) {
                    $shuffleip[]    =  self::$shuffle[self::$ipmap[$i]];
                    $shuffleinvip[] =  self::$shuffle[self::$invipmap[$i]];
                }
            }
        ';

        $k = [
            self::ENCRYPT => $this->keys[self::ENCRYPT],
            self::DECRYPT => $this->keys[self::DECRYPT]
        ];
        $init_encrypt = '';
        $init_decrypt = '';

        // Creating code for en- and decryption.
        $crypt_block = [];
        foreach ([self::ENCRYPT, self::DECRYPT] as $c) {
            /* Do the initial IP permutation. */
            $crypt_block[$c] = '
                $in = unpack("N*", $in);
                $l  = $in[1];
                $r  = $in[2];
                $in = unpack("N*",
                    ($shuffleip[ $r        & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
                    ($shuffleip[($r >>  8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
                    ($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
                    ($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
                    ($shuffleip[ $l        & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
                    ($shuffleip[($l >>  8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
                    ($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
                    ($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01")
                );
                ' . /* Extract L0 and R0 */ '
                $l = $in[1];
                $r = $in[2];
            ';

            $l = '$l';
            $r = '$r';

            // Perform DES or 3DES.
            for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) {
                // Perform the 16 steps.
                for ($i = 0; $i < 16; ++$i) {
                    // start of "the Feistel (F) function" - see the following URL:
                    // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
                    // Merge key schedule.
                    $crypt_block[$c] .= '
                        $b1 = ((' . $r . ' >>  3) & 0x1FFFFFFF)  ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . ';
                        $b2 = ((' . $r . ' >> 31) & 0x00000001)  ^ (' . $r . ' <<  1) ^ ' . $k[$c][++$ki] . ';' .
                        /* S-box indexing. */
                        $l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
                                 $sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
                                 $sbox5[($b1 >>  8) & 0x3F] ^ $sbox6[($b2 >>  8) & 0x3F] ^
                                 $sbox7[ $b1        & 0x3F] ^ $sbox8[ $b2        & 0x3F] ^ ' . $l . ';
                    ';
                    // end of "the Feistel (F) function"

                    // swap L & R
                    list($l, $r) = [$r, $l];
                }
                list($l, $r) = [$r, $l];
            }

            // Perform the inverse IP permutation.
            $crypt_block[$c] .= '$in =
                ($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
                ($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
                ($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
                ($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
                ($shuffleinvip[($l >>  8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
                ($shuffleinvip[($r >>  8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
                ($shuffleinvip[ $l        & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
                ($shuffleinvip[ $r        & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
            ';
        }

        // Creates the inline-crypt function
        $this->inline_crypt = $this->createInlineCryptFunction(
            [
               'init_crypt'    => $init_crypt,
               'init_encrypt'  => $init_encrypt,
               'init_decrypt'  => $init_decrypt,
               'encrypt_block' => $crypt_block[self::ENCRYPT],
               'decrypt_block' => $crypt_block[self::DECRYPT]
            ]
        );
    }
}
<?php

/**
 * ReadBytes trait
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2015 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\System\SSH\Common\Traits;

/**
 * ReadBytes trait
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
trait ReadBytes
{
    /**
     * Read data
     *
     * @param int $length
     * @throws \RuntimeException on connection errors
     */
    public function readBytes($length)
    {
        $temp = fread($this->fsock, $length);
        if (strlen($temp) != $length) {
            throw new \RuntimeException("Expected $length bytes; got " . strlen($temp));
        }
        return $temp;
    }
}
<?php

/**
 * Pure-PHP ssh-agent client.
 *
 * {@internal See http://api.libssh.org/rfc/PROTOCOL.agent}
 *
 * PHP version 5
 *
 * Here are some examples of how to use this library:
 * <code>
 * <?php
 *    include 'vendor/autoload.php';
 *
 *    $agent = new \phpseclib3\System\SSH\Agent();
 *
 *    $ssh = new \phpseclib3\Net\SSH2('www.domain.tld');
 *    if (!$ssh->login('username', $agent)) {
 *        exit('Login Failed');
 *    }
 *
 *    echo $ssh->exec('pwd');
 *    echo $ssh->exec('ls -la');
 * ?>
 * </code>
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2014 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\System\SSH;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\PublicKey;
use phpseclib3\Crypt\PublicKeyLoader;
use phpseclib3\Crypt\RSA;
use phpseclib3\Exception\BadConfigurationException;
use phpseclib3\Net\SSH2;
use phpseclib3\System\SSH\Agent\Identity;

/**
 * Pure-PHP ssh-agent client identity factory
 *
 * requestIdentities() method pumps out \phpseclib3\System\SSH\Agent\Identity objects
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 */
class Agent
{
    use Common\Traits\ReadBytes;

    // Message numbers

    // to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1)
    const SSH_AGENTC_REQUEST_IDENTITIES = 11;
    // this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2).
    const SSH_AGENT_IDENTITIES_ANSWER = 12;
    // the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3)
    const SSH_AGENTC_SIGN_REQUEST = 13;
    // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4)
    const SSH_AGENT_SIGN_RESPONSE = 14;

    // Agent forwarding status

    // no forwarding requested and not active
    const FORWARD_NONE = 0;
    // request agent forwarding when opportune
    const FORWARD_REQUEST = 1;
    // forwarding has been request and is active
    const FORWARD_ACTIVE = 2;

    /**
     * Unused
     */
    const SSH_AGENT_FAILURE = 5;

    /**
     * Socket Resource
     *
     * @var resource
     */
    private $fsock;

    /**
     * Agent forwarding status
     *
     * @var int
     */
    private $forward_status = self::FORWARD_NONE;

    /**
     * Buffer for accumulating forwarded authentication
     * agent data arriving on SSH data channel destined
     * for agent unix socket
     *
     * @var string
     */
    private $socket_buffer = '';

    /**
     * Tracking the number of bytes we are expecting
     * to arrive for the agent socket on the SSH data
     * channel
     *
     * @var int
     */
    private $expected_bytes = 0;

    /**
     * Default Constructor
     *
     * @return Agent
     * @throws BadConfigurationException if SSH_AUTH_SOCK cannot be found
     * @throws \RuntimeException on connection errors
     */
    public function __construct($address = null)
    {
        if (!$address) {
            switch (true) {
                case isset($_SERVER['SSH_AUTH_SOCK']):
                    $address = $_SERVER['SSH_AUTH_SOCK'];
                    break;
                case isset($_ENV['SSH_AUTH_SOCK']):
                    $address = $_ENV['SSH_AUTH_SOCK'];
                    break;
                default:
                    throw new BadConfigurationException('SSH_AUTH_SOCK not found');
            }
        }

        if (in_array('unix', stream_get_transports())) {
            $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
            if (!$this->fsock) {
                throw new \RuntimeException("Unable to connect to ssh-agent (Error $errno: $errstr)");
            }
        } else {
            if (substr($address, 0, 9) != '\\\\.\\pipe\\' || strpos(substr($address, 9), '\\') !== false) {
                throw new \RuntimeException('Address is not formatted as a named pipe should be');
            }

            $this->fsock = fopen($address, 'r+b');
            if (!$this->fsock) {
                throw new \RuntimeException('Unable to open address');
            }
        }
    }

    /**
     * Request Identities
     *
     * See "2.5.2 Requesting a list of protocol 2 keys"
     * Returns an array containing zero or more \phpseclib3\System\SSH\Agent\Identity objects
     *
     * @return array
     * @throws \RuntimeException on receipt of unexpected packets
     */
    public function requestIdentities()
    {
        if (!$this->fsock) {
            return [];
        }

        $packet = pack('NC', 1, self::SSH_AGENTC_REQUEST_IDENTITIES);
        if (strlen($packet) != fputs($this->fsock, $packet)) {
            throw new \RuntimeException('Connection closed while requesting identities');
        }

        $length = current(unpack('N', $this->readBytes(4)));
        $packet = $this->readBytes($length);

        list($type, $keyCount) = Strings::unpackSSH2('CN', $packet);
        if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) {
            throw new \RuntimeException('Unable to request identities');
        }

        $identities = [];
        for ($i = 0; $i < $keyCount; $i++) {
            list($key_blob, $comment) = Strings::unpackSSH2('ss', $packet);
            $temp = $key_blob;
            list($key_type) = Strings::unpackSSH2('s', $temp);
            switch ($key_type) {
                case 'ssh-rsa':
                case 'ssh-dss':
                case 'ssh-ed25519':
                case 'ecdsa-sha2-nistp256':
                case 'ecdsa-sha2-nistp384':
                case 'ecdsa-sha2-nistp521':
                    $key = PublicKeyLoader::load($key_type . ' ' . base64_encode($key_blob));
            }
            // resources are passed by reference by default
            if (isset($key)) {
                $identity = (new Identity($this->fsock))
                    ->withPublicKey($key)
                    ->withPublicKeyBlob($key_blob)
                    ->withComment($comment);
                $identities[] = $identity;
                unset($key);
            }
        }

        return $identities;
    }

    /**
     * Returns the SSH Agent identity matching a given public key or null if no identity is found
     *
     * @return ?Identity
     */
    public function findIdentityByPublicKey(PublicKey $key)
    {
        $identities = $this->requestIdentities();
        $key = (string) $key;
        foreach ($identities as $identity) {
            if (((string) $identity->getPublicKey()) == $key) {
                return $identity;
            }
        }

        return null;
    }

    /**
     * Signal that agent forwarding should
     * be requested when a channel is opened
     *
     * @return void
     */
    public function startSSHForwarding()
    {
        if ($this->forward_status == self::FORWARD_NONE) {
            $this->forward_status = self::FORWARD_REQUEST;
        }
    }

    /**
     * Request agent forwarding of remote server
     *
     * @param SSH2 $ssh
     * @return bool
     */
    private function request_forwarding(SSH2 $ssh)
    {
        if (!$ssh->requestAgentForwarding()) {
            return false;
        }

        $this->forward_status = self::FORWARD_ACTIVE;

        return true;
    }

    /**
     * On successful channel open
     *
     * This method is called upon successful channel
     * open to give the SSH Agent an opportunity
     * to take further action. i.e. request agent forwarding
     *
     * @param SSH2 $ssh
     */
    public function registerChannelOpen(SSH2 $ssh)
    {
        if ($this->forward_status == self::FORWARD_REQUEST) {
            $this->request_forwarding($ssh);
        }
    }

    /**
     * Forward data to SSH Agent and return data reply
     *
     * @param string $data
     * @return string Data from SSH Agent
     * @throws \RuntimeException on connection errors
     */
    public function forwardData($data)
    {
        if ($this->expected_bytes > 0) {
            $this->socket_buffer .= $data;
            $this->expected_bytes -= strlen($data);
        } else {
            $agent_data_bytes = current(unpack('N', $data));
            $current_data_bytes = strlen($data);
            $this->socket_buffer = $data;
            if ($current_data_bytes != $agent_data_bytes + 4) {
                $this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes;
                return false;
            }
        }

        if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
            throw new \RuntimeException('Connection closed attempting to forward data to SSH agent');
        }

        $this->socket_buffer = '';
        $this->expected_bytes = 0;

        $agent_reply_bytes = current(unpack('N', $this->readBytes(4)));

        $agent_reply_data = $this->readBytes($agent_reply_bytes);
        $agent_reply_data = current(unpack('a*', $agent_reply_data));

        return pack('Na*', $agent_reply_bytes, $agent_reply_data);
    }
}
<?php

/**
 * Pure-PHP ssh-agent client.
 *
 * {@internal See http://api.libssh.org/rfc/PROTOCOL.agent}
 *
 * PHP version 5
 *
 * @author    Jim Wigginton <terrafrost@php.net>
 * @copyright 2009 Jim Wigginton
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @link      http://phpseclib.sourceforge.net
 */

namespace phpseclib3\System\SSH\Agent;

use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\PrivateKey;
use phpseclib3\Crypt\Common\PublicKey;
use phpseclib3\Crypt\DSA;
use phpseclib3\Crypt\EC;
use phpseclib3\Crypt\RSA;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\System\SSH\Agent;
use phpseclib3\System\SSH\Common\Traits\ReadBytes;

/**
 * Pure-PHP ssh-agent client identity object
 *
 * Instantiation should only be performed by \phpseclib3\System\SSH\Agent class.
 * This could be thought of as implementing an interface that phpseclib3\Crypt\RSA
 * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
 * The methods in this interface would be getPublicKey and sign since those are the
 * methods phpseclib looks for to perform public key authentication.
 *
 * @author  Jim Wigginton <terrafrost@php.net>
 * @internal
 */
class Identity implements PrivateKey
{
    use ReadBytes;

    // Signature Flags
    // See https://tools.ietf.org/html/draft-miller-ssh-agent-00#section-5.3
    const SSH_AGENT_RSA2_256 = 2;
    const SSH_AGENT_RSA2_512 = 4;

    /**
     * Key Object
     *
     * @var PublicKey
     * @see self::getPublicKey()
     */
    private $key;

    /**
     * Key Blob
     *
     * @var string
     * @see self::sign()
     */
    private $key_blob;

    /**
     * Socket Resource
     *
     * @var resource
     * @see self::sign()
     */
    private $fsock;

    /**
     * Signature flags
     *
     * @var int
     * @see self::sign()
     * @see self::setHash()
     */
    private $flags = 0;

    /**
     * Comment
     *
     * @var null|string
     */
    private $comment;

    /**
     * Curve Aliases
     *
     * @var array
     */
    private static $curveAliases = [
        'secp256r1' => 'nistp256',
        'secp384r1' => 'nistp384',
        'secp521r1' => 'nistp521',
        'Ed25519' => 'Ed25519'
    ];

    /**
     * Default Constructor.
     *
     * @param resource $fsock
     */
    public function __construct($fsock)
    {
        $this->fsock = $fsock;
    }

    /**
     * Set Public Key
     *
     * Called by \phpseclib3\System\SSH\Agent::requestIdentities()
     *
     * @param PublicKey $key
     */
    public function withPublicKey(PublicKey $key)
    {
        if ($key instanceof EC) {
            if (is_array($key->getCurve()) || !isset(self::$curveAliases[$key->getCurve()])) {
                throw new UnsupportedAlgorithmException('The only supported curves are nistp256, nistp384, nistp512 and Ed25519');
            }
        }

        $new = clone $this;
        $new->key = $key;
        return $new;
    }

    /**
     * Set Public Key
     *
     * Called by \phpseclib3\System\SSH\Agent::requestIdentities(). The key blob could be extracted from $this->key
     * but this saves a small amount of computation.
     *
     * @param string $key_blob
     */
    public function withPublicKeyBlob($key_blob)
    {
        $new = clone $this;
        $new->key_blob = $key_blob;
        return $new;
    }

    /**
     * Get Public Key
     *
     * Wrapper for $this->key->getPublicKey()
     *
     * @return mixed
     */
    public function getPublicKey()
    {
        return $this->key;
    }

    /**
     * Sets the hash
     *
     * @param string $hash
     */
    public function withHash($hash)
    {
        $new = clone $this;

        $hash = strtolower($hash);

        if ($this->key instanceof RSA) {
            $new->flags = 0;
            switch ($hash) {
                case 'sha1':
                    break;
                case 'sha256':
                    $new->flags = self::SSH_AGENT_RSA2_256;
                    break;
                case 'sha512':
                    $new->flags = self::SSH_AGENT_RSA2_512;
                    break;
                default:
                    throw new UnsupportedAlgorithmException('The only supported hashes for RSA are sha1, sha256 and sha512');
            }
        }
        if ($this->key instanceof EC) {
            switch ($this->key->getCurve()) {
                case 'secp256r1':
                    $expectedHash = 'sha256';
                    break;
                case 'secp384r1':
                    $expectedHash = 'sha384';
                    break;
                //case 'secp521r1':
                //case 'Ed25519':
                default:
                    $expectedHash = 'sha512';
            }
            if ($hash != $expectedHash) {
                throw new UnsupportedAlgorithmException('The only supported hash for ' . self::$curveAliases[$this->key->getCurve()] . ' is ' . $expectedHash);
            }
        }
        if ($this->key instanceof DSA) {
            if ($hash != 'sha1') {
                throw new UnsupportedAlgorithmException('The only supported hash for DSA is sha1');
            }
        }
        return $new;
    }

    /**
     * Sets the padding
     *
     * Only PKCS1 padding is supported
     *
     * @param string $padding
     */
    public function withPadding($padding)
    {
        if (!$this->key instanceof RSA) {
            throw new UnsupportedAlgorithmException('Only RSA keys support padding');
        }
        if ($padding != RSA::SIGNATURE_PKCS1 && $padding != RSA::SIGNATURE_RELAXED_PKCS1) {
            throw new UnsupportedAlgorithmException('ssh-agent can only create PKCS1 signatures');
        }
        return $this;
    }

    /**
     * Determines the signature padding mode
     *
     * Valid values are: ASN1, SSH2, Raw
     *
     * @param string $format
     */
    public function withSignatureFormat($format)
    {
        if ($this->key instanceof RSA) {
            throw new UnsupportedAlgorithmException('Only DSA and EC keys support signature format setting');
        }
        if ($format != 'SSH2') {
            throw new UnsupportedAlgorithmException('Only SSH2-formatted signatures are currently supported');
        }

        return $this;
    }

    /**
     * Returns the curve
     *
     * Returns a string if it's a named curve, an array if not
     *
     * @return string|array
     */
    public function getCurve()
    {
        if (!$this->key instanceof EC) {
            throw new UnsupportedAlgorithmException('Only EC keys have curves');
        }

        return $this->key->getCurve();
    }

    /**
     * Create a signature
     *
     * See "2.6.2 Protocol 2 private key signature request"
     *
     * @param string $message
     * @return string
     * @throws \RuntimeException on connection errors
     * @throws UnsupportedAlgorithmException if the algorithm is unsupported
     */
    public function sign($message)
    {
        // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
        $packet = Strings::packSSH2(
            'CssN',
            Agent::SSH_AGENTC_SIGN_REQUEST,
            $this->key_blob,
            $message,
            $this->flags
        );
        $packet = Strings::packSSH2('s', $packet);
        if (strlen($packet) != fputs($this->fsock, $packet)) {
            throw new \RuntimeException('Connection closed during signing');
        }

        $length = current(unpack('N', $this->readBytes(4)));
        $packet = $this->readBytes($length);

        list($type, $signature_blob) = Strings::unpackSSH2('Cs', $packet);
        if ($type != Agent::SSH_AGENT_SIGN_RESPONSE) {
            throw new \RuntimeException('Unable to retrieve signature');
        }

        if (!$this->key instanceof RSA) {
            return $signature_blob;
        }

        list($type, $signature_blob) = Strings::unpackSSH2('ss', $signature_blob);

        return $signature_blob;
    }

    /**
     * Returns the private key
     *
     * @param string $type
     * @param array $options optional
     * @return string
     */
    public function toString($type, array $options = [])
    {
        throw new \RuntimeException('ssh-agent does not provide a mechanism to get the private key');
    }

    /**
     * Sets the password
     *
     * @param string|bool $password
     * @return never
     */
    public function withPassword($password = false)
    {
        throw new \RuntimeException('ssh-agent does not provide a mechanism to get the private key');
    }

    /**
     * Sets the comment
     */
    public function withComment($comment = null)
    {
        $new = clone $this;
        $new->comment = $comment;
        return $new;
    }

    /**
     * Returns the comment
     *
     * @return null|string
     */
    public function getComment()
    {
        return $this->comment;
    }
}
# Security Policy

## Supported Versions

| Version | Supported          |
| ------- | ------------------ |
| 1.0.x   | :white_check_mark: |
| 2.0.x   | :white_check_mark: |
| 3.0.x   | :white_check_mark: |

## Reporting a Vulnerability

To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.phpseclib Lead Developer:  TerraFrost (Jim Wigginton)

phpseclib Developers:      monnerat (Patrick Monnerat)
                           bantu (Andreas Fischer)
                           petrich (Hans-Jürgen Petrich)
                           GrahamCampbell (Graham Campbell)
                           hc-jworman# Backers

phpseclib ongoing development is made possible by [Tidelift](https://tidelift.com/subscription/pkg/packagist-phpseclib-phpseclib?utm_source=packagist-phpseclib-phpseclib&utm_medium=referral&utm_campaign=readme) and by contributions by users like you. Thank you.

## Backers

- Allan Simon
- [ChargeOver](https://chargeover.com/)
- Raghu Veer Dendukuri
- Zane Hooper
- [Setasign](https://www.setasign.com/)
- [Charles Severance](https://github.com/csev)
- [Rachel Fish](https://github.com/itsrachelfish)
- Tharyrok
- [cjhaas](https://github.com/cjhaas)
- [istiak-tridip](https://github.com/istiak-tridip)
- [Anna Filina](https://github.com/afilina)
- [blakemckeeby](https://github.com/blakemckeeby)
- [ssddanbrown](https://github.com/ssddanbrown)
- Stefan Beck{
    "name": "phpseclib/phpseclib",
    "type": "library",
    "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
    "keywords": [
        "security",
        "crypto",
        "cryptography",
        "encryption",
        "signature",
        "signing",
        "rsa",
        "aes",
        "blowfish",
        "twofish",
        "ssh",
        "sftp",
        "x509",
        "x.509",
        "asn1",
        "asn.1",
        "BigInteger"
        ],
    "homepage": "http://phpseclib.sourceforge.net",
    "license": "MIT",
    "authors": [
        {
            "name": "Jim Wigginton",
            "email": "terrafrost@php.net",
            "role": "Lead Developer"
        },
        {
            "name": "Patrick Monnerat",
            "email": "pm@datasphere.ch",
            "role": "Developer"
        },
        {
            "name": "Andreas Fischer",
            "email": "bantu@phpbb.com",
            "role": "Developer"
        },
        {
            "name": "Hans-Jürgen Petrich",
            "email": "petrich@tronic-media.com",
            "role": "Developer"
        },
        {
            "name": "Graham Campbell",
            "email": "graham@alt-three.com",
            "role": "Developer"
        }
    ],
    "require": {
        "php": ">=5.6.1",
        "paragonie/constant_time_encoding": "^1|^2|^3",
        "paragonie/random_compat": "^1.4|^2.0|^9.99.99"
    },
    "require-dev": {
        "phpunit/phpunit": "*"
    },
    "suggest": {
        "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
        "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.",
        "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
        "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
        "ext-dom": "Install the DOM extension to load XML formatted public keys."
    },
    "autoload": {
        "files": [
            "phpseclib/bootstrap.php"
        ],
        "psr-4": {
            "phpseclib3\\": "phpseclib/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "phpseclib3\\Tests\\": "tests/"
        }
    },
    "config": {
        "sort-packages": true
    }
}
<p align = 'center'>
  <img src = 'https://skillicons.dev/icons?i=php' alt = 'Asyncio'>
</p>

<h1 align = 'center'>
  Asyncio
</h1>

<p align = 'center'>
  <strong>Modern Async Foundations for PHP</strong>
</p>

<p align = 'center'>
  High-performance asynchronous framework for PHP with support for
  <strong>Revolt</strong> and <strong>Swoole</strong>
</p>

<p align = 'center'>
  <img src = 'https://img.shields.io/github/license/TakNone/asyncio?style=for-the-badge'>
  <img src = 'https://img.shields.io/packagist/php-v/taknone/asyncio?style=for-the-badge&logo=php'>
  <img src = 'https://img.shields.io/packagist/v/taknone/asyncio?style=for-the-badge&logo=composer'>
  <img src = 'https://img.shields.io/github/stars/TakNone/asyncio?style=for-the-badge'>
</p>

* * *

## ✨ Features

- High-performance asynchronous execution for modern PHP projects
- Event-loop driven architecture
- Compatible with **Revolt** and **Swoole**
- Fiber-friendly async design
- Non-blocking file, socket, and stream utilities
- Lightweight helpers for building async-first applications
- MIT licensed and easy to integrate into existing codebases

* * *

## 🛠️ Requirements

- PHP **8.4** or higher
- `revolt/event-loop : ^1.0`
- Optional : `ext-swoole` for high-performance coroutine support
- Optional : `ext-pcntl` for better signal handling

* * *

## 📦 Installation

Install via Composer :

```bash
composer require taknone/asyncio
```

### Optional Extensions

```bash
pecl install swoole
```

| Extension | Purpose |
|------------|------------|
| Swoole | High-performance coroutine runtime |
| PCNTL | Better signal handling |

* * *

## 🏁 Getting Started

The library is designed to be used with async-friendly code, event loops, Fibers, and non-blocking I/O

```php
<?php

require 'vendor/autoload.php';

use function Tak\Asyncio\async;
use function Tak\Asyncio\delay;

use Tak\Asyncio\TimeoutCancellation;

$future = async(function () : void {
    echo 'Background task initialized' , PHP_EOL;
    delay(1.5);
    echo 'Background task completed' , PHP_EOL;
});

echo 'Main execution continues without blocking.' , PHP_EOL;

$future->await(new TimeoutCancellation(2));

echo 'Future resolved successfully' , PHP_EOL;
```

* * *

## 💈 Project Structure

This package is autoloaded through PSR-4 with the `Tak\\Asyncio\\` namespace and includes helper files for :

- `src/functions.php`
- `src/File/functions.php`
- `src/Socket/functions.php`
- `src/ByteStream/functions.php`

That layout is ideal for helper-based async APIs that cover core runtime, file, socket, and stream operations

* * *

## ⁉️ Why Asyncio

Asyncio is built for developers who want a clean async layer without sacrificing PHP performance or portability. It is a good fit for :

- async services
- background workers
- socket servers
- file streaming
- high-concurrency I/O
- coroutine-based applications

* * *

## ⚡ Usage Notes

- Use **Revolt** when you want a standards-friendly event loop
- Use **Swoole** when you want coroutine-based high-performance execution
- Keep I/O non-blocking to get the best results
- Prefer async helpers instead of direct blocking calls inside loop-driven code

* * *

## Contributing

Contributions are welcome. Please keep changes consistent with the existing architecture, naming style, and async-first design

* * *


## 📜 License

This project is licensed under the [MIT License](LICENSE)<?php

declare(strict_types = 1);

namespace Tak\Asyncio\Drivers;

use Tak\Asyncio\Driver;

use Tak\Asyncio\Suspension;

use Swoole\Coroutine;

use Swoole\Timer;

use Swoole\Process;

use Swoole\Event;

use Swoole\Runtime;

final class SwooleDriver implements Driver {
	private static array $registry = array();
	private static array $events = array();

	public function __construct(){
		Event::cycle(self::sweep(...));
		Coroutine::set([
			'log_level'=>SWOOLE_LOG_TRACE,
			'hook_flags'=>SWOOLE_HOOK_ALL,
			'exit_condition'=>static function(){
				$cids = Coroutine::list();
				foreach($cids as $cid){
					if(Coroutine::exists($cid)){
						Coroutine::cancel($cid);
					}
				}
				$timerIds = Timer::list();
				foreach($timerIds as $timerId){
					Timer::clear($timerId);
				}
				return boolval(Coroutine::stats()['coroutine_num'] === 0);
			},
			'enable_deadlock_check'=>false
		]);
		Runtime::enableCoroutine();
	}
	public static function sleep(float $seconds) : void {
		Coroutine::sleep(max($seconds,0.001));
	}
	public static function delay(float $seconds,callable $callback) : string {
		$id = Timer::after(intval($seconds * 1000),function() use($callback,&$id) : void {
			try {
				call_user_func($callback,strval($id));
			} finally {
				unset(self::$registry[$id]);
			}
		});
		self::$registry[$id] = true;
		return strval($id);
	}
	public static function repeat(float $seconds,callable $callback) : string {
		$id = Timer::tick(intval($seconds * 1000),fn(int $timer_id) => call_user_func($callback,strval($timer_id)));
		self::$registry[$id] = true;
		return strval($id);
	}
	public static function queue(callable $callback,mixed ...$args) : void {
		$id = Coroutine::create(function() use($callback,$args) : void {
			$cid = Coroutine::getcid();
			try {
				call_user_func_array($callback,$args);
			} finally {
				unset(self::$registry[$cid]);
			}
		});
		self::$registry[$id] = true;
	}
	public static function defer(callable $callback) : string {
		$id = uniqid('defer_');
		Event::defer(function() use($id,$callback) : void {
			if(array_key_exists($id,self::$registry)){
				call_user_func($callback);
			}
			unset(self::$registry[$id]);
		});
		self::$registry[$id] = true;
		return $id;
	}
	public static function onReadable(mixed $resource,callable $callback) : string {
		/*
		if(is_resource($resource)){
			$stat = fstat($resource);
			if(0100000 === ($stat['mode'] & 0100000)){
				$id = uniqid('defer_');
				$tick = function() use($callback,$id,$resource,&$tick) : void {
					if(is_resource($resource) and array_key_exists($id,self::$registry)){
						$callback($id,$resource);
						Event::defer($tick);
					} else {
						unset(self::$registry[$id]);
					}
				};
				Event::defer($tick);
				self::$registry[$id] = true;
				return $id;
			}
		}
		*/
		$id = uniqid('event_');
		Event::add($resource,static fn(mixed $stream) : mixed => $callback($id,$stream),null,SWOOLE_EVENT_READ);
		self::$registry[$id] = true;
		self::$events[$id] = $resource;
		return $id;
	}
	public static function onWritable(mixed $resource,callable $callback) : string {
		/*
		if(is_resource($resource)){
			$stat = fstat($resource);
			if(0100000 === ($stat['mode'] & 0100000)){
				$id = uniqid('defer_');
				$tick = function() use($callback,$id,$resource,&$tick) : void {
					if(is_resource($resource) and array_key_exists($id,self::$registry)){
						$callback($id,$resource);
						Event::defer($tick);
					} else {
						unset(self::$registry[$id]);
					}
				};
				Event::defer($tick);
				self::$registry[$id] = true;
				return $id;
			}
		}
		*/
		$id = uniqid('event_');
		Event::add($resource,null,static fn(mixed $stream) : mixed => $callback($id,$stream),SWOOLE_EVENT_WRITE);
		self::$registry[$id] = true;
		self::$events[$id] = $resource;
		return $id;
	}
	public static function onSignal(int $signal,callable $callback) : string {
		Process::signal($signal,$callback);
		return uniqid('signal_');
	}
	public static function cancel(string $id) : void {
		if(is_string($id) and str_starts_with($id,'defer_')){
			unset(self::$registry[$id]);
		} else if(is_string($id) and str_starts_with($id,'event_')){
			if(array_key_exists($id,self::$events)){
				unset(self::$registry[$id]);
				Event::del(self::$events[$id]);
				unset(self::$events[$id]);
			}
		} else if(ctype_digit($id) and Timer::exists(intval($id))){
			Timer::clear(intval($id));
		} else if(ctype_digit($id) and Coroutine::exists(intval($id))){
			Coroutine::cancel(intval($id));
		}
	}
	public static function reference(string $id) : string {
		if(array_key_exists($id,self::$registry)){
			self::$registry[$id] = true;
		}
		return $id;
	}
	public static function unreference(string $id) : string {
		if(array_key_exists($id,self::$registry)){
			self::$registry[$id] = false;
		}
		return $id;
	}
	public static function isReferenced(string $id) : bool {
		if(array_key_exists($id,self::$registry)){
			return boolval(self::$registry[$id]);
		} else {
			throw new \Error('Invalid callback identifier '.$id);
		}
	}
	public static function getSuspension() : Suspension {
		$cid = Coroutine::getCid();
		return new class($cid) implements Suspension {
			protected bool $throwBack;
			private mixed $value;

			public function __construct(private int $cid){
			}
			public function suspend() : mixed {
				unset($this->throwBack);
				Coroutine::suspend();
				if(isset($this->throwBack) === false){
					throw new \RuntimeException('Coroutine resumed without a value or exception');
				} else if($this->throwBack){
					throw $this->value;
				} else {
					return $this->value;
				}
			}
			public function resume(mixed $value = null) : void {
				if(isset($this->throwBack) === false){
					$this->value = $value;
					$this->throwBack = false;
					Coroutine::resume($this->cid);
				}
			}
			public function throw(\Throwable $throwable) : void {
				if(isset($this->throwBack) === false){
					$this->value = $throwable;
					$this->throwBack = true;
					Coroutine::resume($this->cid);
				}
			}
		};
	}
	public static function setErrorHandler(callable $callback) : void {
		@set_exception_handler($callback);
	}
	public static function run() : void {
		self::sweep();
		Event::wait();
	}
	public static function sweep() : void {
		if(in_array(true,self::$registry,true) === false){
			array_map(self::cancel(...),array_keys(self::$registry));
			Event::exit();
		}
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\Drivers;

use Tak\Asyncio\Driver;

use Tak\Asyncio\Suspension;

use Revolt\EventLoop;

final class RevoltDriver implements Driver {
	private static bool $running = false;
	private static array $waiters = array();

	public static function sleep(float $seconds) : void {
		$suspension = EventLoop::getSuspension();
		EventLoop::delay($seconds,static fn() : null => $suspension->resume());
		$suspension->suspend();
	}
	public static function delay(float $seconds,callable $callback) : string {
		return EventLoop::delay($seconds,$callback(...));
	}
	public static function repeat(float $seconds,callable $callback) : string {
		return EventLoop::repeat($seconds,$callback(...));
	}
	public static function queue(callable $callback,mixed ...$args) : void {
		EventLoop::queue($callback(...),...$args);
	}
	public static function defer(callable $callback) : string {
		return EventLoop::defer(fn(string $callbackId) => call_user_func($callback));
	}
	public static function onReadable(mixed $resource,callable $callback) : string {
		return EventLoop::onReadable($resource,static fn(string $id,mixed $stream) : mixed => $callback($id,$stream));
	}
	public static function onWritable(mixed $resource,callable $callback) : string {
		return EventLoop::onWritable($resource,static fn(string $id,mixed $stream) : mixed => $callback($id,$stream));
	}
	public static function onSignal(int $signal,callable $callback) : string {
		return EventLoop::onSignal($signal,$callback(...));
	}
	public static function cancel(string $id) : void {
		EventLoop::cancel($id);
	}
	public static function reference(string $id) : string {
		return EventLoop::reference($id);
	}
	public static function unreference(string $id) : string {
		return EventLoop::unreference($id);
	}
	public static function isReferenced(string $id) : bool {
		return EventLoop::isReferenced($id);
	}
	public static function getSuspension() : Suspension {
		$suspension = EventLoop::getSuspension();
		return new class($suspension) implements Suspension {
			protected bool $resolved = false;

			public function __construct(private object $s){
			}
			public function suspend() : mixed {
				$this->resolved = false;
				return $this->s->suspend();
			}
			public function resume(mixed $value = null) : void {
				if($this->resolved === false){
					$this->resolved = true;
					$this->s->resume($value);
				}
			}
			public function throw(\Throwable $throwable) : void {
				if($this->resolved === false){
					$this->resolved = true;
					$this->s->throw($throwable);
				}
			}
		};
	}
	public static function setErrorHandler(callable $callback) : void {
		EventLoop::setErrorHandler($callback(...));
	}
	public static function run() : void {
		if(self::$running){
			$blocked = self::getSuspension();
			self::$waiters[]= $blocked;
			$blocked->suspend();
		} else {
			try {
				self::$running = true;
				EventLoop::run();
			} finally {
				self::$running = false;
				array_map(static fn(Suspension $blocked) : null => $blocked->resume(),self::$waiters);
			}
		}
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio;

interface Resource {
	public function read(? int $length = null,? Cancellation $cancellation = null) : ? string;
	public function write(string $content,? Cancellation $cancellation = null) : ? int;
	public function tell() : int | false;
	public function seek(int $offset,int $whence = SEEK_SET) : int;
	public function lock(int $operation = LOCK_SH | LOCK_EX) : bool;
	public function truncate(int $size) : bool;
	public function flush() : bool;
	public function close() : bool;
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio;

interface FileDriver {
	public function open(string $path,string $mode) : object;

	public function read(string $path) : string;

	public function write(string $path,string $content) : int;

	public function exists(string $path) : bool;

	public function delete(string $path) : bool;

	public function mkdir(string $path,int $permissions = 0777,bool $recursive = true) : bool;

	public function rmdir(string $path) : bool;

	public function move(string $from,string $to) : bool;

	public function size(string $path) : int;

	public function touch(string $path,? int $mtime = null,? int $atime = null) : bool;
	
	public function isFile(string $path) : bool;

	public function isDirectory(string $path) : bool;

	public function listFiles(string $path,int $sorting_order = SCANDIR_SORT_ASCENDING) : array;
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio;

final class DeferredCancellation extends Cancellable implements Cancellation {
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\Socket;

use Tak\Asyncio\Loop;

use Tak\Asyncio\TimeoutCancellation;

use Swoole\Coroutine\Socket;

class StreamSocket {
	protected object $socket;
	private mixed $resource = null;
	private array $pending = [];

	public function __construct(int $domain = AF_INET,int $type = SOCK_STREAM,int $protocol = SOL_TCP){
		switch(Loop::name()){
			case 'Swoole':
				$this->socket = new Socket($domain,$type,$protocol);
				break;
			case 'Revolt':
				$this->socket = @socket_create($domain,$type,$protocol);
				@socket_set_nonblock($this->socket);
				break;
		}
	}
	public function bind(string $address,int $port) : bool {
		$this->check($address,$port);
		return match(Loop::name()){
			'Swoole' => $this->socket->bind($address,$port),
			'Revolt' => @socket_bind($this->socket,$address,$port)
		};
	}
	public function listen(int $backlog) : bool {
		return match(Loop::name()){
			'Swoole' => $this->socket->listen($backlog),
			'Revolt' => @socket_listen($this->socket,$backlog)
		};
	}
	public function accept(float $timeout = -1) : object | false {
		$client = match(Loop::name()){
			'Swoole' => $this->socket->accept($timeout),
			'Revolt' => @socket_accept($this->socket)
		};
		return is_object($client) ? new class($client) extends StreamSocket {
			public function __construct(protected object $socket){
			}
		} : false;
	}
	public function connect(string $host,int $port,float $timeout = -1) : bool {
		$this->check($host,$port);
		switch(Loop::name()){
			case 'Swoole':
				return $this->socket->connect($host,$port,$timeout);
			case 'Revolt':
				if(@socket_connect($this->socket,$host,$port)){
					return true;
				} else {
					if(in_array(socket_last_error($this->socket),array(SOCKET_EINPROGRESS,SOCKET_EALREADY))){
						$cancellation = $timeout > 0 ? new TimeoutCancellation($timeout) : null;
						$cancellation?->throwIfCancelled();
						$suspension = Loop::getSuspension();
						$id = Loop::onWritable($this->getResource(),function(string $id) use($suspension) : void {
							Loop::cancel($id);
							$suspension->resume($this->getOption(SO_ERROR) === 0);
						});
						$cancel = $cancellation?->subscribe($this->pending[$id] = static function(? \Throwable $exception) use($suspension,$id) : void {
							Loop::cancel($id);
							$suspension->throw(is_null($exception) ? new \LogicException('Connection timed out') : $exception);
						});
						try {
							return $suspension->suspend();
						} finally {
							unset($this->pending[$id]);
							$cancellation?->unsubscribe($cancel);
						}
					} else {
						return false;
					}
				}
		}
	}
	public function write(string $data,float $timeout = -1,int $flags = 0) : int | false {
		if($this->isClosed() === false){
			switch(Loop::name()){
				case 'Swoole':
					return $this->socket->sendAll($data,$timeout);
				case 'Revolt':
					$bytesWritten = 0;
					$totalBytes = strlen($data);
					while($bytesWritten < $totalBytes){
						$chunk = substr($data,$bytesWritten);
						$result = @socket_send($this->socket,$chunk,strlen($chunk),$flags);
						if($result === false){
							if(in_array(socket_last_error($this->socket),array(SOCKET_EAGAIN,SOCKET_EWOULDBLOCK))){
								$cancellation = $timeout > 0 ? new TimeoutCancellation($timeout) : null;
								$cancellation?->throwIfCancelled();
								$suspension = Loop::getSuspension();
								$id = Loop::onWritable($this->getResource(),function(string $id) use($suspension) : void {
									Loop::cancel($id);
									$suspension->resume(true);
								});
								$cancel = $cancellation?->subscribe($this->pending[$id] = static function(? \Throwable $exception) use($suspension,$id) : void {
									Loop::cancel($id);
									$suspension->throw(is_null($exception) ? new \LogicException('Writing to socket timed out') : $exception);
								});
								try {
									if($suspension->suspend() === false){
										return $bytesWritten > 0 ? $bytesWritten : false;
									}
								} finally {
									unset($this->pending[$id]);
									$cancellation?->unsubscribe($cancel);
								}
								continue;
							}
							return $bytesWritten > 0 ? $bytesWritten : false;
						} else if($result === 0){
							return $bytesWritten > 0 ? $bytesWritten : false;
						} else {
							$bytesWritten += $result;
						}
					}
					return $bytesWritten;
			}
		} else {
			return false;
		}
	}
	public function read(? int $length = null,float $timeout = -1,int $flags = 0) : string | false {
		if($this->isClosed() === false){
			switch(Loop::name()){
				case 'Swoole':
					return is_null($length) ? $this->socket->recv(1 << 16,$timeout) : $this->socket->recvAll($length,$timeout);
				case 'Revolt':
					$buffer = strval(null);
					$result = @socket_recv($this->socket,$buffer,is_null($length) ? (1 << 16) : $length,is_null($length) ? 0 : $flags);
					if($result === false and in_array(socket_last_error($this->socket),array(SOCKET_EAGAIN,SOCKET_EWOULDBLOCK))){
						$cancellation = $timeout > 0 ? new TimeoutCancellation($timeout) : null;
						$cancellation?->throwIfCancelled();
						$suspension = Loop::getSuspension();
						$id = Loop::onReadable($this->getResource(),function(string $id) use($suspension,&$buffer,$length,$flags) : void {
							Loop::cancel($id);
							$result = @socket_recv($this->socket,$buffer,is_null($length) ? (1 << 16) : $length,is_null($length) ? 0 : $flags);
							$suspension->resume($result);
						});
						$cancel = $cancellation?->subscribe($this->pending[$id] = static function(? \Throwable $exception) use($suspension,$id) : void {
							Loop::cancel($id);
							$suspension->throw(is_null($exception) ? new \LogicException('Reading from socket timed out') : $exception);
						});
						try {
							$result = $suspension->suspend();
						} finally {
							unset($this->pending[$id]);
							$cancellation?->unsubscribe($cancel);
						}
					}
					return $result ? $buffer : false;
			}
		} else {
			return false;
		}
	}
	public function isClosed() : bool {
		switch(Loop::name()){
			case 'Swoole':
				return $this->socket->isClosed();
			case 'Revolt':
				try {
					return boolval($this->getOption(SO_ERROR) !== 0 || $this->getPeerName() === false);
				} catch(\Error){
					return true;
				}
		}
	}
	public function close() : bool {
		switch(Loop::name()){
			case 'Swoole':
				return $this->socket->close();
			case 'Revolt':
				try {
					array_map(call_user_func(...),$this->pending);
					@socket_close($this->socket);
					if(is_resource($this->resource)){
						@fclose($this->resource);
					}
					$this->resource = null;
					$this->pending = [];
					return true;
				} catch(\Error){
					return false;
				}
		}
	}
	public function getPeerName() : array | false {
		switch(Loop::name()){
			case 'Swoole':
				return $this->socket->getpeername();
			case 'Revolt':
				if(@socket_getpeername($this->socket,$address,$port)){
					return compact('address','port');
				} else {
					return false;
				}
		}
	}
	public function getSockName() : array | false {
		switch(Loop::name()){
			case 'Swoole':
				return $this->socket->getsockname();
			case 'Revolt':
				if(@socket_getsockname($this->socket,$address,$port)){
					return compact('address','port');
				} else {
					return false;
				}
		}
	}
	public function setOption(int $option,mixed $value,int $level = SOL_SOCKET) : bool {
		return match(Loop::name()){
			'Swoole' => $this->socket->setOption($level,$option,$value),
			'Revolt' => @socket_set_option($this->socket,$level,$option,$value)
		};
	}
	public function getOption(int $option,int $level = SOL_SOCKET) : mixed {
		return match(Loop::name()){
			'Swoole' => $this->socket->getOption($level,$option),
			'Revolt' => @socket_get_option($this->socket,$level,$option)
		};
	}
	public function setupTls(TlsContext $context) : bool {
		switch(Loop::name()){
			case 'Swoole':
				$this->socket->setProtocol($context->toSwooleConfig());
				return $this->socket->sslHandshake();
			case 'Revolt':
				$stream = $this->getResource();
				@stream_context_set_options($stream,$context->toStreamContext());
				do {
					$result = @stream_socket_enable_crypto($stream,true);
				} while(is_int($result));
				return $result;
		}
	}
	public function getResource() : mixed {
		if(is_resource($this->resource) === false){
			if($this->resource = @socket_export_stream($this->socket)){
				@stream_set_blocking($this->resource,false);
			} else {
				throw new \RuntimeException('socket_export_stream() failed');
			}
		}
		return $this->resource;
	}
	private function check(string $ip,int $port) : void {
		if(filter_var($ip,FILTER_VALIDATE_IP) === false){
			throw new \InvalidArgumentException('Invalid IP !');
		}
		$options = ['options'=>['min_range'=>0,'max_range'=>65535]];
		if(filter_var($port,FILTER_VALIDATE_INT,$options) === false){
			throw new \InvalidArgumentException('Invalid PORT !');
		}
	}
	public function __destruct(){
		if($this->isClosed() === false){
			$this->close();
		}
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\Socket;

final class TlsContext {
	public function __construct(
		public ? string $certificateFile = null,
		public ? string $privateKeyFile = null,
		public bool $verifyPeer = true,
		public bool $verifyPeerName = true,
		public ? string $peerName = null,
		public int $securityLevel = 2,
		public ? string $caFile = null,
		public string $ciphers = 'DEFAULT'
	){
		if($this->certificateFile !== null and file_exists($this->certificateFile) === false){
			throw new \InvalidArgumentException('Certificate file not found : '.$this->certificateFile);
		}
		if($this->privateKeyFile !== null and file_exists($this->privateKeyFile) === false){
			throw new \InvalidArgumentException('Private key file not found : '.$this->privateKeyFile);
		}
		if($this->privateKeyFile !== null and $this->certificateFile === null){
			throw new \LogicException('A private key was provided, but no certificate file was specified');
		}
		if($this->caFile !== null and file_exists($this->caFile) === false){
			throw new \InvalidArgumentException('CA file not found : '.$this->caFile);
		}
		if($this->securityLevel < 0 or $this->securityLevel > 5){
			throw new \InvalidArgumentException('Security level must be between 0 and 5');
		}
	}
	public function toStreamContext() : array {
		return [
			'ssl' => array_filter([
				'local_cert' => $this->certificateFile,
				'local_pk' => $this->privateKeyFile,
				'verify_peer' => $this->verifyPeer,
				'verify_peer_name' => $this->verifyPeerName,
				'peer_name' => $this->peerName,
				'cafile' => $this->caFile,
				'ciphers' => $this->ciphers,
				'capture_peer_cert' => true
			]),
		];
	}
	public function toSwooleConfig() : array {
		return array_filter([
			'ssl_cert_file' => $this->certificateFile,
			'ssl_key_file' => $this->privateKeyFile,
			'ssl_verify_peer' => $this->verifyPeer,
			'ssl_host_name' => $this->peerName,
			'ssl_cafile' => $this->caFile,
			'ssl_ciphers' => $this->ciphers
		]);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\Socket;

defined('CRLF') || define('CRLF',chr(13).chr(10));

class WebSocket {
	protected StreamSocket $stream;
	protected string $buffer;

	public function __construct(public string $path = '/',public array $headers = array()){
		$this->stream = new StreamSocket();
		$this->buffer = strval(null);
	}
	public function accept(float $timeout = -1) : object | false {
		if($client = $this->stream->accept($timeout)){
			return new class($client) extends WebSocket {
				public function __construct(protected StreamSocket $stream){
					$this->buffer = strval(null);
				}
				public function handleHandshake(array $response,float $timeout = -1) : bool {
					$request = $this->stream->read(null,$timeout);
					if($request == false || str_contains($request,'Sec-WebSocket-Key') === false){
						return false;
					}
					if(preg_match('#Sec-WebSocket-Key:\s+(?<key>.+)$#m',$request,$matches)){
						$key = trim($matches['key']);
						$accept = base64_encode(sha1($key.'258EAFA5-E914-47DA-95CA-C5AB0DC85B11',true));
						$answer = 'HTTP/1.1 101 Switching Protocols'.CRLF;
						$answers = $response + array(
							'Upgrade'=>'websocket',
							'Connection'=>'Upgrade',
							'Sec-WebSocket-Accept'=>$accept
						);
						$formatted = implode(CRLF,array_map(static fn(string $k,string $v) : string => strval($k.': '.$v),array_keys($answers),array_values($answers)));
						return boolval($this->stream->write($answer.$formatted.CRLF.CRLF,$timeout));
					} else {
						return false;
					}
				}
				public function read(? int $length = null,float $timeout = -1) : string | false {
					if(is_null($length) and strlen($this->buffer) > 0){
						$content = $this->buffer;
						$this->buffer = strval(null);
						return $content;
					}
					$resume = false;
					while(is_null($length) || strlen($this->buffer) < $length){
						$frame = $this->readFrame($timeout,true);
						if($frame === false){
							return false;
						}
						extract($frame);
						if($opcode === 0x09){
							$this->write($payload,$timeout,0x0A);
							continue;
						}
						if($opcode === 0x0A){
							continue;
						}
						if($opcode === 0x08){
							$this->write(pack('n',1000),$timeout,0x08);
							$this->stream->close();
							return false;
						}
						if($opcode === 0x00){
							if($resume === false){
								continue;
							}
							if(is_null($length)){
								return $payload;
							}
							$this->buffer .= $payload;
							if($fin){
								break;
							} else {
								continue;
							}
						}
						if($opcode === 0x01 || $opcode === 0x02){
							if(is_null($length)){
								return $payload;
							}
							$this->buffer .= $payload;
							$resume = true;
							if($fin){
								break;
							} else {
								continue;
							}
						}
					}
					if(is_null($length)){
						return false;
					}
					$content = substr($this->buffer,0,$length);
					$this->buffer = substr($this->buffer,$length);
					return $content;
				}
				public function write(string $data,float $timeout = -1,int $opcode = 0x1) : int | false {
					return $this->writeAll($this->generateFrame($data,$opcode,false),$timeout);
				}
			};
		} else {
			return false;
		}
	}
	public function connect(string $host,int $port,float $timeout = -1) : bool {
		return boolval($this->stream->connect($host,$port,$timeout) and $this->doHandshake($host,$port,$timeout));
	}
	private function doHandshake(string $host,int $port,float $timeout = -1) : bool {
		$key = base64_encode(random_bytes(16));
		$header = 'GET '.$this->path.' HTTP/1.1'.CRLF;
		$headers = $this->headers + array(
			'Host'=>$host.chr(58).$port,
			'Upgrade'=>'websocket',
			'Connection'=>'Upgrade',
			'Sec-WebSocket-Key'=>$key,
			'Sec-WebSocket-Protocol'=>'binary',
			'Sec-WebSocket-Version'=>'13'
		);
		$formatted = implode(CRLF,array_map(static fn(string $k,string $v) : string => strval($k.': '.$v),array_keys($headers),array_values($headers)));
		$this->stream->write($header.$formatted.CRLF.CRLF,$timeout);
		$response = $this->stream->read(null,$timeout);
		if($response == false || str_contains($response,'101 Switching Protocols') === false){
			return false;
		}
		if(preg_match('#Sec-WebSocket-Accept:\s(?<token>.+)$#mU',$response,$matches)){
			$expected = base64_encode(sha1($key.'258EAFA5-E914-47DA-95CA-C5AB0DC85B11',true));
			return boolval($expected === trim($matches['token']));
		} else {
			return false;
		}
	}
	public function write(string $data,float $timeout = -1,int $opcode = 0x1) : int | false {
		return $this->writeAll($this->generateFrame($data,$opcode,true),$timeout);
	}
	public function read(? int $length = null,float $timeout = -1) : string | false {
		if(is_null($length) and strlen($this->buffer) > 0){
			$content = $this->buffer;
			$this->buffer = strval(null);
			return $content;
		}
		$resume = false;
		while(is_null($length) || strlen($this->buffer) < $length){
			$frame = $this->readFrame($timeout,false);
			if($frame === false){
				return false;
			}
			extract($frame);
			if($opcode === 0x09){
				$this->write($payload,$timeout,0x0A);
				continue;
			}
			if($opcode === 0x0A){
				continue;
			}
			if($opcode === 0x08){
				$this->write(pack('n',1000),$timeout,0x08);
				$this->stream->close();
				return false;
			}
			if($opcode === 0x00){
				if($resume === false){
					continue;
				}
				if(is_null($length)){
					return $payload;
				}
				$this->buffer .= $payload;
				if($fin){
					break;
				} else {
					continue;
				}
			}
			if($opcode === 0x01 || $opcode === 0x02){
				if(is_null($length)){
					return $payload;
				}
				$this->buffer .= $payload;
				$resume = true;
				if($fin){
					break;
				} else {
					continue;
				}
			}
		}
		if(is_null($length)){
			return false;
		}
		$content = substr($this->buffer,0,$length);
		$this->buffer = substr($this->buffer,$length);
		return $content;
	}
	protected function maskPayload(string $payload,string $mask) : string {
		$out = strval(null);
		$len = strlen($payload);
		for($i = 0; $i < $len; $i++){
			$out .= $payload[$i] ^ $mask[$i % 4];
		}
		return $out;
	}
	protected function writeAll(string $data,float $timeout = -1) : int | false {
		$written = 0;
		while($written < strlen($data)){
			$chunk = $this->stream->write(substr($data,$written),$timeout);
			if($chunk === false || $chunk <= 0){
				return false;
			}
			$written += $chunk;
		}
		return $written;
	}
	protected function readExact(int $length,float $timeout = -1) : string | false {
		$data = strval(null);
		while(strlen($data) < $length){
			$chunk = $this->stream->read($length - strlen($data),$timeout);
			if($chunk === false || $chunk === strval(null)){
				return false;
			}
			$data .= $chunk;
		}
		return $data;
	}
	protected function generateFrame(string $data,int $opcode = 0x1,bool $masked = false) : string {
		$len = strlen($data);
		$frame = chr(0x80 | ($opcode & 0x0F));
		if($len <= 125){
			$frame .= chr(intval($masked ? 0x80 : 0x00) | $len);
		} elseif($len <= 65535){
			$frame .= chr(intval($masked ? 0x80 : 0x00) | 126).pack('n',$len);
		} else {
			$frame .= chr(intval($masked ? 0x80 : 0x00) | 127).pack('J',$len);
		}
		if($masked){
			$mask = random_bytes(4);
			$frame .= $mask;
			$data = $this->maskPayload($data,$mask);
		}
		return strval($frame.$data);
	}
	protected function readFrame(float $timeout = -1,bool $maskedExpected = false) : array | false {
		$header = $this->readExact(2,$timeout);
		if($header === false) return false;
		$bytes = unpack('C2',$header);
		$fin = boolval($bytes[1] & 0x80);
		$opcode = intval($bytes[1] & 0x0F);
		$masked = boolval($bytes[2] & 0x80);
		$len = intval($bytes[2] & 0x7F);
		if($len === 126){
			$ext = $this->readExact(2,$timeout);
			if($ext === false) return false;
			$len = unpack('n',$ext)[true];
		} elseif($len === 127){
			$ext = $this->readExact(8,$timeout);
			if($ext === false) return false;
			$len = unpack('J',$ext)[true];
		}
		if($maskedExpected === $masked){
			$mask = strval(null);
			if($masked){
				$mask = $this->readExact(4,$timeout);
				if($mask === false) return false;
			}
			$payload = $this->readExact(intval($len),$timeout);
			if($payload === false) return false;
			if($masked){
				$payload = $this->maskPayload($payload,$mask);
			}
			return compact('fin','opcode','payload');
		} else {
			return false;
		}
	}
	public function __call(string $name,array $arguments) : mixed {
		return call_user_func_array(array($this->stream,$name),$arguments);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\Socket;

function listen(string $address,int $port,int $backlog = 128) : StreamSocket | false {
	$socket = socketConnector();
	return boolval($socket->bind($address,$port) and $socket->listen($backlog)) ? $socket : false;
}

function socketConnector(int $domain = AF_INET,int $type = SOCK_STREAM,int $protocol = SOL_TCP) : StreamSocket {
	return new StreamSocket($domain,$type,$protocol);
}

function connect(string $host,int $port,float $timeout = -1) : StreamSocket | false {
	$socket = socketConnector();
	return $socket->connect($host,$port,$timeout) ? $socket : false;
}

function connectTls(string $host,int $port,TlsContext $context,float $timeout = -1) : StreamSocket | false {
	$socket = socketConnector();
	return boolval($socket->connect($host,$port,$timeout) and $socket->setupTls($context)) ? $socket : false;
}

function createSocketPair(? array $context = null,int $chunkSize = PHP_INT_MAX) : array {
	try {
		set_error_handler(static function(int $errno,string $errstr) : bool {
			throw new \RuntimeException(sprintf('Failed to create socket pair , %s %d',$errstr,$errno));
		});
		$domain = intval(PHP_OS_FAMILY === 'Windows' ? STREAM_PF_INET : STREAM_PF_UNIX);
		$sockets = stream_socket_pair($domain,STREAM_SOCK_STREAM,STREAM_IPPROTO_IP);
		if($sockets === false){
			throw new \RuntimeException('Failed to create socket pair: Unknown error.');
		}
		foreach($sockets as $i => $socket){
			@stream_set_blocking($socket,false);
			@stream_set_chunk_size($socket,$chunkSize);
			if($context){
				@stream_context_set_options($socket,$context);
			}
			$rawSocket = @socket_import_stream($socket);
			@socket_set_option($rawSocket,SOL_SOCKET,TCP_NODELAY,1);
			$sockets[$i] = new readonly class($rawSocket) extends StreamSocket {
				public function __construct(protected object $socket){
				}
			};
		}
		return $sockets;
	} finally {
		restore_error_handler();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\File;

use Tak\Asyncio\Loop;

use Tak\Asyncio\FileDriver;

use Tak\Asyncio\ByteStream\ResourceStream;

use function Tak\Asyncio\async;

use Swoole\Coroutine\System;

final class Filesystem implements FileDriver {
	public function open(string $path,string $mode) : object {
		if($fp = @fopen($path,$mode)){
			return new class($fp){
				public function __construct(private mixed $fp){
					@stream_set_blocking($fp,false);
				}
				public function read(? int $length = null) : string {
					$content = is_null($length) ? stream_get_contents($this->fp) : fread($this->fp,$length);
					if($content === false){
						throw new \Exception('Could not read the file');
					}
					return $content;
				}
				public function write(string $content) : int {
					$length = strlen($content);
					$written = 0;
					while($written < $length){
						$result = fwrite($this->fp,substr($content,$written));
						if($result === false){
							throw new \Exception('Could not write to the file');
						}
						if($result === 0){
							throw new \Exception('Write operation stalled');
						}
						$written += $result;
					}
					return $written;
				}
				public function close() : void {
					if(is_resource($this->fp)){
						@fclose($this->fp);
					}
				}
				public function __destruct(){
					$this->close();
				}
			};
		} else {
			throw new \Exception('Could not open file : '.$path);
		}
	}
	public function read(string $path,? int $length = null) : string {
		if(Loop::name() === 'Swoole'){
			$content = System::readFile($path);
			if($content === false){
				throw new \Exception('Could not read the file '.$path);
			}
			return is_null($length) ? $content : substr($content,0,$length);
		} else if($fp = @fopen($path,'rb')){
			@stream_set_blocking($fp,false);
			$content = is_null($length) ? stream_get_contents($fp) : fread($fp,$length);
			if($content === false){
				throw new \Exception('Could not read the file '.$path);
			}
			@fclose($fp);
			return $content;
		} else {
			throw new \Exception('Could not open file : '.$path);
		}
	}
	public function write(string $path,string $content) : int {
		if(Loop::name() === 'Swoole'){
			$result = System::writeFile($path,$content);
			if($result === false){
				throw new \Exception('Could not write to the file '.$path);
			}
			return strlen($content);
		} else if($fp = @fopen($path,'wb')){
			@stream_set_blocking($fp,false);
			$length = strlen($content);
			$written = 0;
			while($written < $length){
				$result = fwrite($fp,substr($content,$written));
				if($result === false){
					throw new \Exception('Could not write to the file '.$path);
				}
				if($result === 0){
					throw new \Exception('Write operation stalled');
				}
				$written += $result;
			}
			@fclose($fp);
			return $written;
		} else {
			throw new \Exception('Could not open file : '.$path);
		}
	}
	public function exists(string $path) : bool {
		return async(@file_exists(...),$path)->await();
	}
	public function delete(string $path) : bool {
		return async(@unlink(...),$path)->await();
	}
	public function mkdir(string $path,int $permissions = 0777,bool $recursive = true) : bool {
		return async(@mkdir(...),$path,$permissions,$recursive)->await();
	}
	public function rmdir(string $path) : bool {
		if($this->isDirectory($path)){
			$items = $this->listFiles($path);
			foreach($items as $item){
				$fullPath = realpath($path).DIRECTORY_SEPARATOR.$item;
				if($this->isDirectory($fullPath)){
					$this->rmdir($fullPath);
				} else {
					$this->delete($fullPath);
				}
			}
		}
		return async(@rmdir(...),$path)->await();
	}
	public function move(string $from,string $to) : bool {
		return async(@rename(...),$from,$to)->await();
	}
	public function size(string $path) : int {
		$size = async(@filesize(...),$path)->await();
		if($size === false){
			throw new \Exception('Could not determine file size : '.$path);
		}
		return $size;
	}
	public function touch(string $path,? int $mtime = null,? int $atime = null) : bool {
		return async(@touch(...),$path,$mtime,$atime)->await();
	}
	public function isFile(string $path) : bool {
		return async(@is_file(...),$path)->await();
	}
	public function isDirectory(string $path) : bool {
		return async(@is_dir(...),$path)->await();
	}
	public function listFiles(string $path,int $sorting_order = SCANDIR_SORT_ASCENDING) : array {
		return async(static function() use($path,$sorting_order) : array {
			if($files = @scandir($path,$sorting_order)){
				return array_values(array_diff($files,array('.','..')));
			} else {
				throw new \Exception('Failed to list directory : '.$path);
			}
		})->await();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\File;

use Tak\Asyncio\FileDriver;

function getFileDriver() : FileDriver {
	static $driver = null;
	if($driver){
		return $driver;
	} else {
		return $driver = new Filesystem;
	}
}

function openFile(string $path,string $mode) : object {
	return getFileDriver()->open($path,$mode);
}

function read(string $path) : string {
	return getFileDriver()->read($path);
}

function write(string $path,string $content) : int {
	return getFileDriver()->write($path,$content);
}

function exists(string $path) : bool {
	return getFileDriver()->exists($path);
}

function deleteFile(string $path) : bool {
	return getFileDriver()->delete($path);
}

function createDirectory(string $path,int $permissions = 0777,bool $recursive = true) : bool {
	return getFileDriver()->mkdir($path,$permissions,$recursive);
}

function deleteDirectory(string $path) : bool {
	return getFileDriver()->rmdir($path);
}

function move(string $from,string $to) : bool {
	return getFileDriver()->move($from,$to);
}

function getSize(string $path) : int {
	return getFileDriver()->size($path);
}

function touch(string $path,? int $mtime = null,? int $atime = null) : bool {
	return getFileDriver()->touch($path,$mtime,$atime);
}

function isFile(string $path) : bool {
	return getFileDriver()->isFile($path);
}

function isDirectory(string $path) : bool {
	return getFileDriver()->isDirectory($path);
}

function listFiles(string $path,int $sorting_order = SCANDIR_SORT_ASCENDING) : array {
	return getFileDriver()->listFiles($path,$sorting_order);
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio;

use Tak\Asyncio\Promise\Future;

use Tak\Asyncio\Promise\DeferredFuture;

function async(callable $callback,mixed ...$arguments) : Future {
	$deferred = new DeferredFuture();
	Loop::queue(static function() use($callback,$arguments,$deferred) : void {
		try {
			$result = call_user_func_array($callback,$arguments);
			$deferred->complete($result);
		} catch(\Throwable $error){
			$deferred->error($error);
		}
	});
	return $deferred->getFuture();
}

function delay(float $seconds) : void {
	Loop::sleep($seconds);
}

function await(array $futures) : array {
	return array_map(fn(Future $future) : mixed => $future->await(),$futures);
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio;

abstract class Cancellable implements Cancellation {
	private string $next = 'a';
	private array $callbacks = array();
	private ? \Throwable $exception = null;
	private bool $requested = false;

	public function cancel(? \Throwable $exception = null) : void {
		if($this->requested === false){
			$this->exception = $exception;
			$this->requested = true;
			if($callbacks = $this->callbacks){
				array_map($this->subscribe(...),$callbacks);
				$this->callbacks = [];
			}
		}
	}
	public function subscribe(callable $callback) : string {
		$id = strval($this->next = str_increment($this->next));
		if($this->requested){
			Loop::queue($callback,$this->exception);
		} else {
			$this->callbacks[$id] = $callback;
		}
		return $id;
	}
	public function unsubscribe(string $id) : void {
		unset($this->callbacks[$id]);
	}
	public function isRequested() : bool {
		return boolval($this->requested);
	}
	public function throwIfCancelled() : void {
		if($this->requested){
			throw new \RuntimeException('Task was cancelled before awaiting');
		}
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio;

final class TimeoutCancellation extends Cancellable implements Cancellation {
	protected readonly string $id;

	public function __construct(float $timeout){
		$this->id = Loop::delay($timeout,fn() => $this->cancel(new \Error('Operation timed out')));
		Loop::unreference($this->id);
	}
	public function __destruct(){
		Loop::cancel($this->id);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\Sync;

use Tak\Asyncio\Loop;

class Mutex {
	private Pipe $pipe;

	public function __construct(int $locks = 1){
		$this->pipe = new Pipe($locks);
		$this->pipe->push(true);
	}
	public function acquire(float $timeout = -1) : object {
		$this->pipe->pop($timeout);
		return new class($this->pipe) implements Lock {
			private bool $ready = true;

			public function __construct(private Pipe $pipe){
			}
			public function release(float $timeout = -1) : void {
				if($this->ready){
					$this->ready = false;
					$this->pipe->push(true,$timeout);
				}
			}
		};
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\Sync;

interface Lock {
	public function release(float $timeout = -1) : void;
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\Sync;

use Tak\Asyncio\Loop;

use Tak\Asyncio\TimeoutCancellation;

use Swoole\Coroutine\Channel;

use SplQueue;

class Pipe {
	private ? SplQueue $buffer = null;
	private ? SplQueue $consumers = null;
	private ? SplQueue $producers = null;
	private ? Channel $channel = null;
	private bool $closed = false;

	public function __construct(private readonly int $capacity = -1){
		switch(Loop::name()){
			case 'Swoole':
				$this->channel = new Channel($capacity > 0 ? $capacity : 1);
				break;
			case 'Revolt':
				$this->buffer = new SplQueue();
				$this->consumers = new SplQueue();
				$this->producers = new SplQueue();
				break;
		}
	}
	public function push(mixed $data,float $timeout = -1) : void {
		if($this->closed){
			throw new \RuntimeException('Cannot push to a closed channel');
		}
		switch(Loop::name()){
			case 'Swoole':
				$this->channel->push($data,$timeout);
				break;
			case 'Revolt':
				if($this->consumers->isEmpty() === false){
					$suspension = $this->consumers->dequeue();
					Loop::queue($suspension->resume(...),$data);
				} else {
					if($this->capacity > 0 and $this->buffer->count() >= $this->capacity){
						$cancellation = $timeout > 0 ? new TimeoutCancellation($timeout) : null;
						$cancellation?->throwIfCancelled();
						$suspension = Loop::getSuspension();
						$cancel = $cancellation?->subscribe(static function(? \Throwable $exception) use($suspension) : void {
							$suspension->throw(is_null($exception) ? new \LogicException('Awaiting was cancelled') : $exception);
						});
						$this->producers->enqueue($suspension);
						try {
							$suspension->suspend();
						} finally {
							$cancellation?->unsubscribe($cancel);
						}
					}
					$this->buffer->enqueue($data);
				}
				break;
		}
	}
	public function pop(float $timeout = -1) : mixed {
		switch(Loop::name()){
			case 'Swoole':
				return $this->channel->pop($timeout);
			case 'Revolt':
				if($this->buffer->isEmpty() === false){
					$data = $this->buffer->dequeue();
					if($this->producers->isEmpty() === false){
						$suspension = $this->producers->dequeue();
						Loop::queue($suspension->resume(...));
					}
					return $data;
				}
				if($this->closed){
					return null;
				}
				$cancellation = $timeout > 0 ? new TimeoutCancellation($timeout) : null;
				$cancellation?->throwIfCancelled();
				$suspension = Loop::getSuspension();
				$cancel = $cancellation?->subscribe(static function(? \Throwable $exception) use($suspension) : void {
					$suspension->throw(is_null($exception) ? new \LogicException('Awaiting was cancelled') : $exception);
				});
				$this->consumers->enqueue($suspension);
				try {
					return $suspension->suspend();
				} finally {
					$cancellation?->unsubscribe($cancel);
				}
		}
	}
	public function close() : void {
		switch(Loop::name()){
			case 'Swoole':
				$this->channel->close();
				break;
			case 'Revolt':
				while($this->consumers->isEmpty() === false){
					$this->consumers->dequeue()->resume();
				}
				while($this->producers->isEmpty() === false){
					$this->producers->dequeue()->resume();
				}
				break;
		}
		$this->closed = true;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\Promise;

use Tak\Asyncio\Loop;

use Tak\Asyncio\Cancellation;

readonly class Future {
	public function __construct(private FutureState $state){
	}
	public function await(? Cancellation $cancellation = null) : mixed {
		if($this->state->isComplete){
			if($this->state->error){
				if(is_null($this->state->catch) === false){
					if($this->state->finished === false) call_user_func($this->state->catch,$this->state->error);
				} else {
					if($this->state->finished === false) call_user_func($this->state->finally);
					if($this->state->ignore === false) throw $this->state->error;
				}
			}
			if($this->state->finished === false) call_user_func($this->state->finally);
			return $this->state->result;
		}
		$cancellation?->throwIfCancelled();
		$suspension = Loop::getSuspension();
		$id = $cancellation?->subscribe(function(? \Throwable $exception) : void {
			$this->state->error(is_null($exception) ? new \LogicException('Awaiting was cancelled') : $exception);
		});
		$this->state->suspensions []= $suspension;
		try {
			return $suspension->suspend();
		} finally {
			$cancellation?->unsubscribe($id);
		}
	}
	public function isComplete() : bool {
		return $this->state->isComplete;
	}
	public function ignore() : self {
		$this->state->ignore();
		Loop::unreference(Loop::defer($this->await(...)));
		return $this;
	}
	public function catch(callable $catch) : self {
		$this->state->catch($catch(...));
		Loop::unreference(Loop::defer($this->await(...)));
		return $this;
	}
	public function finally(callable $finally) : self {
		$this->state->finally($finally(...));
		Loop::unreference(Loop::defer($this->await(...)));
		return $this;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\Promise;

final class DeferredFuture {
	private FutureState $state;
	private Future $future;

	public function __construct(){
		$this->state = new FutureState();
		$this->future = new Future($this->state);
	}
	public function complete(mixed $value = null) : void {
		$this->state->complete($value);
	}
	public function isComplete() : bool {
		return $this->state->isComplete;
	}
	public function error(\Throwable $throwable) : void {
		$this->state->error($throwable);
	}
	public function getFuture() : Future {
		return $this->future;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\Promise;

final class FutureState {
	public bool $isComplete = false;
	public bool $finished = false;
	public bool $ignore = false;
	public mixed $result = null;
	public ? \Closure $catch = null;
	public ? \Closure $finally = null;
	public ? \Throwable $error = null;
	public array $suspensions = [];

	public function complete(mixed $value = null) : void {
		if($this->isComplete === false){
			$this->result = $value;
			$this->isComplete = true;
			foreach($this->suspensions as $suspension){
				$suspension->resume($value);
			}
			$this->finished = true;
			$this->suspensions = [];
			if(is_null($this->finally) === false){
				call_user_func($this->finally);
			}
		}
	}
	public function ignore() : void {
		$this->ignore = true;
	}
	public function catch(\Closure $catch) : void {
		$this->catch = $catch;
	}
	public function finally(\Closure $finally) : void {
		$this->finally = $finally;
	}
	public function error(\Throwable $throwable) : void {
		if($this->isComplete === false){
			$this->error = $throwable;
			$this->isComplete = true;
			if(is_null($this->catch) === false){
				foreach($this->suspensions as $suspension){
					$suspension->resume();
				}
				call_user_func($this->catch,$throwable);
			} else {
				foreach($this->suspensions as $suspension){
					if($this->ignore === false){
						$suspension->throw($throwable);
					} else {
						$suspension->resume();
					}
				}
			}
			$this->finished = true;
			$this->suspensions = [];
			if(is_null($this->finally) === false){
				call_user_func($this->finally);
			}
		}
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\ByteStream;

use Tak\Asyncio\Loop;

use Tak\Asyncio\Resource;

use Tak\Asyncio\Cancellation;

use function Tak\Asyncio\async;

final class ResourceStream implements Resource {
	public const int CHUNK_SIZE = 8 * 1024;

	public function __construct(protected mixed $fp){
		@stream_set_blocking($fp,false);
	}
	private function shouldUseSingleRead(mixed $stream) : bool {
		$meta = stream_get_meta_data($stream);
		$streamType = strtolower(strval($meta['stream_type'] ?? null));
		return match(true){
			str_contains($streamType,'udp') => true,
			str_contains($streamType,'unix_dgram') => true,
			str_contains($streamType,'stdio') => true,
			default => false
		};
	}
	public function read(? int $length = null,? Cancellation $cancellation = null) : ? string {
		$buffer = strval(null);
		$cancellation?->throwIfCancelled();
		$suspension = Loop::getSuspension();
		$useSingleRead = boolval(is_null($length) and $this->shouldUseSingleRead($this->fp));
		Loop::onReadable($this->fp,static function(string $id,mixed $fp) use($suspension,$useSingleRead,&$buffer,$length) : void {
			$limit = is_null($length) ? self::CHUNK_SIZE : min(self::CHUNK_SIZE,$length - strlen($buffer));
			$chunk = ($limit > 0 ? fread($fp,$limit) : false);
			$buffer .= $chunk;
			if($chunk === false || empty($chunk) || $useSingleRead){
				Loop::cancel($id);
				$suspension->resume(empty($buffer) === false ? $buffer : null);
			}
		});
		$id = $cancellation?->subscribe(function(? \Throwable $exception) use($suspension) : void {
			$suspension->throw(is_null($exception) ? new \LogicException('Awaiting was cancelled') : $exception);
		});
		try {
			return $suspension->suspend();
		} finally {
			$cancellation?->unsubscribe($id);
		}
	}
	public function write(string $content,? Cancellation $cancellation = null) : ? int {
		$buffer = strval(null);
		$written = 0;
		$length = strlen($content);
		$cancellation?->throwIfCancelled();
		$suspension = Loop::getSuspension();
		Loop::onWritable($this->fp,static function(string $id,mixed $fp) use($suspension,$content,&$written,$length) : void {
			$result = fwrite($fp,substr($content,$written,self::CHUNK_SIZE));
			$written += intval($result);
			if($result === false || $written >= $length){
				Loop::cancel($id);
				$suspension->resume(empty($written) === false ? $written : null);
			}
		});
		$id = $cancellation?->subscribe(function(? \Throwable $exception) use($suspension) : void {
			$suspension->throw(is_null($exception) ? new \LogicException('Awaiting was cancelled') : $exception);
		});
		try {
			return $suspension->suspend();
		} finally {
			$cancellation?->unsubscribe($id);
		}
	}
	public function tell() : int | false {
		return async(fn() : int | false => ftell($this->fp))->await();
	}
	public function seek(int $offset,int $whence = SEEK_SET) : int {
		return async(fn() : int => fseek($this->fp,$offset,$whence))->await();
	}
	public function lock(int $operation = LOCK_SH | LOCK_EX) : bool {
		return async(fn() : bool => flock($this->fp,$operation))->await();
	}
	public function truncate(int $size) : bool {
		return async(fn() : bool => ftruncate($this->fp,$size))->await();
	}
	public function flush() : bool {
		return async(fn() : bool => flush($this->fp))->await();
	}
	public function close() : bool {
		return async(fn() : bool => fclose($this->fp))->await();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio\ByteStream;

defined('STDIN') || define('STDIN',fopen('php://stderr','wb'));

defined('STDOUT') || define('STDOUT',fopen('php://stdout','wb'));

function getStdin() : ResourceStream {
	static $stdin = new ResourceStream(STDIN);
	return $stdin;
}

function getStdout() : ResourceStream {
	static $stdout = new ResourceStream(STDOUT);
	return $stdout;
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio;

interface Cancellation {
	public function cancel(? \Throwable $exception = null) : void;
	public function subscribe(callable $callback) : string;
	public function unsubscribe(string $id) : void;
	public function isRequested() : bool;
	public function throwIfCancelled() : void;
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio;

interface Driver {
	public static function sleep(float $seconds) : void;
	public static function delay(float $seconds,callable $callback) : string;
	public static function repeat(float $seconds,callable $callback) : string;
	public static function queue(callable $callback,mixed ...$args) : void;
	public static function defer(callable $callback) : string;

	public static function onReadable(mixed $resource,callable $callback) : string;
	public static function onWritable(mixed $resource,callable $callback) : string;
	public static function onSignal(int $signal,callable $callback) : string;

	public static function cancel(string $id) : void;

	public static function reference(string $id) : string;
	public static function unreference(string $id) : string;
	public static function isReferenced(string $id) : bool;

	public static function setErrorHandler(callable $callback) : void;

	public static function getSuspension() : Suspension;

	public static function run() : void;
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio;

final class Loop {
	private static ? Driver $driver = null;
	private static ? string $name = null;

	public static function get() : Driver {
		if(self::$driver){
			return self::$driver;
		} else {
			if(str_contains(PHP_OS,'WIN') === false and str_starts_with(PHP_SAPI,'cli') and @extension_loaded('swoole')){
				return self::$driver = new Drivers\SwooleDriver;
			} else {
				return self::$driver = new Drivers\RevoltDriver;
			}
		}
	}
	public static function name() : string {
		if(self::$name){
			return self::$name;
		} else {
			$class = get_class(self::get());
			if(preg_match('/\\\\(?<name>\w+)Driver$/',$class,$match)){
				return self::$name = $match['name'];
			} else {
				throw new \RuntimeException('Unknown driver');
			}
		}
	}
	public static function __callStatic(string $name,array $arguments) : mixed {
		return forward_static_call_array(array(static::get(),$name),$arguments);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Asyncio;

interface Suspension {
	public function suspend() : mixed;

	public function resume(mixed $value = null) : void;

	public function throw(\Throwable $throwable) : void;
}

?>                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
# Security Policy

Security is a high priority for `taknone/asyncio` We are committed to addressing any security vulnerabilities that may arise

## Supported Versions

Only the latest stable version of `taknone/asyncio` receives security updates. If you are using an older version, we highly recommend upgrading to the latest release to ensure you have the latest security patches

## Reporting a Vulnerability

If you discover a security vulnerability, please **do not** open a public issue on GitHub. Public disclosure of vulnerabilities can put users at risk

Instead, please report it privately via email :

**Email :** `MrTakNone@gmail.com`

### What to include in your report :

To help us resolve the issue as quickly as possible, please provide the following information :

* **Description :** A clear description of the vulnerability
* **Steps to Reproduce :** A list of steps or a code snippet that triggers the issue
* **Impact :** A summary of how this vulnerability could be exploited
* **Environment :** Details about your PHP version ( e.g., `8.4` ), operating system, and any extensions enabled ( e.g., `swoole`, `pcntl` )

We will acknowledge your report within 48 hours and work with you to fix the issue. We appreciate your efforts in keeping this project secure

## Disclosure Policy

Once the vulnerability has been patched and a new version is released, we encourage you to follow responsible disclosure practices. We will credit you in the release notes for finding the vulnerability, if you wish{
    "name": "taknone/asyncio",
    "license": "MIT",
    "description": "A high-performance async framework for PHP supporting Swoole and Revolt loops",
    "type": "library",
    "keywords": [
        "async",
        "asyncio",
        "asynchronously",
        "non-blocking",
        "non-blocking-io",
        "io",
        "aiofile",
        "aiosocket",
        "aiodatabase",
        "fiber",
        "coroutine",
        "revolt",
        "swoole",
        "php"
    ],
    "autoload": {
        "psr-4": {
            "Tak\\Asyncio\\": "src"
        },
        "files": [
            "src/functions.php",
            "src/File/functions.php",
            "src/Socket/functions.php",
            "src/ByteStream/functions.php"
        ]
    },
    "authors": [
        {
            "name": "Tak None",
            "email": "MrTakNone@gmail.com",
            "role": "Developer"
        }
    ],
    "minimum-stability": "stable",
    "require": {
        "php": ">=8.4",
        "revolt/event-loop": "^1.0"
    },
    "suggest": {
        "ext-swoole": "Required for high-performance Swoole coroutine support ( > 5.0.0 )",
        "ext-pcntl": "Allows for better signal handling"
    }
}# LiveProto

<p>
  <img src = "docs/_images/logo.svg" alt = "logo" style = "vertical-align : middle; width : 24px; height : 24px;"/>
  An <strong>async</strong> , <strong>Pure-PHP</strong> MTProto Telegram client library for both <em>bot</em> & <em>user account</em> handling
</p>

---

## 🚀 Features

* **Full MTProto Protocol** : Complete implementation of Telegram's low-level protocol
* **Asynchronous I/O** : Built with PHP 8's async primitives ( Fibers / Swoole / Asyncio ), enabling non-blocking requests
* **Session Management** : Automatic key exchange, session storage, and reconnection logic
* **Comprehensive API Coverage** : Send and receive messages, manage chats and channels, handle updates, upload/download media, and more

---

## 📦 Installation

Install via Composer :

```bash
composer require taknone/liveproto
```

Then use it like this :

```php
<?php

require 'vendor/autoload.php';
```

Install via Phar :

```php
<?php

if(file_exists('liveproto.php') === false):
    copy('https://installer.liveproto.dev/liveproto.php','liveproto.php');
endif;

require_once 'liveproto.php';
```

---

## 🏁 Getting Started

Example Usage :

```php
<?php

if(file_exists('vendor/autoload.php')):
    require 'vendor/autoload.php';
elseif(file_exists('liveproto.phar')):
    require_once 'liveproto.phar';
elseif(file_exists('liveproto.php') === false):
    copy('https://installer.liveproto.dev/liveproto.php','liveproto.php');
    require_once 'liveproto.php';
endif;

use Tak\Liveproto\Network\Client;

use Tak\Liveproto\Utils\Settings;

$settings = new Settings();
$settings->setApiId(21724);
$settings->setApiHash('3e0cb5efcd52300aec5994fdfc5bdc16');
$settings->setHideLog(true);

$client = new Client('testSession','sqlite',$settings);

$client->start(false);
/* OR
 * $client->connect();
 * 
 * if($client->isAuthorized() === false){
 *     $client->sign_in(bot_token : '123456:AAEK.....');
 * }
 */

try {
	/* 😁 If you would like to avoid errors, enter your username in the line below 😎 */
	$peer = $client->get_input_peer('@TakNone');
	print_r($client->messages->sendMessage($peer,'👋',random_int(PHP_INT_MIN,PHP_INT_MAX)));
} catch(Throwable $error){
	var_dump($error);
} finally {
	$client->stop(); // OR $client->disconnect(); //
}

?>
```

---

## 💬 Community & Chat
Join the project community :
- Chat ( Telegram ) : https://t.me/LiveProtoChat
- News ( Telegram channel ) : https://t.me/LiveProto
- Snippets ( Telegram ) : https://t.me/LiveProtoSnippets

## 🎓 Documentation

Visit [Docs LiveProto](https://docs.LiveProto.dev) and [TL LiveProto](https://tl.LiveProto.dev)

## 📜 License

This project is licensed under the [MIT License](LICENSE)
#!/usr/bin/env bash

LOG(){
	printf "\n=> %s\n" "$*";
}
ERR(){
	printf "\n[ERROR] %s\n" "$*" >&2;
}

# prefer sudo when not root #

SUDO=""
if [ "$(id -u)" -ne 0 ]; then
	if command -v sudo >/dev/null 2>&1; then SUDO="sudo"; else
		ERR "Not root and sudo not found , some install steps may fail"
	fi
fi

# detect package manager #

PKG=""
if command -v apt-get >/dev/null 2>&1; then PKG="apt"; fi
if command -v dnf >/dev/null 2>&1; then PKG="dnf"; fi
if command -v yum >/dev/null 2>&1 && [ -z "$PKG" ]; then PKG="yum"; fi
if command -v pacman >/dev/null 2>&1; then PKG="pacman"; fi
if command -v apk >/dev/null 2>&1; then PKG="apk"; fi
if command -v brew >/dev/null 2>&1; then PKG="brew"; fi

LOG "Package manager detected : ${PKG:-none}"

install_apt(){
	LOG "apt : updating and installing common packages ..."
	$SUDO apt-get update -y || true
	$SUDO apt-get upgrade -y || true
	$SUDO apt-get install -y software-properties-common ca-certificates curl wget git unzip || true
	# Add ondrej PPA if available for newer php #
	if ! grep -RHiE 'ppa:ondrej/php|launchpad\.net/ondrej/php|ondrej/php' /etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null; then
		LOG "Adding ondrej/php PPA (if supported) ..."
		$SUDO add-apt-repository -y ppa:ondrej/php >/dev/null 2>&1 || true
		$SUDO apt-get update -y || true
	else
		LOG "The ondrej/php repo found"
	fi
	PHP_PKG="php8.4"
	if ! apt-cache show "$PHP_PKG" >/dev/null 2>&1; then
		for p in php8.5 php8.3; do
			if apt-cache show "$p" >/dev/null 2>&1; then PHP_PKG="$p"; break; fi
		done
	fi
	LOG "Installing $PHP_PKG and common extensions ..."
	$SUDO apt-get install -y "${PHP_PKG}" "${PHP_PKG}-cli" "${PHP_PKG}-dev" \
		"${PHP_PKG}-xml" "${PHP_PKG}-gmp" "${PHP_PKG}-zip" "${PHP_PKG}-sockets" \
		"${PHP_PKG}-mbstring" "${PHP_PKG}-fileinfo" \
		"${PHP_PKG}-curl" "${PHP_PKG}-intl" || true
}

install_dnf(){
	TOOL="${PKG:-dnf}"
	LOG "$TOOL : installing common packages ..."
	$SUDO $TOOL install -y epel-release curl wget git || true
	$SUDO $TOOL install -y php php-cli php-xml php-gmp php-zip php-mbstring php-fileinfo php-curl php-intl || true
}

install_pacman(){
	LOG "pacman : installing php + common packages"
	$SUDO pacman -Sy --noconfirm php php-pear php-xml php-gmp php-zip php-mbstring php-fileinfo php-curl || true
}

install_apk(){
	LOG "apk : installing php8 + common packages"
	$SUDO apk update || true
	$SUDO apk add --no-cache php8 php8-cli php8-phar php-xml php-gmp php-zip php-mbstring php-fileinfo php-curl php-intl git curl || true
}

install_brew(){
	LOG "Homebrew : installing php"
	if ! command -v brew >/dev/null 2>&1; then
		LOG "Installing Homebrew ..."
		/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || true
		eval "$(/opt/homebrew/bin/brew shellenv 2>/dev/null || true)" || true
	fi
	if brew info php@8.4 >/dev/null 2>&1; then
		brew install php@8.4 || true
		brew link --force --overwrite php@8.4 || true
	else
		brew install php || true
	fi
}

case "$PKG" in
	apt) install_apt ;;
	dnf|yum) install_dnf ;;
	pacman) install_pacman ;;
	apk) install_apk ;;
	brew) install_brew ;;
	*) ERR "Unsupported / undetected package manager. Run this on Debian / Ubuntu, RHEL / Fedora, Arch, Alpine, or macOS" ; exit 1 ;;
esac

# verify php #

if ! command -v php >/dev/null 2>&1; then
	ERR "Aborting : php not found after package install"
	exit 1
fi

PHP_BIN="$(command -v php)"
LOG "PHP : $($PHP_BIN -v | head -n1)"
BITS=$($PHP_BIN -r 'echo PHP_INT_SIZE*8;' 2>/dev/null || echo "unknown")
if [ "$BITS" != "64" ]; then
	ERR "Detected PHP integer size : $BITS bits, LiveProto expects 64-bit PHP, Continue at your own risk"
fi

# check extensions ( best-effort ) #

NEEDED=(openssl gmp json xml dom mbstring curl filter hash zlib intl fileinfo zip sockets)
MISSING=()
for e in "${NEEDED[@]}"; do
	if ! php -r "exit(extension_loaded('$e') ? 0 : 1);" >/dev/null 2>&1; then
		MISSING+=("$e")
	fi
done
if [ ${#MISSING[@]} -ne 0 ]; then
	LOG "Missing extensions : ${MISSING[*]} , Try installing distro packages ( eg. php-gmp, php-hash ) and re-run"
else
	LOG "All common extensions present"
fi

# composer installation #

download_and_install_composer() {
	local INSTALLER_URL="https://getcomposer.org/installer"
	local TMP="composer-setup.php"

	LOG "Downloading Composer installer ( curl -> wget -> php copy )"

	if command -v curl >/dev/null 2>&1; then
		curl --fail --silent --show-error --location \
			--connect-timeout 10 --max-time 60 --retry 3 --retry-delay 2 \
			"$INSTALLER_URL" -o "$TMP" || {
				ERR "curl failed to download Composer installer";
				return 1;
			}
	elif command -v wget >/dev/null 2>&1; then
		wget -q --timeout=20 --tries=3 -O "$TMP" "$INSTALLER_URL" || {
			ERR "wget failed to download Composer installer";
			return 1;
		}
	else
		LOG "No curl / wget found -> trying PHP copy() ( requires allow_url_fopen )"
		if php -r 'echo ini_get("allow_url_fopen");' 2>/dev/null | grep -qiE '1|on|true'; then
			php -r "copy('$INSTALLER_URL','$TMP')" || {
				ERR "php copy() failed to download installer";
				return 1;
			}
		else
			ERR "No curl / wget and PHP allow_url_fopen is disabled. Install curl / wget or enable allow_url_fopen"
			return 1
		fi
	fi
	LOG "Running Composer installer ..."
	# Install to /usr/local/bin if possible ( use sudo if needed ), else to $HOME/.local/bin #
	if [ -n "${SUDO:-}" ]; then
		$SUDO php "$TMP" --install-dir=/usr/local/bin --filename=composer || {
			ERR "Composer installer failed ( sudo )";
			rm -f "$TMP";
			return 1;
		}
	elif [ -w /usr/local/bin ]; then
		php "$TMP" --install-dir=/usr/local/bin --filename=composer || {
			ERR "Composer installer failed";
			rm -f "$TMP"
			return 1;
		}
	else
		mkdir -p "$HOME/.local/bin"
		php "$TMP" --install-dir="$HOME/.local/bin" --filename=composer || {
			ERR "Composer installer failed";
			rm -f "$TMP";
			return 1;
		}
		LOG "Composer installed to $HOME/.local/bin. Add it to PATH if necessary: export PATH=\"\$HOME/.local/bin:\$PATH\""
	fi
	rm -f "$TMP"
	LOG "Composer installed as : $(command -v composer || echo '~/.local/bin/composer')"
	return 0
}

download_and_install_composer || exit 1

if ! command -v composer >/dev/null 2>&1; then
	ERR "Composer missing. Aborting composer steps"
	exit 1
fi

# composer require library #

MTPROTO="$HOME/library"
mkdir -p "$MTPROTO"
cd "$MTPROTO"

LOG "Running : composer require taknone/liveproto"
composer require taknone/liveproto || {
	ERR "composer require failed. Inspect output and retry inside $MTPROTO"
}

LOG "PHP : $($PHP_BIN -v | head -n1)"

if [ -d "$MTPROTO/vendor/taknone/liveproto" ]; then
	LOG "LiveProto installed at : $MTPROTO/vendor/taknone/liveproto"
else
	ERR "LiveProto not found in vendor ( composer may have failed )"
fi

LOG "Done"

exit 0<?php

declare(strict_types = 1);

namespace Tak\Liveproto\Crypto;

use Tak\Liveproto\Utils\Binary;

final class Rsa {
	private const RSAKEYS = [
													'-----BEGIN RSA PUBLIC KEY-----'.
													'MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6'.
													'lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS'.
													'an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw'.
													'Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+'.
													'8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n'.
													'Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB'.
													'-----END RSA PUBLIC KEY-----',
													# '-----BEGIN RSA PUBLIC KEY-----'.
													# 'MIIBCgKCAQEAyMEdY1aR+sCR3ZSJrtztKTKqigvO/vBfqACJLZtS7QMgCGXJ6XIR'.
													# 'yy7mx66W0/sOFa7/1mAZtEoIokDP3ShoqF4fVNb6XeqgQfaUHd8wJpDWHcR2OFwv'.
													# 'plUUI1PLTktZ9uW2WE23b+ixNwJjJGwBDJPQEQFBE+vfmH0JP503wr5INS1poWg/'.
													# 'j25sIWeYPHYeOrFp/eXaqhISP6G+q2IeTaWTXpwZj4LzXq5YOpk4bYEQ6mvRq7D1'.
													# 'aHWfYmlEGepfaYR8Q0YqvvhYtMte3ITnuSJs171+GDqpdKcSwHnd6FudwGO4pcCO'.
													# 'j4WcDuXc2CTHgH8gFTNhp/Y8/SpDOhvn9QIDAQAB'.
													# '-----END RSA PUBLIC KEY-----',
													# '-----BEGIN RSA PUBLIC KEY-----'.
													# 'MIIBCgKCAQEA6LszBcC1LGzyr992NzE0ieY+BSaOW622Aa9Bd4ZHLl+TuFQ4lo4g'.
													# '5nKaMBwK/BIb9xUfg0Q29/2mgIR6Zr9krM7HjuIcCzFvDtr+L0GQjae9H0pRB2OO'.
													# '62cECs5HKhT5DZ98K33vmWiLowc621dQuwKWSQKjWf50XYFw42h21P2KXUGyp2y/'.
													# '+aEyZ+uVgLLQbRA1dEjSDZ2iGRy12Mk5gpYc397aYp438fsJoHIgJ2lgMv5h7WY9'.
													# 't6N/byY9Nw9p21Og3AoXSL2q/2IJ1WRUhebgAdGVMlV1fkuOQoEzR7EdpqtQD9Cs'.
													# '5+bfo3Nhmcyvk5ftB0WkJ9z6bNZ7yxrP8wIDAQAB'.
													# '-----END RSA PUBLIC KEY-----',
													'-----BEGIN RSA PUBLIC KEY-----'.
													'MIIBCgKCAQEAruw2yP/BCcsJliRoW5eBVBVle9dtjJw+OYED160Wybum9SXtBBLX'.
													'riwt4rROd9csv0t0OHCaTmRqBcQ0J8fxhN6/cpR1GWgOZRUAiQxoMnlt0R93LCX/'.
													'j1dnVa/gVbCjdSxpbrfY2g2L4frzjJvdl84Kd9ORYjDEAyFnEA7dD556OptgLQQ2'.
													'e2iVNq8NZLYTzLp5YpOdO1doK+ttrltggTCy5SrKeLoCPPbOgGsdxJxyz5KKcZnS'.
													'Lj16yE5HvJQn0CNpRdENvRUXe6tBP78O39oJ8BTHp9oIjd6XWXAsp2CvK45Ol8wF'.
													'XGF710w9lwCGNbmNxNYhtIkdqfsEcwR5JwIDAQAB'.
													'-----END RSA PUBLIC KEY-----',
													'-----BEGIN RSA PUBLIC KEY-----'.
													'MIIBCgKCAQEAvfLHfYH2r9R70w8prHblWt/nDkh+XkgpflqQVcnAfSuTtO05lNPs'.
													'pQmL8Y2XjVT4t8cT6xAkdgfmmvnvRPOOKPi0OfJXoRVylFzAQG/j83u5K3kRLbae'.
													'7fLccVhKZhY46lvsueI1hQdLgNV9n1cQ3TDS2pQOCtovG4eDl9wacrXOJTG2990V'.
													'jgnIKNA0UMoP+KF03qzryqIt3oTvZq03DyWdGK+AZjgBLaDKSnC6qD2cFY81UryR'.
													'WOab8zKkWAnhw2kFpcqhI0jdV5QaSCExvnsjVaX0Y1N0870931/5Jb9ICe4nweZ9'.
													'kSDF/gip3kWLG0o8XQpChDfyvsqB9OLV/wIDAQAB'.
													'-----END RSA PUBLIC KEY-----',
													'-----BEGIN RSA PUBLIC KEY-----'.
													'MIIBCgKCAQEAs/ditzm+mPND6xkhzwFIz6J/968CtkcSE/7Z2qAJiXbmZ3UDJPGr'.
													'zqTDHkO30R8VeRM/Kz2f4nR05GIFiITl4bEjvpy7xqRDspJcCFIOcyXm8abVDhF+'.
													'th6knSU0yLtNKuQVP6voMrnt9MV1X92LGZQLgdHZbPQz0Z5qIpaKhdyA8DEvWWvS'.
													'Uwwc+yi1/gGaybwlzZwqXYoPOhwMebzKUk0xW14htcJrRrq+PXXQbRzTMynseCoP'.
													'Ioke0dtCodbA3qQxQovE16q9zz4Otv2k4j63cz53J+mhkVWAeWxVGI0lltJmWtEY'.
													'K6er8VqqWot3nqmWMXogrgRLggv/NbbooQIDAQAB'.
													'-----END RSA PUBLIC KEY-----',
													'-----BEGIN RSA PUBLIC KEY-----'.
													'MIIBCgKCAQEAvmpxVY7ld/8DAjz6F6q05shjg8/4p6047bn6/m8yPy1RBsvIyvuD'.
													'uGnP/RzPEhzXQ9UJ5Ynmh2XJZgHoE9xbnfxL5BXHplJhMtADXKM9bWB11PU1Eioc'.
													'3+AXBB8QiNFBn2XI5UkO5hPhbb9mJpjA9Uhw8EdfqJP8QetVsI/xrCEbwEXe0xvi'.
													'fRLJbY08/Gp66KpQvy7g8w7VB8wlgePexW3pT13Ap6vuC+mQuJPyiHvSxjEKHgqe'.
													'Pji9NP3tJUFQjcECqcm0yV7/2d0t/pbCm+ZH1sadZspQCEPPrtbkQBlvHb4OLiIW'.
													'PGHKSMeRFvp3IWcmdJqXahxLCUS1Eh6MAQIDAQAB'.
													'-----END RSA PUBLIC KEY-----',
													'-----BEGIN RSA PUBLIC KEY-----'.
													'MIIBCgKCAQEAxq7aeLAqJR20tkQQMfRn+ocfrtMlJsQ2Uksfs7Xcoo77jAid0bRt'.
													'ksiVmT2HEIJUlRxfABoPBV8wY9zRTUMaMA654pUX41mhyVN+XoerGxFvrs9dF1Ru'.
													'vCHbI02dM2ppPvyytvvMoefRoL5BTcpAihFgm5xCaakgsJ/tH5oVl74CdhQw8J5L'.
													'xI/K++KJBUyZ26Uba1632cOiq05JBUW0Z2vWIOk4BLysk7+U9z+SxynKiZR3/xdi'.
													'XvFKk01R3BHV+GUKM2RYazpS/P8v7eyKhAbKxOdRcFpHLlVwfjyM1VlDQrEZxsMp'.
													'NTLYXb6Sce1Uov0YtNx5wEowlREH1WOTlwIDAQAB'.
													'-----END RSA PUBLIC KEY-----',
													'-----BEGIN RSA PUBLIC KEY-----'.
													'MIIBCgKCAQEAsQZnSWVZNfClk29RcDTJQ76n8zZaiTGuUsi8sUhW8AS4PSbPKDm+'.
													'DyJgdHDWdIF3HBzl7DHeFrILuqTs0vfS7Pa2NW8nUBwiaYQmPtwEa4n7bTmBVGsB'.
													'1700/tz8wQWOLUlL2nMv+BPlDhxq4kmJCyJfgrIrHlX8sGPcPA4Y6Rwo0MSqYn3s'.
													'g1Pu5gOKlaT9HKmE6wn5Sut6IiBjWozrRQ6n5h2RXNtO7O2qCDqjgB2vBxhV7B+z'.
													'hRbLbCmW0tYMDsvPpX5M8fsO05svN+lKtCAuz1leFns8piZpptpSCFn7bWxiA9/f'.
													'x5x17D7pfah3Sy2pA+NDXyzSlGcKdaUmwQIDAQAB'.
													'-----END RSA PUBLIC KEY-----',
													'-----BEGIN RSA PUBLIC KEY-----'.
													'MIIBCgKCAQEAwqjFW0pi4reKGbkc9pK83Eunwj/k0G8ZTioMMPbZmW99GivMibwa'.
													'xDM9RDWabEMyUtGoQC2ZcDeLWRK3W8jMP6dnEKAlvLkDLfC4fXYHzFO5KHEqF06i'.
													'qAqBdmI1iBGdQv/OQCBcbXIWCGDY2AsiqLhlGQfPOI7/vvKc188rTriocgUtoTUc'.
													'/n/sIUzkgwTqRyvWYynWARWzQg0I9olLBBC2q5RQJJlnYXZwyTL3y9tdb7zOHkks'.
													'WV9IMQmZmyZh/N7sMbGWQpt4NMchGpPGeJ2e5gHBjDnlIf2p1yZOYeUYrdbwcS0t'.
													'UiggS4UeE8TzIuXFQxw7fzEIlmhIaq3FnwIDAQAB'.
													'-----END RSA PUBLIC KEY-----'
												];

	static private array $cdnPublicKeys = array();

	static public function addCdn(object $cdnConfig) : void {
		foreach($cdnConfig->public_keys as $cdnPublicKey):
			if(isset($cdnPublicKey->public_key)):
				self::$cdnPublicKeys []= $cdnPublicKey->public_key;
			endif;
		endforeach;
		self::$cdnPublicKeys = array_unique(self::$cdnPublicKeys);
	}
	static public function find(int $fingerprintnumber,string $data) : string | null {
		$publicKeys = array_merge(self::RSAKEYS,self::$cdnPublicKeys);
		foreach($publicKeys as $rsa):
			list($fingerprint,$modulus,$exponent) = self::loadRsa($rsa);
			if($fingerprint === $fingerprintnumber):
				return self::encrypt($data,$modulus,$exponent);
			endif;
		endforeach;
		return null;
	}
	static private function encrypt(string $data,string $modulus,string $exponent) : string {
		$writer = new Binary();
		$writer->write(sha1($data,true));
		$writer->write($data);
		$length = strlen($data);
		if($length < 0xeb):
			$padding = random_bytes(0xeb - $length);
			$writer->write($padding);
		endif;
		$bytes = $writer->read();
		$number = gmp_import($bytes);
		$pow = gmp_powm($number,$exponent,$modulus);
		$string = gmp_export($pow);
		return str_pad($string,0x100,chr(0),STR_PAD_LEFT);
	}
	static private function loadRsa(string $publickey) : array {
		$rsa = \phpseclib3\Crypt\RSA::load($publickey);
		$reflection = new \ReflectionClass($rsa);
		$modulus = $reflection->getProperty('modulus')->getValue($rsa);
		$exponent = $reflection->getProperty('exponent')->getValue($rsa);
		$fingerprint = new Binary();
		$fingerprint->writeBytes($modulus->toBytes());
		$fingerprint->writeBytes($exponent->toBytes());
		$fingerprint->write(substr(sha1($fingerprint->read(),true),-8));
		return array($fingerprint->readLong(),strval($modulus),strval($exponent));
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Crypto;

abstract class Aes {
	static public function encrypt(string $plaintext,string $key,string $iv) : string {
		if(is_callable('tg_encrypt_ige')):
			return tg_encrypt_ige($plaintext,$key,$iv);
		else:
			$ivOne = substr($iv,0,0x10);
			$ivTwo = substr($iv,0x10);
			$ciphertext = strval(null);
			$padding = strlen($plaintext) % 0x10 ? 0x10 - (strlen($plaintext) % 0x10) : 0;
			$plaintext = str_pad($plaintext,strlen($plaintext) + $padding,chr(0),STR_PAD_RIGHT);
			for($i = 0,$length = strlen($plaintext); $i < $length; $i += 0x10):
				$plain = substr($plaintext,$i,0x10);
				$cipher = openssl_encrypt($plain ^ $ivOne,'AES-256-ECB',$key,OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING) ^ $ivTwo;
				$ciphertext .= $cipher;
				$ivOne = $cipher;
				$ivTwo = $plain;
			endfor;
			return $ciphertext;
		endif;
	}
	static public function decrypt(string $ciphertext,string $key,string $iv) : string {
		if(is_callable('tg_decrypt_ige')):
			return tg_decrypt_ige($ciphertext,$key,$iv);
		else:
			$ivOne = substr($iv,0,0x10);
			$ivTwo = substr($iv,0x10);
			$plaintext = strval(null);
			$padding = strlen($ciphertext) % 16 ? 0x10 - strlen($ciphertext) % 0x10 : 0;
			$ciphertext = str_pad($ciphertext,strlen($ciphertext) + $padding,chr(0),STR_PAD_RIGHT);
			for($i = 0,$length = strlen($ciphertext); $i < $length; $i += 0x10):
				$cipher = substr($ciphertext,$i,0x10);
				$plain = openssl_decrypt($cipher ^ $ivTwo,'AES-256-ECB',$key,OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING) ^ $ivOne;
				$plaintext .= $plain;
				$ivOne = $cipher;
				$ivTwo = $plain;
			endfor;
			return $plaintext;
		endif;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Crypto;

readonly class Factorizator {
	static public function decompose(int $pq) : int {
		$y = gmp_random_range(1,gmp_sub($pq,1));
		$c = gmp_random_range(1,gmp_sub($pq,1));
		$g = $r = $q = gmp_init(1);
		while(gmp_cmp($g,1) == 0):
			$x = $y;
			$y = gmp_mod(gmp_add(gmp_powm($y,2,$pq),$c),$pq);
			for($i = 0;$i < gmp_intval($r);$i++):
				$y = gmp_mod(gmp_add(gmp_powm($y,2,$pq),$c),$pq);
			endfor;
			$k = gmp_init(0);
			while(gmp_cmp($k,$r) < 0 and gmp_cmp($g,1) == 0):
				for($i = 0; $i < gmp_intval(gmp_sub($r,$k)); $i++):
					$y = gmp_mod(gmp_add(gmp_mul($y,$y),$c),$pq);
					$q = gmp_mod(gmp_mul($q,gmp_abs(gmp_sub($x,$y))),$pq);
				endfor;
				$g = self::gcd($q,$pq);
				$k = gmp_add($k,$r);
			endwhile;
			$r = gmp_mul($r,2);
		endwhile;
		if(gmp_cmp($g,$pq) == 0):
			while(true):
				$y = gmp_mod(gmp_add(gmp_mul($y,$y),$c),$pq);
				$g = self::gcd(gmp_abs(gmp_sub($x,$y)),$pq);
				if(gmp_cmp($g,1) > 0) break;
			endwhile;
		endif;
		$p = gmp_div($pq,$g);
		return intval(min($p,$g));
	}
	static public function find(int $what) : int {
		$g = 0;
		for($i = 0;$i < 3;$i++):
			$q = (rand(0,127) & 15) + 17;
			$x = rand(0,1000000000) + 1;
			$y = $x;
			$limit = 1 << ($i + 18);
			for($j = 1;$j < $limit;$j++):
				$a = $b = $c = $x;
				$x = self::mul($a,$b,$c,$what);
				$z = ($x < $y) ? $y - $x : $x - $y;
				$g = self::gcd($z,$what);
				if($g != 1) break;
				if(($j & ($j - 1)) == 0) $y = $x;
			endfor;
			if($g > 1) break;
		endfor;
		$p = $what / $g;
		return intval(min($p,$g));
	}
	static public function mul(int $a,int $b,int $c,int $what) : int {
		while($b != 0):
			if(($b & 1) != 0):
				$c += $a;
				if($c >= $what) $c -= $what;
			endif;
			$a += $a;
			if($a >= $what) $a -= $what;
			$b >>= 1;
		endwhile;
		return $c;
	}
	static public function gcd(int | string | \GMP $a,int | string | \GMP $b) : mixed {
		if(extension_loaded('gmp')):
			return gmp_gcd($a,$b);
		else:
			while($a != 0 and $b != 0):
				while(($b & 1) == 0):
					$b >>= 1;
				endwhile;
				while(($a & 1) == 0):
					$a >>= 1;
				endwhile;
				if($a > $b):
					$a -= $b;
				else:
					$b -= $a;
				endif;
			endwhile;
			return ($b == 0) ? $a : $b;
		endif;
	}
	static public function factorize(int $pq) : array {
		if(is_callable('tg_factorize')):
			return array_values(tg_factorize($pq));
		elseif(extension_loaded('gmp')):
			$divisor = self::decompose($pq);
		else:
			$divisor = self::find($pq);
		endif;
		return [$divisor,$pq / $divisor];
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Crypto;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Tools;

use Tak\Liveproto\Enums\ProtocolType;

use phpseclib3\Crypt\AES;

final class Obfuscation {
	private AES $encryptor;
	private AES $decryptor;
	public readonly string $init;

	public function __construct(public ProtocolType $protocol,public int $dc_id,public bool $test_mode = false,public bool $media_only = false,public ? string $secret = null){
		do {
			# init := (56 random bytes) + protocol + dc + (2 random bytes) #
			$init = random_bytes(56).$protocol->toBytes().Helper::pack('v',($media_only ? -1 : +1) * (abs($dc_id) + ($test_mode ? 10000 : 0))).random_bytes(2);
			$first_int = Helper::unpack('V',substr($init,0,4));
			$second_int = Helper::unpack('V',substr($init,4,4));
		} while(in_array($first_int,[0x44414548,0x54534f50,0x20544547,0x4954504f,0xdddddddd,0xeeeeeeee,0x02010316],true) or substr($init,0,1) === chr(0xef) or $second_int === 0x00000000);
		$encryptKey = substr($init,8,32);
		$encryptIV = substr($init,40,16);
		$reversed = strrev($init);
		$decryptKey = substr($reversed,8,32);
		$decryptIV = substr($reversed,40,16);
		$keyRev = substr($reversed,8,32);
		if(is_string($secret)):
			$secret = self::truncate(self::fromLink($secret));
			$encryptKey = hash('sha256',$encryptKey.$secret,true);
			$decryptKey = hash('sha256',$decryptKey.$secret,true);
		endif;
		$this->encryptor = new AES('ctr');
		$this->encryptor->enableContinuousBuffer();
		$this->encryptor->setKey($encryptKey);
		$this->encryptor->setIV($encryptIV);
		$this->decryptor = new AES('ctr');
		$this->decryptor->enableContinuousBuffer();
		$this->decryptor->setKey($decryptKey);
		$this->decryptor->setIV($decryptIV);
		$encrypted = $this->encrypt($init);
		$this->init = substr_replace($init,substr($encrypted,56,8),56,8);
	}
	public function encrypt(string $plaintext) : string | false {
		return $this->encryptor->encrypt($plaintext);
	}
	public function decrypt(string $ciphertext) : string | false {
		return $this->decryptor->encrypt($ciphertext);
	}
	static public function truncate(string $binary) : string {
		if(strlen($binary) === 16):
			return $binary;
		elseif(strlen($binary) === 17 and substr($binary,0,1) === chr(0xdd)):
			return substr($binary,1,16);
		elseif(strlen($binary) >= 18 and substr($binary,0,1) === chr(0xee)):
			return substr($binary,1,16);
		else:
			throw new \InvalidArgumentException('Your binary secret is invalid !');
		endif;
	}
	static public function fromLink(string $secret) : string {
		if(ctype_xdigit($secret)):
			return hex2bin($secret);
		else:
			$bytes = Tools::base64_url_decode($secret);
			if(strlen($bytes) > 17 and strcasecmp($secret,'ee') === 1):
				return chr(0xee).substr($bytes,1);
			else:
				return $bytes;
			endif;
		endif;
	}
	static public function toLink(string $secret) : string {
		if(self::emulateTls($secret)):
			return Tools::base64_url_encode($secret);
		else:
			return bin2hex($secret);
		endif;
	}
	static public function emulateTls(string $secret) : bool {
		return boolval(strlen($secret) >= 17 and substr($secret,0,1) === chr(0xee));
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Crypto;

abstract class Rle {
	static public function decode(string $string) : string {
		$new = strval(null);
		$last = strval(null);
		$null = chr(0);
		foreach(str_split($string) as $cur):
			if($last === $null):
				$new .= str_repeat($last,ord($cur));
				$last = strval(null);
			else:
				$new .= $last;
				$last = $cur;
			endif;
		endforeach;
		return strval($new.$last);
	}
	static public function encode(string $string) : string {
		$new = strval(null);
		$count = 0;
		$null = chr(0);
		foreach(str_split($string) as $cur):
			if($cur === $null):
				$count++;
			else:
				if ($count > 0):
					$new .= $null.chr($count);
					$count = 0;
				endif;
				$new .= $cur;
			endif;
		endforeach;
		if($count > 0) $new .= $null.chr($count);
		return $new;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Crypto;

use Tak\Liveproto\Utils\Binary;

readonly final class AuthKey {
	public string $key;
	public int $auxHash;
	public int $id;

	public function __construct(string $gab,public int $expires_at){
		$this->key = gmp_export($gab);
		$reader = new Binary();
		$reader->write(sha1($this->key,true));
		$this->auxHash = $reader->readLong();
		$reader->read(4);
		$this->id = $reader->readLong();
	}
	public function calcNewNonceHash(string $newNonce,int $nonceNumber) : string {
		$writer = new Binary();
		$writer->write($newNonce);
		$writer->writeByte($nonceNumber);
		$writer->writeLong($this->auxHash);
		$newNonceHash = substr(sha1($writer->read(),true),4);
		$writer->write($newNonceHash);
		return $writer->readLargeInt(128);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Crypto;

use Tak\Liveproto\Errors\Security;

use Tak\Attributes\AttributesEngine;

use Tak\Liveproto\Attributes\Type;

final class Password {
	use AttributesEngine;

	protected function srp(#[Type('account.Password')] object $request,string $password) : object {
		$algo = $request->current_algo;
		$g = $algo->g;
		$p = gmp_import($algo->p);
		Security::checkGoodPrime($p,$g);
		$salt1 = $algo->salt1;
		$salt2 = $algo->salt2;
		$b = gmp_import($request->srp_B);
		$k = gmp_import($this->h($this->str($algo->p).$this->str($g)));
		$x = gmp_import($this->ph2($password,$salt1,$salt2));
		$v = gmp_powm($g,$x,$p);
		$k_v = gmp_mod(gmp_mul($k,$v),$p);
		$a = gmp_import($this->xor(random_bytes(0x100),$request->secure_random));
		$g_a = gmp_powm($g,$a,$p);
		Security::checkG(strval($g_a),$p,true);
		$u = gmp_import($this->h($this->str($g_a).$this->str($request->srp_B)));
		$g_b = gmp_mod(gmp_sub($b,$k_v),$p);
		Security::checkG(strval($g_b),$p,true);
		$s_a = gmp_powm($g_b,gmp_add($a,gmp_mul($u,$x)),$p);
		$k_a = $this->h($this->str($s_a));
		$m1 = $this->h($this->xor($this->h($this->str($algo->p)),$this->h($this->str($g))).$this->h($salt1).$this->h($salt2).$this->str($g_a).$this->str($request->srp_B).$k_a);
		$method = new \Tak\Liveproto\Tl\Types\Other\InputCheckPasswordSRP;
		return $method->request(srp_id : $request->srp_id,A : $this->str($g_a),M1 : $m1);
	}
	protected function digest(#[Type('account.Password')] object $request,string $password) : string {
		$algo = $request->new_algo;
		$g = $algo->g;
		$p = gmp_import($algo->p);
		$salt1 = $algo->salt1;
		$salt2 = $algo->salt2;
		$x = gmp_import($this->ph2($password,$salt1,$salt2));
		$v = gmp_powm($g,$x,$p);
		return $this->str($v);
	}
	private function str(int | string | \GMP $number) : string {
		return str_pad(is_string($number) ? $number : gmp_export($number),0x100,chr(0),STR_PAD_LEFT);
	}
	private function ph1(string $password,string $salt1,string $salt2) : string {
		return $this->sh($this->sh($password,$salt1),$salt2);
	}
	private function ph2(string $password,string $salt1,string $salt2) : string {
		return $this->sh(hash_pbkdf2('sha512',$this->ph1($password,$salt1,$salt2),$salt1,100000,0,true),$salt2);
	}
	private function sh(string $data,string $salt) : string {
		return $this->h($salt.$data.$salt);
	}
	private function h(string $data) : string {
		return hash('sha256',$data,true);
	}
	private function xor(string $a,string $b) : string {
		return $a ^ $b;
	}
}

?>{
    "2FA_CONFIRM_WAIT_%d": "Since this account is active and protected by a 2FA password, we will delete it in 1 week for security purposes. You can cancel this process at any time, you'll be able to reset your account in %d seconds.",
    "ABOUT_TOO_LONG": "About string too long.",
    "ACCESS_TOKEN_EXPIRED": "Access token expired.",
    "ACCESS_TOKEN_INVALID": "Access token invalid.",
    "AD_EXPIRED": "The ad has expired (too old or not found).",
    "ADDRESS_INVALID": "The specified geopoint address is invalid.",
    "ADMIN_ID_INVALID": "The specified admin ID is invalid.",
    "ADMIN_RANK_EMOJI_NOT_ALLOWED": "An admin rank cannot contain emojis.",
    "ADMIN_RANK_INVALID": "The specified admin rank is invalid.",
    "ADMIN_RIGHTS_EMPTY": "The chatAdminRights constructor passed in keyboardButtonRequestPeer.peer_type.user_admin_rights has no rights set (i.e. flags is 0).",
    "ADMINS_TOO_MUCH": "There are too many admins.",
    "ALBUM_PHOTOS_TOO_MANY": "You have uploaded too many profile photos, delete some before retrying.",
    "ANONYMOUS_REACTIONS_DISABLED": "Sorry, anonymous administrators cannot leave reactions or participate in polls.",
    "API_ID_INVALID": "API ID invalid.",
    "API_ID_PUBLISHED_FLOOD": "This API id was published somewhere, you can't use it now.",
    "ARTICLE_TITLE_EMPTY": "The title of the article is empty.",
    "AUDIO_CONTENT_URL_EMPTY": "The remote URL specified in the content field is empty.",
    "AUDIO_TITLE_EMPTY": "An empty audio title was provided.",
    "AUTH_BYTES_INVALID": "The provided authorization is invalid.",
    "AUTH_KEY_DUPLICATED": "Concurrent usage of the current session from multiple connections was detected, the current session was invalidated by the server for security reasons!",
    "AUTH_KEY_INVALID": "The specified auth key is invalid.",
    "AUTH_KEY_PERM_EMPTY": "The method is unavailable for temporary authorization keys, not bound to a permanent authorization key.",
    "AUTH_KEY_UNREGISTERED": "The specified authorization key is not registered in the system (for example, a PFS temporary key has expired).",
    "AUTH_KEY_UNSYNCHRONIZED": "Internal error, please repeat the method call.",
    "AUTH_RESTART": "Restart the authorization process.",
    "AUTH_RESTART_%d": "Internal error (debug info %d), please repeat the method call.",
    "AUTH_TOKEN_ALREADY_ACCEPTED": "The specified auth token was already accepted.",
    "AUTH_TOKEN_EXCEPTION": "An error occurred while importing the auth token.",
    "AUTH_TOKEN_EXPIRED": "The authorization token has expired.",
    "AUTH_TOKEN_INVALID": "The specified auth token is invalid.",
    "AUTH_TOKEN_INVALIDX": "The specified auth token is invalid.",
    "AUTOARCHIVE_NOT_AVAILABLE": "The autoarchive setting is not available at this time: please check the value of the [autoarchive_setting_available field in client config &raquo;](https:\/\/core.telegram.org\/api\/config#client-configuration) before calling this method.",
    "BALANCE_TOO_LOW": "The transaction cannot be completed because the current [Telegram Stars balance](https:\/\/core.telegram.org\/api\/stars) is too low.",
    "BANK_CARD_NUMBER_INVALID": "The specified card number is invalid.",
    "BANNED_RIGHTS_INVALID": "You provided some invalid flags in the banned rights.",
    "BIRTHDAY_INVALID": "An invalid age was specified, must be between 0 and 150 years.",
    "BOOST_NOT_MODIFIED": "You're already [boosting](https:\/\/core.telegram.org\/api\/boost) the specified channel.",
    "BOOST_PEER_INVALID": "The specified `boost_peer` is invalid.",
    "BOOSTS_EMPTY": "No boost slots were specified.",
    "BOOSTS_REQUIRED": "The specified channel must first be [boosted by its users](https:\/\/core.telegram.org\/api\/boost) in order to perform this action.",
    "BOT_ALREADY_DISABLED": "The connected business bot was already disabled for the specified peer.",
    "BOT_APP_BOT_INVALID": "The bot_id passed in the inputBotAppShortName constructor is invalid.",
    "BOT_APP_INVALID": "The specified bot app is invalid.",
    "BOT_APP_SHORTNAME_INVALID": "The specified bot app short name is invalid.",
    "BOT_BUSINESS_MISSING": "The specified bot is not a business bot (the [user](https:\/\/core.telegram.org\/constructor\/user).`bot_business` flag is not set).",
    "BOT_CHANNELS_NA": "Bots can't edit admin privileges.",
    "BOT_COMMAND_DESCRIPTION_INVALID": "The specified command description is invalid.",
    "BOT_COMMAND_INVALID": "The specified command is invalid.",
    "BOT_DOMAIN_INVALID": "Bot domain invalid.",
    "BOT_GAMES_DISABLED": "Games can't be sent to channels.",
    "BOT_GROUPS_BLOCKED": "This bot can't be added to groups.",
    "BOT_INLINE_DISABLED": "This bot can't be used in inline mode.",
    "BOT_INVALID": "This is not a valid bot.",
    "BOT_INVOICE_INVALID": "The specified invoice is invalid.",
    "BOT_METHOD_INVALID": "The specified method cannot be used by bots.",
    "BOT_NOT_CONNECTED_YET": "No [business bot](https:\/\/core.telegram.org\/api\/business#connected-bots) is connected to the currently logged in user.",
    "BOT_ONESIDE_NOT_AVAIL": "Bots can't pin messages in PM just for themselves.",
    "BOT_PAYMENTS_DISABLED": "Please enable bot payments in botfather before calling this method.",
    "BOT_RESPONSE_TIMEOUT": "A timeout occurred while fetching data from the bot.",
    "BOT_SCORE_NOT_MODIFIED": "The score wasn't modified.",
    "BOT_WEBVIEW_DISABLED": "A webview cannot be opened in the specified conditions: emitted for example if `from_bot_menu` or `url` are set and `peer` is not the chat with the bot.",
    "BOTS_TOO_MUCH": "There are too many bots in this chat\/channel.",
    "BROADCAST_FORBIDDEN": "Channel poll voters and reactions cannot be fetched to prevent deanonymization.",
    "BROADCAST_ID_INVALID": "Broadcast ID invalid.",
    "BROADCAST_PUBLIC_VOTERS_FORBIDDEN": "You can't forward polls with public voters.",
    "BROADCAST_REQUIRED": "This method can only be called on a channel, please use stats.getMegagroupStats for supergroups.",
    "BUSINESS_ADDRESS_ACTIVE": "The user is currently advertising a [Business Location](https:\/\/core.telegram.org\/api\/business#location), the location may only be changed (or removed) using [account.updateBusinessLocation &raquo;](https:\/\/core.telegram.org\/method\/account.updateBusinessLocation).  .",
    "BUSINESS_PEER_INVALID": "Messages can't be set to the specified peer through the current [business connection](https:\/\/core.telegram.org\/api\/business#connected-bots).",
    "BUSINESS_PEER_USAGE_MISSING": "You cannot send a message to a user through a [business connection](https:\/\/core.telegram.org\/api\/business#connected-bots) if the user hasn't recently contacted us.",
    "BUSINESS_RECIPIENTS_EMPTY": "You didn't set any flag in inputBusinessBotRecipients, thus the bot cannot work with *any* peer.",
    "BUSINESS_WORK_HOURS_EMPTY": "No work hours were specified.",
    "BUSINESS_WORK_HOURS_PERIOD_INVALID": "The specified work hours are invalid, see [here &raquo;](https:\/\/core.telegram.org\/api\/business#opening-hours) for the exact requirements.",
    "BUTTON_COPY_TEXT_INVALID": "The specified [keyboardButtonCopy](https:\/\/core.telegram.org\/constructor\/keyboardButtonCopy).`copy_text` is invalid.",
    "BUTTON_DATA_INVALID": "The data of one or more of the buttons you provided is invalid.",
    "BUTTON_ID_INVALID": "The specified button ID is invalid.",
    "BUTTON_POS_INVALID": "The position of one of the keyboard buttons is invalid (i.e. a Game or Pay button not in the first position, and so on...).",
    "BUTTON_TEXT_INVALID": "The specified button text is invalid.",
    "BUTTON_TYPE_INVALID": "The type of one or more of the buttons you provided is invalid.",
    "BUTTON_URL_INVALID": "Button URL invalid.",
    "BUTTON_USER_INVALID": "The `user_id` passed to inputKeyboardButtonUserProfile is invalid!",
    "BUTTON_USER_PRIVACY_RESTRICTED": "The privacy setting of the user specified in a [inputKeyboardButtonUserProfile](https:\/\/core.telegram.org\/constructor\/inputKeyboardButtonUserProfile) button do not allow creating such a button.",
    "CALL_ALREADY_ACCEPTED": "The call was already accepted.",
    "CALL_ALREADY_DECLINED": "The call was already declined.",
    "CALL_OCCUPY_FAILED": "The call failed because the user is already making another call.",
    "CALL_PEER_INVALID": "The provided call peer object is invalid.",
    "CALL_PROTOCOL_COMPAT_LAYER_INVALID": "The other side of the call does not support any of the VoIP protocols supported by the local client, as specified by the `protocol.layer` and `protocol.library_versions` fields.",
    "CALL_PROTOCOL_FLAGS_INVALID": "Call protocol flags invalid.",
    "CDN_METHOD_INVALID": "You can't call this method in a CDN DC.",
    "CDN_UPLOAD_TIMEOUT": "A server-side timeout occurred while reuploading the file to the CDN DC.",
    "CHANNEL_FORUM_MISSING": "This supergroup is not a forum.",
    "CHANNEL_ID_INVALID": "The specified supergroup ID is invalid.",
    "CHANNEL_INVALID": "The provided channel is invalid.",
    "CHANNEL_PARICIPANT_MISSING": "The current user is not in the channel.",
    "CHANNEL_PRIVATE": "You haven't joined this channel\/supergroup.",
    "CHANNEL_PUBLIC_GROUP_NA": "channel\/supergroup not available.",
    "CHANNEL_TOO_BIG": "This channel has too many participants (>1000) to be deleted.",
    "CHANNEL_TOO_LARGE": "Channel is too large to be deleted; this error is issued when trying to delete channels with more than 1000 members (subject to change).",
    "CHANNELS_ADMIN_LOCATED_TOO_MUCH": "The user has reached the limit of public geogroups.",
    "CHANNELS_ADMIN_PUBLIC_TOO_MUCH": "You're admin of too many public channels, make some channels private to change the username of this channel.",
    "CHANNELS_TOO_MUCH": "You have joined too many channels\/supergroups.",
    "CHARGE_ALREADY_REFUNDED": "The transaction was already refunded.",
    "CHAT_ABOUT_NOT_MODIFIED": "About text has not changed.",
    "CHAT_ABOUT_TOO_LONG": "Chat about too long.",
    "CHAT_ACTION_FORBIDDEN": "You cannot execute this action.",
    "CHAT_ADMIN_INVITE_REQUIRED": "You do not have the rights to do this.",
    "CHAT_ADMIN_REQUIRED": "You must be an admin in this chat to do this.",
    "CHAT_DISCUSSION_UNALLOWED": "You can't enable forum topics in a discussion group linked to a channel.",
    "CHAT_FORBIDDEN": "This chat is not available to the current user.",
    "CHAT_FORWARDS_RESTRICTED": "You can't forward messages from a protected chat.",
    "CHAT_GUEST_SEND_FORBIDDEN": "You join the discussion group before commenting, see [here &raquo;](https:\/\/core.telegram.org\/api\/discussion#requiring-users-to-join-the-group) for more info.",
    "CHAT_ID_EMPTY": "The provided chat ID is empty.",
    "CHAT_ID_GENERATE_FAILED": "Failure while generating the chat ID.",
    "CHAT_ID_INVALID": "The provided chat id is invalid.",
    "CHAT_INVALID": "Invalid chat.",
    "CHAT_INVITE_PERMANENT": "You can't set an expiration date on permanent invite links.",
    "CHAT_LINK_EXISTS": "The chat is public, you can't hide the history to new users.",
    "CHAT_MEMBER_ADD_FAILED": "Could not add participants.",
    "CHAT_NOT_MODIFIED": "No changes were made to chat information because the new information you passed is identical to the current information.",
    "CHAT_PUBLIC_REQUIRED": "You can only enable join requests in public groups.",
    "CHAT_RESTRICTED": "You can't send messages in this chat, you were restricted.",
    "CHAT_REVOKE_DATE_UNSUPPORTED": "`min_date` and `max_date` are not available for using with non-user peers.",
    "CHAT_SEND_AUDIOS_FORBIDDEN": "You can't send audio messages in this chat.",
    "CHAT_SEND_DOCS_FORBIDDEN": "You can't send documents in this chat.",
    "CHAT_SEND_GAME_FORBIDDEN": "You can't send a game to this chat.",
    "CHAT_SEND_GIFS_FORBIDDEN": "You can't send gifs in this chat.",
    "CHAT_SEND_INLINE_FORBIDDEN": "You can't send inline messages in this group.",
    "CHAT_SEND_MEDIA_FORBIDDEN": "You can't send media in this chat.",
    "CHAT_SEND_PHOTOS_FORBIDDEN": "You can't send photos in this chat.",
    "CHAT_SEND_PLAIN_FORBIDDEN": "You can't send non-media (text) messages in this chat.",
    "CHAT_SEND_POLL_FORBIDDEN": "You can't send polls in this chat.",
    "CHAT_SEND_ROUNDVIDEOS_FORBIDDEN": "You can't send round videos to this chat.",
    "CHAT_SEND_STICKERS_FORBIDDEN": "You can't send stickers in this chat.",
    "CHAT_SEND_VIDEOS_FORBIDDEN": "You can't send videos in this chat.",
    "CHAT_SEND_VOICES_FORBIDDEN": "You can't send voice recordings in this chat.",
    "CHAT_TITLE_EMPTY": "No chat title provided.",
    "CHAT_TOO_BIG": "This method is not available for groups with more than `chat_read_mark_size_threshold` members, [see client configuration &raquo;](https:\/\/core.telegram.org\/api\/config#client-configuration).",
    "CHAT_TYPE_INVALID": "The specified user type is invalid.",
    "CHAT_WRITE_FORBIDDEN": "You can't write in this chat.",
    "CHATLINK_SLUG_EMPTY": "The specified slug is empty.",
    "CHATLINK_SLUG_EXPIRED": "The specified [business chat link](https:\/\/core.telegram.org\/api\/business#business-chat-links) has expired.",
    "CHATLINKS_TOO_MUCH": "Too many [business chat links](https:\/\/core.telegram.org\/api\/business#business-chat-links) were created, please delete some older links.",
    "CHATLIST_EXCLUDE_INVALID": "The specified `exclude_peers` are invalid.",
    "CHATLISTS_TOO_MUCH": "You have created too many folder links, hitting the `chatlist_invites_limit_default`\/`chatlist_invites_limit_premium` [limits &raquo;](https:\/\/core.telegram.org\/api\/config#chatlist-invites-limit-default).",
    "CODE_EMPTY": "The provided code is empty.",
    "CODE_HASH_INVALID": "Code hash invalid.",
    "CODE_INVALID": "Code invalid.",
    "COLLECTIBLE_INVALID": "The specified collectible is invalid.",
    "COLLECTIBLE_NOT_FOUND": "The specified collectible could not be found.",
    "COLOR_INVALID": "The specified color palette ID was invalid.",
    "CONNECTION_API_ID_INVALID": "The provided API id is invalid.",
    "CONNECTION_APP_VERSION_EMPTY": "App version is empty.",
    "CONNECTION_DEVICE_MODEL_EMPTY": "The specified device model is empty.",
    "CONNECTION_ID_INVALID": "The specified connection ID is invalid.",
    "CONNECTION_LANG_PACK_INVALID": "The specified language pack is empty.",
    "CONNECTION_LAYER_INVALID": "Layer invalid.",
    "CONNECTION_NOT_INITED": "Please initialize the connection using initConnection before making queries.",
    "CONNECTION_SYSTEM_EMPTY": "The specified system version is empty.",
    "CONNECTION_SYSTEM_LANG_CODE_EMPTY": "The specified system language code is empty.",
    "CONTACT_ADD_MISSING": "Contact to add is missing.",
    "CONTACT_ID_INVALID": "The provided contact ID is invalid.",
    "CONTACT_MISSING": "The specified user is not a contact.",
    "CONTACT_NAME_EMPTY": "Contact name empty.",
    "CONTACT_REQ_MISSING": "Missing contact request.",
    "CREATE_CALL_FAILED": "An error occurred while creating the call.",
    "CURRENCY_TOTAL_AMOUNT_INVALID": "The total amount of all prices is invalid.",
    "CUSTOM_REACTIONS_TOO_MANY": "Too many custom reactions were specified.",
    "DATA_INVALID": "Encrypted data invalid.",
    "DATA_JSON_INVALID": "The provided JSON data is invalid.",
    "DATA_TOO_LONG": "Data too long.",
    "DATE_EMPTY": "Date empty.",
    "DC_ID_INVALID": "The provided DC ID is invalid.",
    "DH_G_A_INVALID": "g_a invalid.",
    "DOCUMENT_INVALID": "The specified document is invalid.",
    "EDIT_BOT_INVITE_FORBIDDEN": "Normal users can't edit invites that were created by bots.",
    "EMAIL_HASH_EXPIRED": "Email hash expired.",
    "EMAIL_INVALID": "The specified email is invalid.",
    "EMAIL_NOT_ALLOWED": "The specified email cannot be used to complete the operation.",
    "EMAIL_NOT_SETUP": "In order to change the login email with emailVerifyPurposeLoginChange, an existing login email must already be set using emailVerifyPurposeLoginSetup.",
    "EMAIL_UNCONFIRMED": "Email unconfirmed.",
    "EMAIL_UNCONFIRMED_%d": "The provided email isn't confirmed, %d is the length of the verification code that was just sent to the email: use [account.verifyEmail](https:\/\/core.telegram.org\/method\/account.verifyEmail) to enter the received verification code and enable the recovery email.",
    "EMAIL_VERIFY_EXPIRED": "The verification email has expired.",
    "EMOJI_INVALID": "The specified theme emoji is valid.",
    "EMOJI_MARKUP_INVALID": "The specified `video_emoji_markup` was invalid.",
    "EMOJI_NOT_MODIFIED": "The theme wasn't changed.",
    "EMOTICON_EMPTY": "The emoji is empty.",
    "EMOTICON_INVALID": "The specified emoji is invalid.",
    "EMOTICON_STICKERPACK_MISSING": "inputStickerSetDice.emoji cannot be empty.",
    "ENCRYPTED_MESSAGE_INVALID": "Encrypted message invalid.",
    "ENCRYPTION_ALREADY_ACCEPTED": "Secret chat already accepted.",
    "ENCRYPTION_ALREADY_DECLINED": "The secret chat was already declined.",
    "ENCRYPTION_DECLINED": "The secret chat was declined.",
    "ENCRYPTION_ID_INVALID": "The provided secret chat ID is invalid.",
    "ENTITIES_TOO_LONG": "You provided too many styled message entities.",
    "ENTITY_BOUNDS_INVALID": "A specified [entity offset or length](https:\/\/core.telegram.org\/api\/entities#entity-length) is invalid, see [here &raquo;](https:\/\/core.telegram.org\/api\/entities#entity-length) for info on how to properly compute the entity offset\/length.",
    "ENTITY_MENTION_USER_INVALID": "You mentioned an invalid user.",
    "ERROR_TEXT_EMPTY": "The provided error message is empty.",
    "EXPIRE_DATE_INVALID": "The specified expiration date is invalid.",
    "EXPORT_CARD_INVALID": "Provided card is invalid.",
    "EXTENDED_MEDIA_AMOUNT_INVALID": "The specified `stars_amount` of the passed [inputMediaPaidMedia](https:\/\/core.telegram.org\/constructor\/inputMediaPaidMedia) is invalid.",
    "EXTERNAL_URL_INVALID": "External URL invalid.",
    "FILE_CONTENT_TYPE_INVALID": "File content-type is invalid.",
    "FILE_EMTPY": "An empty file was provided.",
    "FILE_ID_INVALID": "The provided file id is invalid.",
    "FILE_MIGRATE_%d": "The file currently being accessed is stored in DC %d, please re-send the query to that DC.",
    "FILE_PART_%d_MISSING": "Part %d of the file is missing from storage. Try repeating the method call to resave the part.",
    "FILE_PART_EMPTY": "The provided file part is empty.",
    "FILE_PART_INVALID": "The file part number is invalid.",
    "FILE_PART_LENGTH_INVALID": "The length of a file part is invalid.",
    "FILE_PART_SIZE_CHANGED": "Provided file part size has changed.",
    "FILE_PART_SIZE_INVALID": "The provided file part size is invalid.",
    "FILE_PART_TOO_BIG": "The uploaded file part is too big.",
    "FILE_PART_TOO_SMALL": "The size of the uploaded file part is too small, please see the documentation for the allowed sizes.",
    "FILE_PARTS_INVALID": "The number of file parts is invalid.",
    "FILE_REFERENCE_%d_EXPIRED": "The file reference of the media file at index %d in the passed media array expired, it [must be refreshed](https:\/\/core.telegram.org\/api\/file_reference).",
    "FILE_REFERENCE_%d_INVALID": "The file reference of the media file at index %d in the passed media array is invalid.",
    "FILE_REFERENCE_EMPTY": "An empty [file reference](https:\/\/core.telegram.org\/api\/file_reference) was specified.",
    "FILE_REFERENCE_EXPIRED": "File reference expired, it must be refetched as described in [the documentation](https:\/\/core.telegram.org\/api\/file_reference).",
    "FILE_REFERENCE_INVALID": "The specified [file reference](https:\/\/core.telegram.org\/api\/file_reference) is invalid.",
    "FILE_TITLE_EMPTY": "An empty file title was specified.",
    "FILE_TOKEN_INVALID": "The master DC did not accept the `file_token` (e.g., the token has expired). Continue downloading the file from the master DC using upload.getFile.",
    "FILEREF_UPGRADE_NEEDED": "The client has to be updated in order to support [file references](https:\/\/core.telegram.org\/api\/file_reference).",
    "FILTER_ID_INVALID": "The specified filter ID is invalid.",
    "FILTER_INCLUDE_EMPTY": "The include_peers vector of the filter is empty.",
    "FILTER_NOT_SUPPORTED": "The specified filter cannot be used in this context.",
    "FILTER_TITLE_EMPTY": "The title field of the filter is empty.",
    "FIRSTNAME_INVALID": "The first name is invalid.",
    "FLOOD_PREMIUM_WAIT_%d": "Please wait %d seconds before repeating the action, or purchase a [Telegram Premium subscription](https:\/\/core.telegram.org\/api\/premium) to remove this rate limit.",
    "FLOOD_WAIT_%d": "Please wait %d seconds before repeating the action.",
    "FOLDER_ID_EMPTY": "An empty folder ID was specified.",
    "FOLDER_ID_INVALID": "Invalid folder ID.",
    "FORM_EXPIRED": "The form was generated more than 10 minutes ago and has expired, please re-generate it using [payments.getPaymentForm](https:\/\/core.telegram.org\/method\/payments.getPaymentForm) and pass the new `form_id`.",
    "FORM_ID_EMPTY": "The specified form ID is empty.",
    "FORM_UNSUPPORTED": "Please update your client.",
    "FORUM_ENABLED": "You can't execute the specified action because the group is a [forum](https:\/\/core.telegram.org\/api\/forum), disable forum functionality to continue.",
    "FRESH_CHANGE_ADMINS_FORBIDDEN": "You were just elected admin, you can't add or modify other admins yet.",
    "FRESH_CHANGE_PHONE_FORBIDDEN": "You can't change phone number right after logging in, please wait at least 24 hours.",
    "FRESH_RESET_AUTHORISATION_FORBIDDEN": "You can't logout other sessions if less than 24 hours have passed since you logged on the current session.",
    "FROM_MESSAGE_BOT_DISABLED": "Bots can't use fromMessage min constructors.",
    "FROM_PEER_INVALID": "The specified from_id is invalid.",
    "GAME_BOT_INVALID": "Bots can't send another bot's game.",
    "GENERAL_MODIFY_ICON_FORBIDDEN": "You can't modify the icon of the \"General\" topic.",
    "GEO_POINT_INVALID": "Invalid geoposition provided.",
    "GIF_CONTENT_TYPE_INVALID": "GIF content-type invalid.",
    "GIF_ID_INVALID": "The provided GIF ID is invalid.",
    "GIFT_SLUG_EXPIRED": "The specified gift slug has expired.",
    "GIFT_SLUG_INVALID": "The specified slug is invalid.",
    "GRAPH_EXPIRED_RELOAD": "This graph has expired, please obtain a new graph token.",
    "GRAPH_INVALID_RELOAD": "Invalid graph token provided, please reload the stats and provide the updated token.",
    "GRAPH_OUTDATED_RELOAD": "The graph is outdated, please get a new async token using stats.getBroadcastStats.",
    "GROUPCALL_ALREADY_DISCARDED": "The group call was already discarded.",
    "GROUPCALL_ALREADY_STARTED": "The groupcall has already started, you can join directly using [phone.joinGroupCall](https:\/\/core.telegram.org\/method\/phone.joinGroupCall).",
    "GROUPCALL_FORBIDDEN": "The group call has already ended.",
    "GROUPCALL_INVALID": "The specified group call is invalid.",
    "GROUPCALL_JOIN_MISSING": "You haven't joined this group call.",
    "GROUPCALL_NOT_MODIFIED": "Group call settings weren't modified.",
    "GROUPCALL_SSRC_DUPLICATE_MUCH": "The app needs to retry joining the group call with a new SSRC value.",
    "GROUPED_MEDIA_INVALID": "Invalid grouped media.",
    "HASH_INVALID": "The provided hash is invalid.",
    "HASHTAG_INVALID": "The specified hashtag is invalid.",
    "HIDE_REQUESTER_MISSING": "The join request was missing or was already handled.",
    "ID_EXPIRED": "The passed prepared inline message ID has expired.",
    "ID_INVALID": "The passed ID is invalid.",
    "IMAGE_PROCESS_FAILED": "Failure while processing image.",
    "IMPORT_FILE_INVALID": "The specified chat export file is invalid.",
    "IMPORT_FORMAT_DATE_INVALID": "The date specified in the import file is invalid.",
    "IMPORT_FORMAT_UNRECOGNIZED": "The specified chat export file was exported from an unsupported chat app.",
    "IMPORT_ID_INVALID": "The specified import ID is invalid.",
    "IMPORT_TOKEN_INVALID": "The specified token is invalid.",
    "INLINE_BOT_REQUIRED": "Only the inline bot can edit message.",
    "INLINE_RESULT_EXPIRED": "The inline query expired.",
    "INPUT_CHATLIST_INVALID": "The specified folder is invalid.",
    "INPUT_CONSTRUCTOR_INVALID": "The specified TL constructor is invalid.",
    "INPUT_FETCH_ERROR": "An error occurred while parsing the provided TL constructor.",
    "INPUT_FETCH_FAIL": "An error occurred while parsing the provided TL constructor.",
    "INPUT_FILE_INVALID": "The specified [InputFile](https:\/\/core.telegram.org\/type\/InputFile) is invalid.",
    "INPUT_FILTER_INVALID": "The specified filter is invalid.",
    "INPUT_LAYER_INVALID": "The specified layer is invalid.",
    "INPUT_METHOD_INVALID": "The specified method is invalid.",
    "INPUT_PEERS_EMPTY": "The specified peer array is empty.",
    "INPUT_REQUEST_TOO_LONG": "The request payload is too long.",
    "INPUT_TEXT_EMPTY": "The specified text is empty.",
    "INPUT_TEXT_TOO_LONG": "The specified text is too long.",
    "INPUT_USER_DEACTIVATED": "The specified user was deleted.",
    "INVITE_FORBIDDEN_WITH_JOINAS": "If the user has anonymously joined a group call as a channel, they can't invite other users to the group call because that would cause deanonymization, because the invite would be sent using the original user ID, not the anonymized channel ID.",
    "INVITE_HASH_EMPTY": "The invite hash is empty.",
    "INVITE_HASH_EXPIRED": "The invite link has expired.",
    "INVITE_HASH_INVALID": "The invite hash is invalid.",
    "INVITE_REQUEST_SENT": "You have successfully requested to join this chat or channel.",
    "INVITE_REVOKED_MISSING": "The specified invite link was already revoked or is invalid.",
    "INVITE_SLUG_EMPTY": "The specified invite slug is empty.",
    "INVITE_SLUG_EXPIRED": "The specified chat folder link has expired.",
    "INVITE_SLUG_INVALID": "The specified invitation slug is invalid.",
    "INVITES_TOO_MUCH": "The maximum number of per-folder invites specified by the `chatlist_invites_limit_default`\/`chatlist_invites_limit_premium` [client configuration parameters &raquo;](https:\/\/core.telegram.org\/api\/config#chatlist-invites-limit-default) was reached.",
    "INVOICE_PAYLOAD_INVALID": "The specified invoice payload is invalid.",
    "JOIN_AS_PEER_INVALID": "The specified peer cannot be used to join a group call.",
    "LANG_CODE_INVALID": "The specified language code is invalid.",
    "LANG_CODE_NOT_SUPPORTED": "The specified language code is not supported.",
    "LANG_PACK_INVALID": "The provided language pack is invalid.",
    "LANGUAGE_INVALID": "The specified lang_code is invalid.",
    "LASTNAME_INVALID": "The last name is invalid.",
    "LIMIT_INVALID": "The provided limit is invalid.",
    "LINK_NOT_MODIFIED": "Discussion link not modified.",
    "LOCATION_INVALID": "The provided location is invalid.",
    "MAX_DATE_INVALID": "The specified maximum date is invalid.",
    "MAX_ID_INVALID": "The provided max ID is invalid.",
    "MAX_QTS_INVALID": "The specified max_qts is invalid.",
    "MD5_CHECKSUM_INVALID": "The MD5 checksums do not match.",
    "MEDIA_CAPTION_TOO_LONG": "The caption is too long.",
    "MEDIA_EMPTY": "The provided media object is invalid.",
    "MEDIA_FILE_INVALID": "The specified media file is invalid.",
    "MEDIA_GROUPED_INVALID": "You tried to send media of different types in an album.",
    "MEDIA_INVALID": "Media invalid.",
    "MEDIA_NEW_INVALID": "The new media is invalid.",
    "MEDIA_PREV_INVALID": "Previous media invalid.",
    "MEDIA_TTL_INVALID": "The specified media TTL is invalid.",
    "MEDIA_TYPE_INVALID": "The specified media type cannot be used in stories.",
    "MEDIA_VIDEO_STORY_MISSING": "A non-story video cannot be repubblished as a story (emitted when trying to resend a non-story video as a story using inputDocument).",
    "MEGAGROUP_GEO_REQUIRED": "This method can only be invoked on a geogroup.",
    "MEGAGROUP_ID_INVALID": "Invalid supergroup ID.",
    "MEGAGROUP_PREHISTORY_HIDDEN": "Group with hidden history for new members can't be set as discussion groups.",
    "MEGAGROUP_REQUIRED": "You can only use this method on a supergroup.",
    "MESSAGE_AUTHOR_REQUIRED": "Message author required.",
    "MESSAGE_DELETE_FORBIDDEN": "You can't delete one of the messages you tried to delete, most likely because it is a service message.",
    "MESSAGE_EDIT_TIME_EXPIRED": "You can't edit this message anymore, too much time has passed since its creation.",
    "MESSAGE_EMPTY": "The provided message is empty.",
    "MESSAGE_ID_INVALID": "The provided message id is invalid.",
    "MESSAGE_IDS_EMPTY": "No message ids were provided.",
    "MESSAGE_NOT_MODIFIED": "The provided message data is identical to the previous message data, the message wasn't modified.",
    "MESSAGE_NOT_READ_YET": "The specified message wasn't read yet.",
    "MESSAGE_POLL_CLOSED": "Poll closed.",
    "MESSAGE_TOO_LONG": "The provided message is too long.",
    "MESSAGE_TOO_OLD": "The message is too old, the requested information is not available.",
    "METHOD_INVALID": "The specified method is invalid.",
    "MIN_DATE_INVALID": "The specified minimum date is invalid.",
    "MSG_ID_INVALID": "Invalid message ID provided.",
    "MSG_TOO_OLD": "[`chat_read_mark_expire_period` seconds](https:\/\/core.telegram.org\/api\/config#chat-read-mark-expire-period) have passed since the message was sent, read receipts were deleted.",
    "MSG_WAIT_FAILED": "A waiting call returned an error.",
    "MSG_WAIT_TIMEOUT": "Spent too much time waiting for a previous query in the invokeAfterMsg request queue, aborting!",
    "MULTI_MEDIA_TOO_LONG": "Too many media files for album.",
    "NETWORK_MIGRATE_%d": "Your IP address is associated to DC %d, please re-send the query to that DC.",
    "NEW_SALT_INVALID": "The new salt is invalid.",
    "NEW_SETTINGS_EMPTY": "No password is set on the current account, and no new password was specified in `new_settings`.",
    "NEW_SETTINGS_INVALID": "The new password settings are invalid.",
    "NEXT_OFFSET_INVALID": "The specified offset is longer than 64 bytes.",
    "NOT_ELIGIBLE": "The current user is not eligible to join the Peer-to-Peer Login Program.",
    "NOT_JOINED": "The current user hasn't joined the Peer-to-Peer Login Program.",
    "OFFSET_INVALID": "The provided offset is invalid.",
    "OFFSET_PEER_ID_INVALID": "The provided offset peer is invalid.",
    "OPTION_INVALID": "Invalid option selected.",
    "OPTIONS_TOO_MUCH": "Too many options provided.",
    "ORDER_INVALID": "The specified username order is invalid.",
    "PACK_SHORT_NAME_INVALID": "Short pack name invalid.",
    "PACK_SHORT_NAME_OCCUPIED": "A stickerpack with this name already exists.",
    "PACK_TITLE_INVALID": "The stickerpack title is invalid.",
    "PARTICIPANT_ID_INVALID": "The specified participant ID is invalid.",
    "PARTICIPANT_JOIN_MISSING": "Trying to enable a presentation, when the user hasn't joined the Video Chat with [phone.joinGroupCall](https:\/\/core.telegram.org\/method\/phone.joinGroupCall).",
    "PARTICIPANT_VERSION_OUTDATED": "The other participant does not use an up to date telegram client with support for calls.",
    "PARTICIPANTS_TOO_FEW": "Not enough participants.",
    "PASSWORD_EMPTY": "The provided password is empty.",
    "PASSWORD_HASH_INVALID": "The provided password hash is invalid.",
    "PASSWORD_MISSING": "You must [enable 2FA](https:\/\/core.telegram.org\/api\/srp) before executing this operation.",
    "PASSWORD_RECOVERY_EXPIRED": "The recovery code has expired.",
    "PASSWORD_RECOVERY_NA": "No email was set, can't recover password via email.",
    "PASSWORD_REQUIRED": "A [2FA password](https:\/\/core.telegram.org\/api\/srp) must be configured to use Telegram Passport.",
    "PASSWORD_TOO_FRESH_%d": "The password was modified less than 24 hours ago, try again in %d seconds.",
    "PAYMENT_PROVIDER_INVALID": "The specified payment provider is invalid.",
    "PAYMENT_UNSUPPORTED": "A detailed description of the error will be received separately as described [here &raquo;](https:\/\/core.telegram.org\/api\/errors#406-not-acceptable).",
    "PEER_FLOOD": "The current account is spamreported, you cannot execute this action, check @spambot for more info.",
    "PEER_HISTORY_EMPTY": "You can't pin an empty chat with a user.",
    "PEER_ID_INVALID": "The provided peer id is invalid.",
    "PEER_ID_NOT_SUPPORTED": "The provided peer ID is not supported.",
    "PEER_TYPES_INVALID": "The passed [keyboardButtonSwitchInline](https:\/\/core.telegram.org\/constructor\/keyboardButtonSwitchInline).`peer_types` field is invalid.",
    "PEERS_LIST_EMPTY": "The specified list of peers is empty.",
    "PERSISTENT_TIMESTAMP_EMPTY": "Persistent timestamp empty.",
    "PERSISTENT_TIMESTAMP_INVALID": "Persistent timestamp invalid.",
    "PERSISTENT_TIMESTAMP_OUTDATED": "Channel internal replication issues, try again later (treat this like an RPC_CALL_FAIL).",
    "PHONE_CODE_EMPTY": "phone_code is missing.",
    "PHONE_CODE_EXPIRED": "The phone code you provided has expired.",
    "PHONE_CODE_HASH_EMPTY": "phone_code_hash is missing.",
    "PHONE_CODE_INVALID": "The provided phone code is invalid.",
    "PHONE_HASH_EXPIRED": "An invalid or expired `phone_code_hash` was provided.",
    "PHONE_MIGRATE_%d": "Your phone number is associated to DC %d, please re-send the query to that DC.",
    "PHONE_NOT_OCCUPIED": "No user is associated to the specified phone number.",
    "PHONE_NUMBER_APP_SIGNUP_FORBIDDEN": "You can't sign up using this app.",
    "PHONE_NUMBER_BANNED": "The provided phone number is banned from telegram.",
    "PHONE_NUMBER_FLOOD": "You asked for the code too many times.",
    "PHONE_NUMBER_INVALID": "The phone number is invalid.",
    "PHONE_NUMBER_OCCUPIED": "The phone number is already in use.",
    "PHONE_NUMBER_UNOCCUPIED": "The phone number is not yet being used.",
    "PHONE_PASSWORD_FLOOD": "You have tried logging in too many times.",
    "PHONE_PASSWORD_PROTECTED": "This phone is password protected.",
    "PHOTO_CONTENT_TYPE_INVALID": "Photo mime-type invalid.",
    "PHOTO_CONTENT_URL_EMPTY": "Photo URL invalid.",
    "PHOTO_CROP_FILE_MISSING": "Photo crop file missing.",
    "PHOTO_CROP_SIZE_SMALL": "Photo is too small.",
    "PHOTO_EXT_INVALID": "The extension of the photo is invalid.",
    "PHOTO_FILE_MISSING": "Profile photo file missing.",
    "PHOTO_ID_INVALID": "Photo ID invalid.",
    "PHOTO_INVALID": "Photo invalid.",
    "PHOTO_INVALID_DIMENSIONS": "The photo dimensions are invalid.",
    "PHOTO_SAVE_FILE_INVALID": "Internal issues, try again later.",
    "PHOTO_THUMB_URL_EMPTY": "Photo thumbnail URL is empty.",
    "PIN_RESTRICTED": "You can't pin messages.",
    "PINNED_DIALOGS_TOO_MUCH": "Too many pinned dialogs.",
    "POLL_ANSWER_INVALID": "One of the poll answers is not acceptable.",
    "POLL_ANSWERS_INVALID": "Invalid poll answers were provided.",
    "POLL_OPTION_DUPLICATE": "Duplicate poll options provided.",
    "POLL_OPTION_INVALID": "Invalid poll option provided.",
    "POLL_QUESTION_INVALID": "One of the poll questions is not acceptable.",
    "POLL_VOTE_REQUIRED": "Cast a vote in the poll before calling this method.",
    "PREMIUM_ACCOUNT_REQUIRED": "A premium account is required to execute this action.",
    "PREMIUM_CURRENTLY_UNAVAILABLE": "You cannot currently purchase a Premium subscription.",
    "PREMIUM_SUB_ACTIVE_UNTIL_%d": "You already have a premium subscription active until unixtime %d .",
    "PREVIOUS_CHAT_IMPORT_ACTIVE_WAIT_%dMIN": "Import for this chat is already in progress, wait %d minutes before starting a new one.",
    "PRICING_CHAT_INVALID": "The pricing for the [subscription](https:\/\/core.telegram.org\/api\/subscriptions) is invalid, the maximum price is specified in the [`stars_subscription_amount_max` config key &raquo;](https:\/\/core.telegram.org\/api\/config#stars-subscription-amount-max).",
    "PRIVACY_KEY_INVALID": "The privacy key is invalid.",
    "PRIVACY_PREMIUM_REQUIRED": "You need a [Telegram Premium subscription](https:\/\/core.telegram.org\/api\/premium) to send a message to this user.",
    "PRIVACY_TOO_LONG": "Too many privacy rules were specified, the current limit is 1000.",
    "PRIVACY_VALUE_INVALID": "The specified privacy rule combination is invalid.",
    "PUBLIC_CHANNEL_MISSING": "You can only export group call invite links for public chats or channels.",
    "PUBLIC_KEY_REQUIRED": "A public key is required.",
    "QUERY_ID_EMPTY": "The query ID is empty.",
    "QUERY_ID_INVALID": "The query ID is invalid.",
    "QUERY_TOO_SHORT": "The query string is too short.",
    "QUICK_REPLIES_TOO_MUCH": "A maximum of [appConfig.`quick_replies_limit`](https:\/\/core.telegram.org\/api\/config#quick-replies-limit) shortcuts may be created, the limit was reached.",
    "QUIZ_ANSWER_MISSING": "You can forward a quiz while hiding the original author only after choosing an option in the quiz.",
    "QUIZ_CORRECT_ANSWER_INVALID": "An invalid value was provided to the correct_answers field.",
    "QUIZ_CORRECT_ANSWERS_EMPTY": "No correct quiz answer was specified.",
    "QUIZ_CORRECT_ANSWERS_TOO_MUCH": "You specified too many correct answers in a quiz, quizzes can only have one right answer!",
    "QUIZ_MULTIPLE_INVALID": "Quizzes can't have the multiple_choice flag set!",
    "QUOTE_TEXT_INVALID": "The specified `reply_to`.`quote_text` field is invalid.",
    "RAISE_HAND_FORBIDDEN": "You cannot raise your hand.",
    "RANDOM_ID_DUPLICATE": "You provided a random ID that was already used.",
    "RANDOM_ID_EMPTY": "Random ID empty.",
    "RANDOM_ID_INVALID": "A provided random ID is invalid.",
    "RANDOM_LENGTH_INVALID": "Random length invalid.",
    "RANGES_INVALID": "Invalid range provided.",
    "REACTION_EMPTY": "Empty reaction provided.",
    "REACTION_INVALID": "The specified reaction is invalid.",
    "REACTIONS_TOO_MANY": "The message already has exactly `reactions_uniq_max` reaction emojis, you can't react with a new emoji, see [the docs for more info &raquo;](https:\/\/core.telegram.org\/api\/config#client-configuration).",
    "RECEIPT_EMPTY": "The specified receipt is empty.",
    "REPLY_MARKUP_BUY_EMPTY": "Reply markup for buy button empty.",
    "REPLY_MARKUP_GAME_EMPTY": "A game message is being edited, but the newly provided keyboard doesn't have a keyboardButtonGame button.",
    "REPLY_MARKUP_INVALID": "The provided reply markup is invalid.",
    "REPLY_MARKUP_TOO_LONG": "The specified reply_markup is too long.",
    "REPLY_MESSAGE_ID_INVALID": "The specified reply-to message ID is invalid.",
    "REPLY_MESSAGES_TOO_MUCH": "Each shortcut can contain a maximum of [appConfig.`quick_reply_messages_limit`](https:\/\/core.telegram.org\/api\/config#quick-reply-messages-limit) messages, the limit was reached.",
    "REPLY_TO_INVALID": "The specified `reply_to` field is invalid.",
    "REPLY_TO_USER_INVALID": "The replied-to user is invalid.",
    "REQUEST_TOKEN_INVALID": "The master DC did not accept the `request_token` from the CDN DC. Continue downloading the file from the master DC using upload.getFile.",
    "RESET_REQUEST_MISSING": "No password reset is in progress.",
    "RESULT_ID_DUPLICATE": "You provided a duplicate result ID.",
    "RESULT_ID_EMPTY": "Result ID empty.",
    "RESULT_ID_INVALID": "One of the specified result IDs is invalid.",
    "RESULT_TYPE_INVALID": "Result type invalid.",
    "RESULTS_TOO_MUCH": "Too many results were provided.",
    "REVOTE_NOT_ALLOWED": "You cannot change your vote.",
    "RIGHT_FORBIDDEN": "Your admin rights do not allow you to do this.",
    "RIGHTS_NOT_MODIFIED": "The new admin rights are equal to the old rights, no change was made.",
    "RINGTONE_INVALID": "The specified ringtone is invalid.",
    "RINGTONE_MIME_INVALID": "The MIME type for the ringtone is invalid.",
    "RSA_DECRYPT_FAILED": "Internal RSA decryption failed.",
    "SCHEDULE_BOT_NOT_ALLOWED": "Bots cannot schedule messages.",
    "SCHEDULE_DATE_INVALID": "Invalid schedule date provided.",
    "SCHEDULE_DATE_TOO_LATE": "You can't schedule a message this far in the future.",
    "SCHEDULE_STATUS_PRIVATE": "Can't schedule until user is online, if the user's last seen timestamp is hidden by their privacy settings.",
    "SCHEDULE_TOO_MUCH": "There are too many scheduled messages.",
    "SCORE_INVALID": "The specified game score is invalid.",
    "SEARCH_QUERY_EMPTY": "The search query is empty.",
    "SEARCH_WITH_LINK_NOT_SUPPORTED": "You cannot provide a search query and an invite link at the same time.",
    "SECONDS_INVALID": "Invalid duration provided.",
    "SECURE_SECRET_REQUIRED": "A secure secret is required.",
    "SEND_AS_PEER_INVALID": "You can't send messages as the specified peer.",
    "SEND_CODE_UNAVAILABLE": "Returned when all available options for this type of number were already used (e.g. flash-call, then SMS, then this error might be returned to trigger a second resend).",
    "SEND_MEDIA_INVALID": "The specified media is invalid.",
    "SEND_MESSAGE_MEDIA_INVALID": "Invalid media provided.",
    "SEND_MESSAGE_TYPE_INVALID": "The message type is invalid.",
    "SENSITIVE_CHANGE_FORBIDDEN": "You can't change your sensitive content settings.",
    "SESSION_EXPIRED": "The session has expired.",
    "SESSION_PASSWORD_NEEDED": "2FA is enabled, use a password to login.",
    "SESSION_REVOKED": "The session was revoked by the user.",
    "SESSION_TOO_FRESH_%d": "This session was created less than 24 hours ago, try again in %d seconds.",
    "SETTINGS_INVALID": "Invalid settings were provided.",
    "SHA256_HASH_INVALID": "The provided SHA256 hash is invalid.",
    "SHORT_NAME_INVALID": "The specified short name is invalid.",
    "SHORT_NAME_OCCUPIED": "The specified short name is already in use.",
    "SHORTCUT_INVALID": "The specified shortcut is invalid.",
    "SIGN_IN_FAILED": "Failure while signing in.",
    "SLOTS_EMPTY": "The specified slot list is empty.",
    "SLOWMODE_MULTI_MSGS_DISABLED": "Slowmode is enabled, you cannot forward multiple messages to this group.",
    "SLOWMODE_WAIT_%d": "Slowmode is enabled in this chat: wait %d seconds before sending another message to this chat.",
    "SLUG_INVALID": "The specified invoice slug is invalid.",
    "SMS_CODE_CREATE_FAILED": "An error occurred while creating the SMS code.",
    "SMSJOB_ID_INVALID": "The specified job ID is invalid.",
    "SRP_A_INVALID": "The specified inputCheckPasswordSRP.A value is invalid.",
    "SRP_ID_INVALID": "Invalid SRP ID provided.",
    "SRP_PASSWORD_CHANGED": "Password has changed.",
    "STARGIFT_INVALID": "The passed [inputInvoiceStarGift](https:\/\/core.telegram.org\/constructor\/inputInvoiceStarGift) is invalid.",
    "STARGIFT_USAGE_LIMITED": "The gift is sold out.",
    "STARREF_AWAITING_END": "The previous referral program was terminated less than 24 hours ago: further changes can be made after the date specified in userFull.starref_program.end_date.",
    "STARREF_HASH_REVOKED": "The specified affiliate link was already revoked.",
    "STARREF_PERMILLE_INVALID": "The specified commission_permille is invalid: the minimum and maximum values for this parameter are contained in the [starref_min_commission_permille](https:\/\/core.telegram.org\/api\/config#starref-min-commission-permille) and [starref_max_commission_permille](https:\/\/core.telegram.org\/api\/config#starref-max-commission-permille) client configuration parameters.",
    "STARREF_PERMILLE_TOO_LOW": "The specified commission_permille is too low: the minimum and maximum values for this parameter are contained in the [starref_min_commission_permille](https:\/\/core.telegram.org\/api\/config#starref-min-commission-permille) and [starref_max_commission_permille](https:\/\/core.telegram.org\/api\/config#starref-max-commission-permille) client configuration parameters.",
    "STARS_INVOICE_INVALID": "The specified Telegram Star invoice is invalid.",
    "STARS_PAYMENT_REQUIRED": "To import this chat invite link, you must first [pay for the associated Telegram Star subscription &raquo;](https:\/\/core.telegram.org\/api\/subscriptions#channel-subscriptions).",
    "START_PARAM_EMPTY": "The start parameter is empty.",
    "START_PARAM_INVALID": "Start parameter invalid.",
    "START_PARAM_TOO_LONG": "Start parameter is too long.",
    "STATS_MIGRATE_%d": "Channel statistics for the specified channel are stored on DC %d, please re-send the query to that DC.",
    "STICKER_DOCUMENT_INVALID": "The specified sticker document is invalid.",
    "STICKER_EMOJI_INVALID": "Sticker emoji invalid.",
    "STICKER_FILE_INVALID": "Sticker file invalid.",
    "STICKER_GIF_DIMENSIONS": "The specified video sticker has invalid dimensions.",
    "STICKER_ID_INVALID": "The provided sticker ID is invalid.",
    "STICKER_INVALID": "The provided sticker is invalid.",
    "STICKER_MIME_INVALID": "The specified sticker MIME type is invalid.",
    "STICKER_PNG_DIMENSIONS": "Sticker png dimensions invalid.",
    "STICKER_PNG_NOPNG": "One of the specified stickers is not a valid PNG file.",
    "STICKER_TGS_NODOC": "You must send the animated sticker as a document.",
    "STICKER_TGS_NOTGS": "Invalid TGS sticker provided.",
    "STICKER_THUMB_PNG_NOPNG": "Incorrect stickerset thumb file provided, PNG \/ WEBP expected.",
    "STICKER_THUMB_TGS_NOTGS": "Incorrect stickerset TGS thumb file provided.",
    "STICKER_VIDEO_BIG": "The specified video sticker is too big.",
    "STICKER_VIDEO_NODOC": "You must send the video sticker as a document.",
    "STICKER_VIDEO_NOWEBM": "The specified video sticker is not in webm format.",
    "STICKERPACK_STICKERS_TOO_MUCH": "There are too many stickers in this stickerpack, you can't add any more.",
    "STICKERS_EMPTY": "No sticker provided.",
    "STICKERS_TOO_MUCH": "There are too many stickers in this stickerpack, you can't add any more.",
    "STICKERSET_INVALID": "The provided sticker set is invalid.",
    "STICKERSET_NOT_MODIFIED": "The passed stickerset information is equal to the current information.",
    "STICKERSET_OWNER_ANONYMOUS": "Provided stickerset can't be installed as group stickerset to prevent admin deanonymization.",
    "STORIES_NEVER_CREATED": "This peer hasn't ever posted any stories.",
    "STORIES_TOO_MUCH": "You have hit the maximum active stories limit as specified by the [`story_expiring_limit_*` client configuration parameters](https:\/\/core.telegram.org\/api\/config#story-expiring-limit-default): you should buy a [Premium](https:\/\/core.telegram.org\/api\/premium) subscription, delete an active story, or wait for the oldest story to expire.",
    "STORY_ID_EMPTY": "You specified no story IDs.",
    "STORY_ID_INVALID": "The specified story ID is invalid.",
    "STORY_NOT_MODIFIED": "The new story information you passed is equal to the previous story information, thus it wasn't modified.",
    "STORY_PERIOD_INVALID": "The specified story period is invalid for this account.",
    "STORY_SEND_FLOOD_MONTHLY_%d": "You've hit the monthly story limit as specified by the [`stories_sent_monthly_limit_*` client configuration parameters](https:\/\/core.telegram.org\/api\/config#stories-sent-monthly-limit-default): wait for the specified number of seconds before posting a new story.",
    "STORY_SEND_FLOOD_WEEKLY_%d": "You've hit the weekly story limit as specified by the [`stories_sent_weekly_limit_*` client configuration parameters](https:\/\/core.telegram.org\/api\/config#stories-sent-weekly-limit-default): wait for the specified number of seconds before posting a new story.",
    "SUBSCRIPTION_EXPORT_MISSING": "You cannot send a [bot subscription invoice](https:\/\/core.telegram.org\/api\/subscriptions#bot-subscriptions) directly, you may only create invoice links using [payments.exportInvoice](https:\/\/core.telegram.org\/method\/payments.exportInvoice).",
    "SUBSCRIPTION_PERIOD_INVALID": "The specified subscription_pricing.period is invalid.",
    "SWITCH_PM_TEXT_EMPTY": "The switch_pm.text field was empty.",
    "SWITCH_WEBVIEW_URL_INVALID": "The URL specified in switch_webview.url is invalid!",
    "TAKEOUT_INIT_DELAY_%d": "Sorry, for security reasons, you will be able to begin downloading your data in %d seconds. We have notified all your devices about the export request to make sure it's authorized and to give you time to react if it's not.",
    "TAKEOUT_INVALID": "The specified takeout ID is invalid.",
    "TAKEOUT_REQUIRED": "A [takeout](https:\/\/core.telegram.org\/api\/takeout) session needs to be initialized first, [see here &raquo; for more info](https:\/\/core.telegram.org\/api\/takeout).",
    "TASK_ALREADY_EXISTS": "An email reset was already requested.",
    "TEMP_AUTH_KEY_ALREADY_BOUND": "The passed temporary key is already bound to another **perm_auth_key_id**.",
    "TEMP_AUTH_KEY_EMPTY": "No temporary auth key provided.",
    "TERMS_URL_INVALID": "The specified [invoice](https:\/\/core.telegram.org\/constructor\/invoice).`terms_url` is invalid.",
    "THEME_FILE_INVALID": "Invalid theme file provided.",
    "THEME_FORMAT_INVALID": "Invalid theme format provided.",
    "THEME_INVALID": "Invalid theme provided.",
    "THEME_MIME_INVALID": "The theme's MIME type is invalid.",
    "THEME_PARAMS_INVALID": "The specified `theme_params` field is invalid.",
    "THEME_TITLE_INVALID": "The specified theme title is invalid.",
    "Timeout": "Timeout while fetching data.",
    "TIMEZONE_INVALID": "The specified timezone does not exist.",
    "TITLE_INVALID": "The specified stickerpack title is invalid.",
    "TMP_PASSWORD_DISABLED": "The temporary password is disabled.",
    "TMP_PASSWORD_INVALID": "The passed tmp_password is invalid.",
    "TO_LANG_INVALID": "The specified destination language is invalid.",
    "TOKEN_EMPTY": "The specified token is empty.",
    "TOKEN_INVALID": "The provided token is invalid.",
    "TOKEN_TYPE_INVALID": "The specified token type is invalid.",
    "TOPIC_CLOSE_SEPARATELY": "The `close` flag cannot be provided together with any of the other flags.",
    "TOPIC_CLOSED": "This topic was closed, you can't send messages to it anymore.",
    "TOPIC_DELETED": "The specified topic was deleted.",
    "TOPIC_HIDE_SEPARATELY": "The `hide` flag cannot be provided together with any of the other flags.",
    "TOPIC_ID_INVALID": "The specified topic ID is invalid.",
    "TOPIC_NOT_MODIFIED": "The updated topic info is equal to the current topic info, nothing was changed.",
    "TOPIC_TITLE_EMPTY": "The specified topic title is empty.",
    "TOPICS_EMPTY": "You specified no topic IDs.",
    "TRANSACTION_ID_INVALID": "The specified transaction ID is invalid.",
    "TRANSCRIPTION_FAILED": "Audio transcription failed.",
    "TRANSLATE_REQ_FAILED": "Translation failed, please try again later.",
    "TRANSLATE_REQ_QUOTA_EXCEEDED": "Translation is currently unavailable due to a temporary server-side lack of resources.",
    "TTL_DAYS_INVALID": "The provided TTL is invalid.",
    "TTL_MEDIA_INVALID": "Invalid media Time To Live was provided.",
    "TTL_PERIOD_INVALID": "The specified TTL period is invalid.",
    "TYPES_EMPTY": "No top peer type was provided.",
    "UNTIL_DATE_INVALID": "Invalid until date provided.",
    "UPDATE_APP_TO_LOGIN": "Please update your client to login.",
    "URL_INVALID": "Invalid URL provided.",
    "USAGE_LIMIT_INVALID": "The specified usage limit is invalid.",
    "USER_ADMIN_INVALID": "You're not an admin.",
    "USER_ALREADY_INVITED": "You have already invited this user.",
    "USER_ALREADY_PARTICIPANT": "The user is already in the group.",
    "USER_BANNED_IN_CHANNEL": "You're banned from sending messages in supergroups\/channels.",
    "USER_BLOCKED": "User blocked.",
    "USER_BOT": "Bots can only be admins in channels.",
    "USER_BOT_INVALID": "User accounts must provide the `bot` method parameter when calling this method. If there is no such method parameter, this method can only be invoked by bot accounts.",
    "USER_BOT_REQUIRED": "This method can only be called by a bot.",
    "USER_CHANNELS_TOO_MUCH": "One of the users you tried to add is already in too many channels\/supergroups.",
    "USER_CREATOR": "For channels.editAdmin: you've tried to edit the admin rights of the owner, but you're not the owner; for channels.leaveChannel: you can't leave this channel, because you're its creator.",
    "USER_DEACTIVATED": "The current account was deleted by the user.",
    "USER_DEACTIVATED_BAN": "The current account was deleted and banned by Telegram's antispam system.",
    "USER_DELETED": "You can't send this secret message because the other participant deleted their account.",
    "USER_GIFT_UNAVAILABLE": "Gifts are not available in the current region ([stars_gifts_enabled](https:\/\/core.telegram.org\/api\/config#stars-gifts-enabled) is equal to false).",
    "USER_ID_INVALID": "The provided user ID is invalid.",
    "USER_INVALID": "Invalid user provided.",
    "USER_IS_BLOCKED": "You were blocked by this user.",
    "USER_IS_BOT": "Bots can't send messages to other bots.",
    "USER_KICKED": "This user was kicked from this supergroup\/channel.",
    "USER_MIGRATE_%d": "Your account is associated to DC %d, please re-send the query to that DC.",
    "USER_NOT_MUTUAL_CONTACT": "The provided user is not a mutual contact.",
    "USER_NOT_PARTICIPANT": "You're not a member of this supergroup\/channel.",
    "USER_PRIVACY_RESTRICTED": "The user's privacy settings do not allow you to do this.",
    "USER_PUBLIC_MISSING": "Cannot generate a link to stories posted by a peer without a username.",
    "USER_RESTRICTED": "You're spamreported, you can't create channels or chats.",
    "USER_VOLUME_INVALID": "The specified user volume is invalid.",
    "USERNAME_INVALID": "The provided username is not valid.",
    "USERNAME_NOT_MODIFIED": "The username was not modified.",
    "USERNAME_NOT_OCCUPIED": "The provided username is not occupied.",
    "USERNAME_OCCUPIED": "The provided username is already occupied.",
    "USERNAME_PURCHASE_AVAILABLE": "The specified username can be purchased on https:\/\/fragment.com.",
    "USERNAMES_ACTIVE_TOO_MUCH": "The maximum number of active usernames was reached.",
    "USERPIC_PRIVACY_REQUIRED": "You need to disable privacy settings for your profile picture in order to make your geolocation public.",
    "USERPIC_UPLOAD_REQUIRED": "You must have a profile picture to publish your geolocation.",
    "USERS_TOO_FEW": "Not enough users (to create a chat, for example).",
    "USERS_TOO_MUCH": "The maximum number of users has been exceeded (to create a chat, for example).",
    "VENUE_ID_INVALID": "The specified venue ID is invalid.",
    "VIDEO_CONTENT_TYPE_INVALID": "The video's content type is invalid.",
    "VIDEO_FILE_INVALID": "The specified video file is invalid.",
    "VIDEO_PAUSE_FORBIDDEN": "You cannot pause the video stream.",
    "VIDEO_STOP_FORBIDDEN": "You cannot stop the video stream.",
    "VIDEO_TITLE_EMPTY": "The specified video title is empty.",
    "VOICE_MESSAGES_FORBIDDEN": "This user's privacy settings forbid you from sending voice messages.",
    "WALLPAPER_FILE_INVALID": "The specified wallpaper file is invalid.",
    "WALLPAPER_INVALID": "The specified wallpaper is invalid.",
    "WALLPAPER_MIME_INVALID": "The specified wallpaper MIME type is invalid.",
    "WALLPAPER_NOT_FOUND": "The specified wallpaper could not be found.",
    "WC_CONVERT_URL_INVALID": "WC convert URL invalid.",
    "WEBDOCUMENT_INVALID": "Invalid webdocument URL provided.",
    "WEBDOCUMENT_MIME_INVALID": "Invalid webdocument mime type provided.",
    "WEBDOCUMENT_SIZE_TOO_BIG": "Webdocument is too big!",
    "WEBDOCUMENT_URL_EMPTY": "The passed web document URL is empty.",
    "WEBDOCUMENT_URL_INVALID": "The specified webdocument URL is invalid.",
    "WEBPAGE_CURL_FAILED": "Failure while fetching the webpage with cURL.",
    "WEBPAGE_MEDIA_EMPTY": "Webpage media empty.",
    "WEBPAGE_NOT_FOUND": "A preview for the specified webpage `url` could not be generated.",
    "WEBPAGE_URL_INVALID": "The specified webpage `url` is invalid.",
    "WEBPUSH_AUTH_INVALID": "The specified web push authentication secret is invalid.",
    "WEBPUSH_KEY_INVALID": "The specified web push elliptic curve Diffie-Hellman public key is invalid.",
    "WEBPUSH_TOKEN_INVALID": "The specified web push token is invalid.",
    "YOU_BLOCKED_USER": "You blocked this user.",
    "YOUR_PRIVACY_RESTRICTED": "You cannot fetch the read date of this message because you have disallowed other users to do so for *your* messages; to fix, allow other users to see *your* exact last online date OR purchase a [Telegram Premium](https:\/\/core.telegram.org\/api\/premium) subscription."
}<?php

declare(strict_types = 1);

namespace Tak\Liveproto\Errors;

use Exception;

final class Security extends Exception {
	static public function checkG(int | string | \GMP $g,int | string | \GMP $p,bool $a_or_b = false) : void {
		/*
		Apart from the conditions on the Diffie-Hellman prime dh_prime and generator g, both sides are to check that g, g_a and g_b are greater than 1 and less than dh_prime - 1. We recommend checking that g_a and g_b are between 2^{2048-64} and dh_prime - 2^{2048-64} as well
		g > 1 , g_a > 1 , g_b > 1
		g < dh_prime ( p ) - 1 , g_a < dh_prime ( p ) - 1 , g_b < dh_prime ( p ) - 1
		*/
		if(gmp_cmp($g,1) < 1 || gmp_cmp($g,gmp_sub($p,1)) > 0):
			throw new Security('The g a / g b is invalid !');
		endif;
		/*
		We recommend checking that g_a and g_b are between 2^{2048-64} and dh_prime - 2^{2048-64} as well
		2^{2048-64} < g_a < dh_prime ( p ) - 2^{2048-64}
		*/
		if($a_or_b === true):
			$maximum = gmp_init('1751908409537131537220509645351687597690304110853111572994449976845956819751541616602568796259317428464425605223064365804210081422215355425149431390635151955247955156636234741221447435733643262808668929902091770092492911737768377135426590363166295684370498604708288556044687341394398676292971255828404734517580702346564613427770683056761383955397564338690628093211465848244049196353703022640400205739093118270803778352768276670202698397214556629204420309965547056893233608758387329699097930255380715679250799950923553703740673620901978370802540218870279314810722790539899334271514365444369275682816');
			if(gmp_cmp($maximum,$g) > 0 || gmp_cmp($g,gmp_sub($p,$maximum)) > 0):
				throw new Security('The g a / g b is invalid !');
			endif;
		endif;
	}
	static public function checkGoodPrime(int | string | \GMP $p,int | string | \GMP $g) : void {
		/*
		 Client is expected to check whether p = dh_prime is a safe 2048-bit prime (meaning that both p and (p-1)/2 are prime, and that 2^2047 < p < 2^2048)
		That g generates a cyclic subgroup of prime order (p-1)/2, i.e. is a quadratic residue mod p
		*/
		if(gmp_cmp($p,0) < 1 || strlen(gmp_strval($p,2)) !== 2048 || self::isPrime($p) === false || self::isPrime(gmp_div_q(gmp_sub($p,1),2)) === false):
			throw new Security('The p is invalid !');
		endif;
		/*
		Since g is always equal to 2, 3, 4, 5, 6 or 7
		This is easily done using quadratic reciprocity law, yielding a simple condition on p mod 4g -- namely
		p mod 8 = 7 for g = 2;
		p mod 3 = 2 for g = 3;
		no extra condition for g = 4;
		p mod 5 = 1 or 4 for g = 5;
		p mod 24 = 19 or 23 for g = 6;
		p mod 7 = 3, 5 or 6 for g = 7
		*/
		$condition = fn(int $mod,int ...$possible) : bool => in_array(intval(gmp_mod($p,$mod)),$possible);
		$checkG = match(intval($g)){
			2 => $condition(8,7),
			3 => $condition(3,2),
			4 => true,
			5 => $condition(5,1,4),
			6 => $condition(24,19,23),
			7 => $condition(7,3,5,6),
			default => false
		};
		if($checkG === false):
			throw new Security('The g is invalid !');
		endif;
	}
	static public function isPrime(int | string | \GMP $num) : bool {
		return boolval(gmp_nextprime(gmp_sub($num,1)) == $num);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Errors;

use Exception;

final class TransportError extends Exception {
	protected const MESSAGES = [
		403=>'Forbidden : Corresponds to HTTP 403 situations',
		404=>'Auth key not found : The specified auth_key_id cannot be found by the DC . Can happen during initial MTProto handshake or when MTProto fields are incorrect ( packet length mismatch , ... )',
		429=>'Transport flood : Too many transport connections from the same IP in a short time or container / service message limits exceeded',
		444=>'Invalid DC : Returned while creating an auth key , connecting to an MTProxy , or when an invalid DC ID is specified'
	];

	public function __construct(protected string $description,int $code = 0){
		$code = abs($code);
		$message = isset(self::MESSAGES[$code]) ? self::MESSAGES[$code] : 'UNKNOWN';
		parent::__construct($message,$code);
	}
	public function getDescription() : string {
		return $this->description;
	}
	public function __toString(){
		return $this->getMessage().chr(32).$this->getCode().chr(32).chr(58).chr(32).$this->getDescription();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Errors;

use Exception;

use function Tak\Asyncio\File\read;

final class RpcError extends Exception {
	protected string $type;
	protected string $description;
	protected int $value;

	protected const CODES = [
		303=>'SEE_OTHER',
		400=>'BAD_REQUEST',
		401=>'UNAUTHORIZED',
		403=>'FORBIDDEN',
		404=>'NOT_FOUND',
		406=>'NOT_ACCEPTABLE',
		420=>'FLOOD',
		500=>'INTERNAL'
	];

	public function __construct(string $message,int $code = 0){
		$this->type = isset(self::CODES[$code]) ? self::CODES[$code] : 'UNKNOWN';
		$this->description = 'UNKNOWN';
		$this->value = 0;
		$descriptions = $this->fetchErrorDescriptions();
		foreach($descriptions as $name => $description):
			$serial = sscanf($message,$name);
			$hasValue = boolval(empty($serial) === false and in_array(null,$serial) === false);
			if($message === $name or $hasValue):
				if($hasValue):
					$this->value = intval($serial[false]);
				endif;
				$this->description = sprintf($description,...$serial);
				break;
			endif;
		endforeach;
		parent::__construct($message,$code);
	}
	public function getType() : string {
		return $this->type;
	}
	public function getDescription() : string {
		return $this->description;
	}
	public function getValue() : int {
		return $this->value;
	}
	private function fetchErrorDescriptions() : array {
		static $descriptions;
		if(isset($descriptions) === false):
			$descriptions = json_decode(read(__DIR__.DIRECTORY_SEPARATOR.'errors.json'),associative : true,flags : JSON_THROW_ON_ERROR);
		endif;
		return $descriptions;
	}
	public function __toString(){
		return $this->getMessage().chr(32).$this->getCode().chr(32).chr(58).chr(32).$this->getDescription();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Handlers;

use Tak\Liveproto\Utils\Instance;

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Filters\Filter;

use Tak\Asyncio\Promise\DeferredFuture;

use Tak\Asyncio\DeferredCancellation;

use Tak\Asyncio\Sync\Mutex;

use Tak\Asyncio\Sync\Lock;

use Tak\Asyncio\Loop;

use Closure;

use Throwable;

use function Tak\Asyncio\async;

use function Tak\Asyncio\delay;

final class Updates {
	public readonly object $load;
	private array $handlers = array();
	private array $channelsPts = array();
	protected Mutex $recoveryMutex;
	protected Lock $recoveryLock;
	protected Mutex $completion;

	public function __construct(public readonly object $client,private readonly object $session){
		$this->load = $session->load();
		$this->recoveryMutex = new Mutex;
		$this->completion = new Mutex;
	}
	public function addEventHandler(object | callable $callback,? string $unique = null,object | array ...$filters) : void {
		if(is_object($callback) and is_a($callback,'Closure') === false):
			$functions = Filter::getFunctions($callback,$unique);
			$this->handlers = array_merge($this->handlers,$functions);
		else:
			$function = Filter::getFunction($callback,$unique);
			$additional = array_map(fn(object | array $filter) : array => array_values(array_filter(is_array($filter) ? $filter : array($filter),fn(mixed $index) : bool => $index instanceof Filter)),$filters);
			$name = key($function);
			$attributes = array_merge($function[$name]['attributes'],$additional);
			$function[$name]['attributes'] = empty($attributes) ? array($attributes) : $attributes;
			$this->handlers = array_merge($this->handlers,$function);
		endif;
	}
	public function removeEventHandler(object | callable $callback,? string $unique = null) : void {
		if(is_object($callback) and is_a($callback,'Closure') === false):
			$functions = Filter::getFunctions($callback,$unique);
			$keys = array_keys($functions);
			foreach($keys as $name):
				unset($this->handlers[$name]);
			endforeach;
		else:
			$function = Filter::getFunction($callback,$unique);
			$name = array_key_first($function);
			unset($this->handlers[$name]);
		endif;
	}
	public function fetchOneUpdate(array $updates,? callable $callback = null,float $timeout = 0) : object {
		$unique = uniqid('LiveProto');
		$deferredFuture = new DeferredFuture();
		$checker = function(object $update) use($deferredFuture,$callback,&$checker,$unique) : void {
			$lock = $this->completion->acquire();
			try {
				if($deferredFuture->isComplete() === false):
					if(is_null($callback) || async($callback,$update)->await()):
						$deferredFuture->complete($update);
						$this->removeEventHandler($checker,$unique);
					endif;
				endif;
			} catch(\Throwable $error){
				Logging::log('Updates',$error->getMessage(),E_WARNING);
			} finally {
				$lock->release();
			}
		};
		$this->addEventHandler($checker,$unique,array(new Filter\Update(...$updates)));
		$deferredCancellation = new DeferredCancellation();
		return new class($updates,$checker,$deferredFuture,$deferredCancellation,$timeout) extends Instance {
			public function __construct(array $updates,protected Closure $checker,public object $deferredFuture,public object $deferredCancellation,protected float $timeout){
				parent::__construct(['updates'=>$updates,'timeout'=>$timeout]);
			}
			public function await() : mixed {
				$future = $this->deferredFuture->getFuture();
				if($this->timeout > 0):
					Loop::unreference(Loop::delay($this->timeout,fn(string $id) : null => $this->cancel(new \Error('Operation timed out'))));
				endif;
				$update = $future->await($this->deferredCancellation);
				return $update;
			}
			public function cancel(? Throwable $previous = null) : void {
				$this->deferredCancellation->cancel($previous);
			}
		};
	}
	public function applyUpdate(object $update,bool $recovery = false) : void {
		if(isset($update->seq)):
			Logging::log('Updates','Checking SEQ of an update : '.$update->getClass());
			$state = $this->state();
			$update->seq_start ??= $update->seq;
			if($update->seq_start === 0):
				Logging::log('Update Special Case','seq_start = 0');
				array_map($this->applyUpdate(...),$update->updates);
			elseif($state->seq + 1 === $update->seq_start):
				Logging::log('Update Accepted','local seq = '.$state->seq.' (+) 1 (===) seq_start = '.$update->seq_start);
				array_map($this->applyUpdate(...),$update->updates);
			elseif($state->seq + 1 > $update->seq_start):
				Logging::log('Update Skipped','local seq = '.$state->seq.' (+) 1 (>) seq_start = '.$update->seq_start);
				return;
			elseif($state->seq + 1 < $update->seq_start):
				Logging::log('Update Missed','local seq = '.$state->seq.' (+) 1 (<) seq_start = '.$update->seq_start);
				($recovery and isset($this->recoveryLock) === false) ? $this->recoveringGaps() : delay(0.5);
				$this->applyUpdate($update,true);
				return;
			endif;
			$state->date = $update->date;
			$state->seq = max($update->seq,$state->seq);
			return;
		endif;
		if(isset($update->qts)):
			Logging::log('Updates','Checking QTS of an update : '.$update->getClass());
			$state = $this->state();
			$update->qts_count = 1;
			if($state->qts <= 0):
				$state->qts = $update->qts - $update->qts_count;
				Logging::log('Updates','Initializing qts = '.$state->qts);
			endif;
			if($update->qts === 0):
				Logging::log('Update Special Case','qts = 0');
			elseif($state->qts + $update->qts_count === $update->qts):
				Logging::log('Update Accepted','local qts = '.$state->qts.' (+) qts count = '.$update->qts_count.' (===) qts = '.$update->qts);
				$state->qts = $update->qts;
			elseif($state->qts + $update->qts_count > $update->qts):
				Logging::log('Update Skipped','local qts = '.$state->qts.' (+) qts count = '.$update->qts_count.' (>) qts = '.$update->qts);
				return;
			elseif($state->qts + $update->qts_count < $update->qts):
				Logging::log('Update Missed','local qts = '.$state->qts.' (+) qts count = '.$update->qts_count.' (<) qts = '.$update->qts);
				($recovery and isset($this->recoveryLock) === false) ? $this->recoveringGaps() : delay(0.5);
				$this->applyUpdate($update,true);
				return;
			endif;
		endif;
		if(isset($update->pts,$update->pts_count)):
			Logging::log('Updates','Checking PTS of an update : '.$update->getClass());
			$channel_id = isset($update->channel_id) ? $update->channel_id : (isset($update->message->peer_id->channel_id) ? $update->message->peer_id->channel_id : 0);
			if($channel_id === 0):
				$state = $this->state();
				if($state->pts + $update->pts_count === $update->pts):
					Logging::log('Update Accepted','local pts = '.$state->pts.' (+) pts count = '.$update->pts_count.' (===) pts = '.$update->pts);
					$state->pts = $update->pts;
				elseif($state->pts + $update->pts_count > $update->pts):
					Logging::log('Update Skipped','local pts = '.$state->pts.' (+) pts count = '.$update->pts_count.' (>) pts = '.$update->pts);
					return;
				elseif($state->pts + $update->pts_count < $update->pts):
					Logging::log('Update Missed','local pts = '.$state->pts.' (+) pts count = '.$update->pts_count.' (<) pts = '.$update->pts);
					($recovery and isset($this->recoveryLock) === false) ? $this->recoveringGaps() : delay(0.5);
					$this->applyUpdate($update,true);
					return;
				endif;
			else:
				$pts = $this->getChannelPts($channel_id);
				if($pts === 1):
					Logging::log('Update Special Case','channel id = '.$channel_id.' & channel pts = '.$pts);
					$this->setChannelPts($channel_id,$update->pts);
				elseif($pts + $update->pts_count === $update->pts):
					Logging::log('Update Accepted','local pts = '.$pts.' (+) pts count = '.$update->pts_count.' (===) pts = '.$update->pts);
					$this->setChannelPts($channel_id,$update->pts);
				elseif($pts + $update->pts_count > $update->pts):
					Logging::log('Update Skipped','local pts = '.$pts.' (+) pts count = '.$update->pts_count.' (>) pts = '.$update->pts);
					return;
				elseif($pts + $update->pts_count < $update->pts):
					Logging::log('Update Missed','local pts = '.$pts.' (+) pts count = '.$update->pts_count.' (<) pts = '.$update->pts);
					($recovery) ? $this->recoveringChannel($channel_id,$pts) : delay(0.5);
					$this->applyUpdate($update,true);
					return;
				endif;
			endif;
		endif;
		Logging::log('Updates','Applying an update : '.$update->getClass());
		try {
			$encryptedMessage = new Filter\Update('updateNewEncryptedMessage');
			if($encryptedMessage->apply($update)):
				$update->decrypted = $this->client->handle_encrypted_update($update);
			endif;
			$encryption = new Filter\Update('updateEncryption');
			if($encryption->apply($update)):
				if($update->chat instanceof \Tak\Liveproto\Tl\Types\Other\EncryptedChat):
					$this->client->finish_secret_chat_creation($update->chat);
				elseif($update->chat instanceof \Tak\Liveproto\Tl\Types\Other\EncryptedChatRequested):
					$this->client->accept_secret_chat($update->chat);
				elseif($update->chat instanceof \Tak\Liveproto\Tl\Types\Other\EncryptedChatDiscarded):
					$this->client->remove_secret($update->chat->id);
				endif;
			endif;
		} catch(\Throwable $error){
			Logging::log('Updates','An encrypted update was skipped : '.$error->getMessage(),E_WARNING);
			return;
		}
		/* TODO : Add separate handlers to manage updates related to phone calls */
		switch($update->getClass()):
			case 'updateConfig':
				if(isset($this->client->config)):
					$this->client->config = $this->client->help->getConfig();
				endif;
				break;
			case 'updateDcOptions':
				if(isset($this->client->config)):
					$this->client->config->dc_options = $update->dc_options;
				endif;
				break;
			case 'updatePtsChanged':
				$this->state(reset : true);
				break;
			case 'updateNewAuthorization':
				$this->state(reset : true);
				break;
			case 'updateChannelTooLong':
				if(is_null($update->pts) === false):
					$this->setChannelPts($update->channel_id,$update->pts);
				endif;
				$this->recoveringChannel(channel_id : $update->channel_id,pts : $update->pts);
				return;
			case 'updateSentPhoneCode':
				$this->client->apply_sent_code($update->sent_code);
				return;
			case 'updateMessageID':
				return;
		endswitch;
		$this->broadcastUpdate($update);
	}
	public function broadcastUpdate(object $update) : void {
		$update->setClient($this->client);
		foreach($this->handlers as $name => $handler):
			Logging::log('Updates','Handler “'.$handler['name'].'” : Starting parameters checks');
			$paramsCustom = array();
			foreach($handler['parameters'] as $parameter):
				$cloned = clone $update;
				$check = $parameter($cloned);
				if($check === false):
					Logging::log('Updates','Handler “'.$handler['name'].'” : Parameter check failed – skipping');
					continue 2;
				endif;
				$paramsCustom []= $cloned->is_custom;
			endforeach;
			Logging::log('Updates','Handler “'.$handler['name'].'” : Parameters checked , Starting attribute checks');
			if(empty($handler['attributes'])):
				$applies = array();
				goto run;
			endif;
			foreach($handler['attributes'] as $i => $attributes):
				Logging::log('Updates','Handler “'.$handler['name'].'”: Applying attributes – '.$i);
				$applies = array_map(fn(object $attribute) : mixed => $attribute->apply(clone $update),$attributes);
				if(empty($applies)):
					Logging::log('Updates','Handler “'.$handler['name'].'” : Events were not generated – '.$i);
					goto run;
				elseif(in_array(false,$applies) === false):
					Logging::log('Updates','Handler “'.$handler['name'].'” : Events generated – '.$i);
					foreach($applies as $i => $event):
						if($event instanceof Instance):
							$event->setClient($this->client);
						endif;
						if($event instanceof Events and isset($event->addBoundMethods)):
							$applies[$i] = $event->addBoundMethods($event);
						endif;
					endforeach;
					Logging::log('Updates','Handler “'.$handler['name'].'” : Added and initialized bound methods on the event – '.$i);
					goto run;
				else:
					Logging::log('Updates','Handler “'.$handler['name'].'” : Some attributes returned false – skipping – '.$i);
					continue;
				endif;
			endforeach;
			continue;
			run:
			if(empty($applies)):
				Logging::log('Updates','Handler “'.$handler['name'].'” : Dispatching original callback');
				$applies = array(clone $update);
			endif;
			Logging::log('Updates','Handler “'.$handler['name'].'” : Calling callback with events');
			$arguments = array_map(fn(mixed $apply,? bool $paramCustom) : mixed => ($paramCustom and ($apply instanceof Instance) === true and ($apply instanceof Events) === false) ? Events::copy($apply)->setClient($this->client) : $apply,$applies,$paramsCustom);
			async($handler['callback'],...$arguments)->catch(fn(\Throwable $error) : bool => error_log($error->getMessage()));
		endforeach;
	}
	public function &state(bool $reset = false) : object {
		if($reset or ($this->load->state instanceof \stdClass and $this->client->isAuthorized())):
			$this->load->state = $this->client->updates->getState();
		endif;
		return $this->load->state;
	}
	public function recoveringGaps() : void {
		$isLocked = isset($this->recoveryLock);
		$this->recoveryLock = $this->recoveryMutex->acquire();
		$unlock = function() : void {
			if(isset($this->recoveryLock)):
				$lock = $this->recoveryLock;
				unset($this->recoveryLock);
				$lock->release();
			endif;
		};
		if($isLocked === false):
			$state = $this->state();
			$differences = $this->client->get_difference(pts : $state->pts,date : $state->date,qts : $state->qts);
			foreach($differences as $difference):
				$newState = $difference->state ?? $difference->intermediate_state;
				if(isset($difference->new_messages)):
					array_map(fn(object $newMessage) : mixed => async($this->applyUpdate(...),new \Tak\Liveproto\Tl\Types\Other\UpdateNewMessage(['message'=>$newMessage])),$difference->new_messages);
				endif;
				if(isset($difference->new_encrypted_messages)):
					$start_qts = $newState->qts - count($difference->new_encrypted_messages);
					$fn = function(object $newEncryptedMessage) use(&$start_qts) : void {
						async($this->applyUpdate(...),new \Tak\Liveproto\Tl\Types\Other\UpdateNewEncryptedMessage(['message'=>$newEncryptedMessage,'qts'=>++$start_qts]));
					};
					array_map($fn,$difference->new_encrypted_messages);
				endif;
				if(isset($difference->other_updates)):
					array_map(fn(object $update) : mixed => async($this->applyUpdate(...),$update),$difference->other_updates);
				endif;
				delay(0.5);
				Logging::log('New State','new pts = '.$newState->pts.' & new qts = '.$newState->qts.' & new date = '.$newState->date.' & new seq = '.$newState->seq);
				$state->pts = $newState->pts;
				$state->qts = $newState->qts;
				$state->date = $newState->date;
				$state->seq = $newState->seq;
				break; // I didn't want to take them all , I'll give it a chance to get the updates itself :) //
			endforeach;
		endif;
		Loop::queue($unlock);
	}
	public function getChannelPts(int $channel_id) : int {
		return key_exists($channel_id,$this->channelsPts) ? $this->channelsPts[$channel_id] : 1;
	}
	public function setChannelPts(int $channel_id,int $pts) : void {
		$this->channelsPts[$channel_id] = $pts;
	}
	public function recoveringChannel(int $channel_id,? int $pts = null) : void {
		try {
			$pts ??= $this->getChannelPts($channel_id);
			$differences = $this->client->get_channel_difference(channel : $channel_id,pts : $pts);
			foreach($differences as $difference):
				if(isset($difference->new_messages)):
					array_map(fn(object $newChannelMessage) : mixed => async($this->applyUpdate(...),new \Tak\Liveproto\Tl\Types\Other\UpdateNewChannelMessage(['message'=>$newChannelMessage])),$difference->new_messages);
				endif;
				if(isset($difference->other_updates)):
					array_map(fn(object $update) : mixed => async($this->applyUpdate(...),$update),$difference->other_updates);
				endif;
				delay(0.5);
				$this->setChannelPts($channel_id,$difference->pts);
			endforeach;
		} catch(\Throwable $error){
			$this->setChannelPts($channel_id,1);
			Logging::log('Updates','Channel '.$channel_id.' updates not being retrieved : '.$error->getMessage(),E_WARNING);
		}
	}
	public function processUpdate(object $update) : void {
		switch($update->getClass()):
			# updatesTooLong#e317af7e = Updates; #
			case 'updatesTooLong':
				$this->recoveringGaps();
				break;
			# updateShort#78d4dec1 update:Update date:int = Updates; #
			case 'updateShort':
				$this->applyUpdate($update->update);
				break;
			# updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates; #
			# updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates; #
			case 'updatesCombined':
			case 'updates':
				$this->saveAccessHash($update);
				$this->applyUpdate($update);
				break;
			# updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector<MessageEntity> ttl_period:flags.25?int = Updates; #
			# updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector<MessageEntity> ttl_period:flags.25?int = Updates; #
			case 'updateShortMessage':
			case 'updateShortChatMessage':
				/*
				 * We need to get users & chats parameters to cache access hashes belonging to peers
				 *
				 * So if you have trouble getting the peers, just enable `autoCachePeers` in the settings
				 */
				try {
					# updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector<MessageEntity> ttl_period:flags.25?int = Updates; #
					if(isset($update->user_id)):
						if($this->load->peers->getPeer(type : 'users',by : 'id',what : $update->user_id) == false):
							$entity = $this->client->inputPeerUserFromMessage(peer : $this->client->inputPeerSelf(),msg_id : $update->id,user_id : $update->user_id);
							$this->client->users->getFullUser($entity);
						endif;
						$update->peer_id = new \Tak\Liveproto\Tl\Types\Other\PeerUser(['user_id'=>$update->user_id]);
						$update->from_id = new \Tak\Liveproto\Tl\Types\Other\PeerUser(['user_id'=>$update->out ? $this->client->get_peer_id('me') : $update->user_id]);
					# updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector<MessageEntity> ttl_period:flags.25?int = Updates; #
					elseif(isset($update->chat_id,$update->from_id)):
						if($this->load->peers->getPeer(type : 'users',by : 'id',what : $update->from_id) == false):
							$entity = $this->client->inputPeerUserFromMessage(peer : $this->client->inputPeerChat(chat_id : $update->chat_id),msg_id : $update->id,user_id : $update->from_id);
							$this->client->users->getFullUser($entity);
						endif;
						$update->peer_id = new \Tak\Liveproto\Tl\Types\Other\PeerChat(['chat_id'=>$update->chat_id]);
						$update->from_id = new \Tak\Liveproto\Tl\Types\Other\PeerUser(['user_id'=>$update->from_id]);
					endif;
					$message = $update->clone(new \Tak\Liveproto\Tl\Types\Other\Message,true);
					$newMessage = new \Tak\Liveproto\Tl\Types\Other\UpdateNewMessage(['message'=>$message,'pts'=>$update->pts,'pts_count'=>$update->pts_count]);
					$this->applyUpdate($newMessage);
					break;
				} catch(\Throwable $error){
					Logging::log('Short Message','When completing the update : '.$error->getMessage(),E_WARNING);
				}
			# updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> ttl_period:flags.25?int = Updates; #
			case 'updateShortSentMessage':
				Logging::log('Process Updates','Received '.$update->getClass(),E_NOTICE);
				$local_pts = intval($update->pts - $update->pts_count);
				$difference = $this->client->updates->getDifference(pts : $local_pts,date : $update->date,pts_limit : $update->pts_count,qts : 0);
				if(isset($difference->new_messages) and count($difference->new_messages) === $update->pts_count):
					Logging::log('Process Updates','updates.getDifference results accepted for '.$update->getClass());
					$fn = function(object $newMessage) use(&$local_pts) : void {
						$this->applyUpdate(new \Tak\Liveproto\Tl\Types\Other\UpdateNewMessage(['message'=>$newMessage,'pts'=>++$local_pts,'pts_count'=>1]));
					};
					array_map($fn,$difference->new_messages);
				endif;
				break;
			default:
				Logging::log('Process Updates','Unknown update : '.$update->getClass(),E_ERROR);
		endswitch;
	}
	# https://core.telegram.org/api/peers #
	# https://core.telegram.org/api/min #
	public function saveAccessHash(object $update) : void {
		$chats = array_filter($update->chats,fn(mixed $peer) : bool => isset($peer->min) === false || $peer->min === false);
		$this->load->peers->setPeers(type : 'chats',peers : array_map(fn(mixed $peer) : array => array('id'=>$peer->id,'access_hash'=>intval($peer->access_hash)),$chats));
		$users = array_filter($update->users,fn(mixed $peer) : bool => isset($peer->min) === false || $peer->min === false);
		$this->load->peers->setPeers(type : 'users',peers : array_map(fn(mixed $peer) : array => array('id'=>$peer->id,'access_hash'=>intval($peer->access_hash)),$users));
	}
	public function __debugInfo() : array {
		return array(
			'handlers'=>array_map(static fn(array $handler) : array => array_diff_key($handler,['callback'=>null]),$this->handlers)
		);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Handlers;

use Tak\Liveproto\Utils\Instance;

use Tak\Liveproto\Filters\Interfaces\Outgoing;

use Tak\Liveproto\Filters\Interfaces\Incoming;

use Tak\Liveproto\Filters\Interfaces\IsMedia;

use Tak\Liveproto\Filters\Interfaces\IsNotMedia;

use Tak\Liveproto\Filters\Interfaces\IsReply;

use Tak\Liveproto\Filters\Interfaces\IsNotReply;

use Tak\Liveproto\Filters\Interfaces\IsViaBot;

use Tak\Liveproto\Filters\Interfaces\IsNotViaBot;

use Tak\Liveproto\Filters\Interfaces\IsEdited;

use Tak\Liveproto\Filters\Interfaces\IsNotEdited;

use Tak\Liveproto\Filters\Interfaces\IsHideEdited;

use Tak\Liveproto\Filters\Interfaces\IsNotHideEdited;

use Tak\Liveproto\Filters\Interfaces\IsQuickReply;

use Tak\Liveproto\Filters\Interfaces\IsNotQuickReply;

use Tak\Liveproto\Filters\Interfaces\IsMentioned;

use Tak\Liveproto\Filters\Interfaces\IsNotMentioned;

use Tak\Liveproto\Filters\Interfaces\IsSilent;

use Tak\Liveproto\Filters\Interfaces\IsNotSilent;

use Tak\Liveproto\Filters\Interfaces\IsPost;

use Tak\Liveproto\Filters\Interfaces\IsNotPost;

use Tak\Liveproto\Filters\Interfaces\IsSuggest;

use Tak\Liveproto\Filters\Interfaces\IsNotSuggest;

use Tak\Liveproto\Filters\Interfaces\IsPinned;

use Tak\Liveproto\Filters\Interfaces\IsNotPinned;

use Tak\Liveproto\Filters\Interfaces\IsForwarded;

use Tak\Liveproto\Filters\Interfaces\IsNotForwarded;

use Tak\Liveproto\Filters\Interfaces\IsBusiness;

use Tak\Liveproto\Filters\Interfaces\IsNotBusiness;

use Tak\Liveproto\Filters\Interfaces\IsPrivate;

use Tak\Liveproto\Filters\Interfaces\IsNotPrivate;

use Tak\Liveproto\Filters\Interfaces\IsGroup;

use Tak\Liveproto\Filters\Interfaces\IsNotGroup;

use Tak\Liveproto\Filters\Interfaces\IsSuperGroup;

use Tak\Liveproto\Filters\Interfaces\IsNotSuperGroup;

use Tak\Liveproto\Filters\Interfaces\IsChannel;

use Tak\Liveproto\Filters\Interfaces\IsNotChannel;

use Tak\Liveproto\Filters\Interfaces\IsBot;

use Tak\Liveproto\Filters\Interfaces\IsNotBot;

use Tak\Liveproto\Filters\Interfaces\IsSelf;

use Tak\Liveproto\Filters\Interfaces\IsNotSelf;

use Tak\Liveproto\Filters\Interfaces\HasEntity;

use Tak\Liveproto\Filters\Interfaces\HasNotEntity;

use Tak\Liveproto\Filters\Interfaces\HasReaction;

use Tak\Liveproto\Filters\Interfaces\HasNotReaction;

use Tak\Liveproto\Filters\Interfaces\HasReplyMarkup;

use Tak\Liveproto\Filters\Interfaces\HasNotReplyMarkup;

use Tak\Liveproto\Filters\Interfaces\HasPhoto;

use Tak\Liveproto\Filters\Interfaces\HasNotPhoto;

use Tak\Liveproto\Filters\Interfaces\HasGeo;

use Tak\Liveproto\Filters\Interfaces\HasNotGeo;

use Tak\Liveproto\Filters\Interfaces\HasContact;

use Tak\Liveproto\Filters\Interfaces\HasNotContact;

use Tak\Liveproto\Filters\Interfaces\HasDocument;

use Tak\Liveproto\Filters\Interfaces\HasNotDocument;

use Tak\Liveproto\Filters\Interfaces\HasWebPage;

use Tak\Liveproto\Filters\Interfaces\HasNotWebPage;

use Tak\Liveproto\Filters\Interfaces\HasVenue;

use Tak\Liveproto\Filters\Interfaces\HasNotVenue;

use Tak\Liveproto\Filters\Interfaces\HasGame;

use Tak\Liveproto\Filters\Interfaces\HasNotGame;

use Tak\Liveproto\Filters\Interfaces\HasInvoice;

use Tak\Liveproto\Filters\Interfaces\HasNotInvoice;

use Tak\Liveproto\Filters\Interfaces\HasGeoLive;

use Tak\Liveproto\Filters\Interfaces\HasNotGeoLive;

use Tak\Liveproto\Filters\Interfaces\HasPoll;

use Tak\Liveproto\Filters\Interfaces\HasNotPoll;

use Tak\Liveproto\Filters\Interfaces\HasDice;

use Tak\Liveproto\Filters\Interfaces\HasNotDice;

use Tak\Liveproto\Filters\Interfaces\HasStory;

use Tak\Liveproto\Filters\Interfaces\HasNotStory;

use Tak\Liveproto\Filters\Interfaces\Message;

use Tak\Liveproto\Filters\Interfaces\NotMessage;

use Tak\Liveproto\Filters\Interfaces\Callback;

use Tak\Liveproto\Filters\Interfaces\NotCallback;

use Tak\Liveproto\Filters\Interfaces\Inline;

use Tak\Liveproto\Filters\Interfaces\NotInline;

final class Events extends Instance implements Outgoing , Incoming , IsMedia , IsNotMedia , IsReply , IsNotReply , IsViaBot , IsNotViaBot , IsEdited , IsNotEdited , IsHideEdited , IsNotHideEdited , IsQuickReply , IsNotQuickReply , IsMentioned , IsNotMentioned , IsSilent , IsNotSilent , IsPost , IsNotPost , IsSuggest , IsNotSuggest , IsPinned , IsNotPinned , IsForwarded , IsNotForwarded , IsBusiness , IsNotBusiness , IsPrivate , IsNotPrivate , IsGroup , IsNotGroup , IsSuperGroup , IsNotSuperGroup , IsChannel , IsNotChannel , IsBot , IsNotBot , IsSelf , IsNotSelf , HasEntity , HasNotEntity , HasReaction , HasNotReaction , HasReplyMarkup , HasNotReplyMarkup , HasPhoto , HasNotPhoto , HasGeo , HasNotGeo , HasContact , HasNotContact , HasDocument , HasNotDocument , HasWebPage , HasNotWebPage , HasVenue , HasNotVenue , HasGame , HasNotGame , HasInvoice , HasNotInvoice , HasGeoLive , HasNotGeoLive , HasPoll , HasNotPoll , HasDice , HasNotDice , HasStory , HasNotStory , Message , NotMessage , Callback , NotCallback , Inline , NotInline {
	static public function copy(object $update) : object {
		$event = $update->clone(__CLASS__);
		$event->class = $update->getClass();
		return $event;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network;

use Tak\Liveproto\Crypto\Obfuscation;

use Tak\Liveproto\Network\Proxy\Uri;

use Tak\Liveproto\Network\Proxy\Socks5SocketConnector;

use Tak\Liveproto\Network\Proxy\Socks4SocketConnector;

use Tak\Liveproto\Network\Proxy\HttpSocketConnector;

use Tak\Asyncio\Socket\StreamSocket;

final class TcpClient {
	private TlsSocket | StreamSocket $socket;
	public bool $connected {
		get => boolval($this->socket->isClosed() === false);
	}

	public function __construct(int $domain){
		$this->socket = new StreamSocket($domain);
		if(defined('TCP_KEEPIDLE')):
			$this->socket->setOption(TCP_KEEPIDLE,5,SOL_TCP);
		endif;
	}
	public function connect(string $ip,int $port,? array $proxy = null) : void {
		if(is_null($proxy)):
			$this->socket->connect(host : $ip,port : $port,timeout : 60);
		else:
			if(preg_match('~^socks5(?<tls>s|(?:\+|\-)?tls)?~i',$proxy['type'],$match)):
				$socks5 = new Socks5SocketConnector(proxyAddress : $proxy['address'],username : $proxy['username'],password : $proxy['password']);
				$this->socket = $socks5->connect(host : $ip,port : $port,secure : isset($match['tls']),timeout : 60);
			elseif(preg_match('~^socks4(?<tls>s|(?:\+|\-)?tls)?~i',$proxy['type'],$match)):
				$socks4 = new Socks4SocketConnector(proxyAddress : $proxy['address'],user : $proxy['user']);
				$this->socket = $socks4->connect(host : $ip,port : $port,secure : isset($match['tls']),timeout : 60);
			elseif(preg_match('~^http(?<tls>s)?~i',$proxy['type'],$match)):
				$http = new HttpSocketConnector(proxyAddress : $proxy['address'],username : $proxy['username'],password : $proxy['password']);
				$this->socket = $http->connect(host : $ip,port : $port,secure : isset($match['tls']),timeout : 60);
			elseif(strtoupper($proxy['type']) === 'MTPROXY'):
				for($useLegacy = false , $retry = 3; $retry >= 0; $retry--):
					try {
						$uri = new Uri($proxy['address']);
						$this->socket = new StreamSocket($uri->domain);
						$this->socket->connect(host : $uri->address,port : $uri->port,timeout : 60);
						if(isset($proxy['secret']) and Obfuscation::emulateTls(Obfuscation::fromLink($proxy['secret']))):
							$tls = new TlsHandshake(proxy : $proxy);
							$this->socket = $tls->exchange(socket : $this->socket,useLegacy : $useLegacy);
						endif;
						break;
					} catch(\Throwable $error){
						$useLegacy = boolval($useLegacy === false);
						if($retry === 0) throw $error;
					}
				endfor;
			else:
				throw new \OutOfRangeException('Proxy type '.$proxy['type'].' is out of supported range : socks4 , socks5 , http , mtproxy');
			endif;
		endif;
	}
	public function close() : bool {
		return $this->socket->close();
	}
	public function write(string $data,int $timeout = 60) : void {
		if($this->connected):
			$this->socket->write($data,$timeout > 0 ? $timeout : -1);
		else:
			throw new \RuntimeException('The connection was completely closed !');
		endif;
	}
	public function read(int $size,int $timeout = 60) : string {
		$result = strval(null);
		while($size > strlen($result)):
			if($this->connected):
				$buffer = $this->socket->read($size - strlen($result),$timeout > 0 ? $timeout : -1);
				if(is_string($buffer)):
					$result .= $buffer;
				else:
					$this->close();
					throw new \RuntimeException('Connection closed by remote host ( EOF ) !');
				endif;
			else:
				throw new \RuntimeException('The connection was completely closed !');
			endif;
		endwhile;
		return $result;
	}
	public function __destruct(){
		$this->close();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network;

use Tak\Liveproto\Tl\Caller;

use Tak\Liveproto\Tl\DocBuilder;

use Tak\Liveproto\Utils\Tools;

use Tak\Liveproto\Utils\Settings;

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Crypto\Rsa;

use Tak\Liveproto\Ipc\SessionLocker;

use Tak\Liveproto\Ipc\SignalHandler;

use Tak\Liveproto\Database\Session;

use Tak\Liveproto\Database\Content;

use Tak\Liveproto\Handlers\Updates;

use Tak\Liveproto\Enums\Authentication;

use Tak\Liveproto\Enums\MTProtoKeepAlive;

use Tak\Liveproto\Filters\Filter;

use Tak\Asyncio\Loop;

use Tak\Asyncio\Sync\Mutex;

use Stringable;

final class Client extends Caller implements Stringable {
	protected Session $session;
	protected Content $load;
	protected TcpTransport $transport;
	protected Sender $sender;
	protected Mutex $mutex;
	public readonly Updates $handler;
	protected ? object $locker;
	public ? object $mtproxy;
	public object $config;
	public array $dcOptions;
	public bool $connected = false;
	public int $takeoutid = 0;

	public function __construct(string | null $resourceName,string | null $storageDriver,public Settings $settings){
		if(is_null($resourceName) === false and empty($resourceName)):
			throw new \InvalidArgumentException('ResourceName cannot be an empty string value');
		endif;
		if(is_null($resourceName) !== is_null($storageDriver)):
			throw new \InvalidArgumentException('The `resourceName` and `storageDriver` parameters must both be null or both have string values');
		endif;
		new Logging($settings);
		$this->locker = in_array($storageDriver,['text',null]) ? null : ($settings->getHotReload() ? new SignalHandler($resourceName,$this) : new SessionLocker($resourceName));
		$this->session = new Session($resourceName,$storageDriver,$settings);
		$this->load = $this->session->load();
		$this->handler = new Updates($this,$this->session);
		if(is_int($this->load->api_id) and $this->load->api_id > 0):
			Logging::log('Client','I used the saved Api Id !');
		else:
			$this->load->api_id = $settings->getApiId();
		endif;
		if(is_string($this->load->api_hash) and empty($this->load->api_hash) === false):
			Logging::log('Client','I used the saved Api Hash !');
		else:
			$this->load->api_hash = $settings->getApiHash();
		endif;
		$this->mutex = new Mutex;
		$this->dcOptions = array(new \Tak\Liveproto\Tl\Types\Other\DcOption(['id'=>$this->load->dc,'ip_address'=>$this->load->ip,'port'=>$this->load->port,'client'=>$this,'media_only'=>isset($this->load->media_only),'expires_at'=>$this->load->expires_at]));
		$proxy = $this->settings->getProxy();
		$this->mtproxy = (is_null($proxy) === false and strtoupper($proxy['type']) === 'MTPROXY') ? $this->inputClientProxy(address : parse_url($proxy['address'],PHP_URL_HOST),port : parse_url($proxy['address'],PHP_URL_PORT)) : null;
	}
	public function connect(bool $reconnect = false,bool $reset = false,bool $origin = true) : void {
		if($reconnect):
			$this->disconnect();
		endif;
		Logging::log('Client','Connect to IP : '.$this->load->ip);
		$this->transport = new TcpTransport($this->load->ip,$this->load->port,$this->load->dc,$this->settings->protocol,$this->settings->proxy,$this->session->testmode,isset($this->load->media_only));
		if($this->load->auth_key instanceof \stdClass or $reset):
			$expires_in = intval($this->load->expires_at - time());
			$expires_in = intval($expires_in > 0 ? $expires_in : 0);
			$connect = new Handshake($this->transport,$this->session);
			list($this->load->auth_key,$this->load->time_offset,$this->load->salt,$this->load->salt_valid_until) = $connect->authentication($this->load->dc,$this->session->testmode,isset($this->load->media_only),$expires_in);
		endif;
		$this->sender = new Sender($this->transport,$this->session,$this->handler,$this->transport->protocol instanceof \Tak\Liveproto\Network\Protocols\Http ? MTProtoKeepAlive::HTTP_LONG_POLL : ($origin ? MTProtoKeepAlive::PING_PONG : MTProtoKeepAlive::NONE));
		$this->connected = true;
		if($origin) $this->init();
	}
	public function init() : void {
		if($this->connected):
			$getConfig = $this->help->getConfig(raw : true);
			$query = $this->initConnection(api_id : $this->load->api_id,device_model : $this->settings->getDeviceModel(),system_version : $this->settings->getSystemVersion(),app_version : $this->settings->getAppVersion(),system_lang_code : $this->settings->getSystemLangCode(),lang_pack : $this->settings->getLangPack(),lang_code : $this->settings->getLangCode(),proxy : $this->mtproxy,query : $getConfig,params : $this->settings->getParams(),raw : true);
			$this->config = $this->invokeWithLayer(layer : $this->layer(),query : $query);
		else:
			throw new \RuntimeException('You are not connected yet to init connection !');
		endif;
	}
	public function setDC(string $ip,int $port,int $id) : void {
		list($this->load->ip,$this->load->port,$this->load->dc) = func_get_args();
		$this->dcOptions = array(new \Tak\Liveproto\Tl\Types\Other\DcOption(['id'=>$id,'ip_address'=>$ip,'port'=>$port,'client'=>$this,'media_only'=>isset($this->load->media_only),'expires_at'=>$this->load->expires_at]));
	}
	public function changeDC(int $dc_id) : void {
		Logging::log('Client','Try change dc ...');
		if(isset($this->config) === false):
			throw new \RuntimeException('To change the datacenter , `init` needs to be called and executed first !');
		endif;
		$lock = $this->mutex->acquire();
		try {
			foreach($this->config->dc_options as $dc):
				if($dc->ipv6 === $this->settings->ipv6 and $dc->id === $dc_id and $dc->media_only === false and $dc->tcpo_only === false and $dc->cdn === false):
					# $this->sender->destroyAuthKey(); #
					$this->setDC($dc->ip_address,$dc->port,$dc->id);
					Logging::log('Client','New IP : '.$dc->ip_address);
					$this->connect(reconnect : true,reset : true);
					break;
				endif;
			endforeach;
		} catch(\Throwable $error){
			Logging::log('Client',$error->getMessage(),E_ERROR);
		} finally {
			Loop::queue($lock->release(...));
		}
	}
	public function switchDC(? int $dc_id = null,bool $cdn = false,bool $media = false,bool $tcpo = false,bool $next = false,bool $renew = false,int $expires_in = 0) : self {
		Logging::log('Client','Try switch dc ...');
		if(isset($this->config) === false):
			throw new \RuntimeException('To switch the datacenter , `init` needs to be called and executed first !');
		endif;
		$lock = $this->mutex->acquire();
		try {
			foreach($this->config->dc_options as $dc):
				if($dc->ipv6 === $this->settings->ipv6 and (is_null($dc_id) or $dc->id === $dc_id) and ($media === true or $dc->media_only === $media) and ($tcpo === true or $dc->tcpo_only === $tcpo) and $dc->cdn === $cdn):
					if($next === false or ($next === true and empty($this->getAuthorizations(ip_address : $dc->ip_address)))):
						Logging::log('Client','Switch IP : '.$dc->ip_address);
						$is_authorized = boolval($expires_in > 0 || empty($this->getAuthorizations(id : $dc->id)) === false);
						if($is_authorized === false):
							$authorization = $this->auth->exportAuthorization(dc_id : $dc->id);
						endif;
						if($dc->cdn === true):
							Rsa::addCdn($this->help->getCdnConfig());
						endif;
						$expires_at = intval($expires_in > 0 ? time() + $expires_in : 0);
						$availableClients = $this->getAuthorizations(ip_address : $dc->ip_address);
						if($expires_at > 0 || empty($availableClients)):
							$dcOption = clone $dc;
							$this->dcOptions []= $dcOption;
							$dcOption->expires_at = $expires_at;
							$client = clone $this;
							$dcOption->client = $client;
						else:
							Logging::log('Client','I used old built clients ...');
							$dcOption = current($availableClients);
							$client = $dcOption->client;
							if($renew):
								$client->dcOptions []= $dcOption;
								$client = clone $client;
							endif;
						endif;
						if($is_authorized === false):
							$importAuthorization = $client->auth->importAuthorization(id : $authorization->id,bytes : $authorization->bytes,raw : true);
							$query = $client->initConnection(api_id : $client->load->api_id,device_model : $client->settings->devicemodel,system_version : $client->settings->systemversion,app_version : $client->settings->appversion,system_lang_code : $client->settings->systemlangcode,lang_pack : $client->settings->langpack,lang_code : $client->settings->langcode,proxy : $this->mtproxy,query : $importAuthorization,params : $this->settings->params,raw : true);
							$client->invokeWithLayer(layer : $client->layer(),query : $query);
							$client->connected = true;
						endif;
						return $client;
					endif;
				endif;
			endforeach;
		} catch(\Throwable $error){
			Logging::log('Client',$error->getMessage(),E_NOTICE);
		} finally {
			Loop::queue($lock->release(...));
		}
		throw new \Exception('There is a problem in creating the client for DC id '.$dc_id.' !');
	}
	public function getTemp(int $dc_id,int $expires_in) : self {
		$this->cleanAuthorizations();
		$availableClients = array_filter($this->dcOptions,fn(object $dcOption) : bool => $dcOption->expires_at > 0 and $dcOption->id === $dc_id);
		if($expires_in > 0 || empty($availableClients)):
			Logging::log('Client','Try get temp ...');
			if($this->load->dc === $dc_id):
				$client = $this->switchDC(dc_id : $dc_id,expires_in : $expires_in);
				$this->sender->bindTempAuthKey(sender : $client->sender);
				$client->init();
				return $client;
			else:
				return $this->switchDC(dc_id : $dc_id)->getTemp(dc_id : $dc_id,expires_in : $expires_in);
			endif;
		else:
			Logging::log('Client','I used the same old temp');
			return current($availableClients)->client;
		endif;
	}
	public function cleanAuthorizations() : void {
		$this->dcOptions = array_filter($this->dcOptions,fn(object $dcOption) : bool => $dcOption->expires_at === 0 || $dcOption->expires_at > time());
	}
	public function getAuthorizations(mixed ...$filters) : array {
		return array_filter($this->dcOptions,fn(object $dcOption) : bool => array_intersect_assoc($dcOption->toArray(),$filters) == $filters);
	}
	public function isAuthorized() : bool {
		return boolval($this->load->step === Authentication::LOGIN);
	}
	public function getStep() : Authentication {
		return $this->load->step;
	}
	public function layer(bool $secret = false) : int {
		return DocBuilder::layer($secret);
	}
	public function registerFilteredFunctions() : void {
		$functions = get_defined_functions();
		foreach($functions['user'] as $function):
			$reflection = new \ReflectionFunction($function);
			$attributes = $reflection->getAttributes(Filter::class); # flag : \ReflectionAttribute::IS_INSTANCEOF
			if(empty($attributes) === false):
				$this->addHandler($function);
			endif;
		endforeach;
	}
	public function registerFilteredClasses() : void {
		$classes = get_declared_classes();
		foreach($classes as $className):
			$reflection = new \ReflectionClass($className);
			if($reflection->isInstantiable()):
				$attributes = $reflection->getAttributes(Filter::class); # flag : \ReflectionAttribute::IS_INSTANCEOF
				if(empty($attributes) === false):
					$this->addHandler($reflection->newInstance());
				endif;
			endif;
		endforeach;
	}
	public function addHandler(object | callable $callback,? string $unique = null,Filter ...$filters) : void {
		$this->handler->addEventHandler($callback,$unique,...$filters);
	}
	public function removeHandler(object | callable $callback,? string $unique = null) : void {
		$this->handler->removeEventHandler($callback,$unique);
	}
	public function fetchUpdate(array $updates,? callable $callback = null,float $timeout = 0) : object {
		return $this->handler->fetchOneUpdate($updates,$callback,$timeout);
	}
	public function start(bool $run_until_disconnected = true) : void {
		if($this->connected === true):
			$this->disconnect();
		endif;
		$lock = is_null($this->locker) ? null : $this->locker->tryLock();
		if($this->connected === false):
			$this->connect();
		endif;
		if(Tools::isCli()):
			if($this->load->step === Authentication::NEED_AUTHENTICATION):
				$input = Tools::readLine('Please enter your phone number ( Or your bot token , you can give it from @BotFather ) : ');
				if(str_contains($input,chr(58))):
					$this->sign_in(bot_token : $input);
				else:
					$this->send_code(phone_number : preg_replace('/[^\d]/',strval(null),$input));
				endif;
			endif;
			if($this->load->step === Authentication::NEED_EMAIL):
				$input = Tools::readLine('Please enter your email : ');
				$this->send_email_code(email : $input);
			endif;
			if($this->load->step === Authentication::NEED_EMAIL_VERIFY):
				$input = Tools::readLine('Please enter that code you received on your email : ');
				$this->verify_email(code : $input);
			endif;
			if($this->load->step === Authentication::NEED_CODE):
				$input = Tools::readLine('Please enter that code you received : ');
				try {
					$this->sign_in(code : $input);
				} catch(\Throwable $error){
					if($error->getMessage() === 'SESSION_PASSWORD_NEEDED'):
						Tools::colorize('Your account has a password !',fg : 'yellow',options : ['underline']);
					elseif($error->getMessage() === 'PHONE_CODE_INVALID'):
						Tools::colorize('The phone code is invalid !',fg : 'red',options : ['blink']);
					endif;
				}
			endif;
			if($this->load->step === Authentication::NEED_PASSWORD):
				$input = Tools::readLine('Please enter your account password : ');
				$this->sign_in(password : $input);
			endif;
			if($this->load->step === Authentication::LOGIN):
				Tools::colorize('✓ Your bot is now running...',fg : 'green',options : ['bold']);
			else:
				$this->stop();
				exit('Cli login does not support the stage your account is logged into ( '.$this->load->step->value.' ) !');
			endif;
		else:
			include(__DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'login.php');
		endif;
		$this->runInBackground();
		if(is_callable($lock)):
			$this->disconnect();
			Logging::log('Client','The start request has been queued for execution !',E_NOTICE);
			$lock();
			Logging::log('Client','Executing a request that was in the queue...',E_NOTICE);
			$this->connect();
		endif;
		$this->registerFilteredFunctions();
		$this->registerFilteredClasses();
		if(is_array($this->settings->takeout)):
			$this->takeoutid = $this->account->initTakeoutSession(...$this->settings->takeout)->id;
		endif;
		$bot = $this->is_bot();
		$this->handler->state(reset : $bot);
		if($this->settings->autoCachePeers):
			iterator_to_array($bot ? $this->get_difference() : $this->get_dialogs());
		endif;
		gc_collect_cycles();
		if($run_until_disconnected):
			Loop::run();
		endif;
	}
	public function stop() : void {
		if($this->takeoutid):
			$this->account->finishTakeoutSession();
		endif;
		if($this->connected):
			$this->disconnect();
		endif;
		if($this->locker):
			$this->locker->unlock();
		endif;
	}
	private function runInBackground() : void {
		if(Tools::isCli() === false):
			headers_sent() || http_response_code(200);
			if(is_callable('litespeed_finish_request')):
				litespeed_finish_request();
			elseif(is_callable('fastcgi_finish_request')):
				fastcgi_finish_request();
			else:
				ignore_user_abort(true);
				if(headers_sent() === false):
					header('Content-Type: text/html');
					header('Connection: close');
				endif;
				@ob_end_flush();
				@flush();
			endif;
		endif;
	}
	public function disconnect() : void {
		if($this->connected):
			Logging::log('Client','Disconnect !',E_WARNING);
			if(isset($this->sender,$this->transport)):
				$this->sender->close();
				$this->transport->close();
			endif;
			$this->connected = false;
			$this->load->save(true);
		else:
			Logging::log('Client','You are not connected yet to disconnect !',E_ERROR);
		endif;
	}
	public function __debugInfo() : array {
		return array(
			'config'=>isset($this->config) ? $this->config : new \stdClass,
			'dcOptions'=>$this->dcOptions,
			'MTProxy'=>$this->mtproxy,
			'deviceModel'=>$this->settings->deviceModel,
			'systemVersion'=>$this->settings->systemVersion,
			'appVersion'=>$this->settings->appVersion,
			'systemLangCode'=>$this->settings->systemLangCode,
			'langPack'=>$this->settings->langPack,
			'langCode'=>$this->settings->langCode,
			'hotReload'=>$this->settings->hotReload,
			'floodSleepThreshold'=>$this->settings->floodSleepThreshold,
			'receiveUpdates'=>$this->settings->receiveUpdates,
			'ipType'=>$this->settings->ipv6 ? 'ipv6' : 'ipv4',
			'takeout'=>$this->settings->takeout,
			'params'=>$this->settings->params,
			'connected'=>$this->connected
		);
	}
	private function __clone() : void {
		$this->session = clone $this->session;
		$this->load = $this->session->load();
		$dcOption = end($this->dcOptions);
		$reset = boolval($this->load->dc !== $dcOption->id || $dcOption->expires_at > 0);
		$this->load->media_only = $dcOption->media_only ? true : null;
		$this->load->expires_at = $dcOption->expires_at;
		$this->setDC($dcOption->ip_address,$dcOption->port,$dcOption->id);
		$this->connect(reset : $reset,origin : false);
	}
	public function __destruct(){
		$this->disconnect();
	}
	public function __toString() : string {
		return $this->session->getStringSession();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network\Protocols;

use Tak\Liveproto\Errors\Security;

use Tak\Liveproto\Errors\TransportError;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Binary;

final class TcpFull {
	private int $client_seqno = 0;
	private int $server_seqno = 0;

	public function encode(string $body) : string {
		$binary = new Binary();
		$binary->writeInt(strlen($body) + 12);
		$binary->writeInt($this->client_seqno);
		$this->client_seqno++;
		$binary->write($body);
		$message = $binary->read();
		$crc = crc32($message);
		$binary->write($message);
		$binary->writeInt($crc);
		return $binary->read();
	}
	public function decode(object $tcpClient) : string {
		$exception = new \RuntimeException('The connection with the server is not established !');
		$invalid = new Security('The response is invalid !');
		$packetBytes = $tcpClient->read(4);
		assert(empty($packetBytes) === false,$exception);
		$packet = Helper::unpack('l',$packetBytes);
		assert($packet >= 0,new TransportError(self::class,$packet));
		assert($packet > 12,$invalid);
		$seqBytes = $tcpClient->read(4);
		assert(empty($seqBytes) === false,$exception);
		$seq = Helper::unpack('V',$seqBytes);
		assert($seq === $this->server_seqno,$invalid);
		$this->server_seqno++;
		$body = $tcpClient->read($packet - 12);
		assert(empty($body) === false,$exception);
		$sum = $tcpClient->read(4);
		assert(empty($sum) === false,$exception);
		$checksum = Helper::unpack('V',$sum);
		$validchecksum = crc32($packetBytes.$seqBytes.$body);
		assert($checksum === $validchecksum,$invalid);
		return $body;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network\Protocols;

use Tak\Liveproto\Crypto\Obfuscation;

use Tak\Liveproto\Enums\ProtocolType;

use Tak\Liveproto\Network\TcpClient;

use Tak\Liveproto\Network\Protocols\TcpPaddedIntermediate;

use Tak\Liveproto\Utils\Logging;

final class TcpObfuscated {
	private TcpPaddedIntermediate $protocol;
	protected Obfuscation $obfuscation;

	public function __construct(TcpClient $tcpClient,int $dc_id,bool $test_mode = false,bool $media_only = false,? string $secret = null){
		$this->protocol = new TcpPaddedIntermediate();
		$this->obfuscation = new Obfuscation(protocol : ProtocolType::PADDEDINTERMEDIATE,dc_id : $dc_id,test_mode : $test_mode,media_only : $media_only,secret : $secret);
		$tcpClient->write($this->obfuscation->init);
	}
	public function encode(string $body) : string {
		return $this->obfuscation->encrypt($this->protocol->encode($body));
	}
	public function decode(object $tcpClient) : string {
		$tcpObfuscation = new class($tcpClient,$this->obfuscation){
			public function __construct(protected object $tcpClient,protected Obfuscation $obfuscation){
			}
			public function read(int $size,int $timeout = 60) : string {
				return $this->obfuscation->decrypt($this->tcpClient->read(size : $size,timeout : $timeout));
			}
		};
		return $this->protocol->decode($tcpObfuscation);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network\Protocols;

use Tak\Liveproto\Network\TcpClient;

use Tak\Liveproto\Errors\TransportError;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Binary;

final class TcpIntermediate {
	public function __construct(? TcpClient $tcpClient = null){
		$tcpClient?->write(str_repeat(chr(238),4));
	}
	public function encode(string $body) : string {
		$binary = new Binary();
		$binary->writeInt(strlen($body));
		$binary->write($body);
		return $binary->read();
	}
	public function decode(object $tcpClient) : string {
		$exception = new \RuntimeException('The connection with the server is not established !');
		$lengthBytes = $tcpClient->read(4);
		assert(empty($lengthBytes) === false,$exception);
		$length = Helper::unpack('V',$lengthBytes);
		$body = $tcpClient->read($length);
		assert(empty($body) === false,$exception);
		if($length === 0x4):
			$code = Helper::unpack('l',$body);
			assert($code >= 0,new TransportError(self::class,$code));
		endif;
		return $body;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network\Protocols;

use Tak\Liveproto\Network\TcpClient;

use Tak\Liveproto\Errors\TransportError;

use Tak\Liveproto\Utils\Helper;

final class TcpAbridged {
	public function __construct(? TcpClient $tcpClient = null){
		$tcpClient?->write(chr(239));
	}
	public function encode(string $body) : string {
		$length = strlen($body) >> 2;
		if($length < 0x7f):
			$message = chr($length);
		else:
			$message = chr(0x7f).substr(Helper::pack('V',$length),0,3);
		endif;
		return $message.$body;
	}
	public function decode(object $tcpClient) : string {
		$exception = new \RuntimeException('The connection with the server is not established !');
		$lengthByte = $tcpClient->read(1);
		assert(empty($lengthByte) === false,$exception);
		$length = ord($lengthByte);
		if($length >= 0x7f):
			$lengthBytes = strval($tcpClient->read(3).chr(0));
			$length = Helper::unpack('V',$lengthBytes);
		endif;
		$length = $length << 2;
		$body = $tcpClient->read($length);
		assert(empty($body) === false,$exception);
		if($length === 0x4):
			$code = Helper::unpack('l',$body);
			assert($code >= 0,new TransportError($code));
		endif;
		return $body;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network\Protocols;

use Tak\Liveproto\Network\TcpClient;

use Tak\Liveproto\Errors\TransportError;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Binary;

final class TcpPaddedIntermediate {
	public function __construct(? TcpClient $tcpClient = null){
		$tcpClient?->write(str_repeat(chr(221),4));
	}
	public function encode(string $body) : string {
		$binary = new Binary();
		$padding = strlen($body) % 16 ? 0x10 - strlen($body) % 0x10 : 0;
		$binary->writeInt(strlen($body) + $padding);
		$binary->write($body.random_bytes($padding));
		return $binary->read();
	}
	public function decode(object $tcpClient) : string {
		$exception = new \RuntimeException('The connection with the server is not established !');
		$lengthBytes = $tcpClient->read(4);
		assert(empty($lengthBytes) === false,$exception);
		$length = Helper::unpack('V',$lengthBytes);
		$body = $tcpClient->read($length);
		assert(empty($body) === false,$exception);
		if($length === 0x4):
			$code = Helper::unpack('l',$body);
			assert($code >= 0,new TransportError(self::class,$code));
		endif;
		return $body;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network\Protocols;

use Tak\Liveproto\Errors\Security;

use Tak\Liveproto\Errors\TransportError;

final class Http {
	public function __construct(private readonly string $host,private readonly int $port){
		$ip = inet_pton($host);
		if($ip !== false and strlen($ip) === 16):
			$this->host = sprintf('[%s]',$ip);
		endif;
	}
	public function encode(string $body) : string {
		return sprintf(
			'POST /api HTTP/1.1'.CRLF.
			'Host: %s:%d'.CRLF.
			'Content-Type: application/x-www-form-urlencoded'.CRLF.
			'Connection: keep-alive'.CRLF.
			'Keep-Alive: timeout=100000, max=10000000'.CRLF.
			'Content-Length: %d'.CRLF.CRLF.'%s',
			$this->host,
			$this->port,
			strlen($body),
			$body
		);
	}
	public function decode(object $tcpClient) : string {
		$headers = strval(null);
		do {
			$piece = $tcpClient->read(2);
			$headers .= $piece;
			if($piece === LFCR):
				$headers .= $tcpClient->read(1);
				break;
			elseif(str_ends_with($headers,CRLF.CRLF)):
				break;
			endif;
		} while(true);
		$headers = explode(CRLF,$headers);
		list($protocol,$code,$description) = explode(chr(32),array_shift($headers),3);
		list($protocol,$version) = explode(chr(47),$protocol);
		if($protocol !== 'HTTP'):
			throw new Security('Wrong protocol : '.$protocol);
		elseif(array_pop($headers).array_pop($headers) !== strval(null)):
			throw new Security('Wrong last HTTP header');
		elseif($code != 200):
			throw new TransportError($code.chr(32).$description,intval($code));
		endif;
		$headers = array_change_key_case(array_column(array_map(fn(string $item) : array => array_map('trim',explode(chr(58),$item,2)),$headers),1,0));
		if(isset($headers['connection'])):
			$close = (strtolower($headers['connection']) === 'close');
		else:
			$close = ($version === '1.0');
		endif;
		assert($close === false,'The http connection is closed !');
		if(isset($headers['content-length'])):
			$length = intval($headers['content-length']);
			if($length > 0):
				$body = $tcpClient->read($length);
			endif;
		endif;
		return $body;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network;

use Tak\Liveproto\Errors\Security;

use Tak\Liveproto\Utils\Binary;

final class PlainSender {
	public function __construct(protected object $transport,private readonly object $session){
	}
	public function send(object $request) : void {
		$writer = new Binary();
		$writer->writeLong(0);
		$writer->writeLong($this->session->getNewMsgId());
		$packet = $request->read();
		$writer->writeInt(strlen($packet));
		$writer->write($packet);
		$this->transport->send($writer->read());
	}
	public function receive() : object {
		$body = $this->transport->receive();
		$reader = new Binary();
		$reader->write($body);
		$authKeyId = $reader->readLong();
		assert($authKeyId === 0,new Security('The auth key id must be equal to zero !'));
		$msgId = $reader->readLong();
		$messageLength = $reader->readInt();
		$message = $reader->read($messageLength);
		$reader = new Binary();
		$reader->write($message);
		return $reader->readObject();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network;

use Tak\Liveproto\Enums\ProtocolType;

final class TcpTransport {
	public object $tcpClient;
	public readonly object $protocol;

	public function __construct(string $ip,int $port,int $dc_id,? ProtocolType $protocol = null,? array $proxy = null,bool $test_mode = false,bool $media_only = false){
		$this->tcpClient = new TcpClient(filter_var($ip,FILTER_VALIDATE_IP,FILTER_FLAG_IPV4) ? AF_INET : AF_INET6);
		$this->tcpClient->connect($ip,$port,$proxy);
		if(is_null($proxy) === false and strtoupper($proxy['type']) === 'MTPROXY'):
			$protocol = ProtocolType::OBFUSCATED;
		else:
			$protocol = is_null($protocol) ? ProtocolType::FULL : $protocol;
		endif;
		$class = strval('\\Tak\\Liveproto\\Network\\Protocols\\'.$protocol->value);
		$this->protocol = match(true){
			$protocol === ProtocolType::ABRIDGED => new $class(tcpClient : $this->tcpClient),
			$protocol === ProtocolType::INTERMEDIATE => new $class(tcpClient : $this->tcpClient),
			$protocol === ProtocolType::PADDEDINTERMEDIATE => new $class(tcpClient : $this->tcpClient),
			$protocol === ProtocolType::OBFUSCATED => new $class(tcpClient : $this->tcpClient,dc_id : $dc_id,test_mode : $test_mode,media_only : $media_only,secret : (is_null($proxy) ? null : $proxy['secret'])),
			$protocol === ProtocolType::HTTP => new $class(host : $ip,port : $port),
			default => new $class
		};
	}
	public function send(string $packet) : void {
		$this->tcpClient->write($this->protocol->encode($packet));
	}
	public function receive() : string {
		return $this->protocol->decode($this->tcpClient);
	}
	public function close() : void {
		$this->tcpClient->close();
	}
	public function __destruct(){
		$this->close();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network;

use Tak\Liveproto\Crypto\Aes;

use Tak\Liveproto\Errors\RpcError;

use Tak\Liveproto\Errors\Security;

use Tak\Liveproto\Errors\TransportError;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Utils\Settings;

use Tak\Liveproto\Tl\All;

use Tak\Liveproto\Tl\MTRequest;

use Tak\Liveproto\Parser\Tl;

use Tak\Liveproto\Enums\NonRpcResult;

use Tak\Liveproto\Enums\MTProtoKeepAlive;

use Tak\Asyncio\TimeoutCancellation;

use Tak\Asyncio\Sync\Mutex;

use Tak\Asyncio\Loop;

use RuntimeException;

use Throwable;

final class Sender {
	protected readonly object $load;
	private array $salts = array();
	private array $pendingAcks = array();
	private int $lastAckTime = 0;
	private array $received = array();
	private array $queue = array();
	protected Mutex $mutex;
	private string $receiveLoop;

	public const UPDATES = array(0xe317af7e,0x313bc7f8,0x4d6deea5,0x78d4dec1,0x725b04c3,0x74ae4240,0x9015e101);

	public const BY_MSG_ID = 'messageId';
	public const BY_IDENTIFIERS = 'identifier';
	public const BY_SEQ_NO = 'sequence';

	public function __construct(protected object $transport,private readonly object $session,private object $handler,private readonly MTProtoKeepAlive $keepAlive){
		$this->load = $session->load();
		$session->reset();
		$this->mutex = new Mutex;
		$this->receiveLoop = strval(null);
		$this->receiveLoop = Loop::defer($this->receivePacket(...));
		Loop::setErrorHandler($this->errors(...));
		gc_enable();
	}
	public function send(MTRequest $request) : void {
		if($this->keepAlive === MTProtoKeepAlive::HTTP_LONG_POLL):
			$httpWait = new MTRequest('types.httpWait');
			$httpRequest = $httpWait->withParameters(max_delay : Settings::envGuess('HTTP_MAX_DELAY',1000),wait_after : Settings::envGuess('HTTP_WAIT_AFTER',200),max_wait : Settings::envGuess('HTTP_MAX_WAIT',2000));
			Loop::queue($this->sendContainer(...),$request,$httpRequest);
		else:
			Loop::queue($this->sendPacket(...),$request);
		endif;
	}
	# https://core.telegram.org/mtproto/service_messages_about_messages#acknowledgment-of-receipt #
	public function sendAcknowledgement() : void {
		$acks = array_unique($this->pendingAcks);
		$elapsed = intval(time() - $this->lastAckTime);
		if($acks and (count($acks) >= 0x10 or (60 <= $elapsed and $elapsed <= 120))):
			$msgsAck = new MTRequest('types.msgsAck',contentRelated : false);
			$ackRequest = $msgsAck->withParameters(msg_ids : $acks);
			$this->send($ackRequest);
			$this->pendingAcks = array();
			$this->lastAckTime = time();
		endif;
	}
	# https://core.telegram.org/mtproto/service_messages#containers #
	public function sendContainer(MTRequest ...$requests) : void {
		# msg_container#73f1f8dc messages:vector<message> = MessageContainer; #
		if(empty($requests) === false):
			$container = new Binary(true);
			$container->writeInt(0x73f1f8dc);
			$container->writeInt(count($requests));
			foreach($requests as $request):
				$message_id = is_null($request->messageId) ? $this->session->getNewMsgId() : $request->messageId;
				$this->queue[strval($request)] = $request;
				$sequence = $this->session->generateSequence($request->contentRelated);
				$container->write($request->toMessage($message_id,$sequence));
			endforeach;
			$mtRequest = new MTRequest($container,contentRelated : false);
			$this->sendPacket($mtRequest);
		endif;
	}
	public function sendPacket(MTRequest $request) : void {
		$message_id = is_null($request->messageId) ? $this->session->getNewMsgId() : $request->messageId;
		$sequence = is_null($request->sequence) ? $this->session->generateSequence($request->contentRelated) : $request->sequence;
		$data = $this->composePlainMessage(request : $request,salt : $this->getFreshFutureSalt(renew : $request->keepOldSalt === false),session_id : $this->load->id,message_id : $message_id,sequence : $sequence);
		$message = $this->encryptMTProtoMessage(data : $data,version : 2);
		$request->messageId = $message_id;
		$this->queue[strval($request)] = $request;
		Logging::log('Send Packet','Request : '.strval($request->getBinary()).' , Packet length : '.strlen($message).' , Message ID : '.$message_id.' , Sequence : '.$sequence.' , Identifier Type : '.var_export($request->identifier,true));
		try {
			$this->transport->send($message);
		} catch(RuntimeException $error){
			Logging::log('Connection Error',$error->getMessage(),E_ERROR);
			$this->close();
		} catch(Throwable $error){
			Logging::log('Send Packet',$error->getMessage(),E_WARNING);
		}
	}
	public function composePlainMessage(MTRequest $request,int $salt,int $session_id,int $message_id,int $sequence) : string {
		$plainWriter = new Binary();
		$plainWriter->writeLong($salt);
		$plainWriter->writeLong($session_id);
		$plainWriter->write($request->toMessage($message_id,$sequence));
		return $plainWriter->read();
	}
	public function encryptMTProtoMessage(string $data,int $version) : string {
		if($version === 1):
			$msgKeyLarge = sha1($data,true);
			$msgKey = substr($msgKeyLarge,4,16);
			list($key,$iv) = Helper::aesCalculate($this->load->auth_key->key,$msgKey,true);
		elseif($version === 2):
			$fmod = fn(int $a,int $b) : int => ($a % $b + $b) % $b;
			$data .= random_bytes($fmod(-(strlen($data) + 12),16) + 12);
			$msgKeyLarge = hash('sha256',substr($this->load->auth_key->key,88,32).$data,true);
			$msgKey = substr($msgKeyLarge,8,16);
			list($key,$iv) = Helper::keyCalculate($this->load->auth_key->key,$msgKey,true);
		else:
			throw new \InvalidArgumentException('The MTProto version argument is invalid !');
		endif;
		$encrypt = Aes::encrypt($data,$key,$iv);
		$cipherWriter = new Binary();
		$cipherWriter->writeLong($this->load->auth_key->id);
		$cipherWriter->write($msgKey);
		$cipherWriter->write($encrypt);
		return $cipherWriter->read();
	}
	# https://core.telegram.org/api/pfs#related-articles #
	public function bindTempAuthKey(self $sender,int $retry = 3) : bool {
		$nonce = Helper::generateRandomLong();
		$authKeyInner = new MTRequest('types.bindAuthKeyInner');
		$bindInner = $authKeyInner->withParameters(nonce : $nonce,temp_auth_key_id : $sender->load->auth_key->id,perm_auth_key_id : $this->load->auth_key->id,temp_session_id : $sender->load->id,expires_at : $sender->load->auth_key->expires_at);
		do {
			try {
				$message_id = $sender->load->last_msg_id = $this->session->getNewMsgId();
				$data = $this->composePlainMessage(request : $bindInner,salt : Helper::generateRandomLong(),session_id : Helper::generateRandomLong(),message_id : $message_id,sequence : 0);
				$cipher = $this->encryptMTProtoMessage(data : $data,version : 1);
				Logging::log('Bind Temp','Expires at : '.strval($sender->load->auth_key->expires_at).' , EncryptedMessage ID : '.$message_id);
				$bindTemp = new MTRequest('functions.auth.bindTempAuthKey',messageId : $message_id,timeout : 10);
				$bindRequest = $bindTemp->withParameters(perm_auth_key_id : $this->load->auth_key->id,nonce : $nonce,expires_at : $sender->load->auth_key->expires_at,encrypted_message : $cipher);
				return $sender($bindRequest);
			} catch(RpcError $error){
				$code = $error->getCode();
			} finally {
				$retry--;
			}
		} while($retry > 0 and $code === 400);
		throw new RuntimeException('Failed to create a temporary client !',$code,$error);
	}
	public function receive(MTRequest $request) : mixed {
		$future = $request->getDeferred()->getFuture();
		$cancellation = $request->timeout > 0 ? new TimeoutCancellation($request->timeout) : $request->cancellation;
		return $future->await($cancellation);
	}
	public function receivedLoop() : void {
		$lock = $this->mutex->acquire();
		foreach($this->received as $hash => $object):
			if(array_key_exists($hash,$this->queue)):
				$request = $this->queue[$hash];
				$deferred = $request->getDeferred();
				if($deferred->isComplete() === false):
					switch($object->status):
						case 'success':
							if(isset($object->result->chats,$object->result->users) and is_array($object->result->chats) and is_array($object->result->users)):
								$this->handler->saveAccessHash($object->result);
							endif;
							if(isset($object->result->vector) and is_callable($object->result->vector)):
								$constructor = $request->getConstructor();
								$comments = Tl::parseDocComment($constructor);
								$return = Tl::parseType($comments['return']);
								$object->result = call_user_func($object->result->vector,$return['type'],true);
							endif;
							if(isset($object->result->bool) and is_callable($object->result->bool)):
								$object->result = call_user_func($object->result->bool,true);
							endif;
							$deferred->complete($object->result);
							break;
						case 'error':
							$deferred->error($object->exception);
							break;
						case 'resend':
							$this->sendPacket($request);
							$request->keepOldSalt || $this->httpLongPoll();
							break;
					endswitch;
					unset($this->received[$hash]);
				endif;
			endif;
		endforeach;
		$lock->release();
	}
	public function receivePacket() : void {
		while(isset($this->receiveLoop)):
			try {
				$body = $this->transport->receive();
				$closure = function(string $result) : void {
					$plain = $this->decryptMTProtoMessage(data : $result,version : 2);
					list($reader,$salt,$session_id,$message_id,$sequence) = $this->decomposePlainMessage($plain);
					if($session_id !== $this->load->id):
						Logging::log('Receive Packet','Server replied with a wrong session id !',E_ERROR);
					endif;
					if($message_id % 2 !== 1):
						Logging::log('Receive Packet','Server sent an even message id !',E_ERROR);
					endif;
					try {
						$this->processMessage($reader,$message_id,$sequence);
						$this->receivedLoop();
						$this->gcCleanup();
					} catch(Throwable $error){
						Logging::log('Process Message',$error->getMessage(),E_WARNING);
					}
				};
				Loop::queue($closure,$body);
			} catch(Security $error){
				Logging::log('Security',$error->getMessage(),E_NOTICE);
			} catch(TransportError $error){
				Logging::log('Transport Error',$error->getMessage(),E_ERROR);
			} catch(RuntimeException $error){
				Logging::log('Connection Error',$error->getMessage(),E_ERROR);
				$this->close();
			} catch(Throwable $error){
				Logging::log('Receive Packet',$error->getMessage(),E_WARNING);
				$this->ping();
				$this->httpLongPoll();
			}
		endwhile;
	}
	public function decryptMTProtoMessage(string $data,int $version) : string {
		$reader = new Binary();
		$reader->write($data);
		if(strlen($data) < 8):
			Logging::log('Decode Message','Body length is less than 8 !',E_NOTICE);
		endif;
		$remoteAuthKeyId = $reader->readLong();
		if($remoteAuthKeyId !== $this->load->auth_key->id):
			Logging::log('Decode Message','Server replied with an invalid auth key !',E_ERROR);
		endif;
		$msgKey = $reader->read(16);
		if($version === 1):
			list($key,$iv) = Helper::aesCalculate($this->load->auth_key->key,$msgKey,false);
		else:
			list($key,$iv) = Helper::keyCalculate($this->load->auth_key->key,$msgKey,false);
		endif;
		$cipher = $reader->read();
		$plain = Aes::decrypt($cipher,$key,$iv);
		if($version === 1):
			$ourKey = sha1($plain,true);
			$ourKey = substr($ourKey,4,16);
		else:
			$ourKey = hash('sha256',substr($this->load->auth_key->key,96,32).$plain,true);
			$ourKey = substr($ourKey,8,16);
		endif;
		if($msgKey !== $ourKey):
			Logging::log('Decode Message','Received msg key does not match with expected one !',E_ERROR);
		endif;
		return strval($plain);
	}
	public function decomposePlainMessage(string $plain) : array {
		$plainReader = new Binary();
		$plainReader->write($plain);
		$salt = $plainReader->readLong();
		$session_id = $plainReader->readLong();
		$mtResponse = MTRequest::fromMessage($plainReader);
		$padding = strlen($plainReader->read());
		if($padding < 12 or $padding > 1024):
			Logging::log('Decode Message','Padding must be between 12 and 1024 bytes !',E_ERROR);
		endif;
		return array($mtResponse->binary,$salt,$session_id,$mtResponse->messageId,$mtResponse->sequence);
	}
	public function processMessage(Binary $reader,int $message_id,int $sequence) : void {
		$object = strval($reader);
		$constructorId = $reader->readInt();
		Logging::log('Process Message',(class_exists($object) ? 'Object : '.$object : 'Constructor Number : 0x'.dechex($constructorId)).' , Message ID : '.$message_id.' , Sequence : '.$sequence);
		# pong#347773c5 msg_id:long ping_id:long = Pong; #
		if($constructorId == 0x347773c5):
			$msg_id = $reader->readLong();
			$ping_id = $reader->readLong();
			if($hash = $this->getHashQueue($msg_id,self::BY_MSG_ID)):
				$this->received[$hash] = (object) ['status'=>'success','result'=>$ping_id];
				Logging::log('Live','Pong !');
			endif;
			return;
		# msg_container is used instead of msg_copy #
		# msg_container#73f1f8dc messages:vector<message> = MessageContainer; #
		elseif($constructorId == 0x73f1f8dc):
			$count = $reader->readInt();
			# message msg_id:long seqno:int bytes:int body:Object = Message; #
			for($i = 0;$i < $count;$i++):
				$msg_id = $reader->readLong();
				$seq_no = $reader->readInt();
				$length = $reader->readInt();
				$position = $reader->tellPosition();
				$this->processMessage($reader,$msg_id,$seq_no);
				$reader->setPosition($length + $position);
			endfor;
			return;
		# gzip_packed#3072cfa1 packed_data:string = Object; #
		elseif($constructorId == 0x3072cfa1):
			$packed_data = $reader->readBytes();
			$unpacked = gzdecode($packed_data);
			$gzip = new Binary();
			$gzip->write($unpacked);
			$this->processMessage($gzip,$message_id,$sequence);
			return;
		# msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck; #
		elseif($constructorId == 0x62d6b459):
			$msg_ids = $reader->readVector('long');
			Logging::log('Msgs Ack',implode(chr(0x20).chr(0x2c).chr(0x20),$msg_ids));
			return;
		# rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; #
		elseif($constructorId == 0xf35c6d01):
			$req_msg_id = $reader->readLong();
			if($hash = $this->getHashQueue($req_msg_id,self::BY_MSG_ID)):
				$constructorId = $reader->readInt();
				# gzip_packed#3072cfa1 packed_data:string = Object; #
				if($constructorId === 0x3072cfa1):
					$packed_data = $reader->readBytes();
					$unpacked = gzdecode($packed_data);
					$reader = new Binary();
					$reader->write($unpacked);
					$constructorId = $reader->readInt();
				endif;
				# rpc_error#2144ca19 error_code:int error_message:string = RpcError; #
				if($constructorId === 0x2144ca19):
					$error_code = $reader->readInt();
					$error_message = $reader->readBytes();
					Logging::log('RPC',$error_code.chr(32).$error_message,E_ERROR);
					$this->received[$hash] = (object) ['status'=>'error','exception'=>new RpcError($error_message,$error_code)];
				# rpc_answer_unknown#5e2ad36e = RpcDropAnswer; #
				elseif($constructorId === 0x5e2ad36e):
					# nothing ! #
				# rpc_answer_dropped_running#cd78e586 = RpcDropAnswer; #
				elseif($constructorId === 0xcd78e586):
					# again nothing ! #
				# rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer; #
				elseif($constructorId === 0xa43ad8b7):
					$msg_id = $reader->readLong();
					$seq_no = $reader->readInt();
					$bytes = $reader->readInt();
				else:
					$result = $reader->readObject(true);
					$this->received[$hash] = (object) ['status'=>'success','result'=>$result];
					if(in_array($constructorId,self::UPDATES)):
						$this->handler->processUpdate($result);
					endif;
				endif;
			endif;
		# new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession #
		elseif($constructorId == 0x9ec20908):
			$first_msg_id = $reader->readLong();
			$unique_id = $reader->readLong();
			$server_salt = $reader->readLong();
			$this->load['salt'] = $server_salt;
			$this->load['salt_valid_until'] = strtotime('+ 30 minutes');
			Logging::log('New Session Created','First Message ID : '.$first_msg_id);
		# bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification; #
		elseif($constructorId == 0xa7eff811):
			$bad_msg_id = $reader->readLong();
			if($hash = $this->getHashQueue($bad_msg_id,self::BY_MSG_ID)):
				$status_msg = (object) ['status'=>'resend'];
				$bad_msg_seqno = $reader->readInt();
				$error_code = $reader->readInt();
				if(in_array($error_code,array(16,17))):
					$this->session->updateTimeOffset($message_id);
				elseif($error_code == 18):
					$this->load['sequence'] = intval(ceil($this->load['sequence'] / 4) * 4);
				elseif(in_array($error_code,array(32,33))):
					$this->session->reset();
				elseif(in_array($error_code,array(34,35))):
					$this->load['sequence'] += 1;
				else:
					$status_msg = (object) ['status'=>'error','exception'=>new RpcError('Bad Msg Notification !',$error_code)];
				endif;
				$this->queue[$hash]->messageId = $this->session->getNewMsgId();
				$this->queue[$hash]->sequence = $this->session->generateSequence($this->queue[$hash]->contentRelated);
				$this->received[$hash] = $status_msg;
				Logging::log('Bad Msg Notification','Bad Message ID : '.$bad_msg_id.' , Error Code : '.$error_code);
			endif;
		# bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification; #
		elseif($constructorId == 0xedab447b):
			$bad_msg_id = $reader->readLong();
			if($hash = $this->getHashQueue($bad_msg_id,self::BY_MSG_ID)):
				$bad_msg_seqno = $reader->readInt();
				$error_code = $reader->readInt(); // 48: incorrect server salt (in this case, the bad_server_salt response is received with the correct salt, and the message is to be re-sent with it) //
				$new_server_salt = $reader->readLong();
				$this->load['salt'] = $new_server_salt;
				$this->load['salt_valid_until'] = strtotime('+ 30 minutes');
				$this->queue[$hash]->sequence = $this->session->generateSequence($this->queue[$hash]->contentRelated);
				$this->received[$hash] = (object) ['status'=>'resend'];
				Logging::log('Bad Server Salt','Bad Message ID : '.$bad_msg_id);
			endif;
		# msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo; #
		elseif($constructorId == 0x276d3ec6):
			$msg_id = $reader->readLong();
			$answer_msg_id = $reader->readLong();
			$bytes = $reader->readInt();
			$status = $reader->readInt();
			$this->pendingAcks []= $answer_msg_id;
		# msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo; #
		elseif($constructorId == 0x809db6df):
			$answer_msg_id = $reader->readLong();
			$bytes = $reader->readInt();
			$status = $reader->readInt();
			$this->pendingAcks []= $answer_msg_id;
		# future_salts#ae500895 req_msg_id:long now:int salts:vector<future_salt> = FutureSalts; #
		elseif($constructorId == 0xae500895):
			$req_msg_id = $reader->readLong();
			if($hash = $this->getHashQueue($req_msg_id,self::BY_MSG_ID)):
				$now = $reader->readInt();
				$count = $reader->readInt();
				# future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt; #
				for($i = 0;$i < $count;$i++):
					$valid_since = $reader->readInt();
					$valid_until = $reader->readInt();
					$salt = $reader->readLong();
					$salts []= (object) ['valid_since'=>$valid_since,'valid_until'=>$valid_until,'salt'=>$salt];
				endfor;
				$this->received[$hash] = (object) ['status'=>'success','result'=>$salts];
				Logging::log('Future Salts','Number of salts : '.count($salts));
			endif;
		# destroy_session_ok#e22045fc session_id:long = DestroySessionRes; #
		# destroy_session_none#62d350c9 session_id:long = DestroySessionRes; #
		elseif(in_array($constructorId,array(0xe22045fc,0x62d350c9))):
			$result = $reader->readObject(true);
			if($hash = $this->getHashQueue(NonRpcResult::DESTROY_SESSION,self::BY_IDENTIFIERS)):
				$this->received[$hash] = (object) ['status'=>'success','result'=>$result];
			endif;
			Logging::log('Destroy Session Res','Session Id : '.$result->session_id);
		# destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes; #
		# destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes; #
		# destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes; #
		elseif(in_array($constructorId,array(0xf660e1d4,0x0a9f2259,0xea109b13))):
			$result = $reader->readObject(true);
			if($hash = $this->getHashQueue(NonRpcResult::DESTROY_AUTH_KEY,self::BY_IDENTIFIERS)):
				$this->received[$hash] = (object) ['status'=>'success','result'=>$result];
			endif;
			Logging::log('Destroy Auth',$result->getClass(),E_WARNING);
		elseif(in_array($constructorId,self::UPDATES)):
			$this->handler->processUpdate($reader->readObject(true));
		else:
			Logging::log('Process Message','Unknown message : 0x'.dechex($constructorId),E_WARNING);
			var_dump($reader->readObject(true));
		endif;
		if($sequence % 2 === 1):
			$this->pendingAcks []= $message_id;
			$this->sendAcknowledgement();
		endif;
	}
	public function getFutureSalts() : array {
		$valid_since = strtotime('+ 36 hours');
		$valid_until = max($this->load->salt_valid_until,strtotime('+ 1 minute'));
		$this->salts = array_filter($this->salts,fn(object $salt) : bool => $salt->valid_since <= $valid_since and $salt->valid_until >= $valid_until);
		if(count($this->salts) <= Settings::envGuess('MIN_VALID_SALTS',0x0)):
			Logging::log('Future Salts','Requesting new future salts from server ...');
			$getSalts = new MTRequest('functions.getFutureSalts',keepOldSalt : true);
			$getSaltsRequest = $getSalts->withParameters(num : Settings::envGuess('FUTURE_SALTS_COUNT',0x20));
			$salts = $this($getSaltsRequest);
			$this->salts = array_merge($this->salts,$salts);
			return $this->getFutureSalts();
		endif;
		return $this->salts;
	}
	public function getFreshFutureSalt(bool $renew = true) : int {
		if($renew and $this->load->salt_valid_until < strtotime('+ 1 minute')):
			$salts = $this->getFutureSalts();
			$future_salt = reset($salts);
			list($this->load->salt,$this->load->salt_valid_until) = array($future_salt->salt,$future_salt->valid_until);
			Logging::log('Fresh Future Salt','A new futures salt replaced the previous one , valid for up to '.intval($future_salt->valid_until - time()).' seconds');
		endif;
		return $this->load->salt;
	}
	public function destroySession(int $session_id) : ? object {
		if(isset($this->receiveLoop) and $session_id !== 0):
			$destroy = new MTRequest('functions.destroySession',identifier : NonRpcResult::DESTROY_SESSION);
			$destroyRequest = $destroy->withParameters(session_id : $session_id);
			$result = $this($destroyRequest);
			Logging::log('Destroy Session','Session Id : '.$session_id.' , Result : '.$result->getClass());
			return $result;
		else:
			return null;
		endif;
	}
	public function destroyAuthKey(float $timeout = 1.0) : bool | object {
		if(isset($this->receiveLoop)):
			try {
				$destroyRequest = new MTRequest('functions.destroyAuthKey',identifier : NonRpcResult::DESTROY_AUTH_KEY);
				$result = $this($destroyRequest);
				Logging::log('Destroy Auth','Result received with '.$timeout.' second timeout');
				return $result;
			} catch(Throwable $error){
				return true;
			}
		else:
			return false;
		endif;
	}
	public function ping() : void {
		if(isset($this->receiveLoop) and $this->keepAlive === MTProtoKeepAlive::PING_PONG):
			Logging::log('Live','Ping ...');
			$ping = new MTRequest('functions.pingDelayDisconnect');
			$pingRequest = $ping->withParameters(ping_id : Helper::generateRandomLong(),disconnect_delay : 75);
			$this->sendPacket($pingRequest);
		endif;
	}
	public function httpLongPoll() : void {
		if(isset($this->receiveLoop) and $this->keepAlive === MTProtoKeepAlive::HTTP_LONG_POLL):
			Logging::log('Live','Http Wait ...');
			$httpWait = new MTRequest('types.httpWait');
			$httpRequest = $httpWait->withParameters(max_delay : 0,wait_after : 0,max_wait : 75 * 1000);
			$this->sendPacket($httpRequest);
		endif;
	}
	public function getHashQueue(mixed $value,string $by) : ? string {
		$filtered = array_filter($this->queue,fn(MTRequest $request) : bool => $request->$by === $value);
		return array_key_first($filtered);
	}
	public function gcCleanup() : void {
		/*
		 * TODO : Let's try not to remove those who are waiting to receive a response from the queue
		 *
		 * $filtered = array_filter($this->queue,fn(MTRequest $request) : bool => is_null($request->getDeferred(false)));
		 */
		$before = count($this->queue);
		$this->queue = array_filter($this->queue,fn(MTRequest $request) : bool => $request->getDeferred(lazyInit : false)?->isComplete() == false);
		$this->queue = array_slice(array : $this->queue,offset : - Settings::envGuess('MAX_QUEUE_LENGTH',1000),preserve_keys : true);
		$after = count($this->queue);
		if($before - $after > 0):
			Logging::log('Garbage Collection','Cleanup : '.strval($before - $after));
			gc_collect_cycles();
		endif;
	}
	public function errors(Throwable $error) : never {
		Logging::log('Sender',$error->getMessage(),E_ERROR);
		throw $error;
	}
	public function close() : void {
		unset($this->receiveLoop);
		Logging::log('Sender','Closed !',E_WARNING);
	}
	public function __invoke(MTRequest $raw) : mixed {
		$this->sendPacket($raw);
		/*
		 * Requests passing through here should not require HTTP_LONG_POLL
		 * Otherwise a function like getFutureSalts would be looking for a new salt in a recursive loop
		 * http_wait requires a `salt` when sending , but we haven't received a new `salt` result to assign to it yet
		 * Away from the container
		 */
		$raw->keepOldSalt || $this->httpLongPoll();
		return $this->receive($raw);
	}
	public function __destruct(){
		$this->close();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Logging;

use Tak\Asyncio\Socket\StreamSocket;

final class TlsSocket {
	public const HEADER_LENGTH = 0x5;
	public const LIMIT_SIZE = 2 ** 14;

	private string $buffer;
	private bool $isFirst = true;

	public function __construct(private StreamSocket $socket){
		if($socket->isClosed()):
			throw new \RuntimeException('Proxy closed the connection after TLS handshake');
		else:
			$this->buffer = strval(null);
		endif;
	}
	public function readexactly(int $size,int $timeout = -1) : string {
		$result = strval(null);
		while($size > strlen($result)):
			if($this->socket->isClosed()):
				throw new \RuntimeException('Connection closed');
			else:
				$buffer = $this->socket->read($size - strlen($result),$timeout);
				if(is_null($buffer) === false):
					$result .= $buffer;
				else:
					$this->socket->close();
					throw new \RuntimeException('Connection closed by remote host ( EOF ) !');
				endif;
			endif;
		endwhile;
		return $result;
	}
	private function recordTls(int $timeout = -1) : void {
		Logging::log('Tls Handshake','TLS recording started ...');
		$header = $this->readexactly(self::HEADER_LENGTH,$timeout);
		$size = Helper::unpack('n',substr($header,0x3,0x2));
		$read = $this->socket->read($size,$timeout);
		if(is_null($read)):
			$this->socket->close();
			throw new \RuntimeException('Connection closed by remote host ( EOF ) !');
		endif;
		assert(strlen($read) === $size,new \RuntimeException('The exact size of the bytes was not read'));
		$this->buffer .= $read;
		Logging::log('Tls Handshake','A data of length '.strlen($read).' was obtained from recording TLS');
	}
	public function __call(string $name,array $arguments) : mixed {
		if($name === 'write'):
			list($data) = $arguments;
			for($offset = 0; $offset < strlen($data); $offset += self::LIMIT_SIZE):
				$chunk = substr($data,$offset,self::LIMIT_SIZE);
				$message = pack('C3',0x17,0x3,0x3).pack('n',strlen($chunk)).$chunk;
				if($this->isFirst):
					$this->socket->write(pack('C6',0x14,0x3,0x3,0x0,0x1,0x1).$message);
					$this->isFirst = false;
				else:
					$this->socket->write($message);
				endif;
				Logging::log('Tls Handshake','A message of length '.strlen($message).' and TLS header was sent');
			endfor;
			return null;
		elseif($name === 'read'):
			list($length,$timeout) = $arguments;
			while(strlen($this->buffer) < $length):
				$this->recordTls($timeout);
			endwhile;
			$content = substr($this->buffer,0,$length);
			$this->buffer = substr($this->buffer,$length);
			if(empty($this->buffer) === false):
				Logging::log('Tls Handshake','A buffer of length '.strlen($this->buffer).' bytes remains');
			endif;
			return $content;
		else:
			return $this->socket->$name(...$arguments);
		endif;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network;

use Tak\Liveproto\Network\PlainSender;

use Tak\Liveproto\Crypto\Factorizator;

use Tak\Liveproto\Crypto\Rsa;

use Tak\Liveproto\Crypto\Aes;

use Tak\Liveproto\Crypto\AuthKey;

use Tak\Liveproto\Errors\Security;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Logging;

final class Handshake {
	public PlainSender $sender;

	public function __construct(object $transport,object $session){
		$this->sender = new PlainSender($transport,$session);
	}
	public function authentication(int $dc_id = 0,bool $test_mode = false,bool $media_only = false,int $expires_in = 0) : array {
		$nonce = strval(gmp_import(random_bytes(0x10)));
		$reqPQ = $this(method : 'reqPqMulti',nonce : $nonce);
		assert($reqPQ->nonce === $nonce,new Security('Nonce from server is not equal to nonce !'));
		$serverNonce = $reqPQ->server_nonce;
		$pq = intval(gmp_import($reqPQ->pq));
		$newNonce = strval(gmp_import(random_bytes(0x20)));
		list($p,$q) = Factorizator::factorize($pq);
		Logging::log('Factorizator','P = '.$p.' & Q = '.$q);
		$pqInnerParams = array(
			'pq'=>gmp_export($pq),
			'p'=>gmp_export(min($p,$q)),
			'q'=>gmp_export(max($p,$q)),
			'nonce'=>$nonce,
			'server_nonce'=>$serverNonce,
			'new_nonce'=>$newNonce
		);
		$expires_at = intval($expires_in > 0 ? time() + $expires_in : 0);
		$dc = ($media_only ? -1 : +1) * (abs($dc_id) + ($test_mode ? 10000 : 0));
		Logging::log('Handshake','Selected DC : '.$dc);
		if($expires_at === 0):
			if($dc_id === 0):
				$pqInnerData = new \Tak\Liveproto\Tl\Types\Other\PQInnerData($pqInnerParams);
			else:
				$pqInnerData = new \Tak\Liveproto\Tl\Types\Other\PQInnerDataDc($pqInnerParams + array('dc'=>$dc));
			endif;
		else:
			if($dc_id === 0):
				$pqInnerData = new \Tak\Liveproto\Tl\Types\Other\PQInnerDataTemp($pqInnerParams + array('expires_in'=>$expires_in));
			else:
				$pqInnerData = new \Tak\Liveproto\Tl\Types\Other\PQInnerDataTempDc($pqInnerParams + array('dc'=>$dc,'expires_in'=>$expires_in));
			endif;
		endif;
		$data = $pqInnerData->read();
		Logging::log('Fingerprints',implode(chr(0x20).chr(0x2c).chr(0x20),$reqPQ->server_public_key_fingerprints));
		foreach($reqPQ->server_public_key_fingerprints as $fingerprint):
			$cipher = Rsa::find($fingerprint,$data);
			if(is_null($cipher) === false):
				Logging::log('Fingerprint',$fingerprint);
				break;
			endif;
		endforeach;
		if(is_null($cipher)):
			throw new \RuntimeException('Fingerprint not found !');
		endif;
		$reqDH = $this(method : 'reqDHParams',nonce : $nonce,server_nonce : $serverNonce,p : gmp_export(min($p,$q)),q : gmp_export(max($p,$q)),public_key_fingerprint : $fingerprint,encrypted_data : $cipher);
		assert($reqDH->nonce === $nonce,new Security('Nonce from server is not equal to nonce !'));
		assert($reqDH->server_nonce === $serverNonce,new Security('Server nonce from server is not equal to server nonce !'));
		if($reqDH instanceof \Tak\Liveproto\Tl\Types\Other\ServerDHParamsFail):
			throw new \Exception('Server DH Params Fail !');
		endif;
		list($key,$iv) = Helper::generateKeyNonces(gmp_export($serverNonce,0x10),gmp_export($newNonce,0x20));
		$decrypted = Aes::decrypt($reqDH->encrypted_answer,$key,$iv);
		// answer_with_hash ( decrypted ) := SHA1(answer) + answer + (0-15 random bytes) //
		Logging::log('Aes','Decrypt ige length = '.strlen($decrypted));
		$dhInner = new Binary();
		$dhInner->write($decrypted);
		$answerHash = $dhInner->read(20); // the first 20 bytes of answer_with_hash must be equal to SHA1 //
		// server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data; //
		$serverDHInnerData = $dhInner->readObject();
		$randomBytes = strlen($dhInner->read());
		$answer = $randomBytes > 0 ? substr($decrypted,20,-abs($randomBytes)) : substr($decrypted,20);
		assert(sha1($answer,true) === $answerHash,new Security('The hashed answer is not equal to the hash received from the server !'));
		assert($serverDHInnerData->nonce === $nonce,new Security('Nonce from server is not equal to nonce !'));
		assert($serverDHInnerData->server_nonce === $serverNonce,new Security('Server nonce from server is not equal to server nonce !'));
		$g = $serverDHInnerData->g;
		$dhPrime = strval(gmp_import($serverDHInnerData->dh_prime));
		Security::checkGoodPrime($dhPrime,$g);
		$g_a = gmp_import($serverDHInnerData->g_a);
		$serverTime = $serverDHInnerData->server_time;
		$timeOffset = $serverTime - time();
		for($retryId = 0;$retryId < 3;$retryId++):
			$b = strval(gmp_import(random_bytes(0x800)));
			$g_b = strval(gmp_powm($g,$b,$dhPrime));
			$g_a_b = strval(gmp_powm($g_a,$b,$dhPrime));
			Security::checkG(strval($g),$dhPrime);
			Security::checkG(strval($g_a),$dhPrime,true);
			Security::checkG(strval($g_b),$dhPrime,true);
			$clientDHData = (new \Tak\Liveproto\Tl\Types\Other\ClientDHInnerData)(nonce : $nonce,server_nonce : $serverNonce,retry_id : $retryId,g_b : gmp_export($g_b));
			$data = $clientDHData->read();
			$clientDhEncrypted = Aes::encrypt(sha1($data,true).$data,$key,$iv);
			Logging::log('Aes','Encrypt ige length = '.strlen($clientDhEncrypted));
			$setClientDH = $this(method : 'setClientDHParams',nonce : $nonce,server_nonce : $serverNonce,encrypted_data : $clientDhEncrypted);
			assert($setClientDH->nonce === $nonce,new Security('Nonce from server is not equal to nonce !'));
			assert($setClientDH->server_nonce === $serverNonce,new Security('Server nonce from server is not equal to server nonce !'));
			$authKey = new AuthKey(gab : $g_a_b,expires_at : $expires_at);
			if($setClientDH instanceof \Tak\Liveproto\Tl\Types\Other\DhGenOk):
				$newNonceHashCalculated = $authKey->calcNewNonceHash(gmp_export($newNonce,0x20),0x1);
				assert($setClientDH->new_nonce_hash1 === $newNonceHashCalculated,new Security('Nonce hash 1 is not equal to nonce hash calculated !'));
				$genSalt = new Binary();
				$genSalt->write(substr(gmp_export($newNonce,0x20),0,8) ^ substr(gmp_export($serverNonce,0x10),0,8));
				$salt = $genSalt->readLong();
				$salt_valid_until = strtotime('+ 30 minutes');
				Logging::log('Generate','Salt : '.$salt);
				Logging::log('Handshake','OK !');
				return array($authKey,$timeOffset,$salt,$salt_valid_until);
			elseif($setClientDH instanceof \Tak\Liveproto\Tl\Types\Other\DhGenRetry):
				$newNonceHashCalculated = $authKey->calcNewNonceHash(gmp_export($newNonce,0x20),0x2);
				assert($setClientDH->new_nonce_hash2 === $newNonceHashCalculated,new Security('Nonce hash 2 is not equal to nonce hash calculated !'));
				Logging::log('Handshake','Dh gen retry !',E_ERROR);
				continue;
			elseif($setClientDH instanceof \Tak\Liveproto\Tl\Types\Other\DhGenFail):
				$newNonceHashCalculated = $authKey->calcNewNonceHash(gmp_export($newNonce,0x20),0x3);
				assert($setClientDH->new_nonce_hash3 === $newNonceHashCalculated,new Security('Nonce hash 3 is not equal to nonce hash calculated !'));
				Logging::log('Handshake','Dh gen fail !',E_ERROR);
				break;
			else:
				Logging::log('Handshake','Fail !'.$setClientDH);
			endif;
		endfor;
		throw new \RuntimeException('Authentication failed !');
	}
	public function __invoke(string $method,mixed ...$arguments) : object {
		$class = strval('Tak\\Liveproto\\Tl\\Functions\Other\\'.ucfirst($method));
		$raw = new $class;
		$this->sender->send($raw->request(...$arguments));
		return $this->sender->receive();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network\Proxy;

use Tak\Asyncio\Socket\TlsContext;

use Tak\Asyncio\Socket\StreamSocket;

final class Socks5SocketConnector {
	private StreamSocket $socket;

	private const REPLIES = [
		0 => 'Succeeded',
		1 => 'General SOCKS server failure',
		2 => 'Connection not allowed by ruleset',
		3 => 'Network unreachable',
		4 => 'Host unreachable',
		5 => 'Connection refused',
		6 => 'TTL expired',
		7 => 'Command not supported',
		8 => 'Address type not supported'
	];
	
	public function __construct(private readonly string $proxyAddress,private readonly ? string $username = null,private readonly ? string $password = null){
		$this->socket = new StreamSocket(new Uri($proxyAddress)->domain);
	}
	public function connect(string $host,int $port,TlsContext $context = new TlsContext,bool $secure = false,int $timeout = -1) : StreamSocket {
		$uri = new Uri($this->proxyAddress);
		if($this->socket->connect($uri->address,$uri->port,$timeout) === false):
			throw new \Error('Connection to proxy failed');
		endif;
		self::tunnel($this->socket,$host,$port,$this->username,$this->password,$timeout);
		if($secure):
			$this->socket->setupTls($context);
		endif;
		return $this->socket;
	}
	static public function tunnel(StreamSocket $socket,string $host,int $port,? string $username,? string $password,int $timeout = -1) : void {
		if(is_null($username) !== is_null($password)):
			throw new \RuntimeException('Both or neither username and password must be provided !');
		endif;
		$methods = chr(0);
		if(isset($username) and isset($password)) $methods .= chr(2);
		$socket->write(chr(5).chr(strlen($methods)).$methods);
		$read = function(int $length) use($socket,$timeout) : string {
			assert($length > 0);
			$buffer = strval(null);
			do {
				$limit = $length - strlen($buffer);
				assert($limit > 0);
				$chunk = $socket->read($limit,$timeout);
				if($chunk === null):
					throw new \RuntimeException('The socket was closed before the tunnel could be established');
				endif;
				$buffer .= $chunk;
			} while(strlen($buffer) !== $length);
			return $buffer;
		};
		$version = ord($read(1));
		if($version !== 5):
			throw new \RuntimeException('Wrong SOCKS5 version : '.$version);
		endif;
		$method = ord($read(1));
		if($method === 2):
			if(is_null($username) or is_null($password)):
				throw new \RuntimeException('Unexpected method : '.$method);
			endif;
			$socket->write(chr(1).chr(strlen($username)).$username.chr(strlen($password)).$password);
			$version = ord($read(1));
			if($version !== 1):
				throw new \RuntimeException('Wrong authorized SOCKS version : '.$version);
			endif;
			$result = ord($read(1));
			if($result !== 0):
				throw new \RuntimeException('Wrong authorization status : '.$result);
			endif;
		elseif($method !== 0):
			throw new \RuntimeException('Unexpected method : '.$method);
		endif;
		$ip = inet_pton($host);
		$payload = pack('C3',0x5,0x1,0x0);
		if($ip !== false):
			$payload .= chr(strlen($ip) === 4 ?  0x1 : 0x4).$ip;
		else:
			$payload .= chr(0x3).chr(strlen($host)).$host;
		endif;
		$payload .= pack('n',$port);
		$socket->write($payload);
		$version = ord($read(1));
		if($version !== 5):
			throw new \RuntimeException('Wrong SOCKS5 version : '.$version);
		endif;
		$reply = ord($read(1));
		if($reply !== 0):
			$reply = self::REPLIES[$reply] ?? $reply;
			throw new \RuntimeException('Wrong SOCKS5 reply : '.$reply);
		endif;
		$rsv = ord($read(1));
		if($rsv !== 0):
			throw new \RuntimeException('Wrong SOCKS5 RSV : '.$rsv);
		endif;
		$read(match(ord($read(1))){
			0x1 => 4 + 2,
			0x4 => 16 + 2,
			0x3 => ord($read(1)) + 2
		});
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network\Proxy;

use Tak\Asyncio\Socket\TlsContext;

use Tak\Asyncio\Socket\StreamSocket;

final class HttpSocketConnector {
	private StreamSocket $socket;

	public function __construct(private readonly string $proxyAddress,private readonly ? string $username = null,private readonly ? string $password = null){
		$this->socket = new StreamSocket(new Uri($proxyAddress)->domain);
	}
	public function connect(string $host,int $port,TlsContext $context = new TlsContext,bool $secure = false,int $timeout = -1) : StreamSocket {
		$uri = new Uri($this->proxyAddress);
		if($this->socket->connect($uri->address,$uri->port,$timeout) === false):
			throw new \Error('Connection to proxy failed');
		endif;
		self::tunnel($this->socket,$host,$port,$this->username,$this->password,$timeout);
		if($secure):
			$this->socket->setupTls($context);
		endif;
		return $this->socket;
	}
	static public function tunnel(StreamSocket $socket,string $host,int $port,? string $username,? string $password,int $timeout = -1) : void {
		if(is_null($username) or is_null($password)):
			$authHeader = strval(null);
		else:
			$authHeader = 'Proxy-Authorization: Basic '.base64_encode($username.':'.$password).CRLF;
		endif;
		$ip = inet_pton($host);
		if($ip !== false and strlen($ip) === 16):
			$host = sprintf('[%s]',$ip);
		endif;
		$socket->write('CONNECT '.$host.':'.$port.' HTTP/1.1'.CRLF.'Host: '.$host.':'.$port.CRLF.'Accept: */*'.CRLF.$authHeader.'Connection: keep-Alive'.CRLF.CRLF);
		$read = function(int $length) use($socket,$timeout) : string {
			assert($length > 0);
			$buffer = strval(null);
			do {
				$limit = $length - strlen($buffer);
				assert($limit > 0);
				$chunk = $socket->read($limit,$timeout);
				if($chunk === null):
					throw new \RuntimeException('The socket was closed before the tunnel could be established');
				endif;
				$buffer .= $chunk;
			} while(strlen($buffer) !== $length);
			return $buffer;
		};
		$headers = strval(null);
		do {
			$piece = $read(2);
			$headers .= $piece;
			if($piece === LFCR):
				$headers .= $read(1);
				break;
			elseif(str_ends_with($headers,CRLF.CRLF)):
				break;
			endif;
		} while(true);
		$headers = explode(CRLF,$headers);
		list($protocol,$code,$description) = explode(chr(32),array_shift($headers),3);
		list($protocol,$version) = explode(chr(47),$protocol);
		if($protocol !== 'HTTP'):
			throw new \RuntimeException('Wrong protocol : '.$protocol);
		elseif(array_pop($headers).array_pop($headers) !== strval(null)):
			throw new \RuntimeException('Wrong last HTTP header');
		elseif($code != 200):
			throw new \RuntimeException($code.chr(32).$description,intval($code));
		endif;
		$headers = array_change_key_case(array_column(array_map(fn(string $item) : array => array_map('trim',explode(chr(58),$item,2)),$headers),1,0));
		if(isset($headers['content-length'])):
			$length = intval($headers['content-length']);
			if($length > 0):
				$content = $read($length);
			endif;
		endif;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network\Proxy;

final class Uri {
	public readonly string $scheme;
	public readonly ? string $user;
	public readonly ? string $pass;
	public readonly string $host;
	public readonly int $port;
	public readonly string $path;
	public readonly ? string $query;
	public readonly ? string $fragment;
	public int $domain {
		get => intval($this->ipVersion === 6 ? AF_INET6 : AF_INET);
	}
	public int $protocol {
		get => match($this->scheme){
			'udp' => SOL_UDP,
			default => SOL_TCP
		};
	}
	public int $type {
		get => match($this->scheme){
			'udp' => SOCK_DGRAM,
			default => SOCK_STREAM
		};
	}
	public int $ipVersion {
		get {
			$ip = trim($this->host,'[]');
			return match(true){
				boolval(filter_var($ip,FILTER_VALIDATE_IP,FILTER_FLAG_IPV4)) => 4,
				boolval(filter_var($ip,FILTER_VALIDATE_IP,FILTER_FLAG_IPV6)) => 6,
				default => 0
			};
		}
	}
	public string $address {
		get => trim($this->host,'[]');
	}

	public function __construct(string $uri){
		$parts = parse_url($uri);
		if($parts === false || isset($parts['host']) === false){
			throw new \InvalidArgumentException('Invalid URI : '.$uri);
		}
		$this->scheme = $parts['scheme'] ?? 'tcp';
		$this->user = $parts['user'] ?? null;
		$this->pass = $parts['pass'] ?? null;
		$this->host = $parts['host'];
		$this->port = $parts['port'] ?? $this->getDefaultPort($this->scheme);
		$this->path = $parts['path'] ?? '/';
		$this->query = $parts['query'] ?? null;
		$this->fragment = $parts['fragment'] ?? null;
	}
	private function getDefaultPort(string $scheme) : int {
		return match($scheme){
			'http' , 'ws' => 80,
			'https' , 'wss' => 443,
			'ftp' => 21,
			'ssh' => 22,
			default => 0
		};
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network\Proxy;

use Tak\Asyncio\Socket\TlsContext;

use Tak\Asyncio\Socket\StreamSocket;

final class Socks4SocketConnector {
	private StreamSocket $socket;

	private const REPLIES = [
		0x5a => 'Succeeded',
		0x5b => 'Request rejected or failed',
		0x5c => 'Request failed because client is not running identd',
		0x5d => 'Request different user id'
	];

	public function __construct(private readonly string $proxyAddress,private readonly ? string $user = null){
		$this->socket = new StreamSocket(new Uri($proxyAddress)->domain);
	}
	public function connect(string $host,int $port,TlsContext $context = new TlsContext,bool $secure = false,int $timeout = -1) : StreamSocket {
		$uri = new Uri($this->proxyAddress);
		if($this->socket->connect($uri->address,$uri->port,$timeout) === false):
			throw new \Error('Connection to proxy failed');
		endif;
		self::tunnel($this->socket,$host,$port,$this->user,$timeout);
		if($secure):
			$this->socket->setupTls($context);
		endif;
		return $this->socket;
	}
	static public function tunnel(StreamSocket $socket,string $host,int $port,? string $user,int $timeout = -1) : void {
		$ip = inet_pton($host);
		/*
		 * If host is an IPv4 address we will use SOCKS4. Otherwise , for domain names use SOCKS4a
		 * For SOCKS4a we must send 0.0.0.1 as DSTIP and append domain after USERID NUL
		 */
		$payload = pack('C2',0x4,0x1);
		$payload .= pack('n',$port);
		if(extension_loaded('iconv')):
			$user = @iconv('UTF-8','ASCII//TRANSLIT',strval($user));
		endif;
		if($ip !== false and strlen($ip) === 4):
			$payload .= $ip;
			$payload .= strval($user);
			$payload .= chr(0);
		else:
			$payload .= inet_pton('0.0.0.1');
			$payload .= strval($user);
			$payload .= chr(0);
			if(function_exists('idn_to_ascii')):
				$host = idn_to_ascii($host,IDNA_DEFAULT,INTL_IDNA_VARIANT_UTS46) ?: $host;
			endif;
			$payload .= $host;
			$payload .= chr(0);
		endif;
		$socket->write($payload);
		$read = function(int $length) use($socket,$timeout) : string {
			assert($length > 0);
			$buffer = strval(null);
			do {
				$limit = $length - strlen($buffer);
				assert($limit > 0);
				$chunk = $socket->read($limit,$timeout);
				if($chunk === null):
					throw new \RuntimeException('The socket was closed before the tunnel could be established');
				endif;
				$buffer .= $chunk;
			} while(strlen($buffer) !== $length);
			return $buffer;
		};
		$version = ord($read(1));
		if($version !== 0):
			throw new \RuntimeException('Wrong SOCKS4 version : '.$version);
		endif;
		$reply = ord($read(1));
		if($reply !== 0x5a):
			$reply = self::REPLIES[$reply] ?? $reply;
			throw new \RuntimeException('Wrong SOCKS4 reply : '.$reply);
		endif;
		$read(2);
		$read(4);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Network;

use Tak\Liveproto\Utils\Tools;

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Utils\TlsHello;

use Tak\Asyncio\Socket\StreamSocket;

# https://github.com/DrKLO/Telegram/blob/ddc90f16be1ab952114005347e0102365ba6460b/TMessagesProj/jni/tgnet/ConnectionSocket.cpp #
final class TlsHandshake {
	public string $secret;
	public string $secretDomain;

	public function __construct(public array $proxy){
		list($this->secret,$this->secretDomain) = $this->separate(strval($proxy['secret']));
	}
	public function exchange(StreamSocket $socket,bool $useLegacy) : object {
		$this->doHandshake($socket,$useLegacy);
		return new TlsSocket($socket);
	}
	public function doHandshake(StreamSocket $socket,bool $useLegacy) : void {
		$hello = new TlsHello($this->secretDomain);
		$buffer = $hello->writeToBuffer($useLegacy ? TlsHello::OPS_LEGACY : TlsHello::OPS);
		if(empty($buffer) === false):
			$hmac = hash_hmac('sha256',$buffer,$this->secret,true);
			$timeBytes = pack('V',time());
			$hmacBytes = substr($hmac,0,28).($timeBytes ^ substr($hmac,28,4));
			$tempBuffer = substr($buffer,0,11).$hmacBytes.substr($buffer,11 + 32);
			$socket->write($tempBuffer);
		endif;
		$chunk = null;
		readBuffer:
			do {
				if($socket->isClosed()):
					throw new \RuntimeException('The connection may have been closed due to sending incorrect information to the proxy');
				else:
					$chunk .= $socket->read() ?? throw new \RuntimeException('Connection closed by remote host ( EOF ) !');
				endif;
			} while(empty($chunk));
		$length = strlen($chunk);
		if($length > 64 * 1024):
			Logging::log('Tls Handshake','TLS client hello too much data',E_ERROR);
			$socket->close();
		elseif($length >= 16):
			if(substr($chunk,0,3) === pack('C3',0x16,0x3,0x3)):
				$len1 = intval(ord($chunk[3]) << 8) | ord($chunk[4]);
				if($len1 > 64 * 1024 - 5):
					Logging::log('Tls Handshake','TLS len1 invalid',E_ERROR);
					$socket->close();
				elseif($length >= intval($hello2Start = $len1 + 5)):
					if(substr($chunk,$hello2Start,9) === pack('C9',0x14,0x3,0x3,0x0,0x1,0x1,0x17,0x3,0x3)):
						$len2 = intval(ord($chunk[$hello2Start + 9]) << 8) | ord($chunk[$hello2Start + 10]);
						if($len2 <= 64 * 1024 - $len1 - 5 - 11):
							if($length >= $len2 + $len1 + 5 + 11):
								$prefix = substr($tempBuffer,11,32);
								$payload = substr_replace($chunk,str_repeat(chr(0),32),11,32);
								$hmac = hash_hmac('sha256',$prefix.$payload,$this->secret,true);
								if(hash_equals(substr($chunk,11,32),$hmac)):
									Logging::log('Tls Handshake','TLS hello complete');
								else:
									Logging::log('Tls Handshake','TLS hash mismatch',E_ERROR);
									$socket->close();
								endif;
							else:
								Logging::log('Tls Handshake','TLS client hello wait for more data',E_NOTICE);
								goto readBuffer;
							endif;
						else:
							Logging::log('Tls Handshake','TLS len2 invalid',E_ERROR);
							$socket->close();
						endif;
					else:
						Logging::log('Tls Handshake','TLS hello2 mismatch',E_ERROR);
						$socket->close();
					endif;
				else:
					Logging::log('Tls Handshake','TLS client hello wait for more data',E_NOTICE);
					goto readBuffer;
				endif;
			else:
				Logging::log('Tls Handshake','TLS hello1 mismatch',E_ERROR);
				$socket->close();
			endif;
		endif;
	}
	public function separate(string $secret) : array {
		$bytes = ctype_xdigit($secret) ? hex2bin($secret) : Tools::base64_url_decode($secret);
		$raw =  substr($bytes,intval(strlen($bytes) > 17 and strcasecmp($secret,'ee') === 1));
		return array(substr($raw,0,16),substr($raw,16));
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

enum TransferKind : string {
	case FILE = 'file';
	case STREAM = 'stream';
	case CALLBACK = 'callback';
	case BROWSER = 'browser';
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

enum PeerType : string {
	case SELF = 'self';
	case USER = 'user';
	case BOT = 'bot';
	case CHAT = 'chat';
	case GIGAGROUP = 'gigagroup';
	case MEGAGROUP = 'megagroup';
	case CHANNEL = 'channel';
	case UNKNOWN = 'unknown';

	public function getChatType() : string {
		return match($this){
			self::SELF , self::USER , self::BOT => 'private',
			self::CHAT => 'group',
			self::GIGAGROUP , self::MEGAGROUP => 'supergroup',
			self::CHANNEL => 'channel',
			default => 'unknown'
		};
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

enum EmailPurpose : string {
	case LOGINSETUP = 'emailVerifyPurposeLoginSetup';
	case LOGINCHANGE = 'emailVerifyPurposeLoginChange';
	case PASSPORT = 'emailVerifyPurposePassport';
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

# https://github.com/tdlib/td/blob/master/td/telegram/files/FileType.h #
enum FileType : string {
	case THUMBNAIL = 'thumbnail';
	case PROFILE_PHOTO = 'profile_photo';
	case PHOTO = 'photo';
	case VOICE = 'voice';
	case VIDEO = 'video';
	case DOCUMENT = 'document';
	case ENCRYPTED = 'encrypted';
	case TEMP = 'temp';
	case STICKER = 'sticker';
	case AUDIO = 'audio';
	case ANIMATION = 'animation';
	case ENCRYPTED_THUMBNAIL = 'encrypted_thumbnail';
	case WALLPAPER = 'wallpaper';
	case VIDEO_NOTE = 'video_note';
	case SECURE_DECRYPTED = 'secure_decrypted';
	case SECURE_ENCRYPTED = 'secure_encrypted';
	case BACKGROUND = 'background';
	case DOCUMENT_AS_FILE = 'document_as_file';
	case RINGTONE = 'ringtone';
	case CALL_LOG = 'call_log';
	case PHOTO_STORY = 'photo_story';
	case VIDEO_STORY = 'video_story';
	case SELF_DESTRUCTING_PHOTO = 'self_destructing_photo';
	case SELF_DESTRUCTING_VIDEO = 'self_destructing_video';
	case SELF_DESTRUCTING_VIDEONOTE = 'self_destructing_videonote';
	case SELF_DESTRUCTING_VOICENOTE = 'self_destructing_voicenote';
	case SIZE = 'size';

	static public function fromId(int $id) : self {
		return self::cases()[$id] ?? throw new \InvalidArgumentException('Invalid FileType ID !');
	}
	public function toId() : int {
		return array_search($this,self::cases());
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

enum RekeyState : int {
	case IDLE = 0;
	case REQUESTED = 1;
	case ACCEPTED = 2;
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

enum Authentication : int {
	case NEED_AUTHENTICATION = 0;
	case NEED_CODE = 1;
	case NEED_CODE_PAYMENT_REQUIRED = 2;
	case NEED_EMAIL = 3;
	case NEED_EMAIL_VERIFY = 4;
	case NEED_PASSWORD = 5;
	case NEED_SIGNUP = 6;
	case LOGIN = 7;
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

enum ProtocolType : string {
	case FULL = 'TcpFull';
	case ABRIDGED = 'TcpAbridged';
	case INTERMEDIATE = 'TcpIntermediate';
	case PADDEDINTERMEDIATE = 'TcpPaddedIntermediate';
	case OBFUSCATED = 'TcpObfuscated';
	case HTTP = 'Http';

	public function toBytes() : string {
		return gmp_export(match($this){
			self::ABRIDGED => 0xefefefef,
			self::INTERMEDIATE => 0xeeeeeeee,
			self::PADDEDINTERMEDIATE => 0xdddddddd,
			self::HTTP => 0x54534f50,
			default => throw new \Exception('There is no bytes for this protocol !')
		});
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

# https://github.com/tdlib/td/blob/master/td/telegram/PhotoSizeSource.h #
enum PhotoSizeType : int {
	case LEGACY = 0;
	case THUMBNAIL = 1;
	case DIALOGPHOTO_SMALL = 2;
	case DIALOGPHOTO_BIG = 3;
	case STICKERSET_THUMBNAIL = 4;
	case FULL_LEGACY = 5;
	case DIALOGPHOTO_SMALL_LEGACY = 6;
	case DIALOGPHOTO_BIG_LEGACY = 7;
	case STICKERSET_THUMBNAIL_LEGACY = 8;
	case STICKERSET_THUMBNAIL_VERSION = 9;
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

enum NonRpcResult : string {
	case DESTROY_SESSION = 'destroySession';
	case DESTROY_AUTH_KEY = 'destroyAuthKey';
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

enum CommandType : string {
	case DOT = '.';
	case SLASH = '/';
	case BACKSLASH = '\\';
	case EXCLAMATION = '!';
	case COLON = ':';
	case SEMICOLON = ';';
	case HASH = '#';
	case DOLLAR = '$';
	case AMPERSAND = '&';
	case ASTERISK = '*';
	case CARET = '^';
	case TILDE = '~';
	case PIPE = '|';
	case AT = '@';
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

enum MTProtoKeepAlive : string {
	case PING_PONG = 'ping-pong'; // Primary application-level keepalive for MTProto : ping ( client ) <-> pong ( server ) //
	case HTTP_LONG_POLL = 'http-long-poll'; // HTTP long-polling ( e.g. http_wait / long polling style transports ) //
	case NONE = 'none'; // No persistent keepalive ( one-shot connections ) //
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Enums;

enum Endianness : int {
	case BIG = 1;
	case LITTLE = -1;
	case UNKNOWN = 0;

	public static function detect() : self {
		$hex = bin2hex(pack('S',0x0102));
		return match($hex){
			'0102' => self::BIG,
			'0201' => self::LITTLE,
			default => self::UNKNOWN
		};
	}
	public function isBig() : bool {
		return $this === self::BIG;
	}
	public function isLittle() : bool {
		return $this === self::LITTLE;
	}
}

?><?php

declare(strict_types = 1);

defined('CRLF') || define('CRLF',chr(13).chr(10));

defined('LFCR') || define('LFCR',chr(10).chr(13));

defined('SIGTSTP') || define('SIGTSTP',20);

defined('SIGINT') || define('SIGINT',2);

defined('SIGQUIT') || define('SIGQUIT',3);

defined('SIGTERM') || define('SIGTERM',15);

defined('SIGHUP') || define('SIGHUP',1);

class_alias(Tak\Liveproto\Network\Client::class,Tak\Liveproto\API::class);

class_alias(Tak\Liveproto\Filters\Filter::class,Tak\Liveproto\Handler::class);

class_alias(Tak\Liveproto\Errors\RpcError::class,Tak\Liveproto\Errors::class);

const REQUIRED_PHP_VERSION = '8.3.0';

const REQUIRED_EXTENSIONS = array(
	'openssl',
	'gmp',
	'json',
	'xml',
	'dom',
	'filter',
	'hash',
	'zlib',
	'fileinfo'
);

if(version_compare(PHP_VERSION,REQUIRED_PHP_VERSION,'>=') === false):
	throw new \LogicException('Minimum PHP version required : '.REQUIRED_PHP_VERSION);
endif;

if(PHP_INT_SIZE !== 8):
	throw new \LogicException('PHP must be 64-bit');
endif;

foreach(REQUIRED_EXTENSIONS as $extension):
	if(extension_loaded($extension) === false):
		throw new \LogicException('Extension '.$extension.' is not loaded');
	endif;
endforeach;

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Attributes;

use Tak\Liveproto\Parser\Tl;

use Tak\Liveproto\Utils\Instance;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class Type implements ValidatorInterface {
	protected array $types;

	public function __construct(string ...$types){
		$this->types = array_filter(array_map(trim(...),$types));
	}
	public function validate(string $name,mixed $value) : mixed {
		if($value instanceof Instance === false){
			throw new InvalidArgumentException('$'.$name.' must be Instance');
		}
		$type = Tl::parseReturn($value);
		if(in_array($type,$this->types,true) === false){
			throw new InvalidArgumentException('$'.$name.' must be'.strval(count($this->types) > 1 ? ' one of ' : chr(32)).implode(chr(32).chr(44).chr(32),$this->types).' type , given '.$type);
		}
		return $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Utils;

use phpseclib3\Crypt\EC\Curves\Curve25519;

use phpseclib3\Math\BigInteger;

final class TlsHello {
	private const MAX_GREASE = 8;
	public const OPS_LEGACY = [
		['type'=>'string','data'=>"\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03"],
		['type'=>'zero','len'=>32],
		['type'=>'string','data'=>"\x20"],
		['type'=>'random','len'=>32],
		['type'=>'string','data'=>"\x00\x20"],
		['type'=>'grease','seed'=>0],
		['type'=>'string','data'=>"\x13\x01\x13\x02\x13\x03\xc0\x2b\xc0\x2f\xc0\x2c\xc0\x30\xcc\xa9\xcc\xa8\xc0\x13\xc0\x14\x00\x9c\x00\x9d\x00\x2f\x00\x35\x01\x00\x01\x93"],
		['type'=>'grease','seed'=>2],
		['type'=>'string','data'=>"\x00\x00"],
		['type'=>'permutation','entities'=>[
			[
				['type'=>'string','data'=>"\x00\x00"],
				['type'=>'begin'],
				['type'=>'begin'],
				['type'=>'string','data'=>"\x00"],
				['type'=>'begin'],
				['type'=>'domain'],
				['type'=>'end'],
				['type'=>'end'],
				['type'=>'end'],
			],
			[['type'=>'string','data'=>"\x00\x05\x00\x05\x01\x00\x00\x00\x00"]],
			[
				['type'=>'string','data'=>"\x00\x0a\x00\x0a\x00\x08"],
				['type'=>'grease','seed'=>4],
				['type'=>'string','data'=>"\x00\x1d\x00\x17\x00\x18"],
			],
			[['type'=>'string','data'=>"\x00\x0b\x00\x02\x01\x00"]],
			[['type'=>'string','data'=>"\x00\x0d\x00\x12\x00\x10\x04\x03\x08\x04\x04\x01\x05\x03\x08\x05\x05\x01\x08\x06\x06\x01"]],
			[['type'=>'string','data'=>"\x00\x10\x00\x0e\x00\x0c\x02\x68\x32\x08\x68\x74\x74\x70\x2f\x31\x2e\x31"]],
			[['type'=>'string','data'=>"\x00\x12\x00\x00"]],
			[['type'=>'string','data'=>"\x00\x17\x00\x00"]],
			[['type'=>'string','data'=>"\x00\x1b\x00\x03\x02\x00\x02"]],
			[['type'=>'string','data'=>"\x00\x23\x00\x00"]],
			[
				['type'=>'string','data'=>"\x00\x2b\x00\x07\x06"],
				['type'=>'grease','seed'=>6],
				['type'=>'string','data'=>"\x03\x04\x03\x03"]
			],
			[['type'=>'string','data'=>"\x00\x2d\x00\x02\x01\x01"]],
			[
				['type'=>'string','data'=>"\x00\x33\x00\x2b\x00\x29"],
				['type'=>'grease','seed'=>4],
				['type'=>'string','data'=>"\x00\x01\x00\x00\x1d\x00\x20"],
				['type'=>'K'],
			],
			[['type'=>'string','data'=>"\x44\x69\x00\x05\x00\x03\x02\x68\x32"]],
			[['type'=>'string','data'=>"\xff\x01\x00\x01\x00"]],
		]],
		['type'=>'grease','seed'=>3],
		['type'=>'string','data'=>"\x00\x01\x00"],
		['type'=>'P']
	];
	public const OPS = [
		['type'=>'string','data'=>"\x16\x03\x01"],
		['type'=>'begin'],
		['type'=>'string','data'=>"\x01\x00"],
		['type'=>'begin'], 
		['type'=>'string','data'=>"\x03\x03"],
		['type'=>'zero','len'=>32],
		['type'=>'string','data'=>"\x20"],
		['type'=>'random','len'=>32],
		['type'=>'string','data'=>"\x00\x20"],
		['type'=>'grease','seed'=>0],
		['type'=>'string','data'=>"\x13\x01\x13\x02\x13\x03\xc0\x2b\xc0\x2f\xc0\x2c\xc0\x30\xcc\xa9\xcc\xa8\xc0\x13\xc0\x14\x00\x9c\x00\x9d\x00\x2f\x00\x35\x01\x00"],
		['type'=>'begin'],
		['type'=>'grease','seed'=>2],
		['type'=>'string','data'=>"\x00\x00"],
		['type'=>'permutation','entities'=>[
			[
				['type'=>'string','data'=>"\x00\x00"],
				['type'=>'begin'],
				['type'=>'begin'],
				['type'=>'string','data'=>"\x00"],
				['type'=>'begin'],
				['type'=>'domain'],
				['type'=>'end'],
				['type'=>'end'],
				['type'=>'end'],
			],
			[['type'=>'string','data'=>"\x00\x05\x00\x05\x01\x00\x00\x00\x00"]],
			[
				['type'=>'string','data'=>"\x00\x0a\x00\x0c\x00\x0a"],
				['type'=>'grease','seed'=>4],
				['type'=>'string','data'=>"\x11\xec\x00\x1d\x00\x17\x00\x18"],
			],
			[['type'=>'string','data'=>"\x00\x0b\x00\x02\x01\x00"]],
			[['type'=>'string','data'=>"\x00\x0d\x00\x12\x00\x10\x04\x03\x08\x04\x04\x01\x05\x03\x08\x05\x05\x01\x08\x06\x06\x01"]],
			[['type'=>'string','data'=>"\x00\x10\x00\x0e\x00\x0c\x02\x68\x32\x08\x68\x74\x74\x70\x2f\x31\x2e\x31"]],
			[['type'=>'string','data'=>"\x00\x12\x00\x00"]],
			[['type'=>'string','data'=>"\x00\x17\x00\x00"]],
			[['type'=>'string','data'=>"\x00\x1b\x00\x03\x02\x00\x02"]],
			[['type'=>'string','data'=>"\x00\x23\x00\x00"]],
			[
				['type'=>'string','data'=>"\x00\x2b\x00\x07\x06"],
				['type'=>'grease','seed'=>6],
				['type'=>'string','data'=>"\x03\x04\x03\x03"],
			],
			[['type'=>'string','data'=>"\x00\x2d\x00\x02\x01\x01"]],
			[
				['type'=>'string','data'=>"\x00\x33\x04\xef\x04\xed"],
				['type'=>'grease','seed'=>4],
				['type'=>'string','data'=>"\x00\x01\x00\x11\xec\x04\xc0"],
				['type'=>'M'],
				['type'=>'K'],
				['type'=>'string','data'=>"\x00\x1d\x00\x20"],
				['type'=>'K'],
			],
			[['type'=>'string','data'=>"\x44\xcd\x00\x05\x00\x03\x02\x68\x32"]],
			[
				['type'=>'string','data'=>"\xfe\x0d"],
				['type'=>'begin'],
				['type'=>'string','data'=>"\x00\x00\x01\x00\x01"],
				['type'=>'random','len'=>1],
				['type'=>'string','data'=>"\x00\x20"],
				['type'=>'random','len'=>32],
				['type'=>'begin'],
				['type'=>'E'],
				['type'=>'end'],
				['type'=>'end'],
			],
			[['type'=>'string','data'=>"\xff\x01\x00\x01\x00"]],
		]],
		['type'=>'grease','seed'=>3],
		['type'=>'string','data'=>"\x00\x01\x00"],
		['type'=>'P'],
		['type'=>'end'],
		['type'=>'end'],
		['type'=>'end'],
	];

	private array $grease = array();
	private array $heap = array();
	public string $buffer;

	public function __construct(private ? string $domain = null){
		$r = random_bytes(self::MAX_GREASE);
		for($i = 0; $i < self::MAX_GREASE; $i++):
			$v = ord($r[$i]);
			$v = ($v & 0xF0) + 0x0A;
			if($i % 2 === 1 and $v === $this->grease[$i - 1]):
				$v ^= 0x10;
			endif;
			$this->grease[$i] = $v;
		endfor;
		$this->buffer = strval(null);
	}
	public function writeToBuffer(array $ops) : string {
		foreach($ops as $op){
			$this->buffer .= $this->writeOp($op);
		}
		return $this->buffer;
	}
	private function writeOp(array $op) : string {
		$type = $op['type'];
		switch($type):
			case 'string':
				return $op['data'];
			case 'random':
				return random_bytes($op['len']);
			case 'K':
				return self::generatePublicKey();
			case 'M':
				return self::generateKeyMlKem768();
			case 'E':
				$lengths = array(0x90,0xb0,0xd0,0xf0);
				$length = $lengths[array_rand($lengths)];
				return random_bytes($length);
			case 'P':
				$length = strlen($this->buffer);
				if($length <= 0x201):
					$size = abs(0x201 - $length);
					return pack('C2',0x0,0x15).chr(($size >> 8) & 0xFF).chr($size & 0xFF).str_repeat(chr(0),$size);
				endif;
				return strval(null);
			case 'zero':
				return str_repeat(chr(0),$op['len']);
			case 'domain':
				return substr(strval($this->domain),0,253);
			case 'grease':
				$seed = $op['seed'];
				$v = $this->grease[$seed % count($this->grease)];
				return chr($v).chr($v);
			case 'begin':
				$this->heap []= strlen($this->buffer);
				return pack('C2',0,0);
			case 'end':
				$offset = intval(array_pop($this->heap));
				$size = strlen($this->buffer) - ($offset + 2);
				$this->buffer[$offset] = chr(($size >> 8) & 0xFF);
				$this->buffer[$offset + 1] = chr($size & 0xFF);
				return strval(null);
			case 'permutation':
				$entities = $op['entities'];
				shuffle($entities);
				foreach($entities as $sub):
					$this->writeToBuffer($sub);
				endforeach;
				return strval(null);
			default:
				return strval(null);
		endswitch;
	}
	static private function generatePublicKey() : string {
		$curve = new Curve25519();
		$curve->setCoefficients(new BigInteger('486662'));
		$scalarBytes = random_bytes(0x20);
		$scalar = new BigInteger($scalarBytes,0x100);
		$basePoint = $curve->getBasePoint();
		$resultPoint = $curve->multiplyPoint($basePoint,$scalar);
		$affine = $curve->convertToAffine($resultPoint);
		$xInt = $affine[false];
		$xBytes = $xInt->toBytes();
		return str_pad($xBytes,0x20,chr(0),STR_PAD_LEFT);
	}
	static private function generateKeyMlKem768() : string {
		$Q = 3329;
		$N = 384;
		$valuesCount = $N * 2;
		$rand = random_bytes($valuesCount * 4);
		$vals = @unpack('V*',$rand);
		$out = strval(null);
		for($i = 0;$i < $N;$i++):
			$a = $vals[$i * 2 + 1] % $Q;
			$b = $vals[$i * 2 + 2] % $Q;
			$out .= chr($a & 0xFF);
			$out .= chr((($a >> 8) | (($b & 0x0F) << 4)) & 0xFF);
			$out .= chr(($b >> 4) & 0xFF);
		endfor;
		$out .= random_bytes(32);
		if(strlen($out) !== intval($N * 3 + 32)):
				throw new \LengthException('ML-KEM768 : produced unexpected length',strlen($out));
		endif;
		return $out;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Utils;

use Tak\Liveproto\Enums\Endianness;

abstract class Helper {
	static public function unpack(string $format,string $string,int $offset = 0,Endianness $byteorder = Endianness::LITTLE) : mixed {
		$un = unpack($format,$byteorder->isBig() ? strrev($string) : $string,$offset);
		$result = is_array($un) ? $un[true] : $un;
		return $result;
	}
	static public function pack(string $format,mixed $value,Endianness $byteorder = Endianness::LITTLE) : string {
		return pack($format,$byteorder->isLittle() ? $value : strrev(strval($value)));
	}
	static public function generateRandomLong() : int {
		$long = random_int(PHP_INT_MIN,PHP_INT_MAX);
		return $long === 0 ? call_user_func(__METHOD__) : $long;
	}
	static public function generateRandomLargeInt(int $bits = 0x40) : string {
		$bytes = intdiv($bits,8);
		return strval(gmp_import(random_bytes($bytes),$bytes));
	}
	static public function generateRandomString(int $length = 0x10) : string {
		return substr(str_shuffle(implode([...range('A','Z'),...range('a','z'),...range(0,9)])),-abs($length));
	}
	/* V2 : https://core.telegram.org/mtproto/description#defining-aes-key-and-initialization-vector */
	static public function keyCalculate(string $authKey,string $msgKey,bool $client) : array {
		$x = $client ? 0x0 : 0x8;
		$a = hash('sha256',$msgKey.substr($authKey,$x,0x24),true);
		$b = hash('sha256',substr($authKey,0x28 + $x,0x24).$msgKey,true);
		$key = substr($a,0x0,0x8).substr($b,0x8,0x10).substr($a,0x18,0x8);
		$iv = substr($b,0x0,0x8).substr($a,0x8,0x10).substr($b,0x18,0x8);
		return [$key,$iv];
	}
	/* V1 : https://core.telegram.org/mtproto/description_v1#defining-aes-key-and-initialization-vector */
	static public function aesCalculate(string $authKey,string $msgKey,bool $client) : array {
		$x = $client ? 0x0 : 0x8;
		$a = sha1($msgKey.substr($authKey,$x,0x20),true);
		$b = sha1(substr($authKey,$x + 0x20,0x10).$msgKey.substr($authKey,$x + 0x30,0x10),true);
		$c = sha1(substr($authKey,$x + 0x40,0x20).$msgKey,true);
		$d = sha1($msgKey.substr($authKey,$x + 0x60,0x20),true);
		$key = substr($a,0x0,0x8).substr($b,0x8,0xc).substr($c,0x4,0xc);
		$iv = substr($a,0x8,0xc).substr($b,0x0,0x8).substr($c,0x10,0x4).substr($d,0x0,0x8);
		return [$key,$iv];
	}
	static public function generateKeyNonces(string $serverNonce,string $newNonce) : array {
		$hash1 = sha1($newNonce.$serverNonce,true);
		$hash2 = sha1($serverNonce.$newNonce,true);
		$hash3 = sha1($newNonce.$newNonce,true);
		$key = $hash1.substr($hash2,0x0,0xc);
		$iv = substr($hash2,0xc,0x8).$hash3.substr($newNonce,0x0,0x4);
		return [$key,$iv];
	}
	# https://core.telegram.org/api/offsets#hash-generation #
	static public function hashGeneration(int $hash = 0,array $ids = array()) : int {
		foreach($ids as $id):
			if(is_string($id)):
				$id = self::unpack('P',substr(md5($id,true),0,8),Endianness::BIG);
			else:
				$id = intval($id);
			endif;
			$hash = $hash ^ ($hash >> 21) & ~ ( 1 << (8 * PHP_INT_SIZE - 1) >> 20);
			$hash = $hash ^ ($hash << 35);
			$hash = $hash ^ ($hash >> 4) & ~ ( 1 << (8 * PHP_INT_SIZE - 1) >> 3);
			$hash = $hash + $id;
		endforeach;
		return $hash;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Utils;

abstract class StringTools {
	static public function diff(string $oldText,string $newText) : array {
		$old = self::splitGraphemes($oldText);
		$new = self::splitGraphemes($newText);
		$m = count($old);
		$n = count($new);
		$dp = array_fill(0,$m + 1,array_fill(0,$n + 1,0));
		for($i = $m - 1;$i >= 0;$i--):
			for($j = $n - 1;$j >= 0;$j--):
				if($old[$i] === $new[$j]):
					$dp[$i][$j] = $dp[$i + 1][$j + 1] + 1;
				else:
					$dp[$i][$j] = max($dp[$i + 1][$j],$dp[$i][$j + 1]);
				endif;
			endfor;
		endfor;
		$ops = array();
		$i = 0;
		$j = 0;
		while($i < $m or $j < $n):
			if($i < $m and $j < $n and $old[$i] === $new[$j]):
				$i++;
				$j++;
				continue;
			endif;
			$startNew = $j;
			$deleted = array();
			$inserted = array();
			while($i < $m or $j < $n):
				if($i < $m and $j < $n and $old[$i] === $new[$j]):
					break;
				elseif($i < $m and boolval($j === $n or $dp[$i + 1][$j] >= $dp[$i][$j + 1])):
					$deleted[] = $old[$i];
					$i++;
				elseif($j < $n):
					$inserted[] = $new[$j];
					$j++;
				else:
					break;
				endif;
			endwhile;
			$deletedText = implode($deleted);
			$insertedText = implode($inserted);
			$newPrefix = implode(array_slice($new,0,$startNew));
			$offset = self::offset($newText,strlen($newPrefix));
			$oldLength = self::length($deletedText);
			$newLength = self::length($insertedText);
			if($oldLength > 0 and $newLength > 0):
				$ops[] = [
					'type' => 'replace',
					'offset' => $offset,
					'length' => $newLength,
					'old' => $deletedText,
					'new' => $insertedText
				];
			elseif($oldLength > 0):
				$ops[] = [
					'type' => 'delete',
					'offset' => $offset,
					'length' => $oldLength,
					'old' => $deletedText
				];
			elseif($newLength > 0):
				$ops[] = [
					'type' => 'insert',
					'offset' => $offset,
					'length' => $newLength,
					'new' => $insertedText
				];
			endif;
		endwhile;
		return $ops;
	}
	static private function splitGraphemes(string $text) : array {
		if(empty($text)):
			return array();
		elseif(function_exists('grapheme_strlen') and function_exists('grapheme_substr')):
			return array_map(fn(int $i) : string => grapheme_substr($text,$i,0x1),range(0x0,grapheme_strlen($text) - 0x1));
		else:
			if(preg_match_all('/\X/u',$text,$matches)):
				return reset($matches);
			else:
				throw new \InvalidArgumentException('Invalid UTF-8 input');
			endif;
		endif;
	}
	static public function offset(string | array $text,int $byteOffset) : int {
		$text = is_array($text) ? array_values($text) : $text;
		$length = is_array($text) ? count($text) : strlen($text);
		$offset = 0;
		for($i = 0;$i < $length;$i++):
			$byte = ord($text[$i]);
			if(($byte & 0xc0) != 0x80):
				if($i >= $byteOffset):
					return $offset;
				else:
					$offset += intval($byte >= 0xf0) + 0x1;
				endif;
			endif;
		endfor;
		return $offset;
	}
	static public function length(string | array $text) : int {
		$text = is_array($text) ? array_values($text) : $text;
		$length = is_array($text) ? count($text) : strlen($text);
		$byteLength = 0;
		for($i = 0;$i < $length;$i++):
			$byte = ord($text[$i]);
			if(($byte & 0xc0) != 0x80):
				$byteLength += intval($byte >= 0xf0) + 0x1;
			endif;
		endfor;
		return $byteLength;
	}
	static public function substr(string | array $text,int $offset,? int $length = null) : string {
		$text = is_array($text) ? implode($text) : $text;
		return mb_convert_encoding(substr(mb_convert_encoding($text,'UTF-16'),$offset << 0x1,is_int($length) ? ($length << 0x1) : null),'UTF-8','UTF-16');
	}
	static public function strsplice(string | array $text,string | array $replace,int $offset,? int $length = null) : string {
		$text = is_array($text) ? implode($text) : $text;
		$replace = is_array($replace) ? implode($replace) : $replace;
		return mb_convert_encoding(substr_replace(mb_convert_encoding($text,'UTF-16'),mb_convert_encoding($replace,'UTF-16'),$offset << 0x1,is_int($length) ? ($length << 0x1) : null),'UTF-8','UTF-16');
	}
	static public function strsplit(string | array $text,int $length) : array {
		$text = is_array($text) ? implode($text) : $text;
		return array_map(fn(string $chunk) : string => mb_convert_encoding($chunk,'UTF-8','UTF-16'),str_split(mb_convert_encoding($text,'UTF-16'),$length << 0x1));
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Utils;

use Tak\Liveproto\Tl\All;

use Stringable;

final class Binary implements Stringable {
	public readonly bool $repeating;
	public readonly int $id;
	private int $position;
	private int $length;
	private string $data;
	private array $previousread;
	private array $previouswrite;

	public function __construct(bool $repeating = false){
		$this->repeating = $repeating;
		$this->id = intval(microtime(true) * 1000);
		$this->position = 0;
		$this->length = 0;
		$this->data = strval(null);
		$this->previousread = array();
		$this->previouswrite = array();
	}
	public function readByte() : mixed {
		return Helper::unpack('C',$this->read(1));
	}
	public function readInt() : mixed {
		return Helper::unpack('V',$this->read(4));
	}
	public function readLong() : mixed {
		return Helper::unpack('P',$this->read(8));
	}
	public function readDouble() : mixed {
		return Helper::unpack('e',$this->read(8));
	}
	public function readLargeInt(int $bits = 0x40) : mixed {
		$bytes = intdiv($bits,8);
		return strval(gmp_import($this->read($bytes),$bytes));
	}
	public function readBytes() : string {
		$firstByte = $this->readByte();
		if($firstByte == 0xfe):
			$length = $this->readByte() | ($this->readByte() << 8) | ($this->readByte() << 16);
			$padding = $length % 4;
		else:
			$length = $firstByte;
			$padding = ($length + 1) % 4;
		endif;
		$data = $this->read($length);
		$this->read($padding > 0 ? 0x4 - $padding : 0);
		return $data;
	}
	public function readBool(bool $undo = false) : bool {
		if($undo) $this->undo();
		$object = new \Tak\Liveproto\Tl\Types\Other\BoolFalse;
		$request = $object->request();
		return boolval($this->readInt() !== $request->readInt());
	}
	public function readVector(string $type,bool $undo = false) : array {
		if($undo) $this->undo();
		$vector = array();
		$vector_id = $this->readInt();
		if($vector_id !== 0x1cb5c415):
			throw new \RuntimeException('The constructor id of the vector is wrong : '.dechex($vector_id));
		endif;
		$length = $this->readInt();
		for($i = 0;$i < $length;$i++):
			$vector[] = match(strtolower($type)){
				'int' => $this->readInt(),
				'int128' => $this->readLargeInt(128),
				'int256' => $this->readLargeInt(256),
				'int512' => $this->readLargeInt(512),
				'long' => $this->readLong(),
				'double' => $this->readDouble(),
				'string' => $this->readBytes(),
				'bytes' => $this->readBytes(),
				'bool' => $this->readBool(),
				default => $this->readObject()
			};
		endfor;
		return $vector;
	}
	public function readObject(bool $undo = false) : object {
		if($undo) $this->undo();
		$constructorId = $this->readInt();
		$response = match(intval($constructorId)){
			0xbc799737 , 0x997275b5 , 0x3fedd339 => (object) ['bool'=>$this->readBool(...)],
			0x1cb5c415 => (object) ['vector'=>$this->readVector(...)],
			default => All::getConstructor($constructorId)->response($this)
		};
		return $response;
	}
	public function read(int $length = PHP_INT_MAX) : mixed {
		$read = substr($this->data,0x0,$length);
		$this->data = substr($this->data,$length);
		$this->position += strlen($read);
		$this->previousread []= $read;
		if(empty($this->data) and $this->repeating):
			$this->data = implode($this->previousread);
			$this->position = 0;
			$this->previousread = array();
		endif;
		return $read;
	}
	public function redo(int $limit = PHP_INT_MAX) : mixed {
		$write = substr(strval(array_pop($this->previouswrite)),0x0,$limit);
		$this->data = substr($this->data,0x0,-strlen($write));
		$this->length -= strlen($write);
		return $this;
	}
	public function tellLength() : int {
		return $this->length;
	}
	public function tellPosition() : int {
		return $this->position;
	}
	public function writeByte(mixed $value) : self {
		return $this->write(Helper::pack('C',$value));
	}
	public function writeInt(mixed $value) : self {
		return $this->write(Helper::pack('V',$value));
	}
	public function writeLong(mixed $value) : self {
		return $this->write(Helper::pack('P',$value));
	}
	public function writeDouble(mixed $value) : self {
		return $this->write(Helper::pack('e',$value));
	}
	public function writeLargeInt(mixed $value,int $bits = 0x40) : self {
		$bytes = intdiv($bits,8);
		return $this->write(gmp_export($value,$bytes));
	}
	public function writeBytes(string $data) : self {
		$length = strlen($data);
		if($length < 0xfe):
			$padding = ($length + 1) % 0x4;
			$this->writeByte($length);
		else:
			$padding = $length % 0x4;
			$this->writeByte(0xfe);
			$this->writeByte(($length >> 0) % 0x100);
			$this->writeByte(($length >> 8) % 0x100);
			$this->writeByte(($length >> 16) % 0x100);
		endif;
		$this->write($data);
		return $this->write(str_repeat(chr(0),$padding > 0 ? 0x4 - $padding : 0));
	}
	public function writeBool(bool $boolean,bool $redo = false) : self {
		if($redo) $this->redo();
		$constructor = $boolean ? new \Tak\Liveproto\Tl\Types\Other\BoolTrue : new \Tak\Liveproto\Tl\Types\Other\BoolFalse;
		return $constructor->write($this);
	}
	public function writeVector(array $vectors,string $type,bool $redo = false) : self {
		if($redo) $this->redo();
		$this->writeInt(0x1cb5c415);
		$this->writeInt(count($vectors));
		foreach($vectors as $vector):
			match($type){
				'int' => $this->writeInt($vector),
				'int128' => $this->writeLargeInt($vector,128),
				'int256' => $this->writeLargeInt($vector,256),
				'int512' => $this->writeLargeInt($vector,512),
				'long' => $this->writeLong($vector),
				'double' => $this->writeDouble($vector),
				'string' => $this->writeBytes($vector),
				'bytes' => $this->writeBytes($vector),
				'bool' => $this->writeBool($vector),
				default => $this->writeObject($vector)
			};
		endforeach;
		return $this;
	}
	public function writeObject(object $object,bool $redo = false) : self {
		if($redo) $this->redo();
		return $this->write($object->read());
	}
	public function write(string $data) : self {
		$this->data .= $data;
		$this->length += strlen($data);
		$this->previouswrite []= $data;
		return $this;
	}
	public function undo(int $limit = PHP_INT_MAX) : self {
		$write = substr(strval(array_pop($this->previousread)),0x0,$limit);
		if(empty($write) === false):
			$this->position -= strlen($write);
			$this->data = $write.$this->data;
			$this->previouswrite []= $write;
			array_pop($this->previouswrite);
		endif;
		return $this;
	}
	public function setLength(int $length) : self {
		$this->length = $length;
		return $this;
	}
	public function setPosition(int $position) : self {
		if($position - $this->position > 0) $this->read($position - $this->position);
		return $this;
	}
	public function __debugInfo() : array {
		$class = strval($this);
		return array(
			'class'=>class_exists($class) ? new $class : null,
			'bytes'=>$this->data
		);
	}
	public function __toString() : string {
		try {
			$remaining = $this->tellLength() - $this->tellPosition();
			if($remaining > 4):
				$constructorId = $this->readInt();
				$this->undo();
				return All::getConstructor($constructorId)->getClass();
			else:
				return strval(null);
			endif;
		} catch(\Throwable){
			return strval($constructorId);
		}
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Utils;

use function Tak\Asyncio\File\openFile;

use function Tak\Asyncio\File\getSize;

use function Tak\Asyncio\File\deleteFile;

use function Tak\Asyncio\File\exists;

final class Logging {
	private const COLORS = [
		E_ERROR=>['message'=>'Error','settings'=>['fg'=>'bright_cyan','bg'=>'red','options'=>['bold']]],
		E_WARNING=>['message'=>'Warning','settings'=>['fg'=>'bright_magenta','bg'=>'yellow','options'=>['blink']]],
		E_PARSE=>['message'=>'Parse','settings'=>['fg'=>'bright_red','bg'=>'green','options'=>['underline']]],
		E_NOTICE=>['message'=>'Notice','settings'=>['fg'=>'bright_yellow','bg'=>'black']],
		E_ALL=>['message'=>'Info','settings'=>['fg'=>'cyan','bg'=>'black']]
	];

	static public string $path = '.'.DIRECTORY_SEPARATOR.'Liveproto.log';
	static public int $maxsize = 0xa00000;
	static public bool $hide = false;

	public function __construct(Settings $settings){
		if(is_string($settings->pathLog)) self::$path = $settings->pathLog;
		if(is_int($settings->maxSizeLog)) self::$maxsize = $settings->maxSizeLog;
		if(is_bool($settings->hideLog)) self::$hide = $settings->hideLog;
	}
	static public function log(string $name,mixed $text,int $level = E_ALL) : void {
		static $log = null;
		if(boolval(error_reporting() & $level) === false) return;
		if(array_key_exists($level,self::COLORS)):
			$message = self::COLORS[$level]['message'];
			$settings = self::COLORS[$level]['settings'];
		else:
			throw new \InvalidArgumentException('The log level is invalid or not supported');
		endif;
		if(Tools::inDestructor() === false and self::$maxsize > 0):
			if(exists(self::$path) and getSize(self::$path) >= self::$maxsize):
				try {
					deleteFile(self::$path);
				} catch(\Throwable $error){
					error_log('Error while deleting previous log : '.$error->getMessage());
				} finally {
					$log = null;
				}
			endif;
			if(exists(self::$path) === false or is_null($log)):
				$log = openFile(self::$path,'a+');
			endif;
			$backtrace = debug_backtrace();
			$log->write(str_pad($name.' ( '.$message.' ) ',0x20,chr(0x20),STR_PAD_RIGHT).'[ '.date('Y/m/d H:i:s').' ]'.' : '.print_r($text,true).' on line '.$backtrace[false]['line'].PHP_EOL);
		endif;
		if(self::$hide === false):
			Tools::colorize(str_pad($message,10,chr(0x20),STR_PAD_RIGHT).' : '.print_r($text,true),...$settings);
		endif;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Utils;

final class Settings {
	protected array $data;

	public function __get(string $name) : mixed {
		$index = strtolower($name);
		$value = isset($this->data[$index]) ? $this->data[$index] : self::envGuess($index);
		switch($index):
			case 'apiid':
				if(is_int($value) and $value <= 0) throw new \Exception('In the Settings , a valid value for the API ID has not been set');
				is_int($value) || $value = 21724;
				break;
			case 'apihash':
				if(is_string($value) and strlen($value) !== 32) throw new \Exception('In the Settings , a valid value for the API HASH has not been set');
				is_string($value) || $value = '3e0cb5efcd52300aec5994fdfc5bdc16';
				break;
			case 'devicemodel':
				is_string($value) || $value = php_uname('s');
				break;
			case 'systemversion':
				is_string($value) || $value = php_uname('r');
				break;
			case 'appversion':
				is_string($value) || $value = '0.26.8.1721-universal';
				break;
			case 'systemlangcode':
				is_string($value) || $value = (extension_loaded('intl') ? locale_get_primary_language(locale_get_default()).'-'.locale_get_region(locale_get_default()) : 'en-US');
				break;
			case 'langpack':
				is_string($value) || $value = 'android';
				break;
			case 'langcode':
				is_string($value) || $value = (extension_loaded('intl') ? locale_get_primary_language(locale_get_default()) : 'en');
				break;
			case 'hotreload':
				is_bool($value) || $value = true;
				break;
			case 'floodsleepthreshold':
				is_int($value) || $value = 120;
				break;
			case 'receiveupdates':
				is_bool($value) || $value = true;
				break;
			case 'maxconnections':
				is_int($value) || $value = 10;
				$value = min(max($value,1),100);
				break;
			case 'minconnections':
				is_int($value) || $value = 5;
				$value = min(max($value,1),$this->maxConnections);
				break;
			case 'mediaworkers':
				is_int($value) || $value = 3;
				$value = max($value,1);
				break;
			case 'paralleldownloads':
				is_int($value) || $value = 8;
				$value = min(max($value,1),100);
				break;
			case 'paralleluploads':
				is_int($value) || $value = 10;
				$value = min(max($value,1),100);
				break;
			case 'autocachepeers':
				is_bool($value) || $value = false;
				break;
			case 'ipv6':
				is_bool($value) || $value = false;
				break;
			case 'takeout':
				is_array($value) || $value = false;
				break;
			case 'protocol':
				is_a($value,'Tak\\Liveproto\\Enums\\ProtocolType') || $value = null;
				break;
			case 'proxy':
				if(is_array($value) and array_is_list($value) === false):
					if(isset($value['url']) and is_string($value['url'])):
						$parsed = parse_url($value['url']);
						if(isset($parsed['scheme']) and isset($value['type']) === false):
							$value['type'] = $parsed['scheme'];
						endif;
						if(isset($parsed['host'],$parsed['port']) and isset($value['address']) === false):
							$value['address'] = $parsed['host'].chr(58).min($parsed['port'],65535);
						endif;
						if(isset($parsed['user']) and isset($value['username']) === false):
							$value['username'] = $value['user'] = $parsed['user'];
						endif;
						if(isset($parsed['pass']) and isset($value['password']) === false):
							$value['password'] = $parsed['pass'];
						endif;
						if(isset($parsed['query'])):
							parse_str($parsed['query'],$query);
							if(isset($query['server'],$query['port']) and isset($value['address']) === false):
								$value['address'] = $query['server'].chr(58).min(abs(intval($query['port'])),65535);
							endif;
							if(isset($query['secret']) and isset($value['secret']) === false):
								$value['secret'] = $query['secret'];
							endif;
						endif;
					endif;
					if(isset($value['type']) === false) throw new \Exception('The `type` parameter value must be set in the proxy');
					if(is_string($value['type']) === false) throw new \Exception('The value of the `type` parameter in the proxy must be of string type');
					if(isset($value['address']) === false) throw new \Exception('The `address` parameter value must be set in the proxy');
					if(is_string($value['address']) === false) throw new \Exception('The value of the `address` parameter in the proxy must be of string type');
					if(isset($value['username']) === false || is_string($value['username']) === false):
						$value['username'] = null;
					endif;
					if(isset($value['password']) === false || is_string($value['password']) === false):
						$value['password'] = null;
					endif;
					if(isset($value['user']) === false || is_string($value['user']) === false):
						$value['user'] = null;
					endif;
					if(isset($value['secret']) === false || is_string($value['secret']) === false):
						$value['secret'] = null;
					endif;
				else:
					$value = null;
				endif;
				break;
			case 'params':
				is_object($value) || $value = null;
				break;
		endswitch;
		switch($index):
			case 'testmode':
				is_bool($value) || $value = false;
				break;
			case 'dc':
				is_int($value) || $value = 0;
				$value = min(max($value,0),5);
				break;
			case 'savetime':
				is_numeric($value) || $value = 0x3;
				$value = min(max($value,1),60);
				break;
			case 'server':
				is_string($value) || $value = 'localhost';
				break;
			case 'username':
				is_string($value) || $value = strval(null);
				break;
			case 'password':
				is_string($value) || $value = strval(null);
				break;
			case 'database':
				is_string($value) || $value = $this->username;
				break;
		endswitch;
		return $value;
	}
	public function __set(string $name,mixed $value) : void {
		$this->data[strtolower($name)] = $value;
	}
	public function __unset(string $name) : void {
		unset($this->data[strtolower($name)]);
	}
	public function __isset(string $name) : bool {
		return is_null($this->$name) === false;
	}
	public function __call(string $method,array $arguments) : mixed {
		if(preg_match('~^set([a-z0-9]+)$~i',$method,$match)):
			$name = $match[true];
			$this->$name = (array_is_list($arguments) and count($arguments) === 1) ? $arguments[false] : $arguments;
			return $this;
		elseif(preg_match('~^get([a-z0-9]+)$~i',$method,$match)):
			$name = $match[true];
			return $this->$name;
		else:
			throw new \Exception('Call to undefined function '.$method.'()');
		endif;
	}
	public function __debugInfo() : array {
		return $this->data;
	}
	static public function envGuess(string $name,mixed $default = null) : mixed {
		$camel = Tools::snakeTocamel(strtolower($name));
		$snake = Tools::camelTosnake($name);
		$names = array($name,$camel,lcfirst($camel),$snake,strtoupper($snake));
		foreach($names as $name):
			$env = $_ENV[$name] ?? null;
			if(is_null($env) === false):
				return $env;
			endif;
			/* Env can be `true` / `false` / `integer` / `JSON` (array) */
			$env = getenv($name);
			if($env !== false):
				$json = json_decode(strval($env),true);
				return match(true){
					is_numeric($env) => intval($env),
					boolval(is_null($json) === false) => $json,
					default => $env
				};
			endif;
		endforeach;
		return $default;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Utils;

use function Tak\Asyncio\ByteStream\getStdin;

use function Tak\Asyncio\ByteStream\getStdout;

defined('STDOUT') || define('STDOUT',fopen('php://stdout','wb'));

abstract class Tools {
	static public function readLine(? string $prompt = null,? object $cancellation = null) : string {
		try {
			$stdin = getStdin();
			$stdout = getStdout();
			if(is_null($prompt) === false) $stdout->write(content : $prompt,cancellation : $cancellation);
			static $lines = array(null);
			while(count($lines) < 2 and is_null($chunk = $stdin->read(cancellation : $cancellation)) === false):
				$chunk = explode(chr(10),str_replace(array(chr(13),chr(10).chr(10)),chr(10),$chunk));
				$lines[count($lines) - 1] .= array_shift($chunk);
				$lines = array_merge($lines,$chunk);
			 endwhile;
		} catch(\Throwable $error){
			Logging::log('Tools',$error->getMessage(),E_WARNING);
		}
		return strval(array_shift($lines));
	}
	static public function snakeTocamel(string $str) : string {
		return str_replace('_',strval(null),ucwords($str,'_'));
	}
	static public function camelTosnake(string $str) : string {
		return strtolower(preg_replace('/([a-z])([A-Z])/','$1_$2',$str));
	}
	static public function isCli() : bool {
		return in_array(PHP_SAPI,['cli','cli-server','phpdbg','embed']);
	}
	static public function colorize(mixed $text,? string $fg = null,? string $bg = null,array $options = []) : void {
		if(is_string($text) === false):
			$text = var_export($text,true);
		endif;
		$fgMap = [
			'black'=>30,
			'red'=>31,
			'green'=>32,
			'yellow'=>33,
			'blue'=>34,
			'magenta'=>35,
			'cyan'=>36,
			'white'=>37,
			'reset'=>39,
			'bright_black'=>90,
			'bright_red'=>91,
			'bright_green'=>92,
			'bright_yellow'=>93,
			'bright_blue'=>94,
			'bright_magenta'=>95,
			'bright_cyan'=>96,
			'bright_white'=>97
		];
		$bgMap = [
			'black'=>40,
			'red'=>41,
			'green'=>42,
			'yellow'=>43,
			'blue'=>44,
			'magenta'=>45,
			'cyan'=>46,
			'white'=>47,
			'reset'=>49,
			'bright_black'=>100,
			'bright_red'=>101,
			'bright_green'=>102,
			'bright_yellow'=>103,
			'bright_blue'=>104,
			'bright_magenta'=>105,
			'bright_cyan'=>106,
			'bright_white'=>107
		];
		$optsMap = [
			'reset'=>0,
			'bold'=>1,
			'dim'=>2,
			'underline'=>4,
			'blink'=>5,
			'reverse'=>7,
			'hidden'=>8,
		];
		$cssColorMap = [
			'black'=>'black',
			'red'=>'#d11',
			'green'=>'#0a0',
			'yellow'=>'#d90',
			'blue'=>'#06c',
			'magenta'=>'#c0f',
			'cyan'=>'#0af',
			'white'=>'#c0c0c0',
			'bright_black'=>'#666',
			'bright_red'=>'#ff6f6f',
			'bright_green'=>'#6f6',
			'bright_yellow'=>'#ffd86f',
			'bright_blue'=>'#6fb3ff',
			'bright_magenta'=>'#ff9cff',
			'bright_cyan'=>'#7ff',
			'bright_white'=>'#fff'
		];
		if(self::isCli()):
			if(self::cli_supports_ansi()):
				$codes = array();
				if(empty($fg) === false and array_key_exists($fg,$fgMap)):
					$codes []= $fgMap[$fg];
				endif;
				if(empty($bg) === false and array_key_exists($bg,$bgMap)):
					$codes []= $bgMap[$bg];
				endif;
				foreach($options as $opt):
					if(array_key_exists($opt,$optsMap)):
						$codes []= $optsMap[$opt];
					endif;
				endforeach;
				if(empty($codes)):
					print($text);
				else:
					printf(chr(27).'[%sm%s'.chr(27).'[0m'.PHP_EOL,implode(chr(59),$codes),$text);
				endif;
			else:
				print($text);
			endif;
		else:
			$escaped = htmlspecialchars($text,ENT_QUOTES | ENT_SUBSTITUTE,'UTF-8');
			$styles = array();
			if(in_array('bold',$options,true)):
				$styles []= 'font-weight: 700';
			endif;
			if(in_array('dim',$options,true)):
				$styles []= 'opacity: 0.75';
			endif;
			if(in_array('underline',$options,true)):
				$styles []= 'text-decoration: underline';
			endif;
			if(in_array('blink',$options,true)):
				$styles []= 'text-decoration: blink';
			endif;
			if(in_array('reverse',$options,true)):
				list($fg,$bg) = array($bg,$fg);
			endif;
			if(in_array('hidden',$options,true)):
				$styles []= 'visibility: hidden';
			endif;
			if(empty($fg) === false and array_key_exists($fg,$cssColorMap)):
				$styles []= 'color: '.$cssColorMap[$fg];
			endif;
			if(empty($bg) === false and array_key_exists($bg,$cssColorMap)):
				$styles []= 'background-color: '.$cssColorMap[$bg];
			endif;
			$styleAttr = strval(empty($styles) ? null : ' style = '.chr(34).implode(chr(59).chr(32),$styles).chr(34));
			if(str_contains($escaped,chr(10))):
				print('<pre'.$styleAttr.'>'.$escaped.'</pre>');
			else:
				print('<span'.$styleAttr.'>'.$escaped.'</span><br>');
			endif;
		endif;
	}
	static public function cli_supports_ansi() : bool {
		if(function_exists('stream_isatty')):
			if(@stream_isatty(STDOUT) === false) return false;
		endif;
		if(DIRECTORY_SEPARATOR === chr(92)):
			if(function_exists('sapi_windows_vt100_support')):
				@sapi_windows_vt100_support(STDOUT,true);
			endif;
		endif;
		return true;
	}
	static public function marshal(array $data) : array {
		foreach($data as $key => $value):
			if(is_object($value) || is_array($value) || is_bool($value) || mb_check_encoding(var_export($value,true),'UTF-8') === false):
				$data[$key] = 'serialize:'.base64_encode(serialize($value));
			elseif(is_string($value) and str_starts_with($value,'serialize:')):
				$serialize = substr($value,10);
				$data[$key] = unserialize(base64_decode($serialize));
			endif;
		endforeach;
		return $data;
	}
	static public function inferType(mixed $data) : string {
		$type = match(gettype($data)){
			'boolean' => 'BOOLEAN',
			'object' , 'array' => 'LONGTEXT',
			'integer' => 'BIGINT', // abs($data) > 0x7fffffff ? 'BIGINT' : 'INT' //
			'double' => 'REAL',
			'string' => 'TEXT', // mb_strlen($data) > 0xffff ? 'LONGTEXT' : 'TEXT' //
			default => 'VARCHAR (1024)' // mb_strlen(strval($data)) //
		};
		return $type;
	}
	static public function specifyType(string $type,mixed $data) : mixed {
		$type = strtoupper(trim($type));
		return match(true){
			str_starts_with($type,'BOOLEAN') => boolval($data),
			str_starts_with($type,'BIGINT') => is_numeric($data) ? intval($data) : $data,
			str_starts_with($type,'REAL') => floatval($data),
			str_starts_with($type,'TEXT') , str_starts_with($type,'VARCHAR') => strval($data),
			str_starts_with($type,'LONGTEXT') => json_validate($data) ? json_decode($data,true) : $data,
			default => $data
		};
	}
	static public function is_valid_mysql_identifier_unicode(string $name) : bool {
		/*
		 * Unicode-aware MySQL validation :
		 * Allows Unicode letters / digits ( using \p{L}\p{N} ), underscore and dollar sign
		 * MySQL allows leading digit but identifier cannot be all digits
		 * Max length 64 codepoints ( approx, MySQL stores identifiers in UTF-8, most deployments treat 64 characters )
		 */
		return boolval(preg_match('/^(?!^\d+$)[\p{L}\p{N}_\$]{1,64}$/u',$name));
	}
	static public function is_valid_sqlite_identifier_unicode(string $name) : bool {
		/*
		 * Unicode-aware SQLite validation ( unquoted-name style ):
		 * Start with a Unicode letter or underscore
		 * Then Unicode letters / digits / underscore / dollar
		 * Max length 64
		 */
		return boolval(preg_match('/^[\p{L}_][\p{L}\p{N}_\$]{0,63}$/u',$name));
	}
	static public function base64_url_encode(string $string) : string {
		return rtrim(strtr(base64_encode($string),chr(43).chr(47),chr(45).chr(95)),chr(61));
	}
	static public function base64_url_decode(string $string) : string | false {
		return base64_decode(strtr($string,chr(45).chr(95),chr(43).chr(47)));
	}
	static function inDestructor(? array $stack = null) : bool {
		$stack ??= debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
		foreach($stack as $frame):
			if(isset($frame['function']) and $frame['function'] === '__destruct'):
				return true;
			endif;
		endforeach;
		return false;
	}
	static public function populateIds(array $results,array $indexes) : array {
		$ids = array();
		foreach($results as $result):
			foreach($indexes as $index):
				if(is_array($index) === false) $index = array($index);
				$values = array_filter(array_map(fn(string | int | array $property) : mixed => self::getNested($result,$property),$index));
				$ids []= empty($values) ? 0 : reset($values);
			endforeach;
		endforeach;
		return $ids;
	}
	static public function getNested(mixed $result,mixed $property) : mixed {
		if(is_string($property)):
			$result = isset($result->$property) ? $result->$property : null;
		elseif(is_int($property)):
			$result = isset($result[$property]) ? $result[$property] : null;
		elseif(is_array($property)):
			foreach($property as $i):
				$result = self::getNested($result,$i);
			endforeach;
		endif;
		return $result;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Utils;

use Tak\Liveproto\Parser\Tl;

use Stringable;

use JsonSerializable;

use ArrayAccess;

abstract class Instance implements Stringable , JsonSerializable , ArrayAccess {
	protected object $client;
	protected array $sdtClass;

	public function __construct(array $dictionary = array()){
		$this->sdtClass = $dictionary;
	}
	public function &__get(string $name) : mixed {
		if(isset($this->sdtClass[$name]) === false):
			$this->sdtClass[$name] = null;
		endif;
		return $this->sdtClass[$name];
	}
	public function __set(string $name,mixed $value) : void {
		$this->sdtClass[$name] = $value;
	}
	public function __unset(string $name) : void {
		unset($this->sdtClass[$name]);
	}
	public function __isset(string $name) : bool {
		return isset($this->sdtClass[$name]);
	}
	public function __call(string $name,array $arguments) : mixed {
		if($this->$name and is_callable($this->$name)):
			return call_user_func($this->$name,...$arguments);
		elseif(isset($this->client)):
			return call_user_func(array($this->client,$name),...$arguments);
		else:
			throw new \Exception('Call to undefined function '.$name.'()');
		endif;
	}
	public function __invoke(mixed ...$arguments) : mixed {
		if(method_exists($this,'request') and method_exists($this,'response')):
			if(count($arguments) === 1):
				if(array_key_exists('reader',$arguments)):
					if($arguments['reader'] instanceof Binary):
						return $this->response(...$arguments);
					endif;
				endif;
			endif;
			return $this->request(...$arguments);
		else:
			throw new \Exception('The object does not have a request and response method !');
		endif;
	}
	public function stream(bool $resolveKeys = false) : Binary {
		if($resolveKeys):
			$comments = Tl::parseDocComment($this);
			$params = array_keys($comments['param']);
			$arguments = array_intersect_key($this->sdtClass,array_flip(array_map(fn(string $param) : string => strtok($param,chr(36)),$params)));
			return $this->request(...$arguments);
		else:
			return $this->request(...$this->sdtClass);
		endif;
	}
	public function read() : string {
		return $this->stream()->read();
	}
	public function write(Binary $writer) : Binary {
		$writer->write($this->read());
		return $writer;
	}
	public function __sleep() : array {
		return array('sdtClass');
	}
	public function __debugInfo() : array {
		return array_filter($this->sdtClass,fn(mixed $value) : bool => is_a($value,'\Closure') === false);
	}
	static public function __set_state(array $arrays) : object {
		return new static($arrays['sdtClass']);
	}
	public function __toString() : string {
		return $this->dumpTree();
	}
	public function &offsetGet(mixed $offset) : mixed {
		if(isset($this->sdtClass[$offset]) === false):
			$this->sdtClass[$offset] = null;
		endif;
		return $this->sdtClass[$offset];
	}
	public function offsetSet(mixed $offset,mixed $value) : void {
		$this->sdtClass[$offset] = $value;
	}
	public function offsetUnset(mixed $offset) : void {
		unset($this->sdtClass[$offset]);
	}
	public function offsetExists(mixed $offset) : bool {
		return isset($this->sdtClass[$offset]);
	}
	public function toArray() : array {
		$class = ['_'=>$this->getClass()];
		return array_merge($class,$this->sdtClass);
	}
	public function jsonSerialize() : array {
		return $this->toArray();
	}
	public function getClass() : string {
		$split = explode(chr(92),get_class($this));
		$name = lcfirst(array_pop($split));
		$space = lcfirst(array_pop($split));
		return strval($space === 'other' ? $name : $space.chr(46).$name);
	}
	public function clone(string | object $object,bool $deep = false) : object {
		$cloned = new $object($this->sdtClass);
		if($deep and $cloned instanceof self):
			$cloned = $cloned->stream(true)->readObject();
		endif;
		return $cloned;
	}
	public function setClient(object | null $client) : self {
		if(is_null($client)):
			unset($this->client);
		else:
			$this->client = $client;
		endif;
		return $this;
	}
	public function getClient() : object | null {
		return isset($this->client) ? $this->client : null;
	}
	private function dumpTree(array $array = array(),int $depth = 0) : string {
		$string = strval(null);
		$array = empty($array) ? $this->sdtClass : $array;
		$newline = (Tools::isCli() ? chr(10) : (ob_get_level() > 0 ? PHP_EOL : '<br>'));
		if($depth === 0) $string .= $newline.'┌';
		foreach($array as $key => $value):
			$string .= $newline.($depth > 0 ? str_repeat('│'.chr(9),$depth) : null).'├ '.$key.(' ► '.($this->stringifyType($value) === 'array' ? call_user_func(__METHOD__,$value,$depth + 1) : $this->stringifyType($value)));
		endforeach;
		if($depth === 0) $string .= $newline.'└';
		return $string;
	}
	private function stringifyType(mixed $type) : string {
		return match(gettype($type)){
			'boolean' => $type ? 'true' : 'false',
			'integer' => strval($type),
			'double' => strval($type),
			'object' => $type::class,
			'NULL' => 'null',
			'array' => 'array',
			'string' => $type,
			default => 'unknown'
		};
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Ipc;

use Tak\Liveproto\Utils\Logging;

final class SessionLocker {
	private mixed $fp;

	public function __construct(string $name){
		$this->fp = fopen(sys_get_temp_dir().DIRECTORY_SEPARATOR.urlencode($name).chr(95).md5($_SERVER['SCRIPT_FILENAME']),'c+');
		if($this->fp === false):
			Logging::log('Session Locker','Session not locked',E_ERROR);
			exit('No access to lock the session');
		endif;
	}
	private function commitState(bool $status) : void {
		rewind($this->fp);
		ftruncate($this->fp,0);
		fwrite($this->fp,strval(intval($status)));
		fflush($this->fp);
	}
	public function tryLock() : ? callable {
		Logging::log('Session Locker','Attempt to lock...');
		if(flock($this->fp,LOCK_EX | LOCK_NB)):
			$this->commitState(false);
			return null;
		else:
			rewind($this->fp);
			$queue = boolval(fread($this->fp,1));
			$this->commitState(true);
			if($queue === false):
				return function() : void {
					flock($this->fp,LOCK_EX);
					$this->commitState(false);
				};
			else:
				Logging::log('Client','Request blocked !',E_NOTICE);
				fclose($this->fp);
				exit('⚠️ Previous process + one more process are in the execution queue...');
			endif;
		endif;
	}
	public function unlock() : void {
		if(flock($this->fp,LOCK_UN | LOCK_NB)):
			$this->commitState(false);
		endif;
		fclose($this->fp);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Ipc;

use Tak\Liveproto\Utils\Logging;

use Tak\Asyncio\Loop;

final class SignalHandler {
	private mixed $fp;

	public const STOP_SIGNALS = [
		SIGTSTP=>'Interactive Stop ( Ctrl+Z )',
		SIGINT=>'Interrupt ( Ctrl+C )',
		SIGQUIT=>'Quit ( Ctrl+\\ )',
		SIGTERM=>'Termination Request'
	];
	public const RESTART_SIGNALS = [
		SIGHUP=>'Hangup ( reload / restart request )'
	];

	public function __construct(string $name,protected readonly object $client){
		$this->fp = fopen(sys_get_temp_dir().DIRECTORY_SEPARATOR.urlencode($name).chr(95).md5($_SERVER['SCRIPT_FILENAME']),'c+');
		if(function_exists('cli_set_process_title')):
			cli_set_process_title(uniqid('LiveProto'));
		endif;
		$this->register();
	}
	public function tryLock() : null {
		if(flock($this->fp,LOCK_EX | LOCK_NB) === false and function_exists('posix_kill')):
			rewind($this->fp);
			$pid = intval(stream_get_contents($this->fp));
			if($pid !== 0 and posix_kill($pid,0)):
				@posix_kill($pid,SIGTERM);
			endif;
		endif;
		rewind($this->fp);
		ftruncate($this->fp,0);
		fwrite($this->fp,strval(getmypid()));
		fflush($this->fp);
		return null;
	}
	public function unlock() : void {
		$uri = stream_get_meta_data($this->fp)['uri'];
		fclose($this->fp);
		@unlink($uri);
	}
	public function register() : void {
		if(extension_loaded('pcntl')):
			foreach(self::STOP_SIGNALS as $signal => $reason):
				Loop::unreference(Loop::onSignal($signal,fn() : null => $this->stop($reason)));
			endforeach;
			foreach(self::RESTART_SIGNALS as $signal => $reason):
				Loop::unreference(Loop::onSignal($signal,fn() : null => $this->restart($reason)));
			endforeach;
		else:
			Logging::log('Signal Handler','Signal handling requires pcntl extension !',E_WARNING);
		endif;
	}
	public function stop(? string $reason = null) : void {
		if(is_null($reason) === false):
			error_log('Stop : '.$reason);
		endif;
		$this->client->stop();
		die('The process was stopped');
	}
	public function restart(? string $reason = null) : void {
		if(is_null($reason) === false):
			error_log('Restart : '.$reason);
		endif;
		$this->client->connect(reconnect : true);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Database;

use Tak\Liveproto\Utils\Tools;

use Tak\Liveproto\Utils\Logging;

use Tak\Asyncio\Loop;

use Tak\Asyncio\Sync\Mutex;

use PDO;

final class SQLite implements AbstractDB , AbstractPeers {
	protected object $connection;

	public function __construct(string $path){
		$this->connection = new PDO('sqlite:'.$path);
		$this->connection->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
		$this->connection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);
	}
	public function init(string $table) : bool {
		if($this->connection->query('SELECT name FROM sqlite_master WHERE type = \'table\' AND name = '.chr(39).$table.chr(39))->fetch()):
			return false;
		else:
			$this->connection->exec(
				'CREATE TABLE IF NOT EXISTS '.$table.' (
				`id` BIGINT NOT NULL DEFAULT 0
				)'
			);
			$this->connection->prepare('INSERT OR IGNORE INTO '.$table.' (`id`) VALUES (:id)')->execute(['id'=>0]);
			return true;
		endif;
	}
	public function set(string $table,string $key,mixed $value,string $type) : void {
		static $mutex = new Mutex;
		$lock = $mutex->acquire();
		try {
			if($this->exists($table,$key) === false):
				$this->connection->exec('ALTER TABLE '.$table.' ADD COLUMN '.$key.chr(32).$type);
			endif;
			$this->connection->prepare('UPDATE '.$table.' SET '.$key.' = :new')->execute(['new'=>$value]);
		} catch(\Throwable $error){
			Logging::log('SQLite',$error->getMessage(),E_WARNING);
		} finally {
			Loop::queue($lock->release(...));
		}
	}
	public function get(string $table) : array | null {
		$stmt = $this->connection->query('SELECT * FROM '.$table.' LIMIT 1');
		if($datas = $stmt->fetch()){
			return $this->castTypes($table,$datas);
		} else {
			return null;
		}
	}
	public function delete(string $table,string $key) : void {
		$this->connection->exec('UPDATE '.$table.' SET `'.$key.'` = NULL');
	}
	public function exists(string $table,string $key) : bool {
		$columnsStmt = $this->connection->prepare('PRAGMA table_info('.$table.')');
		$columnsStmt->execute();
		$columns = $columnsStmt->fetchAll();
		$fields = array_column($columns,'name');
		return in_array($key,$fields);
	}
	public function initPeer(string $table) : bool {
		if($this->connection->query('SELECT name FROM sqlite_master WHERE type = \'table\' AND name = '.chr(39).$table.chr(39))->fetch()):
			return false;
		else:
			$this->connection->exec(
				'CREATE TABLE IF NOT EXISTS '.$table.' (
				`id` BIGINT PRIMARY KEY
				)'
			);
			return true;
		endif;
	}
	public function setPeer(string $table,mixed $value) : void {
		static $mutex = new Mutex;
		$lock = $mutex->acquire();
		try {
			$keys = array_keys($value);
			$columnsStmt = $this->connection->prepare('PRAGMA table_info('.$table.')');
			$columnsStmt->execute();
			$columns = $columnsStmt->fetchAll();
			$fields = array_column($columns,'name');
			foreach($value as $k => $v):
				if(in_array($k,$fields) === false):
					$type = Tools::inferType($v);
					$this->connection->exec('ALTER TABLE '.$table.' ADD COLUMN `'.$k.'` '.$type);
				endif;
			endforeach;
			$this->connection->prepare(
				implode(chr(32),array(
					'INSERT INTO '.$table,
					'(`'.implode(chr(96).chr(44).chr(96),$keys).'`)',
					'VALUES',
					'('.chr(58).implode(chr(44).chr(58),$keys).')',
					'ON CONFLICT(`id`) DO UPDATE SET',
					implode(chr(44),array_map(fn(string $key) : string => strval($key.' = excluded.'.$key),$keys))
				))
			)->execute($value);
		} catch(\Throwable $error){
			Logging::log('SQLite',$error->getMessage(),E_WARNING);
		} finally {
			Loop::queue($lock->release(...));
		}
	}
	public function getPeer(string $table,string $key,mixed $value) : array | null {
		$stmt = $this->connection->prepare('SELECT * FROM '.$table.' WHERE '.$key.' = :value');
		$stmt->execute(['value'=>$value]);
		if($datas = $stmt->fetch()){
			return $this->castTypes($table,$datas);
		} else {
			return null;
		}
	}
	public function deletePeer(string $table,string $key,mixed $value) : void {
		$this->connection->prepare('DELETE FROM '.$table.' WHERE '.$key.' = :value')->execute(['value'=>$value]);
	}
	private function castTypes(string $table,array $datas) : array {
		$stmt = $this->connection->query('PRAGMA table_info('.$table.')');
		while($column = $stmt->fetch()){
			$field = strval($column['name'] ?? null);
			$type = strval($column['type'] ?? null);
			if(array_key_exists($field,$datas)){
				$datas[$field] = Tools::specifyType($type,$datas[$field]);
			}
		}
		return $datas;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Database;

use Tak\Liveproto\Utils\Tools;

final class CachedPeers {
	private array $datas;
	protected ? object $connection = null;

	public function __construct(private readonly ? string $name){
		$this->datas = [
			'users'=>array(),
			'chats'=>array(),
			'secrets'=>array()
		];
	}
	public function init(object $connection) : void {
		if(is_null($this->name) === false and is_subclass_of($connection,AbstractPeers::class)):
			foreach(array_keys($this->datas) as $key):
				$connection->initPeer($this->name.chr(95).strtoupper($key));
			endforeach;
			$this->connection = $connection;
		endif;
	}
	public function getPeer(string $type,string $by,mixed $what) : array | null {
		$filtered = array_filter($this->datas[$type],fn(array $row) : bool => $row[$by] === $what);
		if($found = reset($filtered)):
			return $found;
		elseif(isset($this->connection)):
			$found = $this->connection->getPeer($this->name.chr(95).strtoupper($type),$by,$what);
			return is_null($found) ? $found : Tools::marshal($found);
		else:
			return null;
		endif;
	}
	public function setPeers(string $type,array $peers) : void {
		if(isset($this->connection)):
			foreach($peers as $peer):
				$this->connection->setPeer($this->name.chr(95).strtoupper($type),Tools::marshal($peer));
			endforeach;
		else:
			$this->datas[$type] = array_unique(array_merge($peers,$this->datas[$type]),SORT_REGULAR);
		endif;
	}
	public function deletePeer(string $type,string $by,mixed $what) : void {
		if(isset($this->connection)):
			$this->connection->deletePeer($this->name.chr(95).strtoupper($type),$by,$what);
		else:
			$this->datas[$type] = array_filter($this->datas[$type],fn(array $row) : bool => $row[$by] !== $what);
		endif;
	}
	public function __debugInfo() : array {
		return array('peers'=>$this->datas);
	}
	public function __sleep() : array {
		return array('name','datas');
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Database;

use Tak\Liveproto\Utils\Tools;

use Tak\Liveproto\Utils\Logging;

use Tak\Asyncio\Loop;

use Tak\Asyncio\Sync\Mutex;

use PDO;

final class MySQL implements AbstractDB , AbstractPeers {
	protected object $connection;

	public function __construct(string $server,string $username,string $password,string $database){
		$this->connection = new PDO('mysql:host='.$server.'; dbname='.$database.'; charset=utf8mb4',$username,$password);
		$this->connection->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
		$this->connection->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);
	}
	public function init(string $table) : bool {
		if($this->connection->query('SHOW TABLES LIKE '.chr(39).$table.chr(39))->fetch() and $this->connection->query('SELECT * FROM '.$table.' LIMIT 1')->fetch()){
			return false;
		} else {
			$this->connection->exec('CREATE TABLE IF NOT EXISTS '.$table.' (`id` BIGINT NOT NULL DEFAULT 0) DEFAULT CHARSET=utf8mb4');
			$this->connection->prepare('INSERT IGNORE INTO '.$table.' (`id`) VALUES (:id)')->execute(['id'=>0]);
			return true;
		}
	}
	public function set(string $table,string $key,mixed $value,string $type) : void {
		static $mutex = new Mutex;
		$lock = $mutex->acquire();
		try {
			if($this->exists($table,$key) === false){
				$this->connection->exec('ALTER TABLE '.$table.' ADD COLUMN IF NOT EXISTS '.$key.chr(32).$type);
			}
			$this->connection->prepare('UPDATE '.$table.' SET '.$key.' = :new')->execute(['new'=>$value]);
		} catch(\Throwable $error){
			Logging::log('MySQL',$error->getMessage(),E_WARNING);
		} finally {
			Loop::queue($lock->release(...));
		}
	}
	public function get(string $table) : array | null {
		$stmt = $this->connection->query('SELECT * FROM '.$table.' LIMIT 1');
		if($datas = $stmt->fetch()){
			return $this->castTypes($table,$datas);
		} else {
			return null;
		}
	}
	public function delete(string $table,string $key) : void {
		$this->connection->exec('ALTER TABLE '.$table.' DROP COLUMN '.$key);
	}
	public function exists(string $table,string $key) : bool {
		$stmt = $this->connection->query('DESCRIBE '.$table);
		$columns = $stmt->fetchAll(PDO::FETCH_COLUMN);
		return in_array($key,$columns);
	}
	public function initPeer(string $table) : bool {
		if($this->connection->query('SHOW TABLES LIKE '.chr(39).$table.chr(39))->fetch()){
			return false;
		} else {
			$this->connection->exec('CREATE TABLE IF NOT EXISTS '.$table.' (`id` BIGINT PRIMARY KEY) DEFAULT CHARSET=utf8mb4');
			return true;
		}
	}
	public function setPeer(string $table,mixed $value) : void {
		static $mutex = new Mutex;
		$lock = $mutex->acquire();
		try {
			$keys = array_keys($value);
			foreach($value as $key=>$val){
				$type = Tools::inferType($val);
				$this->connection->exec('ALTER TABLE '.$table.' ADD COLUMN IF NOT EXISTS `'.$key.'` '.$type);
			}
			$cols = implode(chr(96).chr(44).chr(96),$keys);
			$placeholders = chr(58).implode(chr(44).chr(58),$keys);
			$update = implode(chr(44),array_map(fn($k) => $k.' = VALUES('.$k.')',$keys));
			$this->connection->prepare('INSERT INTO '.$table.' (`'.$cols.'`) VALUES ('.$placeholders.') ON DUPLICATE KEY UPDATE '.$update)->execute($value);
		} catch(\Throwable $error){
			Logging::log('MySQL',$error->getMessage(),E_WARNING);
		} finally {
			Loop::queue($lock->release(...));
		}
	}
	public function getPeer(string $table,string $key,mixed $value) : array | null {
		$stmt = $this->connection->prepare('SELECT * FROM '.$table.' WHERE '.$key.' = :value');
		$stmt->execute(['value'=>$value]);
		if($datas = $stmt->fetch()){
			return $this->castTypes($table,$datas);
		} else {
			return null;
		}
	}
	public function deletePeer(string $table,string $key,mixed $value) : void {
		$this->connection->prepare('DELETE FROM '.$table.' WHERE '.$key.' = :value')->execute(['value'=>$value]);
	}
	private function castTypes(string $table,array $datas) : array {
		$stmt = $this->connection->query('SHOW COLUMNS FROM '.$table);
		while($column = $stmt->fetch()){
			$field = strval($column['Field'] ?? null);
			$type = strval($column['Type'] ?? null);
			if(array_key_exists($field,$datas)){
				$datas[$field] = Tools::specifyType($type,$datas[$field]);
			}
		}
		return $datas;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Database;

use Tak\Asyncio\Loop;

use ArrayAccess;

final class Content implements ArrayAccess {
	protected string $pending;
	protected bool $cloned;
	protected float $lastsave;
	protected Session $session;

	public function __construct(public array $data,protected float $savetime){
		$this->cloned = false;
		$this->lastsave = microtime(true);
		/* register_shutdown_function(fn() : null => $this->save(true)); */
	}
	public function setSession(Session $session) : self {
		$this->session = $session;
		return $this;
	}
	public function save(bool $urgent = false) : void {
		if(isset($this->session)):
			if($this->cloned === false):
				$sleep = $this->savetime - (microtime(true) - $this->lastsave);
				if($sleep <= 0 || $urgent):
					$this->lastsave = microtime(true);
					$this->pending = strval(null);
					$this->session->save();
				elseif(empty($this->pending)):
					$this->pending = Loop::unreference(Loop::delay($sleep,fn(string $id) : null => $this->save(true)));
				endif;
			endif;
		else:
			throw new \Exception('The session is not set up , I can not save new information !');
		endif;
	}
	public function &__get(string $property) : mixed {
		if(isset($this->data[$property]) === false):
			$this->data[$property] = null;
		endif;
		return $this->data[$property];
	}
	public function __set(string $name,mixed $value) : void {
		$this->data[$name] = $value;
		$this->save();
	}
	public function __unset(string $name) : void {
		unset($this->data[$name]);
		$this->save();
	}
	public function __isset(string $name) : bool {
		return isset($this->data[$name]);
	}
	public function &offsetGet(mixed $offset) : mixed {
		if(isset($this->data[$offset]) === false):
			$this->data[$offset] = null;
		endif;
		return $this->data[$offset];
	}
	public function offsetSet(mixed $offset,mixed $value) : void {
		$this->data[$offset] = $value;
		$this->save();
	}
	public function offsetUnset(mixed $offset) : void {
		unset($this->data[$offset]);
		$this->save();
	}
	public function offsetExists(mixed $offset) : bool {
		return isset($this->data[$offset]);
	}
	public function toArray() : array {
		return $this->data;
	}
	public function __debugInfo() : array {
		return $this->data;
	}
	public function __clone() : void {
		$this->cloned = true;
	}
	public function __serialize() : array {
		return array(
			'pending'=>strval(null),
			'cloned'=>$this->cloned,
			'savetime'=>$this->savetime,
			'lastsave'=>$this->lastsave,
			'data'=>$this->data
		);
	}
	/*
	public function __wakeup() : void {
		register_shutdown_function(fn() : null => $this->save(true));
	}
	*/
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Database;

interface AbstractPeers {
	public function initPeer(string $table) : bool;

	public function setPeer(string $table,mixed $value) : void;

	public function getPeer(string $table,string $key,mixed $value) : ? array;
	
	public function deletePeer(string $table,string $key,mixed $value) : void;
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Database;

use Tak\Liveproto\Enums\Authentication;

use Tak\Liveproto\Utils\Settings;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Tools;

use function Tak\Asyncio\File\isFile;

use function Tak\Asyncio\File\read;

use function Tak\Asyncio\File\write;

use function Tak\Asyncio\File\getSize;

final class Session {
	protected Content $content;
	protected MySQL $mysql;
	protected SQLite $sqlite;
	private array $servers = array(
		['ip'=>'149.154.175.50','ipv6'=>'2001:b28:f23d:f001:0000:0000:0000:000a','port'=>443,'dc'=>1],
		['ip'=>'149.154.167.51','ipv6'=>'2001:67c:4e8:f002:0000:0000:0000:000a','port'=>443,'dc'=>2],
		['ip'=>'149.154.175.100','ipv6'=>'2001:b28:f23d:f003:0000:0000:0000:000a','port'=>443,'dc'=>3],
		['ip'=>'149.154.167.91','ipv6'=>'2001:67c:4e8:f004:0000:0000:0000:000a','port'=>443,'dc'=>4],
		['ip'=>'91.108.56.180','ipv6'=>'2001:b28:f23f:f005:0000:0000:0000:000a','port'=>443,'dc'=>5]
	);
	private array $testservers = array(
		['ip'=>'149.154.175.40','ipv6'=>'2001:b28:f23d:f001:0000:0000:0000:000e','port'=>80,'dc'=>1],
		['ip'=>'149.154.167.40','ipv6'=>'2001:67c:4e8:f002:0000:0000:0000:000e','port'=>80,'dc'=>2],
		['ip'=>'149.154.175.117','ipv6'=>'2001:b28:f23d:f003:0000:0000:0000:000e','port'=>80,'dc'=>3]
	);
	private string $mode;

	public function __construct(public readonly string | null $name,? string $mode,public readonly Settings $settings){
		$this->mode = strtolower(strval($mode));
	}
	public function generate() : object {
		if($this->dc > 0):
			if($this->testmode):
				if($this->dc <= count($this->testservers)):
					$server = $this->testservers[$this->dc - 1];
				else:
					throw new \Exception('The ID of the test data center must be less than '.count($this->testservers));
				endif;
			else:
				if($this->dc <= count($this->servers)):
					$server = $this->servers[$this->dc - 1];
				else:
					throw new \Exception('The ID of the data center must be less than '.count($this->servers));
				endif;
			endif;
		else:
			if($this->testmode):
				$server = $this->testservers[array_rand($this->testservers)];
			else:
				$server = $this->servers[array_rand($this->servers)];
			endif;
		endif;
		return new Content([
			'id'=>0,
			'api_id'=>0,
			'api_hash'=>strval(null),
			'dc'=>$server['dc'],
			'ip'=>strval($this->ipv6 ? $server['ipv6'] : $server['ip']),
			'port'=>$server['port'],
			'auth_key'=>new \stdClass,
			'media_only'=>false,
			'expires_at'=>0,
			'salt'=>0,
			'salt_valid_until'=>0,
			'sequence'=>0,
			'time_offset'=>0,
			'last_msg_id'=>0,
			'logout_tokens'=>array(),
			'peers'=>new CachedPeers($this->name),
			'state'=>(object) array('pts'=>1,'qts'=>-1,'date'=>1,'seq'=>0),
			'step'=>Authentication::NEED_AUTHENTICATION
		],$this->savetime);
	}
	public function load() : object {
		if(isset($this->content)):
			return $this->content;
		elseif(is_null($this->name)):
			$this->content = $this->generate();
			$this->content->setSession($this);
			return $this->content;
		else:
			switch($this->mode):
				case 'string':
					$file = '.'.DIRECTORY_SEPARATOR.$this->name.'.session';
					if(isFile($file) and getSize($file)):
						$this->content = unserialize(gzinflate(base64_decode(read($file))))->setSession($this);
					else:
						$content = $this->generate();
						write($file,base64_encode(gzdeflate(serialize($content))));
						$this->content = $content->setSession($this);
					endif;
					break;
				case 'sqlite':
					Tools::is_valid_sqlite_identifier_unicode($this->name) || throw new \InvalidArgumentException('resourceName : must start with a letter / _ and contain only Unicode letters / digits / _ / $ ( 1..64 chars ) !');
					$path = empty($this->database) ? $this->name : $this->database;
					$this->sqlite = new SQLite($path.'.db');
					if($this->sqlite->init($this->name)):
						$content = $this->generate();
					else:
						$content = new Content(Tools::marshal($this->sqlite->get($this->name)),$this->savetime);
					endif;
					$this->content = $content->setSession($this);
					$this->content->peers->init($this->sqlite);
					$this->content->save(true);
					break;
				case 'mysql':
					Tools::is_valid_mysql_identifier_unicode($this->name) || throw new \InvalidArgumentException('resourceName : must be 1..64 Unicode letters / digits / _ / $ and not composed only of digits !');
					if(empty($this->server)):
						throw new \Exception('Server parameter for mysql database is empty !');
					elseif(empty($this->username)):
						throw new \Exception('Username parameter for mysql database is empty !');
					elseif(empty($this->password)):
						throw new \Exception('Password parameter for mysql database is empty !');
					elseif(empty($this->database)):
						throw new \Exception('Database parameter for mysql database is empty !');
					else:
						$this->mysql = new MySQL($this->server,$this->username,$this->password,$this->database);
						if($this->mysql->init($this->name)):
							$content = $this->generate();
						else:
							$content = new Content(Tools::marshal($this->mysql->get($this->name)),$this->savetime);
						endif;
						$this->content = $content->setSession($this);
						$this->content->peers->init($this->mysql);
						$this->content->save(true);
					endif;
					break;
				case 'text':
					$this->content = unserialize(gzinflate(base64_decode($this->name)))->setSession($this);
					break;
				default:
					throw new \InvalidArgumentException('The database mode is invalid ! It must be one of the modes of string , sqlite , mysql , text !');
			endswitch;
		endif;
		return $this->content;
	}
	public function save() : void {
		if(Tools::inDestructor() === false and is_null($this->name) === false):
			switch($this->mode):
				case 'string':
					$file = '.'.DIRECTORY_SEPARATOR.$this->name.'.session';
					if(isFile($file)):
						write($file,base64_encode(gzdeflate(serialize($this->content))));
					endif;
					break;
				case 'sqlite':
					$data = Tools::marshal($this->content->toArray());
					array_walk($data,fn(mixed $value,string $key) : mixed => $this->sqlite->set($this->name,$key,$value,Tools::inferType($value)));
					break;
				case 'mysql':
					$data = Tools::marshal($this->content->toArray());
					array_walk($data,fn(mixed $value,string $key) : mixed => $this->mysql->set($this->name,$key,$value,Tools::inferType($value)));
					break;
				case 'text':
					/*
					 * New information in the text session is not stored anywhere
					 * You may encounter warnings in some cases
					 * I do not recommend this type of session
					 */
					break;
				default:
					throw new \InvalidArgumentException('The database mode is invalid ! It must be one of the modes of string , sqlite , mysql , text !');
			endswitch;
		endif;
	}
	public function reset(? int $id = null) : void {
		$this->content['id'] = is_null($id) ? Helper::generateRandomLong() : $id;
		$this->content['sequence'] = 0;
		$this->content['last_msg_id'] = 0;
		gc_collect_cycles();
	}
	public function getServerTime() : int {
		return intval(time() + $this->content['time_offset']);
	}
	public function updateTimeOffset(int $msgId) : void {
		$old = $this->content['time_offset'];
		$sec = intval($msgId >> 32);
		$this->content['time_offset'] = $sec - time();
		if($new !== $old):
			$this->content['last_msg_id'] = 0;
		endif;
	}
	public function getNewMsgId() : int {
		$now = $this->getServerTime();
		$msgId = intval($now << 32);
		$msgId = $msgId & (~ 0x3);
		$this->content['last_msg_id'] = $msgId = boolval($msgId <= $this->content['last_msg_id']) ? intval($this->content['last_msg_id'] + 4) : $msgId;
		return $msgId;
	}
	public function generateSequence(bool $contentRelated = true) : int {
		if($contentRelated):
			$seqno = $this->content['sequence'] * 2 + 1;
			$this->content['sequence'] += 1;
			return $seqno;
		else:
			return $this->content['sequence'] * 2;
		endif;
	}
	public function getStringSession() : string {
		$session = clone $this;
		$content = $session->load();
		return base64_encode(gzdeflate(serialize($content)));
	}
	public function __get(string $property) : mixed {
		return $this->settings->$property;
	}
	public function __set(string $property,mixed $value) : void {
		$this->settings->$property = $value;
	}
	public function __unset(string $property) : void {
		unset($this->settings->$property);
	}
	public function __isset(string $property) : bool {
		return isset($this->settings->$property);
	}
	public function __debugInfo() : array {
		return array(
			'content'=>isset($this->content) ? $this->content : null,
			'ipv6'=>$this->ipv6,
			'testmode'=>$this->testmode,
			'dc'=>$this->dc,
			'savetime'=>$this->savetime,
			'server'=>$this->server,
			'username'=>$this->username,
			'password'=>$this->password,
			'database'=>$this->database
		);
	}
	public function __clone() : void {
		$this->content = clone $this->content;
		$this->reset(id : 0);
	}
	public function __sleep() : array {
		return array('settings');
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Database;

interface AbstractDB {
	public function init(string $table) : bool;

	public function set(string $table,string $key,mixed $value,string $type) : void;

	public function get(string $table) : ? array;

	public function delete(string $table,string $key) : void;

	public function exists(string $table,string $key) : bool;
}

?><?php

declare(strict_types = 1);

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Network\Client;

use Tak\Liveproto\Enums\Authentication;

defined('LOGO_SVG') || define('LOGO_SVG',<<<SVG
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="288.58 338.44 595.97 535.54">
	<path fill="#227ca0" d="   M 432.12 417.70   C 432.25 422.40 432.54 425.95 431.41 431.14   Q 429.95 435.17 428.51 439.12   Q 425.00 448.72 417.93 455.08   Q 412.15 460.28 401.86 464.60   A 2.83 2.73 31.2 0 1 400.85 464.83   Q 399.36 464.87 397.49 465.36   Q 389.79 467.37 381.92 466.24   Q 359.72 463.04 348.02 443.51   Q 344.23 437.19 343.09 430.26   Q 341.93 423.14 343.04 414.52   L 346.18 400.48   Q 351.76 385.29 360.37 371.59   C 365.93 362.75 374.85 349.97 382.64 340.74   Q 385.78 337.02 390.37 339.32   Q 392.02 340.15 394.15 343.12   C 405.08 358.35 413.39 369.65 421.55 384.96   Q 428.00 397.07 430.80 410.79   Q 431.53 414.34 432.12 417.70   Z   M 388.08 352.97   A 0.75 0.75 0.0 0 0 387.13 353.15   Q 372.55 371.28 361.87 391.62   Q 355.88 403.02 353.40 415.08   C 349.95 431.89 359.13 448.03 374.75 454.17   C 383.76 457.71 393.87 457.52 402.51 453.26   Q 419.23 445.02 421.64 426.18   Q 422.09 422.68 421.09 416.46   Q 419.05 403.73 413.75 393.24   C 406.66 379.22 398.20 367.13 388.95 353.84   Q 388.52 353.22 388.08 352.97   Z"></path>
	<path fill="#216623" d="   M 346.18 400.48   L 343.04 414.52   Q 343.19 413.87 343.05 413.45   Q 342.92 413.04 342.24 412.81   Q 321.23 405.40 302.33 393.97   A 0.58 0.58 0.0 0 0 301.46 394.51   Q 302.51 409.85 302.75 415.81   C 303.13 424.96 304.53 433.02 305.57 443.49   Q 306.01 447.91 309.28 465.00   C 311.33 475.72 314.88 487.92 317.73 496.79   Q 323.53 514.83 333.00 532.15   Q 362.36 585.72 416.65 610.79   C 431.31 617.56 448.68 623.11 464.59 626.34   Q 496.19 632.76 513.75 637.30   C 529.99 641.49 545.71 648.16 558.95 658.91   A 0.36 0.36 0.0 0 0 559.53 658.67   Q 559.63 657.56 559.02 656.00   C 550.14 633.24 535.40 612.00 518.47 595.79   Q 516.79 594.17 514.12 594.12   Q 509.76 594.02 504.62 593.41   C 484.81 591.08 467.08 588.43 448.86 583.67   Q 436.86 580.54 430.66 578.55   Q 414.47 573.34 395.38 565.61   Q 393.49 564.85 384.90 560.58   A 0.20 0.20 0.0 0 1 384.82 560.29   Q 384.87 560.21 385.04 560.14   Q 385.26 560.06 385.48 560.15   Q 387.59 561.09 388.04 561.20   Q 391.26 562.00 405.33 565.88   Q 414.67 568.45 432.51 571.94   Q 443.30 574.04 466.92 577.19   C 480.22 578.96 491.81 579.52 505.06 580.53   A 0.27 0.27 0.0 0 0 505.31 580.11   Q 504.89 579.44 504.17 578.82   Q 482.87 560.27 465.11 547.95   C 463.06 546.52 460.56 544.57 458.40 544.34   Q 434.40 541.76 421.12 539.12   Q 402.22 535.35 377.65 527.00   C 371.19 524.53 364.74 522.23 358.50 519.38   Q 354.44 517.53 351.32 516.48   Q 350.30 516.14 349.79 515.34   A 0.34 0.34 0.0 0 1 350.08 514.82   C 350.37 514.83 352.64 516.14 353.80 516.44   Q 378.42 522.83 386.50 524.21   Q 389.42 524.71 394.26 525.62   C 408.00 528.22 422.49 529.74 438.97 531.59   A 0.28 0.28 0.0 0 0 439.19 531.10   C 437.84 529.83 435.73 528.80 434.63 528.10   Q 410.59 512.72 387.72 500.78   Q 350.07 481.13 334.37 472.02   A 0.09 0.09 0.0 0 1 334.33 471.91   L 334.34 471.90   A 0.12 0.12 0.0 0 1 334.50 471.84   L 413.61 502.25   A 0.47 0.46 88.8 0 0 414.20 501.63   Q 413.63 500.36 413.15 499.61   Q 402.55 483.00 397.87 473.42   Q 396.51 470.64 396.17 469.99   A 0.54 0.53 -30.0 0 1 396.37 469.27   L 396.38 469.26   A 0.45 0.45 0.0 0 1 396.96 469.37   C 400.22 473.52 404.47 479.56 408.09 484.09   Q 416.63 494.79 423.53 505.02   C 425.25 507.56 426.90 508.97 429.45 510.31   Q 449.41 520.79 468.54 533.11   A 0.65 0.65 0.0 0 0 469.52 532.41   L 458.76 488.55   L 466.97 488.80   Q 465.33 488.70 464.15 489.22   A 0.59 0.58 -21.5 0 0 463.83 489.94   L 480.11 540.03   A 7.61 7.55 9.8 0 0 482.73 543.72   Q 505.88 561.37 526.22 582.05   A 0.46 0.46 0.0 0 0 527.01 581.75   Q 527.17 577.93 526.88 576.12   Q 520.43 535.49 504.22 499.02   Q 504.06 498.65 504.10 498.01   A 0.20 0.19 30.4 0 1 504.46 497.92   Q 516.03 515.90 524.31 536.66   Q 527.41 544.44 530.20 552.27   Q 537.33 574.14 539.76 596.22   A 5.55 5.51 -68.9 0 0 541.10 599.27   Q 555.19 615.24 565.78 632.40   A 0.62 0.61 -61.4 0 0 566.92 632.06   C 566.81 624.93 568.05 617.94 567.92 610.97   Q 567.67 598.28 566.74 584.50   Q 566.40 579.55 565.37 574.59   Q 564.81 571.91 563.66 564.72   Q 562.36 556.60 559.79 548.75   Q 559.27 546.41 558.60 544.13   C 548.42 509.76 528.11 478.57 498.37 458.16   A 0.49 0.49 0.0 0 0 497.62 458.43   Q 497.53 458.75 497.60 459.22   Q 497.59 451.62 497.06 449.23   Q 496.15 445.06 495.28 440.65   C 528.18 461.02 553.13 492.29 566.46 528.27   Q 575.47 552.60 578.58 578.03   C 580.72 595.45 581.38 613.73 580.02 631.61   C 579.09 643.78 578.92 648.65 578.04 655.72   Q 577.54 659.80 578.09 662.69   C 578.82 666.52 579.27 671.13 580.49 675.16   Q 581.09 677.14 581.14 679.03   A 0.38 0.38 0.0 0 0 581.87 679.15   Q 585.10 670.26 588.81 659.59   Q 591.25 652.56 591.40 648.83   C 591.65 642.90 591.94 637.62 591.81 633.39   Q 591.46 621.99 593.05 598.27   C 596.06 553.14 610.43 509.50 637.12 473.15   Q 659.02 443.31 691.41 425.19   Q 713.88 412.62 737.98 405.52   C 752.41 401.27 767.34 397.20 782.50 393.52   C 805.20 388.02 828.52 380.91 848.55 369.90   C 855.53 366.06 864.02 360.32 868.95 355.45   C 871.80 352.64 876.39 347.24 880.55 349.30   Q 883.67 350.85 884.06 354.76   Q 884.31 357.32 884.50 366.75   Q 884.86 384.83 882.89 411.49   Q 880.32 446.15 873.10 478.43   Q 871.58 485.19 867.92 498.21   Q 862.06 518.98 853.26 539.25   C 836.72 577.32 807.40 610.27 769.92 628.16   Q 752.84 636.31 733.69 641.17   Q 715.71 645.73 699.77 648.02   C 682.71 650.46 669.08 652.48 653.38 656.89   C 637.36 661.39 623.33 668.42 612.05 680.26   Q 600.90 691.96 592.34 710.33   Q 584.21 727.77 577.92 748.15   Q 567.58 781.65 559.45 806.70   A 0.34 0.33 75.9 0 0 560.01 807.04   C 573.29 792.86 584.21 780.40 603.03 758.79   C 620.03 739.28 638.67 720.78 660.62 709.11   Q 674.52 701.73 689.09 699.89   Q 697.99 698.77 707.50 701.01   C 728.36 705.93 733.40 727.28 725.52 745.05   C 708.86 782.63 661.83 800.32 623.68 804.79   Q 602.15 807.31 580.18 807.87   A 2.21 2.20 19.6 0 0 578.59 808.62   Q 550.06 841.38 520.67 870.92   Q 518.71 872.89 516.48 873.79   A 2.56 2.44 33.0 0 1 515.47 873.98   C 510.97 873.95 509.75 870.17 511.82 866.81   C 527.20 841.89 539.49 815.18 548.81 787.66   C 555.78 767.06 562.24 744.91 566.01 723.77   C 569.44 704.55 568.03 684.57 552.57 670.91   Q 542.71 662.21 529.31 656.92   Q 514.20 650.94 499.00 647.76   Q 474.50 642.63 455.47 637.99   Q 435.92 633.23 417.39 625.36   Q 369.80 605.16 338.42 564.10   C 306.20 521.95 292.81 468.82 289.72 416.75   Q 289.53 413.53 288.70 394.50   Q 288.41 387.81 288.85 382.39   Q 289.24 377.61 293.22 376.34   C 295.09 375.75 297.37 376.93 298.83 377.93   C 313.75 388.13 329.29 394.63 346.18 400.48   Z   M 633.70 502.73   Q 624.67 518.82 618.66 536.39   Q 607.82 568.06 605.07 601.25   C 604.35 610.02 604.53 617.09 604.29 628.29   A 0.32 0.32 0.0 0 0 604.89 628.46   C 622.16 599.87 643.90 575.08 669.35 552.86   Q 687.39 537.12 704.78 524.09   Q 705.61 524.62 706.20 524.18   Q 741.60 498.29 756.46 487.71   Q 760.90 484.56 764.99 482.70   A 0.62 0.62 0.0 0 1 765.87 483.31   C 765.74 485.26 761.68 489.74 760.03 491.54   Q 741.99 511.23 724.00 530.25   Q 720.76 533.67 721.61 537.54   L 712.97 534.91   A 2.72 2.72 0.0 0 0 710.52 535.35   Q 679.00 559.39 653.14 589.12   Q 625.11 621.33 607.52 659.53   Q 605.20 664.56 603.86 668.82   A 0.32 0.32 0.0 0 0 604.39 669.14   Q 619.71 654.30 639.78 647.08   Q 659.60 639.96 683.48 636.73   Q 706.22 633.65 720.67 630.53   Q 721.05 630.45 723.79 629.85   Q 751.11 623.91 773.99 610.82   Q 795.33 598.61 811.76 579.81   C 827.09 562.27 838.75 541.53 846.78 519.48   Q 855.09 497.11 859.63 476.63   Q 859.95 475.15 862.57 462.58   C 863.32 458.97 863.39 455.89 864.27 452.33   Q 865.08 449.00 865.56 444.64   C 866.33 437.57 867.66 430.82 868.26 423.09   Q 869.03 413.22 869.70 404.99   Q 871.14 387.45 871.11 371.14   A 0.48 0.47 -20.0 0 0 870.33 370.78   C 860.62 378.85 848.91 385.05 838.31 389.34   Q 818.39 397.39 800.42 402.11   C 771.07 409.82 752.98 414.61 734.22 420.50   Q 712.02 427.47 690.68 440.70   C 666.66 455.58 647.49 477.75 633.70 502.73   Z   M 590.60 793.54   Q 606.31 792.38 622.24 789.94   C 649.64 785.74 676.78 776.25 697.44 757.46   C 705.42 750.21 712.39 740.06 712.82 729.10   C 713.33 716.19 700.37 713.02 690.42 714.68   C 672.87 717.61 656.75 727.39 642.73 739.23   Q 629.58 750.36 619.45 761.21   Q 608.99 772.42 590.43 793.19   A 0.21 0.21 0.0 0 0 590.60 793.54   Z"></path>
	<path fill="#62b8e2" d="   M 388.08 352.97   Q 388.52 353.22 388.95 353.84   C 398.20 367.13 406.66 379.22 413.75 393.24   Q 419.05 403.73 421.09 416.46   Q 422.09 422.68 421.64 426.18   Q 419.23 445.02 402.51 453.26   C 393.87 457.52 383.76 457.71 374.75 454.17   C 359.13 448.03 349.95 431.89 353.40 415.08   Q 355.88 403.02 361.87 391.62   Q 372.55 371.28 387.13 353.15   A 0.75 0.75 0.0 0 1 388.08 352.97   Z   M 409.0898 418.5684   A 13.45 8.05 76.5 0 0 413.7776 403.6108   A 13.45 8.05 76.5 0 0 402.8102 392.4116   A 13.45 8.05 76.5 0 0 398.1224 407.3692   A 13.45 8.05 76.5 0 0 409.0898 418.5684   Z"></path>
	<path fill="#61ae39" d="   M 846.78 519.48   C 824.35 521.72 802.54 526.08 780.35 529.98   Q 788.75 492.36 797.44 455.00   Q 798.29 451.36 797.55 450.01   Q 794.97 445.29 790.46 447.45   Q 753.17 465.30 683.94 500.67   Q 679.74 502.82 677.43 505.98   Q 655.72 502.74 633.70 502.73   C 647.49 477.75 666.66 455.58 690.68 440.70   Q 712.02 427.47 734.22 420.50   C 752.98 414.61 771.07 409.82 800.42 402.11   Q 818.39 397.39 838.31 389.34   C 848.91 385.05 860.62 378.85 870.33 370.78   A 0.48 0.47 -20.0 0 1 871.11 371.14   Q 871.14 387.45 869.70 404.99   Q 869.03 413.22 868.26 423.09   C 867.66 430.82 866.33 437.57 865.56 444.64   Q 865.08 449.00 864.27 452.33   C 863.39 455.89 863.32 458.97 862.57 462.58   Q 859.95 475.15 859.63 476.63   Q 855.09 497.11 846.78 519.48   Z"></path>
	<path fill="#227ca0" d="   M 495.28 440.65   Q 496.15 445.06 497.06 449.23   Q 497.59 451.62 497.60 459.22   Q 494.27 477.98 477.29 486.25   Q 475.03 487.36 466.97 488.80   L 458.76 488.55   C 450.48 486.50 441.26 481.03 437.11 473.38   Q 434.59 468.72 434.49 468.54   C 431.11 462.25 431.15 453.50 431.95 446.88   Q 432.24 444.40 433.88 440.03   Q 435.14 436.69 436.19 433.24   Q 436.74 433.20 436.91 432.65   Q 438.03 429.00 439.57 426.40   Q 440.94 424.07 441.75 422.01   Q 449.53 409.34 459.52 396.02   C 462.62 391.88 466.45 392.41 469.33 396.43   C 480.26 411.74 488.54 424.99 495.28 440.65   Z   M 463.92 479.94   Q 467.98 479.98 469.19 479.61   C 488.78 473.54 491.89 453.93 483.58 437.32   Q 475.94 422.04 465.63 407.14   Q 465.19 406.51 464.71 406.51   Q 464.22 406.50 463.78 407.12   Q 453.15 421.80 445.18 436.91   C 436.52 453.34 439.20 473.01 458.66 479.49   Q 459.86 479.90 463.92 479.94   Z"></path>
	<path fill="#61ae39" d="   M 343.04 414.52   Q 341.93 423.14 343.09 430.26   Q 344.23 437.19 348.02 443.51   Q 359.72 463.04 381.92 466.24   Q 389.79 467.37 397.49 465.36   Q 399.36 464.87 400.85 464.83   A 2.83 2.73 31.2 0 0 401.86 464.60   Q 412.15 460.28 417.93 455.08   Q 425.00 448.72 428.51 439.12   Q 429.95 435.17 431.41 431.14   Q 433.91 431.54 436.19 433.24   Q 435.14 436.69 433.88 440.03   Q 432.24 444.40 431.95 446.88   C 431.15 453.50 431.11 462.25 434.49 468.54   Q 434.59 468.72 437.11 473.38   C 441.26 481.03 450.48 486.50 458.76 488.55   L 469.52 532.41   A 0.65 0.65 0.0 0 1 468.54 533.11   Q 449.41 520.79 429.45 510.31   C 426.90 508.97 425.25 507.56 423.53 505.02   Q 416.63 494.79 408.09 484.09   C 404.47 479.56 400.22 473.52 396.96 469.37   A 0.45 0.45 0.0 0 0 396.38 469.26   L 396.37 469.27   A 0.54 0.53 -30.0 0 0 396.17 469.99   Q 396.51 470.64 397.87 473.42   Q 402.55 483.00 413.15 499.61   Q 413.63 500.36 414.20 501.63   A 0.47 0.46 88.8 0 1 413.61 502.25   L 334.50 471.84   A 0.12 0.12 0.0 0 0 334.34 471.90   L 334.33 471.91   A 0.09 0.09 0.0 0 0 334.37 472.02   Q 350.07 481.13 387.72 500.78   Q 410.59 512.72 434.63 528.10   C 435.73 528.80 437.84 529.83 439.19 531.10   A 0.28 0.28 0.0 0 1 438.97 531.59   C 422.49 529.74 408.00 528.22 394.26 525.62   Q 389.42 524.71 386.50 524.21   Q 378.42 522.83 353.80 516.44   C 352.64 516.14 350.37 514.83 350.08 514.82   A 0.34 0.34 0.0 0 0 349.79 515.34   Q 350.30 516.14 351.32 516.48   Q 354.44 517.53 358.50 519.38   C 364.74 522.23 371.19 524.53 377.65 527.00   Q 355.06 528.46 333.00 532.15   Q 323.53 514.83 317.73 496.79   C 314.88 487.92 311.33 475.72 309.28 465.00   Q 306.01 447.91 305.57 443.49   C 304.53 433.02 303.13 424.96 302.75 415.81   Q 302.51 409.85 301.46 394.51   A 0.58 0.58 0.0 0 1 302.33 393.97   Q 321.23 405.40 342.24 412.81   Q 342.92 413.04 343.05 413.45   Q 343.19 413.87 343.04 414.52   Z"></path>
	<path fill="#62b8e2" d="   M 464.71 406.51   Q 465.19 406.51 465.63 407.14   Q 475.94 422.04 483.58 437.32   C 491.89 453.93 488.78 473.54 469.19 479.61   Q 467.98 479.98 463.92 479.94   Q 459.86 479.90 458.66 479.49   C 439.20 473.01 436.52 453.34 445.18 436.91   Q 453.15 421.80 463.78 407.12   Q 464.22 406.50 464.71 406.51   Z   M 479.7115 456.3039   A 9.17 6.01 75.4 0 0 483.2159 445.9151   A 9.17 6.01 75.4 0 0 475.0885 438.5561   A 9.17 6.01 75.4 0 0 471.5841 448.9449   A 9.17 6.01 75.4 0 0 479.7115 456.3039   Z"></path>
	<path fill="#216623" d="   M 441.75 422.01   Q 440.94 424.07 439.57 426.40   Q 438.03 429.00 436.91 432.65   Q 436.74 433.20 436.19 433.24   Q 433.91 431.54 431.41 431.14   C 432.54 425.95 432.25 422.40 432.12 417.70   L 441.75 422.01   Z"></path>
	<path fill="#61ae39" d="   M 559.79 548.75   L 530.20 552.27   Q 527.41 544.44 524.31 536.66   Q 516.03 515.90 504.46 497.92   A 0.20 0.19 30.4 0 0 504.10 498.01   Q 504.06 498.65 504.22 499.02   Q 520.43 535.49 526.88 576.12   Q 527.17 577.93 527.01 581.75   A 0.46 0.46 0.0 0 1 526.22 582.05   Q 505.88 561.37 482.73 543.72   A 7.61 7.55 9.8 0 1 480.11 540.03   L 463.83 489.94   A 0.59 0.58 -21.5 0 1 464.15 489.22   Q 465.33 488.70 466.97 488.80   Q 475.03 487.36 477.29 486.25   Q 494.27 477.98 497.60 459.22   Q 497.53 458.75 497.62 458.43   A 0.49 0.49 0.0 0 1 498.37 458.16   C 528.11 478.57 548.42 509.76 558.60 544.13   Q 559.27 546.41 559.79 548.75   Z"></path>
	<path fill="#519e34" d="   M 677.43 505.98   C 675.31 510.51 680.16 512.53 683.77 514.24   Q 694.30 519.22 704.78 524.09   Q 687.39 537.12 669.35 552.86   C 643.90 575.08 622.16 599.87 604.89 628.46   A 0.32 0.32 0.0 0 1 604.29 628.29   C 604.53 617.09 604.35 610.02 605.07 601.25   Q 607.82 568.06 618.66 536.39   Q 624.67 518.82 633.70 502.73   Q 655.72 502.74 677.43 505.98   Z"></path>
	<path fill="#519e34" d="   M 846.78 519.48   C 838.75 541.53 827.09 562.27 811.76 579.81   Q 795.33 598.61 773.99 610.82   Q 751.11 623.91 723.79 629.85   Q 721.05 630.45 720.67 630.53   Q 706.22 633.65 683.48 636.73   Q 659.60 639.96 639.78 647.08   Q 619.71 654.30 604.39 669.14   A 0.32 0.32 0.0 0 1 603.86 668.82   Q 605.20 664.56 607.52 659.53   Q 625.11 621.33 653.14 589.12   Q 679.00 559.39 710.52 535.35   A 2.72 2.72 0.0 0 1 712.97 534.91   L 721.61 537.54   Q 747.67 556.32 759.83 564.44   Q 761.59 565.61 764.77 566.21   C 769.78 567.15 772.44 564.07 773.55 559.28   Q 776.96 544.53 780.35 529.98   C 802.54 526.08 824.35 521.72 846.78 519.48   Z"></path>
	<path fill="#519e34" d="   M 333.00 532.15   Q 355.06 528.46 377.65 527.00   Q 402.22 535.35 421.12 539.12   Q 434.40 541.76 458.40 544.34   C 460.56 544.57 463.06 546.52 465.11 547.95   Q 482.87 560.27 504.17 578.82   Q 504.89 579.44 505.31 580.11   A 0.27 0.27 0.0 0 1 505.06 580.53   C 491.81 579.52 480.22 578.96 466.92 577.19   Q 443.30 574.04 432.51 571.94   Q 414.67 568.45 405.33 565.88   Q 391.26 562.00 388.04 561.20   Q 387.59 561.09 385.48 560.15   Q 385.26 560.06 385.04 560.14   Q 384.87 560.21 384.82 560.29   A 0.20 0.20 0.0 0 0 384.90 560.58   Q 393.49 564.85 395.38 565.61   Q 414.47 573.34 430.66 578.55   Q 436.86 580.54 448.86 583.67   C 467.08 588.43 484.81 591.08 504.62 593.41   Q 509.76 594.02 514.12 594.12   Q 516.79 594.17 518.47 595.79   C 535.40 612.00 550.14 633.24 559.02 656.00   Q 559.63 657.56 559.53 658.67   A 0.36 0.36 0.0 0 1 558.95 658.91   C 545.71 648.16 529.99 641.49 513.75 637.30   Q 496.19 632.76 464.59 626.34   C 448.68 623.11 431.31 617.56 416.65 610.79   Q 362.36 585.72 333.00 532.15   Z"></path>
	<path fill="#519e34" d="   M 530.20 552.27   L 559.79 548.75   Q 562.36 556.60 563.66 564.72   Q 564.81 571.91 565.37 574.59   Q 566.40 579.55 566.74 584.50   Q 567.67 598.28 567.92 610.97   C 568.05 617.94 566.81 624.93 566.92 632.06   A 0.62 0.61 -61.4 0 1 565.78 632.40   Q 555.19 615.24 541.10 599.27   A 5.55 5.51 -68.9 0 1 539.76 596.22   Q 537.33 574.14 530.20 552.27   Z"></path>
</svg>
SVG);

if(isset($this) === false or ($this instanceof Client) === false){
	throw new \LogicException('login.php must be included from Client::start()');
}

Logging::$hide = true;

$step = $this->load->step;

try {
	if($_SERVER['REQUEST_METHOD'] === 'POST'){
		if($step === Authentication::NEED_AUTHENTICATION and isset($_POST['send_code'])){
			if(isset($_POST['login_method'])){
				if($_POST['login_method'] === 'token' and isset($_POST['token']) and str_contains($_POST['token'],chr(58))){
					$token = trim($_POST['token']);
					$this->sign_in(bot_token : $token);
				} elseif($_POST['login_method'] === 'phone' and isset($_POST['phone']) and isset($_POST['country_code'])){
					$phone_number = preg_replace('/[^\d]/',strval(null),$_POST['country_code'].$_POST['phone']);
					$this->send_code(phone_number : $phone_number);
				}
			}
		} elseif($step === Authentication::NEED_CODE and isset($_POST['code'])){
			$code = trim($_POST['code']);
			try {
				$authorization = $this->sign_in(code : $code);
				if($authorization instanceof \Tak\Liveproto\Tl\Types\Auth\AuthorizationSignUpRequired):
					$this->sign_up(first_name : 'Live',last_name : 'Proto');
				endif;
			} catch(\Throwable $e){
				if($e->getMessage() !== 'SESSION_PASSWORD_NEEDED'){
					throw $e;
				}
			}
		} elseif($step === Authentication::NEED_PASSWORD and isset($_POST['password'])){
			$password = trim($_POST['password']);
			$this->sign_in(password : $password);
		}
	}
} catch(\Throwable $e){
	$error = $e->getMessage();
}

$stage = $this->load->step->value;

@ob_clean();

?>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width,initial-scale=1.0">
	<title>Secure Login System</title>
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
	<style>
		:root {
			--primary: #6366f1;
			--primary-dark: #4f46e5;
			--bg: #f9fafb;
			--card-bg: #ffffff;
			--text: #111827;
			--text-light: #6b7280;
			--error: #ef4444;
			--success: #10b981;
			--failed: #dbde28;
		}
		* {
			margin: 0;
			padding: 0;
			box-sizing: border-box;
			font-family: 'Segoe UI',system-ui,sans-serif;
		}
		body {
			background: var(--bg);
			min-height: 100vh;
			display: flex;
			justify-content: center;
			align-items: center;
			padding: 20px;
			background-image: radial-gradient(#d1d5db 1px,transparent 1px);
			background-size: 20px 20px;
		}
		.login-container {
			width: 100%;
			max-width: 420px;
			position: relative;
			z-index: 10;
		}
		.login-card {
			background: var(--card-bg);
			border-radius: 24px;
			padding: 40px 30px;
			box-shadow: 0 25px 50px -12px rgba(0,0,0,0.15);
			position: relative;
			overflow: hidden;
			transform: translateY(0);
			transition: transform 0.4s ease,box-shadow 0.4s ease;
		}
		.login-card:hover {
			transform: translateY(-5px);
			box-shadow: 0 30px 60px -10px rgba(0,0,0,0.2);
		}
		.rgb-border {
			position: absolute;
			top: -3px;
			left: -3px;
			right: -3px;
			bottom: -3px;
			background: var(--rgb-border);
			background-size: 300% 300%;
			border-radius: 27px;
			z-index: -1;
			animation: rgb-animation 3s linear infinite;
			filter: blur(3px);
			opacity: 0.7;
		}
		.logo-container {
			text-align: center;
			margin-bottom: 30px;
			animation: float 4s ease-in-out infinite;
		}
		h1 {
			text-align: center;
			color: var(--text);
			margin-bottom: 10px;
			font-weight: 700;
			font-size: 28px;
			letter-spacing: -0.5px;
		}
		.subtitle {
			text-align: center;
			color: var(--text-light);
			margin-bottom: 32px;
			font-size: 16px;
			line-height: 1.5;
		}
		.step-indicator {
			display: flex;
			justify-content: center;
			gap: 12px;
			margin-bottom: 30px;
		}
		.step {
			width: 12px;
			height: 12px;
			border-radius: 50%;
			background: #e5e7eb;
			transition: all 0.3s ease;
		}
		.step.active {
			background: var(--primary);
			transform: scale(1.2);
		}
		.form-group {
			margin-bottom: 24px;
			position: relative;
		}
		.input-label {
			display: block;
			margin-bottom: 8px;
			color: var(--text);
			font-weight: 500;
			font-size: 14px;
			display: flex;
			align-items: center;
		}
		.input-label i {
			margin-right: 8px;
			color: var(--primary);
		}
		.input-field {
			width: 100%;
			padding: 16px 20px;
			border: 2px solid #e5e7eb;
			border-radius: 16px;
			font-size: 16px;
			transition: all 0.3s ease;
			outline: none;
			background: var(--card-bg);
			color: var(--text);
			box-shadow: inset 0 1px 3px rgba(0,0,0,0.05);
		}
		.input-field:focus {
			border-color: var(--primary);
			box-shadow: 0 0 0 4px rgba(99,102,241,0.2);
			transform: translateY(-2px);
		}
		.input-field::placeholder {
			color: #9ca3af;
		}
		.phone-group {
			display: flex;
			gap: 10px;
		}
		.country-code {
			flex: 0 0 80px;
		}
		.phone-number {
			flex: 1;
		}
		.method-selector {
			display: flex;
			gap: 12px;
			margin-bottom: 24px;
		}
		.method-btn {
			flex: 1;
			padding: 16px;
			background: #f3f4f6;
			border: none;
			border-radius: 16px;
			font-size: 16px;
			font-weight: 600;
			cursor: pointer;
			transition: all 0.3s ease;
			display: flex;
			flex-direction: column;
			align-items: center;
			justify-content: center;
		}
		.method-btn i {
			font-size: 24px;
			margin-bottom: 8px;
			color: var(--primary);
		}
		.method-btn:hover {
			background: #e5e7eb;
			transform: translateY(-3px);
		}
		.method-btn.active {
			background: var(--primary);
			color: white;
			box-shadow: 0 10px 20px -10px rgba(79,70,229,0.4);
		}
		.method-btn.active i {
			color: white;
		}
		.submit-btn {
			width: 100%;
			padding: 18px;
			background: var(--primary);
			color: white;
			border: none;
			border-radius: 16px;
			font-size: 16px;
			font-weight: 600;
			cursor: pointer;
			transition: all 0.3s ease;
			box-shadow: 0 10px 20px -10px rgba(79,70,229,0.5);
			position: relative;
			overflow: hidden;
		}
		.submit-btn::before {
			content: '';
			position: absolute;
			top: 0;
			left: -100%;
			width: 100%;
			height: 100%;
			background: linear-gradient(90deg,transparent,rgba(255,255,255,0.2),transparent);
			transition: 0.5s;
		}
		.submit-btn:hover {
			transform: translateY(-3px);
			box-shadow: 0 15px 25px -10px rgba(79,70,229,0.6);
			background: var(--primary-dark);
		}
		.submit-btn:hover::before {
			left: 100%;
		}
		.submit-btn:active {
			transform: translateY(1px);
		}
		.back-btn {
			display: block;
			text-align: center;
			margin-top: 20px;
			color: var(--primary);
			font-weight: 600;
			text-decoration: none;
			cursor: pointer;
			transition: all 0.3s ease;
		}
		.back-btn:hover {
			color: var(--primary-dark);
			transform: translateX(-3px);
		}
		.back-btn i {
			margin-right: 5px;
		}
		.success-message {
			text-align: center;
			padding: 40px 0;
			animation: fadeIn 0.6s ease;
		}
		.success-icon {
			font-size: 80px;
			color: var(--success);
			margin-bottom: 20px;
			animation: scaleIn 0.5s ease,pulse 2s infinite;
		}
		.failed-message {
			text-align: center;
			padding: 40px 0;
			animation: fadeIn 0.6s ease;
		}
		.failed-icon {
			font-size: 80px;
			color: var(--failed);
			margin-bottom: 20px;
			animation: scaleIn 0.5s ease,pulse 2s infinite;
		}
		.error-message {
			background: rgba(239,68,68,0.1);
			color: var(--error);
			padding: 16px;
			border-radius: 12px;
			margin-bottom: 24px;
			text-align: center;
			animation: shake 0.5s ease;
			border: 1px solid rgba(239,68,68,0.2);
		}
		.password-toggle {
			position: absolute;
			right: 16px;
			top: 42px;
			color: var(--text-light);
			cursor: pointer;
		}
		@keyframes rgb-animation {
			0% { background-position: 0% 50%; }
			100% { background-position: 300% 50%; }
		}
		@keyframes float {
			0% { transform: translateY(0px); }
			50% { transform: translateY(-10px); }
			100% { transform: translateY(0px); }
		}
		@keyframes scaleIn {
			0% { transform: scale(0); opacity: 0; }
			100% { transform: scale(1); opacity: 1; }
		}
		@keyframes pulse {
			0% { transform: scale(1); }
			50% { transform: scale(1.05); }
			100% { transform: scale(1); }
		}
		@keyframes fadeIn {
			from { opacity: 0; transform: translateY(20px); }
			to { opacity: 1; transform: translateY(0); }
		}
		@keyframes shake {
			0%,100% { transform: translateX(0); }
			20%,60% { transform: translateX(-8px); }
			40%,80% { transform: translateX(8px); }
		}
		.particles {
			position: fixed;
			top: 0;
			left: 0;
			width: 100%;
			height: 100%;
			z-index: 1;
			pointer-events: none;
		}
		.particle {
			position: absolute;
			border-radius: 50%;
			background: var(--primary);
			opacity: 0.3;
			animation: float-particle 15s infinite linear;
		}
		@keyframes float-particle {
			0% { transform: translateY(0) translateX(0) rotate(0deg); }
			100% { transform: translateY(-100vh) translateX(100px) rotate(360deg); }
		}
	</style>
</head>
<body>
	<div class="particles" id="particles"></div>
	<div class="login-container">
		<div class="login-card">
			<div class="rgb-border"></div>
			<?php if(isset($error)): ?>
				<div class="error-message">
					<i class="fas fa-exclamation-circle"></i> <?= htmlspecialchars($error) ?>
				</div>
			<?php endif; ?>
			<?php if($stage === 0): ?>
				<div class="logo-container">
					<?= LOGO_SVG ?>
				</div>
				<h1>Welcome</h1>
				<p class="subtitle">Choose your preferred login method to continue</p>
				<form method="POST">
					<div class="method-selector">
						<button type="button" class="method-btn" id="tokenBtn">
							<i class="fas fa-key"></i>
							Token
						</button>
						<button type="button" class="method-btn" id="phoneBtn">
							<i class="fas fa-mobile-alt"></i>
							Phone
						</button>
					</div>
					<input type="hidden" name="login_method" id="loginMethod" value="token">
					<div id="tokenField">
						<div class="form-group">
							<label class="input-label"><i class="fas fa-fingerprint"></i> Your Token</label>
							<input type="text" class="input-field" name="token" placeholder="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" minlength="35" maxlength="46">
						</div>
					</div>
					<div id="phoneField" style="display: none;">
						<div class="form-group">
							<label class="input-label"><i class="fas fa-phone"></i> Phone Number</label>
							<div class="phone-group">
								<div class="country-code">
									<input type="text" class="input-field" name="country_code" placeholder="+1" value="+1">
								</div>
								<div class="phone-number">
									<input type="tel" class="input-field" name="phone" placeholder="Enter phone number" pattern="[0-9]{5,15}">
								</div>
							</div>
						</div>
					</div>
					<button type="submit" name="send_code" class="submit-btn">Continue</button>
				</form>
			<?php elseif($stage === 1): ?>
				<div class="logo-container">
					<?= LOGO_SVG ?>
				</div>
				<h1>Verification Code</h1>
				<p class="subtitle">
					We sent a 5-digit code to 
					<?= htmlspecialchars($this->load->phonenumber) ?>
				</p>
				<div class="step-indicator">
					<div class="step active"></div>
					<div class="step active"></div>
					<div class="step"></div>
				</div>
				<form method="POST">
					<div class="form-group">
						<label class="input-label"><i class="fas fa-shield-alt"></i> Verification Code</label>
						<input type="text" class="input-field" name="code" placeholder="Enter 5-digit code" pattern="[0-9]{5}" maxlength="5" required autofocus>
					</div>
					<button type="submit" name="sign_in" class="submit-btn">Verify Code</button>
					<a class="back-btn" onclick="history.back()"><i class="fas fa-arrow-left"></i> Back</a>
				</form>
			<?php elseif($stage === 5): ?>
				<div class="logo-container">
					<?= LOGO_SVG ?>
				</div>
				<h1>Two-Factor Authentication</h1>
				<p class="subtitle">Enter your 2FA password for enhanced security</p>
				<div class="step-indicator">
					<div class="step active"></div>
					<div class="step active"></div>
					<div class="step active"></div>
				</div>
				<form method="POST">
					<div class="form-group">
						<label class="input-label"><i class="fas fa-lock"></i> 2FA Password</label>
						<input type="password" class="input-field" id="passwordInput" name="password" placeholder="Enter your password" required autofocus>
						<span class="password-toggle" id="passwordToggle">
							<i class="fas fa-eye"></i>
						</span>
					</div>
					<button type="submit" class="submit-btn">Complete Login</button>
					<a class="back-btn" onclick="history.back()"><i class="fas fa-arrow-left"></i> Back</a>
				</form>
			<?php elseif($stage === 7): ?>
				<div class="success-message">
					<div class="success-icon">
						<i class="fas fa-check-circle"></i>
					</div>
					<h1>Login Successful !</h1>
					<p class="subtitle">Your bot is now running...</p>
				</div>
			<?php else: ?>
				<div class="failed-message">
					<div class="failed-icon">
						<i class="fas fa-exclamation-triangle"></i>
					</div>
					<h1>Login Failed !</h1>
					<p class="subtitle">Web login does not support the stage your account is logged into ( Stage : <?= $stage ?> )</p>
				</div>
			<?php endif; ?>
		</div>
	</div>
	<script>
		const tokenBtn = document.getElementById('tokenBtn');
		if(tokenBtn){
			tokenBtn.addEventListener('click',function(){
				this.classList.add('active');
				document.getElementById('phoneBtn').classList.remove('active');
				document.getElementById('loginMethod').value = 'token';
				document.getElementById('tokenField').style.display = 'block';
				document.getElementById('phoneField').style.display = 'none';
			});
			tokenBtn.classList.add('active');
		}

		const phoneBtn = document.getElementById('phoneBtn');
		if(phoneBtn){
			phoneBtn.addEventListener('click',function(){
				this.classList.add('active');
				document.getElementById('tokenBtn').classList.remove('active');
				document.getElementById('loginMethod').value = 'phone';
				document.getElementById('tokenField').style.display = 'none';
				document.getElementById('phoneField').style.display = 'block';
			});
		}

		const passwordInput = document.getElementById('passwordInput');
		const passwordToggle = document.getElementById('passwordToggle');
		if(passwordInput && passwordToggle){
			passwordToggle.addEventListener('click',function(){
				if(passwordInput.type === 'password'){
					passwordInput.type = 'text';
					passwordToggle.innerHTML = '<i class="fas fa-eye-slash"></i>';
				} else {
					passwordInput.type = 'password';
					passwordToggle.innerHTML = '<i class="fas fa-eye"></i>';
				}
			});
		}

		const codeInput = document.querySelector('input[name="code"]');
		if(codeInput){
			codeInput.addEventListener('input',function(){
				if(this.value.length === 5){
					this.form.submit();
				}
			});
		}

		function createParticles(){
			const particlesContainer = document.getElementById('particles');
			const particleCount = 20;
			for(let i = 0; i < particleCount; i++){
				const particle = document.createElement('div');
				particle.classList.add('particle');
				const size = Math.random() * 20 + 5;
				const posX = Math.random() * 100;
				const posY = Math.random() * 100;
				const animationDuration = Math.random() * 20 + 10;
				const animationDelay = Math.random() * 5;
				const hue = Math.floor(Math.random() * 360);
				particle.style.width = `${size}px`;
				particle.style.height = `${size}px`;
				particle.style.left = `${posX}%`;
				particle.style.top = `${posY}%`;
				particle.style.background = `hsl(${hue},70%,60%)`;
				particle.style.animationDuration = `${animationDuration}s`;
				particle.style.animationDelay = `-${animationDelay}s`;
				particlesContainer.appendChild(particle);
			}
		}
		window.addEventListener('load',createParticles);
	</script>
</body>
</html>
<?php

if($stage < 7){
	ob_start();
	$this->stop();
	ob_end_clean();
	die();
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters;

final class FilterOr {
	private array $types;

	public function __construct(\ReflectionUnionType $object){
		$this->types = $object->getTypes();
	}
	public function check(object $update) : bool {
		$conditions = array();
		foreach($this->types as $type):
			$condition = match(true){
				$type instanceof \ReflectionIntersectionType => new FilterAnd($type),
				$type instanceof \ReflectionNamedType => new FilterName($type),
				default => throw new \Exception('Unknown Type Filter !')
			};
			$conditions []= $condition->check($update);
		endforeach;
		return in_array(true,$conditions) === true;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters;

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Enums\PeerType;

final class Interfaces {
	public function __construct(private readonly string $name){
	}
	public function check(object $update) : bool {
		$client = $update->getClient();
		$isCustom = $update->is_custom;
		$update->is_custom = true;
		try {
			switch($this->name):
				case 'Tak\\Liveproto\\Filters\\Interfaces\\Outgoing':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->out) === true;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\Incoming':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->out) === false;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsMedia':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotMedia':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsReply':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->reply_to) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotReply':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->reply_to) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsViaBot':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->via_bot_id) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotViaBot':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->via_bot_id) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsEdited':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->edit_date) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotEdited':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->edit_date) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsHideEdited':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->edit_hide) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotHideEdited':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->edit_hide) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsQuickReply':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->quick_reply_shortcut_id) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotQuickReply':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->quick_reply_shortcut_id) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsMentioned':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->mentioned) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotMentioned':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->mentioned) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsSilent':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->silent) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotSilent':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->silent) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsPost':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->post) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotPost':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->post) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsSuggest':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->suggested_post) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotSuggest':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->suggested_post) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsPinned':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->pinned) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotPinned':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->pinned) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsForwarded':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->fwd_from) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotForwarded':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->fwd_from) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsBusiness':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return isset($update->connection_id) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotBusiness':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return isset($update->connection_id) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsPrivate':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id)->getChatType() === 'private');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer)->getChatType() === 'private');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypePM) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotPrivate':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id)->getChatType() !== 'private');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer)->getChatType() !== 'private');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypePM) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsGroup':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id)->getChatType() === 'group');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer)->getChatType() === 'group');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeChat) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotGroup':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id)->getChatType() !== 'group');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer)->getChatType() !== 'group');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeChat) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsSuperGroup':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id)->getChatType() === 'supergroup');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer)->getChatType() === 'supergroup');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeMegagroup) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotSuperGroup':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id)->getChatType() !== 'supergroup');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer)->getChatType() !== 'supergroup');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeMegagroup) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsChannel':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id)->getChatType() === 'channel');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer)->getChatType() === 'channel');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeBroadcast) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotChannel':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id)->getChatType() !== 'channel');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer)->getChatType() !== 'channel');
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeBroadcast) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsBot':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id) === PeerType::BOT);
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer) === PeerType::BOT);
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeBotPM) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotBot':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id) !== PeerType::BOT);
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer) !== PeerType::BOT);
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeBotPM) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsSelf':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id) === PeerType::SELF);
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer) === PeerType::SELF);
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeSameBotPM) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\IsNotSelf':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($client->get_peer_type($update->message->peer_id) !== PeerType::SELF);
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
						return boolval($client->get_peer_type($update->peer) !== PeerType::SELF);
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
						return boolval($update->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeSameBotPM) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasEntity':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->entities) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return empty($update->entities) === false;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotEntity':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->entities) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return empty($update->entities) === true;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasReaction':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->reactions) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotReaction':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->reactions) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasReplyMarkup':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->reply_markup) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotReplyMarkup':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->reply_markup) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasPhoto':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaPhoto) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaPhoto) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotPhoto':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaPhoto) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaPhoto) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasGeo':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGeo) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGeo) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotGeo':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGeo) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGeo) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasContact':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaContact) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaContact) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotContact':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaContact) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaContact) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasDocument':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaDocument) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaDocument) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotDocument':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaDocument) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaDocument) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasWebPage':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaWebPage) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaWebPage) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotWebPage':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaWebPage) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaWebPage) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasVenue':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaVenue) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaVenue) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotVenue':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaVenue) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaVenue) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasGame':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGame) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGame) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotGame':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGame) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGame) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasInvoice':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaInvoice) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaInvoice) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotInvoice':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaInvoice) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaInvoice) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasGeoLive':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGeoLive) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGeoLive) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotGeoLive':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGeoLive) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaGeoLive) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasPoll':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaPoll) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaPoll) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotPoll':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaPoll) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaPoll) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasDice':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaDice) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaDice) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotDice':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaDice) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaDice) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasStory':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaStory) === true;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaStory) === true;
					else:
						return false;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\HasNotStory':
					if($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
						return boolval($update->message->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaStory) === false;
					elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification):
						return boolval($update->media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaStory) === false;
					else:
						return true;
					endif;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\Message':
					return boolval($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message) === true;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\NotMessage':
					return boolval($update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message) === false;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\Callback':
					return boolval($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateInlineBotCallbackQuery or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBusinessBotCallbackQuery) === true;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\NotCallback':
					return boolval($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateInlineBotCallbackQuery or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBusinessBotCallbackQuery) === false;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\Inline':
					return boolval($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateInlineBotCallbackQuery or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineSend) === true;
				case 'Tak\\Liveproto\\Filters\\Interfaces\\NotInline':
					return boolval($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateInlineBotCallbackQuery or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineSend) === false;
				default:
					$update->is_custom = $isCustom;
					return true;
			endswitch;
		} catch(\Throwable $error){
			Logging::log('Interfaces',$error->getMessage(),E_ERROR);
			$update->is_custom = $isCustom;
			return false;
		}
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters;

final class FilterAnd {
	private array $types;

	public function __construct(\ReflectionIntersectionType $object){
		$this->types = $object->getTypes();
	}
	public function check(object $update) : bool {
		$conditions = array();
		foreach($this->types as $type):
			$condition = match(true){
				$type instanceof \ReflectionUnionType => new FilterOr($type),
				$type instanceof \ReflectionNamedType => new FilterName($type),
				default => throw new \Exception('Unknown Type Filter !')
			};
			$conditions []= $condition->check($update);
		endforeach;
		return in_array(false,$conditions) === false;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Events;

use Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Handlers\Events;

use Tak\Liveproto\Utils\StringTools;

final class Messages extends Filter {
	public function __construct(Filter ...$filters){
		$this->items = $filters;
	}
	public function apply(object $update) : object | bool {
		if(isset($update->message) and $update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
			$applies = array_map(fn($filter) : mixed => $filter->apply($update),$this->items);
			$event = Events::copy($update);
			$event->addBoundMethods = $this->boundMethods(...);
			return in_array(false,$applies) ? false : $event;
		else:
			return false;
		endif;
	}
	private function boundMethods(object $event) : object {
		$event->getPeer = function(mixed $peer = null) use($event) : object {
			return $event->get_input_peer(is_null($peer) ? $event->message->peer_id : $peer);
		};
		$event->getPeerId = function() use($event) : int {
			try {
				return $event->get_peer_id($event->message->peer_id);
			} catch(\Throwable){
				throw new \Exception('The update does not contain a valid peer id');
			}
		};
		$event->getReply = function() use($event) : object | false {
			if($event->message->reply_to instanceof \Tak\Liveproto\Tl\Types\Other\MessageReplyHeader):
				$messages = ($event->message->peer_id instanceof \Tak\Liveproto\Tl\Types\Other\PeerUser ? $event->getClient()->messages->getMessages(array($event->getClient()->inputMessageID($event->message->reply_to->reply_to_msg_id))) : $event->getClient()->channels->getMessages($event->getPeer(),array($event->getClient()->inputMessageID($event->message->reply_to->reply_to_msg_id))));
				# messages.messagesNotModified#74535f21 count:int = messages.Messages; #
				return isset($messages->messages) ? end($messages->messages) : $event;
			elseif($event->message->reply_to instanceof \Tak\Liveproto\Tl\Types\Other\MessageReplyStoryHeader):
				$stories = $event->getClient()->stories->getStoriesByID($event->get_input_peer($event->message->reply_to->user_id),array($event->message->reply_to->story_id));
				return end($stories->stories);
			else:
				return false;
			endif;
		};
		$event->respond = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			$args += ['businessConnectionId'=>isset($event->connection_id) ? $event->connection_id : null];
			return $event->send_content($peer,...$args);
		};
		$event->reply = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			$reply_to = array_key_exists('input_reply_to',$args) ? $args['input_reply_to'] : [];
			$args += ['reply_to'=>$event->inputReplyToMessage($event->message->id,...$reply_to),'businessConnectionId'=>isset($event->connection_id) ? $event->connection_id : null];
			return $event->send_content($peer,...$args);
		};
		$event->forward = function(mixed $peer,mixed ...$args) use($event) : object {
			$to = $event->get_input_peer($peer);
			$peer = $event->getPeer();
			$reply_to = array_key_exists('input_reply_to',$args) ? $args['input_reply_to'] : [];
			$args += empty($reply_to) ? [] : ['reply_to'=>boolval(isset($reply_to['peer']) || isset($reply_to['story_id'])) ? $event->inputReplyToStory(...$reply_to) : $event->inputReplyToMessage(...$reply_to)];
			return $event->getClient()->messages->forwardMessages($peer,array($event->message->id),array(random_int(PHP_INT_MIN,PHP_INT_MAX)),$to,...$args);
		};
		$event->edit = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			$args += ['businessConnectionId'=>isset($event->connection_id) ? $event->connection_id : null];
			return $event->edit_content($peer,$event->message->id,...$args);
		};
		$event->pin = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			$args += ['unpin'=>null,'businessConnectionId'=>isset($event->connection_id) ? $event->connection_id : null];
			return $event->getClient()->messages->updatePinnedMessage($peer,$event->message->id,...$args);
		};
		$event->unpin = function(bool $all = false,mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			if($all === true):
				return $event->getClient()->messages->unpinAllMessages($peer,...$args);
			else:
				$args += ['unpin'=>true,'businessConnectionId'=>isset($event->connection_id) ? $event->connection_id : null];
				return $event->getClient()->messages->updatePinnedMessage($peer,$event->message->id,...$args);
			endif;
		};
		$event->delete = function(? true $revoke = null) use($event) : object {
			return $event->message->peer_id instanceof \Tak\Liveproto\Tl\Types\Other\PeerUser ? $event->getClient()->messages->deleteMessages(array($event->message->id),$revoke,businessConnectionId : isset($event->connection_id) ? $event->connection_id : null) : $event->getClient()->channels->deleteMessages($event->getPeer(),array($event->message->id));
		};
		$event->reaction = function(string | int | array | null $reaction,mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			if(is_null($reaction)):
				$reaction = $event->reactionEmpty();
			elseif(is_string($reaction)):
				$reaction = array($event->reactionEmoji($reaction));
			elseif(is_int($reaction)):
				$reaction = array($event->reactionCustomEmoji($reaction));
			elseif(is_array($reaction)):
				$reaction = array_map(fn(string | int | null $emoji) : object => is_string($emoji) ? $event->reactionEmoji($emoji) : (is_int($emoji) ? $event->reactionCustomEmoji($emoji) : $event->reactionEmpty()),$reaction);
			endif;
			$args += ['reaction'=>$reaction];
			return $event->getClient()->messages->sendReaction($peer,$event->message->id,...$args);
		};
		$event->paidReaction = function(int $count = 0x1,mixed ...$args) use($event) : bool {
			$peer = $event->getPeer();
			$random_id = intval(time() << 32) | random_int(0x0,0xffffffff);
			return $event->getClient()-messages->sendPaidReaction($peer,$event->message->id,$count,$random_id,...$args);
		};
		$event->screenshot = function(array $reply_to = array()) use($event) : object {
			$reply_to = $event->inputReplyToMessage($event->message->id,...$reply_to);
			$peer = $event->getPeer();
			return $event->getClient()->messages->sendScreenshotNotification($peer,$reply_to,random_int(PHP_INT_MIN,PHP_INT_MAX));
		};
		$event->block = function(mixed ...$args) use($event) : bool {
			$peer = $event->getPeer();
			return $event->getClient()->contacts->block($peer,...$args);
		};
		$event->unblock = function(mixed ...$args) use($event) : bool {
			$peer = $event->getPeer();
			return $event->getClient()->contacts->unblock($peer,...$args);
		};
		$event->download = function(mixed $destination,mixed ...$args) use($event) : mixed {
			if(isset($event->message->media) === false):
				throw new \Exception('The message does not contain a media');
			else:
				return $event->getClient()->download_media($destination,$event->message->media,...$args);
			endif;
		};
		$event->click = function(mixed ...$args) use($event) : mixed {
			if($event->message->reply_markup === null):
				throw new \Exception('The message does not contain a reply markup');
			else:
				return $event->getClient()->click_button($event->message,...$args);
			endif;
		};
		$event->resolveSuggestion = function(mixed ...$args) use($event) : mixed {
			if($event->message->suggested_post === null):
				throw new \Exception('The message is not a suggested post');
			else:
				$peer = $event->getPeer();
				return $event->getClient()->messages->toggleSuggestedPostApproval($peer,$event->message->id,...$args);
			endif;
		};
		$event->message->format = function() use($event) : array {
			return $event->getClient()->format_entities($event->message->message,$event->message->entities);
		};
		$event->message->type = match($event->message->peer_id?->getClass()){
			'peerChannel' => ($event->message->post ? 'channel' : 'supergroup'),
			'peerUser' => 'private',
			'peerChat' => 'group',
			default => $event->get_peer_type($event->message->peer_id)->getChatType()
		};
		unset($event->addBoundMethods);
		return $event;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Events;

use Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Handlers\Events;

final class CallbackQuery extends Filter {
	public function __construct(Filter ...$filters){
		$this->items = $filters;
	}
	public function apply(object $update) : object | bool {
		if($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateInlineBotCallbackQuery or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBusinessBotCallbackQuery):
			$applies = array_map(fn($filter) : mixed => $filter->apply($update),$this->items);
			$event = Events::copy($update);
			$event->addBoundMethods = $this->boundMethods(...);
			return in_array(false,$applies) ? false : $event;
		else:
			return false;
		endif;
	}
	private function boundMethods(object $event) : object {
		$event->getPeer = function(mixed $peer = null) use($event) : object {
			return $event->get_input_peer(is_null($peer) ? ($event->class === 'updateBotCallbackQuery' ? $event->peer : ($event->class === 'updateBusinessBotCallbackQuery' ? $event->message->peer_id : $event->user_id)) : $peer);
		};
		$event->getPeerId = function() use($event) : int {
			$peer = ($event->class === 'updateBotCallbackQuery' ? $event->peer : ($event->class === 'updateBusinessBotCallbackQuery' ? $event->message->peer_id : $event));
			try {
				return $event->get_peer_id($peer);
			} catch(\Throwable){
				throw new \Exception('The update does not contain a valid peer id');
			}
		};
		$event->respond = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			$args += ['businessConnectionId'=>isset($event->connection_id) ? $event->connection_id : null];
			return $event->send_content($peer,...$args);
		};
		$event->reply = function(mixed ...$args) use($event) : object {
			if($event->class === 'updateBotCallbackQuery' or $event->class === 'updateBusinessBotCallbackQuery'):
				$peer = $event->getPeer();
				$reply_to = array_key_exists('input_reply_to',$args) ? $args['input_reply_to'] : [];
				$args += ['reply_to'=>$event->inputReplyToMessage(isset($event->message) ? $event->message->id : $event->msg_id,...$reply_to),'businessConnectionId'=>isset($event->connection_id) ? $event->connection_id : null];
				return $event->send_content($peer,...$args);
			elseif($event->class === 'updateInlineBotCallbackQuery'):
				throw new \Exception('This method is not available for this update');
			endif;
		};
		$event->forward = function(mixed $peer,mixed ...$args) use($event) : object {
			$to = $event->get_input_peer($peer);
			$peer = $event->getPeer();
			$reply_to = array_key_exists('input_reply_to',$args) ? $args['input_reply_to'] : [];
			$args += empty($reply_to) ? [] : ['reply_to'=>boolval(isset($reply_to['peer']) || isset($reply_to['story_id'])) ? $event->inputReplyToStory(...$reply_to) : $event->inputReplyToMessage(...$reply_to)];
			if($event->class === 'updateBotCallbackQuery'):
				return $event->getClient()->messages->forwardMessages($peer,array($event->msg_id),array(random_int(PHP_INT_MIN,PHP_INT_MAX)),$to,...$args);
			elseif($event->class === 'updateInlineBotCallbackQuery' or $event->class === 'updateBusinessBotCallbackQuery'):
				throw new \Exception('This method is not available for this update');
			endif;
		};
		$event->edit = function(mixed ...$args) use($event) : mixed {
			$peer = $event->getPeer();
			if($event->class === 'updateBotCallbackQuery'or $event->class === 'updateBusinessBotCallbackQuery'):
				$args += ['businessConnectionId'=>isset($event->connection_id) ? $event->connection_id : null];
				return $event->edit_content($peer,($event->class === 'updateBotCallbackQuery' ? $event->msg_id : $event->message->id),...$args);
			elseif($event->class === 'updateInlineBotCallbackQuery'):
				return $event->edit_inline($event->msg_id,...$args);
			endif;
		};
		$event->pin = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			if($event->class === 'updateBotCallbackQuery' or $event->class === 'updateBusinessBotCallbackQuery'):
				$args += ['unpin'=>null,'businessConnectionId'=>isset($event->connection_id) ? $event->connection_id : null];
				return $event->getClient()->messages->updatePinnedMessage($peer,($event->class === 'updateBotCallbackQuery' ? $event->msg_id : $event->message->id),...$args);
			elseif($event->class === 'updateInlineBotCallbackQuery'):
				throw new \Exception('This method is not available for this update');
			endif;
		};
		$event->unpin = function(bool $all = false,mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			if($event->class === 'updateBotCallbackQuery' or $event->class === 'updateBusinessBotCallbackQuery'):
				if($all === true):
					return $event->getClient()->messages->unpinAllMessages($peer,...$args);
				else:
					$args += ['unpin'=>true,'businessConnectionId'=>isset($event->connection_id) ? $event->connection_id : null];
					return $event->getClient()->messages->updatePinnedMessage($peer,($event->class === 'updateBotCallbackQuery' ? $event->msg_id : $event->message->id),...$args);
				endif;
			elseif($event->class === 'updateInlineBotCallbackQuery'):
				throw new \Exception('This method is not available for this update');
			endif;
		};
		$event->delete = function(? true $revoke = null) use($event) : object {
			if($event->class === 'updateBotCallbackQuery'):
				return $event->peer instanceof \Tak\Liveproto\Tl\Types\Other\PeerUser ? $event->getClient()->messages->deleteMessages(array($event->msg_id),$revoke,businessConnectionId : isset($event->connection_id) ? $event->connection_id : null) : $event->getClient()->channels->deleteMessages($event->getPeer(),array($event->msg_id));
			elseif($event->class === 'updateInlineBotCallbackQuery' or $event->class === 'updateBusinessBotCallbackQuery'):
				throw new \Exception('This method is not available for this update');
			endif;
		};
		$event->reaction = function(string | int | array | null $reaction,mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			if($event->class === 'updateBotCallbackQuery'):
				if(is_null($reaction)):
					$reaction = $event->reactionEmpty();
				elseif(is_string($reaction)):
					$reaction = array($event->reactionEmoji($reaction));
				elseif(is_int($reaction)):
					$reaction = array($event->reactionCustomEmoji($reaction));
				elseif(is_array($reaction)):
					$reaction = array_map(fn(string | int | null $emoji) : object => is_string($emoji) ? $event->reactionEmoji($emoji) : (is_int($emoji) ? $event->reactionCustomEmoji($emoji) : $event->reactionEmpty()),$reaction);
				endif;
				$args += ['reaction'=>$reaction];
				return $event->getClient()->messages->sendReaction($peer,$event->id,...$args);
			elseif($event->class === 'updateInlineBotCallbackQuery' or $event->class === 'updateBusinessBotCallbackQuery'):
				throw new \Exception('This method is not available for this update');
			endif;
		};
		$event->paidReaction = function(int $count = 0x1,mixed ...$args) use($event) : bool {
			$peer = $event->getPeer();
			$random_id = intval(time() << 32) | random_int(0x0,0xffffffff);
			return $event->getClient()-messages->sendPaidReaction($peer,$event->id,$count,$random_id,...$args);
		};
		$event->answerCallback = function(int $cache,mixed ...$args) use($event) : bool {
			return $event->getClient()->messages->setBotCallbackAnswer($event->query_id,$cache,...$args);
		};
		if($event->class === 'updateBotCallbackQuery' or $event->class === 'updateBusinessBotCallbackQuery'):
			$event->type = $event->get_peer_type($event->class === 'updateBotCallbackQuery' ? $event->peer : $event->message->peer_id)->getChatType();
		endif;
		unset($event->addBoundMethods);
		return $event;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Events;

use Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Handlers\Events;

final class ChosenInlineResult extends Filter {
	public function __construct(Filter ...$filters){
		$this->items = $filters;
	}
	public function apply(object $update) : object | bool {
		if($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineSend):
			$applies = array_map(fn($filter) : mixed => $filter->apply($update),$this->items);
			$event = Events::copy($update);
			$event->addBoundMethods = $this->boundMethods(...);
			return in_array(false,$applies) ? false : $event;
		else:
			return false;
		endif;
	}
	private function boundMethods(object $event) : object {
		$event->getPeer = function(mixed $peer = null) use($event) : object {
			return $event->get_input_peer(is_null($peer) ? $event->user_id : $peer);
		};
		$event->getPeerId = function() use($event) : int {
			try {
				return $event->get_peer_id($event);
			} catch(\Throwable){
				throw new \Exception('The update does not contain a valid peer id');
			}
		};
		$event->respond = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			return $event->send_content($peer,...$args);
		};
		$event->edit = function(mixed ...$args) use($event) : bool {
			if($event->msg_id === null):
				throw new \Exception('The inline result does not contain a msg id');
			else:
				return $event->edit_inline($event->msg_id,...$args);
			endif;
		};
		unset($event->addBoundMethods);
		return $event;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Events;

use Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Handlers\Events;

final class NewMessage extends Filter {
	public function __construct(Filter ...$filters){
		$this->items = $filters;
	}
	public function apply(object $update) : object | bool {
		if($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateNewMessage or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateNewChannelMessage or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotNewBusinessMessage or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateQuickReplyMessage):
			$messages = new Messages(...$this->items);
			return $messages->apply($update);
		else:
			return false;
		endif;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Events;

use Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Handlers\Events;

final class NewScheduledMessage extends Filter {
	public function __construct(Filter ...$filters){
		$this->items = $filters;
	}
	public function apply(object $update) : object | bool {
		if($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateNewScheduledMessage):
			$messages = new Messages(...$this->items);
			return $messages->apply($update);
		else:
			return false;
		endif;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Events;

use Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Handlers\Events;

final class NewJoinRequest extends Filter {
	public function __construct(Filter ...$filters){
		$this->items = $filters;
	}
	public function apply(object $update) : object | bool {
		# updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector<long> = Update; #
		# updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update; #
		if($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdatePendingJoinRequests or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotChatInviteRequester):
			$applies = array_map(fn($filter) : mixed => $filter->apply($update),$this->items);
			$event = Events::copy($update);
			$event->addBoundMethods = $this->boundMethods(...);
			return in_array(false,$applies) ? false : $event;
		else:
			return false;
		endif;
	}
	private function boundMethods(object $event) : object {
		$event->getPeer = function(mixed $peer = null) use($event) : object {
			return $event->get_input_peer(is_null($peer) ? $event->peer : $peer);
		};
		$event->getPeerId = function() use($event) : int {
			try {
				return $event->get_peer_id($event->peer);
			} catch(\Throwable){
				throw new \Exception('The update does not contain a valid peer id');
			}
		};
		$event->respond = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			return $event->send_content($peer,...$args);
		};
		$event->hideRequest = function(? true $approved = null,bool $all = false,...$args) use($event) : object {
			$peer = $event->getPeer();
			if($all === true):
				return $event->getClient()->messages->hideAllChatJoinRequests($peer,...$args);
			else:
				$user = $event->get_input_user($event->class === 'updateBotChatInviteRequester' ? $event->user_id : current($event->recent_requesters));
				return $event->getClient()->messages->hideChatJoinRequest($peer,$user,$approved);
			endif;
		};
		$event->type = $event->get_peer_type($event->peer)->getChatType();
		unset($event->addBoundMethods);
		return $event;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Events;

use Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Handlers\Events;

final class InlineQuery extends Filter {
	public function __construct(Filter ...$filters){
		$this->items = $filters;
	}
	public function apply(object $update) : object | bool {
		if($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
			$applies = array_map(fn($filter) : mixed => $filter->apply($update),$this->items);
			$event = Events::copy($update);
			$event->addBoundMethods = $this->boundMethods(...);
			return in_array(false,$applies) ? false : $event;
		else:
			return false;
		endif;
	}
	private function boundMethods(object $event) : object {
		$event->getPeer = function(mixed $peer = null) use($event) : object {
			return $event->get_input_peer(is_null($peer) ? $event->user_id : $peer);
		};
		$event->getPeerId = function() use($event) : int {
			try {
				return $event->get_peer_id($event);
			} catch(\Throwable){
				throw new \Exception('The update does not contain a valid peer id');
			}
		};
		$event->respond = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			return $event->send_content($peer,...$args);
		};
		$event->answerInline = function(array $results,int $cache,? string $switch_text = null,? string $switch_url = null,? string $start_param = null,mixed ...$args) use($event) : bool {
			if(is_null($switch_text) === false or is_null($switch_url) === false or is_null($start_param) === false):
				if(is_null($switch_url) === false):
					$args += ['switch_webview'=>$event->inlineBotWebView(text : strval($switch_text ?? $switch_url),url : strval($switch_url))];
				else:
					$args += ['switch_pm'=>$event->inlineBotSwitchPM(text : strval($switch_text ?? $start_param),start_param : substr(trim(preg_replace('/[^\w-]+/',strval(null),strval($start_param ?? $switch_text))),0,64))];
				endif;
			endif;
			return $event->getClient()->messages->setInlineBotResults($event->query_id,$results,$cache,...$args);
		};
		$event->type = match(true){
			$event->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeBroadcast => 'channel',
			$event->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeMegagroup => 'supergroup',
			$event->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypePM => 'private',
			$event->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeChat => 'group',
			$event->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeSameBotPM => 'self',
			$event->peer_type instanceof \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeBotPM => 'bot',
			default => 'unknown'
		};
		unset($event->addBoundMethods);
		return $event;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Events;

use Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Handlers\Events;

final class NewStory extends Filter {
	public function __construct(Filter ...$filters){
		$this->items = $filters;
	}
	public function apply(object $update) : object | bool {
		if($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateStory):
			$applies = array_map(fn($filter) : mixed => $filter->apply($update),$this->items);
			$event = Events::copy($update);
			$event->addBoundMethods = $this->boundMethods(...);
			return in_array(false,$applies) ? false : $event;
		else:
			return false;
		endif;
	}
	private function boundMethods(object $event) : object {
		$event->getPeer = function(mixed $peer = null) use($event) : object {
			return $event->get_input_peer(is_null($peer) ? $event->peer : $peer);
		};
		$event->getPeerId = function() use($event) : int {
			try {
				return $event->get_peer_id($event->peer);
			} catch(\Throwable){
				throw new \Exception('The update does not contain a valid peer id');
			}
		};
		$event->respond = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			return $event->send_content($peer,...$args);
		};
		$event->reply = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			$reply_to = array_key_exists('input_reply_to',$args) ? $args['input_reply_to'] : [];
			$args += ['reply_to'=>$event->inputReplyToStory($peer,$event->story->id,...$reply_to)];
			return $event->send_content($peer,...$args);
		};
		$event->forward = function(mixed $peer,mixed ...$args) use($event) : object {
			$to = $event->get_input_peer($peer);
			$peer = $event->getPeer();
			$reply_to = array_key_exists('input_reply_to',$args) ? $args['input_reply_to'] : [];
			$args += empty($reply_to) ? [] : ['reply_to'=>boolval(isset($reply_to['peer']) || isset($reply_to['story_id'])) ? $event->inputReplyToStory(...$reply_to) : $event->inputReplyToMessage(...$reply_to)];
			$media = $event->inputMediaStory(peer : $peer,id : $event->story->id);
			$drop_caption = boolval(array_key_exists('drop_media_captions',$args) and boolval($args['drop_media_captions']));
			$message = boolval($drop_caption === false and isset($event->story->caption)) ? strval($event->story->caption) : strval(null);
			$args += ['entities'=>$drop_caption ? null : $event->story->entities];
			return $event->getClient()->messages->sendMedia($to,$media,$message,random_int(PHP_INT_MIN,PHP_INT_MAX),...$args);
		};
		$event->reaction = function(string | int | array | null $reaction,mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			if(is_null($reaction)):
				$reaction = $event->reactionEmpty();
			elseif(is_string($reaction)):
				$reaction = array($event->reactionEmoji($reaction));
			elseif(is_int($reaction)):
				$reaction = array($event->reactionCustomEmoji($reaction));
			elseif(is_array($reaction)):
				$reaction = array_map(fn(string | int | null $emoji) : object => is_string($emoji) ? $event->reactionEmoji($emoji) : (is_int($emoji) ? $event->reactionCustomEmoji($emoji) : $event->reactionEmpty()),$reaction);
			endif;
			$args += ['reaction'=>$reaction];
			return $event->getClient()->stories->sendReaction($peer,$event->story->id,...$args);
		};
		$event->download = function(mixed $destination,mixed ...$args) use($event) : mixed {
			if(isset($event->story->media) === false):
				throw new \Exception('The message does not contain a media');
			else:
				return $event->getClient()->download_media($destination,$event->story->media,...$args);
			endif;
		};
		$event->getLink = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			return $event->getClient()->stories->exportStoryLink($peer,$event->story->id,...$args);
		};
		$event->getStories = function(mixed ...$args) use($event) : object {
			$peer = $event->getPeer();
			return $event->getClient()->stories->getPeerStories($peer,...$args);
		};
		$event->type = $event->get_peer_type($event->peer)->getChatType();
		unset($event->addBoundMethods);
		return $event;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Events;

use Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Handlers\Events;

final class MessageEdited extends Filter {
	public function __construct(Filter ...$filters){
		$this->items = $filters;
	}
	public function apply(object $update) : object | bool {
		if($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateEditMessage or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateEditChannelMessage or $update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotEditBusinessMessage):
			$messages = new Messages(...$this->items);
			return $messages->apply($update);
		else:
			return false;
		endif;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Events;

use Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Handlers\Events;

final class Precheckout extends Filter {
	public function __construct(Filter ...$filters){
		$this->items = $filters;
	}
	public function apply(object $update) : object | bool {
		if($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotPrecheckoutQuery):
			$applies = array_map(fn($filter) : mixed => $filter->apply($update),$this->items);
			$event = Events::copy($update);
			$event->addBoundMethods = $this->boundMethods(...);
			return in_array(false,$applies) ? false : $event;
		else:
			return false;
		endif;
	}
	private function boundMethods(object $event) : object {
		$event->getPeer = function(mixed $peer = null) use($event) : object {
			return $event->get_input_peer(is_null($peer) ? $event->user_id : $peer);
		};
		$event->getPeerId = function() use($event) : int {
			return $event->user_id;
		};
		$event->respond = function(mixed ...$args) use($event) : object {
			$args += ['businessConnectionId'=>isset($event->connection_id) ? $event->connection_id : null];
			$peer = $event->getPeer();
			return $event->send_content($peer,...$args);
		};
		$event->approve = function(...$args) use($event) : object {
			return $event->getClient()->messages->setBotPrecheckoutResults($event->query_id,...$args);
		};
		unset($event->addBoundMethods);
		return $event;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Filters\Filter;

final class Command extends Filter {
	public function __construct(object | array | string ...$commands){
		$this->items = $commands;
	}
	public function apply(object $update) : array | false {
		$regex = array_map(fn(string | int $key,object | array | string $value) : string => ('~^(?<prefix>\\'.strval(is_int($key) ? '/' : ($value instanceof \BackedEnum ? (is_string($value->value) ? $value->value : '/') : (is_array($value) ? implode('|\\',array_map(fn($type) : string => strval($type instanceof \BackedEnum ? (is_string($type->value) ? $type->value : '/') : $type),$value)) : $value))).')(?<command>'.strval(is_int($key) ? $value : $key).')(?<space>\s*)(?<parameter>.*)~'),array_keys($this->items),array_values($this->items));
		$check = new Regex(...$regex);
		return $check->apply($update);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Filters\Filter;

final class Chats extends Filter {
	public function __construct(int ...$ids){
		$this->items = array_filter($ids);
	}
	public function apply(object $update) : bool {
		if($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineSend):
			return in_array($update->user_id,$this->items);
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
			return in_array($update->user_id,$this->items);
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
			return in_array($this->getId($update->peer),$this->items) || in_array($update->user_id,$this->items);
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateInlineBotCallbackQuery):
			return in_array($update->user_id,$this->items);
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBusinessBotCallbackQuery):
			return in_array($this->getId($update->message->peer_id),$this->items) || in_array($update->user_id,$this->items);
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateDraftMessage):
			return in_array($this->getId($update->peer),$this->items);
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateStory):
			return in_array($this->getId($update->peer),$this->items);
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotPrecheckoutQuery):
			return in_array($update->user_id,$this->items);
		elseif(isset($update->message) and $update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
			return in_array($this->getId($update->message->peer_id),$this->items) || boolval(is_null($update->message->from_id) === false and in_array($this->getId($update->message->from_id),$this->items));
		endif;
		return false;
	}
	private function getId(object $peer) : int {
		return match(true){
			isset($peer->user_id) and is_int($peer->user_id) => $peer->user_id,
			isset($peer->chat_id) and is_int($peer->chat_id) => $peer->chat_id,
			isset($peer->channel_id) and is_int($peer->channel_id) => $peer->channel_id,
			default => 0
		};
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Filters\Filter;

final class Regex extends Filter {
	public function __construct(string ...$patterns){
		$this->items = $patterns;
	}
	public function apply(object $update) : array | false {
		$update->regex = new \stdClass;
		$update->regex->patterns = $this->items;
		if($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineSend):
			if($update->regex->matched = $this->match($update->query)):
				return $update->regex->matched;
			endif;
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery):
			if($update->regex->matched = $this->match($update->query)):
				return $update->regex->matched;
			endif;
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery):
			if($update->data and $update->regex->matched = $this->match($update->data)):
				return $update->regex->matched;
			endif;
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateInlineBotCallbackQuery):
			if($update->data and $update->regex->matched = $this->match($update->data)):
				return $update->regex->matched;
			endif;
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBusinessBotCallbackQuery):
			if($update->data and $update->regex->matched = $this->match($update->data)):
				return $update->regex->matched;
			endif;
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateDraftMessage):
			if($update->draft->message and $update->regex->matched = $this->match($update->draft->message)):
				return $update->regex->matched;
			endif;
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateStory):
			if($update->story->caption and $update->regex->matched = $this->match($update->story->caption)):
				return $update->regex->matched;
			endif;
		elseif($update instanceof \Tak\Liveproto\Tl\Types\Other\UpdateBotPrecheckoutQuery):
			if($update->regex->matched = $this->match($update->payload)):
				return $update->regex->matched;
			endif;
		elseif(isset($update->message) and $update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
			if($update->regex->matched = $this->match($update->message->message)):
				return $update->regex->matched;
			endif;
		endif;
		unset($update->regex->matched);
		return false;
	}
	private function match(string $subject) : array {
		$matched = array();
		foreach($this->items as $pattern):
			if(preg_match($pattern,$subject,$match)):
				$matched = array_merge($matched,$match);
			endif;
		endforeach;
		return $matched;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Filter;

use Tak\Liveproto\Filters\Filter;

final class Update extends Filter {
	public function __construct(string ...$updates){
		$this->items = $updates;
	}
	public function apply(object $update) : object | false {
		$class = $update->getClass();
		$check = array_map(fn(string $type) : bool => strcasecmp($class,$type) === 0,$this->items);
		return in_array(true,$check) ? $update : false;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters;

use Attribute;

#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION | Attribute::IS_REPEATABLE)]
abstract class Filter {
	public array $items;

	abstract public function apply(object $update) : mixed;

	static public function getFunctions(object $object,? string $unique = null) : array {
		$reflection = new \ReflectionObject($object);
		$functions = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
		$filters = [];
		foreach($functions as $function):
			$closure = $function->getClosure($object);
			$attributes = $function->getAttributes(__CLASS__); # flag : \ReflectionAttribute::IS_INSTANCEOF
			if(empty($attributes) === false):
				$hash = md5(strval(new \ReflectionFunction($closure)).strval($unique));
				$filters[$hash]['name'] = strval($reflection->getName().'::'.$function->getName());
				$filters[$hash]['callback'] = $closure;
				$filters[$hash]['attributes'] = array_map(fn(object $attribute) : array => $attribute->getArguments(),$attributes);
				$filters[$hash]['parameters'] = array();
				$parameters = $function->getParameters();
				foreach($parameters as $parameter):
					$type = $parameter->getType();
					if(is_null($type) === false):
						$conditions = match(true){
							$type instanceof \ReflectionIntersectionType => new FilterAnd($type),
							$type instanceof \ReflectionUnionType => new FilterOr($type),
							$type instanceof \ReflectionNamedType => new FilterName($type),
							default => throw new \Exception('Unknown Type Filter !')
						};
						$filters[$hash]['parameters'] []= $conditions->check(...);
					endif;
				endforeach;
			endif;
		endforeach;
		return $filters;
	}
	static public function getFunction(callable $function,? string $unique = null) : array {
		$closure = $function(...);
		$reflection = new \ReflectionFunction($closure);
		$filters = [];
		$hash = md5(strval($reflection).strval($unique));
		$filters[$hash]['name'] = strval($reflection->getName());
		$filters[$hash]['callback'] = $closure;
		$attributes = $reflection->getAttributes(__CLASS__); # flag : \ReflectionAttribute::IS_INSTANCEOF
		$filters[$hash]['attributes'] = array_map(fn(object $attribute) : array => $attribute->getArguments(),$attributes);
		$parameters = $reflection->getParameters();
		$filters[$hash]['parameters'] = array();
		foreach($parameters as $parameter):
			$type = $parameter->getType();
			if(is_null($type) === false):
				$conditions = match(true){
					$type instanceof \ReflectionIntersectionType => new FilterAnd($type),
					$type instanceof \ReflectionUnionType => new FilterOr($type),
					$type instanceof \ReflectionNamedType => new FilterName($type),
					default => throw new \Exception('Unknown Type Filter !')
				};
				$filters[$hash]['parameters'] []= $conditions->check(...);
			endif;
		endforeach;
	return $filters;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters;

final class FilterName {
	private string $condition;

	public function __construct(\ReflectionNamedType $object){
		$this->condition = $object->getName();
	}
	public function check(object $update) : bool {
		$interfaces = new Interfaces($this->condition);
		return $interfaces->check($update);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsSuggest {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotWebPage {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasDocument {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsPrivate {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface Inline {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasWebPage {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasReplyMarkup {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotHideEdited {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotDice {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasReaction {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotReaction {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsBot {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotGame {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotInvoice {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsMentioned {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasGeo {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface NotCallback {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsGroup {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotPoll {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface NotMessage {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface Incoming {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsReply {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsSilent {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasDice {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasEntity {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotViaBot {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotSilent {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotPinned {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotReply {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotMedia {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsEdited {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsHideEdited {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotStory {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsChannel {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface Message {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsMedia {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsSuperGroup {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsPinned {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasInvoice {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasPhoto {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsQuickReply {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotReplyMarkup {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotGeo {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsBusiness {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotSuggest {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotSuperGroup {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotVenue {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsPost {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotPost {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotBot {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasVenue {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotMentioned {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsForwarded {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasContact {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotContact {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasGeoLive {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotBusiness {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsViaBot {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasStory {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface Callback {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotDocument {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasGame {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface Outgoing {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotPhoto {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotEdited {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotQuickReply {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotForwarded {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotChannel {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotEntity {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotSelf {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface NotInline {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsSelf {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasPoll {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface HasNotGeoLive {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotPrivate {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Filters\Interfaces;

interface IsNotGroup {}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl;

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Tl\Methods\Account;

use Tak\Liveproto\Tl\Methods\Auth;

use Tak\Liveproto\Tl\Methods\Buttons;

use Tak\Liveproto\Tl\Methods\Dialog;

use Tak\Liveproto\Tl\Methods\Download;

use Tak\Liveproto\Tl\Methods\Entities;

use Tak\Liveproto\Tl\Methods\FileId;

use Tak\Liveproto\Tl\Methods\Inline;

use Tak\Liveproto\Tl\Methods\Media;

use Tak\Liveproto\Tl\Methods\Messages;

use Tak\Liveproto\Tl\Methods\Peers;

use Tak\Liveproto\Tl\Methods\Users;

use Tak\Liveproto\Tl\Methods\Channels;

use Tak\Liveproto\Tl\Methods\SecretChat;

use Tak\Liveproto\Tl\Methods\Upload;

use Tak\Liveproto\Tl\Methods\Utilities;

use Tak\Liveproto\Errors\RpcError;

use Tak\Attributes\AttributesEngine;

use function Tak\Asyncio\async;

use function Tak\Asyncio\delay;

use function Tak\Asyncio\await;

abstract class Caller {
	use AttributesEngine {
		__set as attrSet;
		__get as attrGet;
		__call as attrCall;
	}

	protected ? object $dhConfig = null;
	protected array $peersType = array();
	protected array $peersId = array();
	protected array $secretChats = array();
	protected array $connections = array();

	use Account;
	use Auth;
	use Buttons;
	use Dialog;
	use Download;
	use Entities;
	use FileId;
	use Inline;
	use Media;
	use Messages;
	use Peers;
	use Users;
	use Channels;
	use SecretChat;
	use Upload;
	use Utilities;

	public function __set(string $property,mixed $value) : void {
		if(property_exists($this,$property)):
			$this->attrSet($property,$value);
		else:
			throw new \Error('Property '.$property.' does not exist');
		endif;
	}
	public function __get(string $property) : mixed {
		if(property_exists($this,$property)):
			return $this->attrGet($property);
		else:
			return new Properties($this,$property);
		endif;
	}
	public function __call(string $name,array $arguments) : mixed {
		if(method_exists($this,$name)):
			return $this->attrCall($name,$arguments);
		else:
			$other = new Properties($this);
			return $other->$name(...$arguments);
		endif;
	}
	public function __invoke(string $request,array $arguments) : mixed {
		$split = explode(str_contains($request,chr(46)) ? chr(46) : chr(47),$request);
		if(count($split) === 2):
			$name = $split[true];
			$space = new Properties($this,$split[false]);
		elseif(count($split) === 1):
			$name = $split[false];
			$space = new Properties($this);
		else:
			throw new \Exception('Namespace ('.$request.') not found !');
		endif;
		return $space->$name(...$arguments);
	}
}

final class Properties {
	public function __construct(private readonly object $parent,private readonly string $property = 'other'){
	}
	public function __get(string $property) : mixed {
		if(property_exists($this->parent,$property)):
			$reflection = new \ReflectionClass($this->parent);
			$property = $reflection->getProperty($property);
			return $property->getValue($this->parent);
		else:
			# return new self($this->parent,$property);
			throw new \Exception('Undefined property: Client'.chr(58).chr(58).chr(36).$property);
		endif;
	}
	public function __call(string $name,array $arguments) : mixed {
		if(preg_match('~^(.+?)(?:_)?multiple$~i',$name,$match)):
			$name = $match[true];
			if(isset($arguments['responses'])):
				$responses = boolval($arguments['responses']);
				unset($arguments['responses']);
			else:
				$responses = false;
			endif;
			if(isset($arguments['queued'])):
				$queued = boolval($arguments['queued']);
				unset($arguments['queued']);
			else:
				$queued = false;
			endif;
			if(isset($arguments['cooldown'])):
				$cooldown = floatval($arguments['cooldown']);
				unset($arguments['cooldown']);
			else:
				$cooldown = -1;
			endif;
			$processes = array();
			$lastMessageId = null;
			foreach($arguments as $i => $argument):
				if($queued === true):
					if(is_null($lastMessageId) === false):
						$argument += ['afterId'=>$lastMessageId];
					endif;
					$lastMessageId = $this->session->getNewMsgId();
					$argument += ['messageid'=>$lastMessageId];
				endif;
				if($responses === false):
					$argument += ['response'=>$responses];
				endif;
				$processes []= async(fn(string $method) : mixed => call_user_func($method,$name,$argument),__METHOD__);
				if($cooldown > 0):
					delay($cooldown);
				endif;
			endforeach;
			$results = await($processes);
			ksort($results);
			return $results;
		endif;
		if($class = $this->createObject('Tak\\Liveproto\\Tl\\Functions\\'.ucfirst($this->property).'\\'.ucfirst($name))):
			$parameters = [
				'raw'=>[
					'func'=>is_bool(...),
					'default'=>false
				],
				'response'=>[
					'func'=>is_bool(...),
					'default'=>true
				],
				'timeout'=>[
					'func'=>is_int(...),
					'default'=>0
				],
				'floodwaitlimit'=>[
					'func'=>is_int(...),
					'default'=>0
				],
				'messageid'=>[
					'func'=>is_int(...),
					'default'=>null
				],
				'identifier'=>[
					'func'=>null,
					'default'=>null
				],
				'extra'=>[
					'func'=>null,
					'default'=>null
				]
			];
			$filtered = array();
			foreach($parameters as $key => $value):
				if(array_key_exists($key,$arguments)):
					$filtered[$key] = boolval(is_null($value['func']) or call_user_func($value['func'],$arguments[$key])) ? $arguments[$key] : $value['default'];
					unset($arguments[$key]);
				else:
					$filtered[$key] = $value['default'];
				endif;
			endforeach;
			extract($filtered);
			if(array_key_exists('takeout',$arguments)):
				if($arguments['takeout'] === true):
					unset($arguments['takeout']);
					$arguments['raw'] = true;
					$request = call_user_func(__METHOD__,$name,$arguments);
					return $this->parent->invokeWithTakeout($this->takeoutid,$request,...$filtered);
				else:
					unset($arguments['takeout']);
				endif;
			endif;
			if(array_key_exists('receiveUpdates',$arguments)):
				if($arguments['receiveUpdates'] === false):
					unset($arguments['receiveUpdates']);
					$arguments['raw'] = true;
					$request = call_user_func(__METHOD__,$name,$arguments);
					return $this->parent->invokeWithoutUpdates($request,...$filtered);
				else:
					unset($arguments['receiveUpdates']);
				endif;
			endif;
			/*
			if(boolval(array_key_exists('receiveUpdates',$arguments) and $arguments['receiveUpdates'] === false) || boolval(array_key_exists('receiveUpdates',$arguments) === false and $this->settings->receiveUpdates === false)):
				$arguments['receiveUpdates'] = true;
				$arguments['raw'] = true;
				$request = call_user_func(__METHOD__,$name,$arguments);
				return $this->parent->invokeWithoutUpdates($request,...$filtered);
			endif;
			if(array_key_exists('receiveUpdates',$arguments)):
				unset($arguments['receiveUpdates']);
			endif;
			*/
			if(array_key_exists('afterId',$arguments)):
				if(is_numeric($arguments['afterId'])):
					$afterId = intval($arguments['afterId']);
					unset($arguments['afterId']);
					$arguments['raw'] = true;
					$request = call_user_func(__METHOD__,$name,$arguments);
					return $this->parent->invokeAfterMsg($afterId,$request,...$filtered);
				else:
					unset($arguments['afterId']);
				endif;
			endif;
			if(array_key_exists('businessConnectionId',$arguments)):
				if(empty($arguments['businessConnectionId']) === false):
					$businessConnectionId = strval($arguments['businessConnectionId']);
					unset($arguments['businessConnectionId']);
					$arguments['raw'] = true;
					$request = call_user_func(__METHOD__,$name,$arguments);
					return $this->parent->invokeWithBusinessConnection($businessConnectionId,$request,...$filtered);
				else:
					unset($arguments['businessConnectionId']);
				endif;
			endif;
			$request = new $class($arguments);
			if($raw):
				return $request;
			elseif($this->connected):
				$mtRequest = new MTRequest($request,messageId : $messageid,identifier : $identifier,timeout : $timeout);
				$this->sender->send($mtRequest);
				try {
					$result = $response ? $this->sender->receive($mtRequest) : new \stdClass;
				} catch(RpcError $error){
					$floodmax = max($this->settings->floodSleepThreshold,$floodwaitlimit);
					if($error->getCode() == 420 and $floodmax >= $error->getValue()):
						Logging::log('Caller','Waiting for '.$error->getValue().' seconds to resend the request due to a flood error',E_NOTICE);
						delay(max(0,$error->getValue() - 1));
						$result = call_user_func(__METHOD__,$name,$arguments + $filtered);
					elseif($error->getCode() == 500):
						Logging::log('Caller','Encountered an INTERNAL error , Resending the request',E_NOTICE);
						$result = call_user_func(__METHOD__,$name,$arguments + $filtered);
					else:
						throw $error;
					endif;
				}
				if(is_null($extra) === false):
					$result->extra = $extra;
				endif;
				return $result;
			else:
				throw new \RuntimeException('You are not yet connected to send a request !');
			endif;
		elseif($class = $this->createObject('Tak\\Liveproto\\Tl\\Types\\'.ucfirst($this->property).'\\'.ucfirst($name))):
			return new $class($arguments);
		elseif(method_exists($this->parent,$name)):
			$reflection = new \ReflectionClass($this->parent);
			$method = $reflection->getMethod($name);
			return $method->invoke($this->parent,...$arguments);
		else:
			throw new \Exception('Call to undefined function '.$name.'()');
		endif;
	}
	private function createObject(string $class) : object | false {
		return class_exists($class) ? new $class : false;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<publicforward> forwards Vector<chat> chats Vector<user> users string next_offset
 * @return stats.PublicForwards
 */

final class PublicForwards extends Instance {
	public function request(int $count,array $forwards,array $chats,array $users,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x93037e20);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeVector($forwards,'publicforward');
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['count'] = $reader->readInt();
		$result['forwards'] = $reader->readVector('publicforward');
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param statsgraph views_graph statsgraph reactions_by_emotion_graph
 * @return stats.MessageStats
 */

final class MessageStats extends Instance {
	public function request(object $views_graph,object $reactions_by_emotion_graph) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7fe91c14);
		$writer->writeObject($views_graph);
		$writer->writeObject($reactions_by_emotion_graph);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['views_graph'] = $reader->readObject();
		$result['reactions_by_emotion_graph'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param statsdaterangedays period statsabsvalueandprev followers statsabsvalueandprev views_per_post statsabsvalueandprev shares_per_post statsabsvalueandprev reactions_per_post statsabsvalueandprev views_per_story statsabsvalueandprev shares_per_story statsabsvalueandprev reactions_per_story statspercentvalue enabled_notifications statsgraph growth_graph statsgraph followers_graph statsgraph mute_graph statsgraph top_hours_graph statsgraph interactions_graph statsgraph iv_interactions_graph statsgraph views_by_source_graph statsgraph new_followers_by_source_graph statsgraph languages_graph statsgraph reactions_by_emotion_graph statsgraph story_interactions_graph statsgraph story_reactions_by_emotion_graph Vector<postinteractioncounters> recent_posts_interactions
 * @return stats.BroadcastStats
 */

final class BroadcastStats extends Instance {
	public function request(object $period,object $followers,object $views_per_post,object $shares_per_post,object $reactions_per_post,object $views_per_story,object $shares_per_story,object $reactions_per_story,object $enabled_notifications,object $growth_graph,object $followers_graph,object $mute_graph,object $top_hours_graph,object $interactions_graph,object $iv_interactions_graph,object $views_by_source_graph,object $new_followers_by_source_graph,object $languages_graph,object $reactions_by_emotion_graph,object $story_interactions_graph,object $story_reactions_by_emotion_graph,array $recent_posts_interactions) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x396ca5fc);
		$writer->writeObject($period);
		$writer->writeObject($followers);
		$writer->writeObject($views_per_post);
		$writer->writeObject($shares_per_post);
		$writer->writeObject($reactions_per_post);
		$writer->writeObject($views_per_story);
		$writer->writeObject($shares_per_story);
		$writer->writeObject($reactions_per_story);
		$writer->writeObject($enabled_notifications);
		$writer->writeObject($growth_graph);
		$writer->writeObject($followers_graph);
		$writer->writeObject($mute_graph);
		$writer->writeObject($top_hours_graph);
		$writer->writeObject($interactions_graph);
		$writer->writeObject($iv_interactions_graph);
		$writer->writeObject($views_by_source_graph);
		$writer->writeObject($new_followers_by_source_graph);
		$writer->writeObject($languages_graph);
		$writer->writeObject($reactions_by_emotion_graph);
		$writer->writeObject($story_interactions_graph);
		$writer->writeObject($story_reactions_by_emotion_graph);
		$writer->writeVector($recent_posts_interactions,'postinteractioncounters');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['period'] = $reader->readObject();
		$result['followers'] = $reader->readObject();
		$result['views_per_post'] = $reader->readObject();
		$result['shares_per_post'] = $reader->readObject();
		$result['reactions_per_post'] = $reader->readObject();
		$result['views_per_story'] = $reader->readObject();
		$result['shares_per_story'] = $reader->readObject();
		$result['reactions_per_story'] = $reader->readObject();
		$result['enabled_notifications'] = $reader->readObject();
		$result['growth_graph'] = $reader->readObject();
		$result['followers_graph'] = $reader->readObject();
		$result['mute_graph'] = $reader->readObject();
		$result['top_hours_graph'] = $reader->readObject();
		$result['interactions_graph'] = $reader->readObject();
		$result['iv_interactions_graph'] = $reader->readObject();
		$result['views_by_source_graph'] = $reader->readObject();
		$result['new_followers_by_source_graph'] = $reader->readObject();
		$result['languages_graph'] = $reader->readObject();
		$result['reactions_by_emotion_graph'] = $reader->readObject();
		$result['story_interactions_graph'] = $reader->readObject();
		$result['story_reactions_by_emotion_graph'] = $reader->readObject();
		$result['recent_posts_interactions'] = $reader->readVector('postinteractioncounters');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param statsdaterangedays period statsabsvalueandprev members statsabsvalueandprev messages statsabsvalueandprev viewers statsabsvalueandprev posters statsgraph growth_graph statsgraph members_graph statsgraph new_members_by_source_graph statsgraph languages_graph statsgraph messages_graph statsgraph actions_graph statsgraph top_hours_graph statsgraph weekdays_graph Vector<statsgrouptopposter> top_posters Vector<statsgrouptopadmin> top_admins Vector<statsgrouptopinviter> top_inviters Vector<user> users
 * @return stats.MegagroupStats
 */

final class MegagroupStats extends Instance {
	public function request(object $period,object $members,object $messages,object $viewers,object $posters,object $growth_graph,object $members_graph,object $new_members_by_source_graph,object $languages_graph,object $messages_graph,object $actions_graph,object $top_hours_graph,object $weekdays_graph,array $top_posters,array $top_admins,array $top_inviters,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xef7ff916);
		$writer->writeObject($period);
		$writer->writeObject($members);
		$writer->writeObject($messages);
		$writer->writeObject($viewers);
		$writer->writeObject($posters);
		$writer->writeObject($growth_graph);
		$writer->writeObject($members_graph);
		$writer->writeObject($new_members_by_source_graph);
		$writer->writeObject($languages_graph);
		$writer->writeObject($messages_graph);
		$writer->writeObject($actions_graph);
		$writer->writeObject($top_hours_graph);
		$writer->writeObject($weekdays_graph);
		$writer->writeVector($top_posters,'statsgrouptopposter');
		$writer->writeVector($top_admins,'statsgrouptopadmin');
		$writer->writeVector($top_inviters,'statsgrouptopinviter');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['period'] = $reader->readObject();
		$result['members'] = $reader->readObject();
		$result['messages'] = $reader->readObject();
		$result['viewers'] = $reader->readObject();
		$result['posters'] = $reader->readObject();
		$result['growth_graph'] = $reader->readObject();
		$result['members_graph'] = $reader->readObject();
		$result['new_members_by_source_graph'] = $reader->readObject();
		$result['languages_graph'] = $reader->readObject();
		$result['messages_graph'] = $reader->readObject();
		$result['actions_graph'] = $reader->readObject();
		$result['top_hours_graph'] = $reader->readObject();
		$result['weekdays_graph'] = $reader->readObject();
		$result['top_posters'] = $reader->readVector('statsgrouptopposter');
		$result['top_admins'] = $reader->readVector('statsgrouptopadmin');
		$result['top_inviters'] = $reader->readVector('statsgrouptopinviter');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param statsgraph views_graph statsgraph reactions_by_emotion_graph
 * @return stats.StoryStats
 */

final class StoryStats extends Instance {
	public function request(object $views_graph,object $reactions_by_emotion_graph) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x50cd067c);
		$writer->writeObject($views_graph);
		$writer->writeObject($reactions_by_emotion_graph);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['views_graph'] = $reader->readObject();
		$result['reactions_by_emotion_graph'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param statsgraph votes_graph
 * @return stats.PollStats
 */

final class PollStats extends Instance {
	public function request(object $votes_graph) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2999beed);
		$writer->writeObject($votes_graph);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['votes_graph'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title Vector<sponsoredmessagereportoption> options
 * @return channels.SponsoredMessageReportResult
 */

final class SponsoredMessageReportResultChooseOption extends Instance {
	public function request(string $title,array $options) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x846f9e42);
		$writer->writeBytes($title);
		$writer->writeVector($options,'sponsoredmessagereportoption');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readBytes();
		$result['options'] = $reader->readVector('sponsoredmessagereportoption');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<sendaspeer> peers Vector<chat> chats Vector<user> users
 * @return channels.SendAsPeers
 */

final class SendAsPeers extends Instance {
	public function request(array $peers,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf496b0c6);
		$writer->writeVector($peers,'sendaspeer');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peers'] = $reader->readVector('sendaspeer');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return channels.ChannelParticipants
 */

final class ChannelParticipantsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf0173fe9);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return channels.SponsoredMessageReportResult
 */

final class SponsoredMessageReportResultAdsHidden extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e3bcf2f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<channelparticipant> participants Vector<chat> chats Vector<user> users
 * @return channels.ChannelParticipants
 */

final class ChannelParticipants extends Instance {
	public function request(int $count,array $participants,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9ab0feaf);
		$writer->writeInt($count);
		$writer->writeVector($participants,'channelparticipant');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['participants'] = $reader->readVector('channelparticipant');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param channelparticipant participant Vector<chat> chats Vector<user> users
 * @return channels.ChannelParticipant
 */

final class ChannelParticipant extends Instance {
	public function request(object $participant,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdfb80317);
		$writer->writeObject($participant);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['participant'] = $reader->readObject();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<channeladminlogevent> events Vector<chat> chats Vector<user> users
 * @return channels.AdminLogResults
 */

final class AdminLogResults extends Instance {
	public function request(array $events,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xed8af74d);
		$writer->writeVector($events,'channeladminlogevent');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['events'] = $reader->readVector('channeladminlogevent');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return channels.SponsoredMessageReportResult
 */

final class SponsoredMessageReportResultReported extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xad798849);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<quickreply> quick_replies Vector<message> messages Vector<chat> chats Vector<user> users
 * @return messages.QuickReplies
 */

final class QuickReplies extends Instance {
	public function request(array $quick_replies,array $messages,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc68d6695);
		$writer->writeVector($quick_replies,'quickreply');
		$writer->writeVector($messages,'message');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['quick_replies'] = $reader->readVector('quickreply');
		$result['messages'] = $reader->readVector('message');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count
 * @return messages.SavedDialogs
 */

final class SavedDialogsNotModified extends Instance {
	public function request(int $count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc01f6fe8);
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<stickerpack> packs Vector<document> stickers Vector<int> dates
 * @return messages.RecentStickers
 */

final class RecentStickers extends Instance {
	public function request(int $hash,array $packs,array $stickers,array $dates) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x88d37c56);
		$writer->writeLong($hash);
		$writer->writeVector($packs,'stickerpack');
		$writer->writeVector($stickers,'document');
		$writer->writeVector($dates,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['packs'] = $reader->readVector('stickerpack');
		$result['stickers'] = $reader->readVector('document');
		$result['dates'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<stickersetcovered> sets
 * @return messages.StickerSetInstallResult
 */

final class StickerSetInstallResultArchive extends Instance {
	public function request(array $sets) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x35e410a8);
		$writer->writeVector($sets,'stickersetcovered');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['sets'] = $reader->readVector('stickersetcovered');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<message> messages Vector<forumtopic> topics Vector<chat> chats Vector<user> users
 * @return messages.Messages
 */

final class Messages extends Instance {
	public function request(array $messages,array $topics,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1d73e7ea);
		$writer->writeVector($messages,'message');
		$writer->writeVector($topics,'forumtopic');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['messages'] = $reader->readVector('message');
		$result['topics'] = $reader->readVector('forumtopic');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.RecentStickers
 */

final class RecentStickersNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb17f890);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<exportedchatinvite> invites Vector<user> users
 * @return messages.ExportedChatInvites
 */

final class ExportedChatInvites extends Instance {
	public function request(int $count,array $invites,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbdc62dcc);
		$writer->writeInt($count);
		$writer->writeVector($invites,'exportedchatinvite');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['invites'] = $reader->readVector('exportedchatinvite');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<saveddialog> dialogs Vector<message> messages Vector<chat> chats Vector<user> users
 * @return messages.SavedDialogs
 */

final class SavedDialogsSlice extends Instance {
	public function request(int $count,array $dialogs,array $messages,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x44ba9dd9);
		$writer->writeInt($count);
		$writer->writeVector($dialogs,'saveddialog');
		$writer->writeVector($messages,'message');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['dialogs'] = $reader->readVector('saveddialog');
		$result['messages'] = $reader->readVector('message');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true pm true group string title
 * @return messages.HistoryImportParsed
 */

final class HistoryImportParsed extends Instance {
	public function request(null | bool $pm = null,null | bool $group = null,null | string $title = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5e0fb7b9);
		$flags = 0;
		$flags |= $pm ? (1 << 0) : 0;
		$flags |= $group ? (1 << 1) : 0;
		$flags |= is_null($title) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pm'] = boolval($flags & (1 << 0));
		$result['group'] = boolval($flags & (1 << 1));
		if($flags & (1 << 2)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param messagesfilter filter int count true inexact
 * @return messages.SearchCounter
 */

final class SearchCounter extends Instance {
	public function request(object $filter,int $count,null | bool $inexact = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe844ebff);
		$flags = 0;
		$flags |= $inexact ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($filter);
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['inexact'] = boolval($flags & (1 << 1));
		$result['filter'] = $reader->readObject();
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int cache_time true alert true has_url true native_ui string message string url
 * @return messages.BotCallbackAnswer
 */

final class BotCallbackAnswer extends Instance {
	public function request(int $cache_time,null | bool $alert = null,null | bool $has_url = null,null | bool $native_ui = null,null | string $message = null,null | string $url = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x36585ea4);
		$flags = 0;
		$flags |= $alert ? (1 << 1) : 0;
		$flags |= $has_url ? (1 << 3) : 0;
		$flags |= $native_ui ? (1 << 4) : 0;
		$flags |= is_null($message) ? 0 : (1 << 0);
		$flags |= is_null($url) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($message) === false):
			$writer->writeBytes($message);
		endif;
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		$writer->writeInt($cache_time);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['alert'] = boolval($flags & (1 << 1));
		$result['has_url'] = boolval($flags & (1 << 3));
		$result['native_ui'] = boolval($flags & (1 << 4));
		if($flags & (1 << 0)):
			$result['message'] = $reader->readBytes();
		else:
			$result['message'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['url'] = $reader->readBytes();
		else:
			$result['url'] = null;
		endif;
		$result['cache_time'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id botinlineresult result Vector<inlinequerypeertype> peer_types int cache_time Vector<user> users
 * @return messages.PreparedInlineMessage
 */

final class PreparedInlineMessage extends Instance {
	public function request(int $query_id,object $result,array $peer_types,int $cache_time,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xff57708d);
		$writer->writeLong($query_id);
		$writer->writeObject($result);
		$writer->writeVector($peer_types,'inlinequerypeertype');
		$writer->writeInt($cache_time);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['query_id'] = $reader->readLong();
		$result['result'] = $reader->readObject();
		$result['peer_types'] = $reader->readVector('inlinequerypeertype');
		$result['cache_time'] = $reader->readInt();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param updates updates Vector<missinginvitee> missing_invitees
 * @return messages.InvitedUsers
 */

final class InvitedUsers extends Instance {
	public function request(object $updates,array $missing_invitees) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7f5defa6);
		$writer->writeObject($updates);
		$writer->writeVector($missing_invitees,'missinginvitee');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['updates'] = $reader->readObject();
		$result['missing_invitees'] = $reader->readVector('missinginvitee');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<messagepeerreaction> reactions Vector<chat> chats Vector<user> users string next_offset
 * @return messages.MessageReactionsList
 */

final class MessageReactionsList extends Instance {
	public function request(int $count,array $reactions,array $chats,array $users,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31bd492d);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeVector($reactions,'messagepeerreaction');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['count'] = $reader->readInt();
		$result['reactions'] = $reader->readVector('messagepeerreaction');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count
 * @return messages.Dialogs
 */

final class DialogsNotModified extends Instance {
	public function request(int $count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf0e3e596);
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<messageviews> views Vector<chat> chats Vector<user> users
 * @return messages.MessageViews
 */

final class MessageViews extends Instance {
	public function request(array $views,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb6c4f543);
		$writer->writeVector($views,'messageviews');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['views'] = $reader->readVector('messageviews');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param chatfull full_chat Vector<chat> chats Vector<user> users
 * @return messages.ChatFull
 */

final class ChatFull extends Instance {
	public function request(object $full_chat,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe5d7d19c);
		$writer->writeObject($full_chat);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['full_chat'] = $reader->readObject();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.SavedReactionTags
 */

final class SavedReactionTagsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x889b59ef);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<searchresultsposition> positions
 * @return messages.SearchResultsPositions
 */

final class SearchResultsPositions extends Instance {
	public function request(int $count,array $positions) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x53b22baf);
		$writer->writeInt($count);
		$writer->writeVector($positions,'searchresultsposition');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['positions'] = $reader->readVector('searchresultsposition');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date
 * @return messages.SentEncryptedMessage
 */

final class SentEncryptedMessage extends Instance {
	public function request(int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x560f8935);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count
 * @return messages.Messages
 */

final class MessagesNotModified extends Instance {
	public function request(int $count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x74535f21);
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<stickerpack> packs Vector<document> stickers
 * @return messages.FavedStickers
 */

final class FavedStickers extends Instance {
	public function request(int $hash,array $packs,array $stickers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2cb51097);
		$writer->writeLong($hash);
		$writer->writeVector($packs,'stickerpack');
		$writer->writeVector($stickers,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['packs'] = $reader->readVector('stickerpack');
		$result['stickers'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.QuickReplies
 */

final class QuickRepliesNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5f91eb5b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.SavedGifs
 */

final class SavedGifsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe8025ca2);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int g bytes p int version bytes random
 * @return messages.DhConfig
 */

final class DhConfig extends Instance {
	public function request(int $g,string $p,int $version,string $random) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2c221edd);
		$writer->writeInt($g);
		$writer->writeBytes($p);
		$writer->writeInt($version);
		$writer->writeBytes($random);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['g'] = $reader->readInt();
		$result['p'] = $reader->readBytes();
		$result['version'] = $reader->readInt();
		$result['random'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<highscore> scores Vector<user> users
 * @return messages.HighScores
 */

final class HighScores extends Instance {
	public function request(array $scores,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9a3bfd99);
		$writer->writeVector($scores,'highscore');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['scores'] = $reader->readVector('highscore');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.FavedStickers
 */

final class FavedStickersNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9e8fa6d3);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<chatinviteimporter> importers Vector<user> users
 * @return messages.ChatInviteImporters
 */

final class ChatInviteImporters extends Instance {
	public function request(int $count,array $importers,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x81b6b00a);
		$writer->writeInt($count);
		$writer->writeVector($importers,'chatinviteimporter');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['importers'] = $reader->readVector('chatinviteimporter');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<textwithentities> result
 * @return messages.TranslatedText
 */

final class TranslateResult extends Instance {
	public function request(array $result) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x33db32f8);
		$writer->writeVector($result,'textwithentities');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readVector('textwithentities');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<stickersetcovered> sets
 * @return messages.ArchivedStickers
 */

final class ArchivedStickers extends Instance {
	public function request(int $count,array $sets) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4fcba9c8);
		$writer->writeInt($count);
		$writer->writeVector($sets,'stickersetcovered');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['sets'] = $reader->readVector('stickersetcovered');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param webpage webpage Vector<chat> chats Vector<user> users
 * @return messages.WebPage
 */

final class WebPage extends Instance {
	public function request(object $webpage,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfd5e12bd);
		$writer->writeObject($webpage);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['webpage'] = $reader->readObject();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id
 * @return messages.HistoryImport
 */

final class HistoryImport extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1662af0b);
		$writer->writeLong($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<messagepeervote> votes Vector<chat> chats Vector<user> users string next_offset
 * @return messages.VotesList
 */

final class VotesList extends Instance {
	public function request(int $count,array $votes,array $chats,array $users,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4899484e);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeVector($votes,'messagepeervote');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['count'] = $reader->readInt();
		$result['votes'] = $reader->readVector('messagepeervote');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true caption
 * @return messages.MessageEditData
 */

final class MessageEditData extends Instance {
	public function request(null | bool $caption = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x26b5dde6);
		$flags = 0;
		$flags |= $caption ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['caption'] = boolval($flags & (1 << 0));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<chat> chats
 * @return messages.Chats
 */

final class Chats extends Instance {
	public function request(array $chats) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x64ff9fd5);
		$writer->writeVector($chats,'chat');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chats'] = $reader->readVector('chat');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<sponsoredmessage> messages Vector<chat> chats Vector<user> users int posts_between int start_delay int between_delay
 * @return messages.SponsoredMessages
 */

final class SponsoredMessages extends Instance {
	public function request(array $messages,array $chats,array $users,null | int $posts_between = null,null | int $start_delay = null,null | int $between_delay = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xffda656d);
		$flags = 0;
		$flags |= is_null($posts_between) ? 0 : (1 << 0);
		$flags |= is_null($start_delay) ? 0 : (1 << 1);
		$flags |= is_null($between_delay) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($posts_between) === false):
			$writer->writeInt($posts_between);
		endif;
		if(is_null($start_delay) === false):
			$writer->writeInt($start_delay);
		endif;
		if(is_null($between_delay) === false):
			$writer->writeInt($between_delay);
		endif;
		$writer->writeVector($messages,'sponsoredmessage');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['posts_between'] = $reader->readInt();
		else:
			$result['posts_between'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['start_delay'] = $reader->readInt();
		else:
			$result['start_delay'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['between_delay'] = $reader->readInt();
		else:
			$result['between_delay'] = null;
		endif;
		$result['messages'] = $reader->readVector('sponsoredmessage');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<chat> chats
 * @return messages.Chats
 */

final class ChatsSlice extends Instance {
	public function request(int $count,array $chats) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9cd81144);
		$writer->writeInt($count);
		$writer->writeVector($chats,'chat');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['chats'] = $reader->readVector('chat');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<dialog> dialogs Vector<message> messages Vector<chat> chats Vector<user> users
 * @return messages.Dialogs
 */

final class Dialogs extends Instance {
	public function request(array $dialogs,array $messages,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x15ba6c40);
		$writer->writeVector($dialogs,'dialog');
		$writer->writeVector($messages,'message');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['dialogs'] = $reader->readVector('dialog');
		$result['messages'] = $reader->readVector('message');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id int expire_date
 * @return messages.BotPreparedInlineMessage
 */

final class BotPreparedInlineMessage extends Instance {
	public function request(string $id,int $expire_date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ecf0511);
		$writer->writeBytes($id);
		$writer->writeInt($expire_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readBytes();
		$result['expire_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.StickerSetInstallResult
 */

final class StickerSetInstallResultSuccess extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x38641628);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<dialogfilter> filters true tags_enabled
 * @return messages.DialogFilters
 */

final class DialogFilters extends Instance {
	public function request(array $filters,null | bool $tags_enabled = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2ad93719);
		$flags = 0;
		$flags |= $tags_enabled ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($filters,'dialogfilter');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['tags_enabled'] = boolval($flags & (1 << 0));
		$result['filters'] = $reader->readVector('dialogfilter');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param messagemedia media Vector<chat> chats Vector<user> users
 * @return messages.WebPagePreview
 */

final class WebPagePreview extends Instance {
	public function request(object $media,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c9a88ac);
		$writer->writeObject($media);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['media'] = $reader->readObject();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.Reactions
 */

final class ReactionsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb06fdbdf);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<stickerset> sets
 * @return messages.AllStickers
 */

final class AllStickers extends Instance {
	public function request(int $hash,array $sets) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcdbbcebb);
		$writer->writeLong($hash);
		$writer->writeVector($sets,'stickerset');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['sets'] = $reader->readVector('stickerset');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash Vector<emojigroup> groups
 * @return messages.EmojiGroups
 */

final class EmojiGroups extends Instance {
	public function request(int $hash,array $groups) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x881fb94b);
		$writer->writeInt($hash);
		$writer->writeVector($groups,'emojigroup');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readInt();
		$result['groups'] = $reader->readVector('emojigroup');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.FoundStickerSets
 */

final class FoundStickerSetsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd54b65d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<stickersetcovered> sets
 * @return messages.FoundStickerSets
 */

final class FoundStickerSets extends Instance {
	public function request(int $hash,array $sets) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8af09dd2);
		$writer->writeLong($hash);
		$writer->writeVector($sets,'stickersetcovered');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['sets'] = $reader->readVector('stickersetcovered');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stickerset set Vector<stickerpack> packs Vector<stickerkeyword> keywords Vector<document> documents
 * @return messages.StickerSet
 */

final class StickerSet extends Instance {
	public function request(object $set,array $packs,array $keywords,array $documents) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6e153f16);
		$writer->writeObject($set);
		$writer->writeVector($packs,'stickerpack');
		$writer->writeVector($keywords,'stickerkeyword');
		$writer->writeVector($documents,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['set'] = $reader->readObject();
		$result['packs'] = $reader->readVector('stickerpack');
		$result['keywords'] = $reader->readVector('stickerkeyword');
		$result['documents'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param botapp app true inactive true request_write_access true has_settings
 * @return messages.BotApp
 */

final class BotApp extends Instance {
	public function request(object $app,null | bool $inactive = null,null | bool $request_write_access = null,null | bool $has_settings = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeb50adf5);
		$flags = 0;
		$flags |= $inactive ? (1 << 0) : 0;
		$flags |= $request_write_access ? (1 << 1) : 0;
		$flags |= $has_settings ? (1 << 2) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($app);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['inactive'] = boolval($flags & (1 << 0));
		$result['request_write_access'] = boolval($flags & (1 << 1));
		$result['has_settings'] = boolval($flags & (1 << 2));
		$result['app'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peersettings settings Vector<chat> chats Vector<user> users
 * @return messages.PeerSettings
 */

final class PeerSettings extends Instance {
	public function request(object $settings,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6880b94d);
		$writer->writeObject($settings);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['settings'] = $reader->readObject();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bot_id webviewresult webview Vector<user> users
 * @return messages.ChatInviteJoinResult
 */

final class ChatInviteJoinResultWebView extends Instance {
	public function request(int $bot_id,object $webview,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2f51c337);
		$writer->writeLong($bot_id);
		$writer->writeObject($webview);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['bot_id'] = $reader->readLong();
		$result['webview'] = $reader->readObject();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<dialog> dialogs Vector<message> messages Vector<chat> chats Vector<user> users updates.state state
 * @return messages.PeerDialogs
 */

final class PeerDialogs extends Instance {
	public function request(array $dialogs,array $messages,array $chats,array $users,object $state) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3371c354);
		$writer->writeVector($dialogs,'dialog');
		$writer->writeVector($messages,'message');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		$writer->writeObject($state);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['dialogs'] = $reader->readVector('dialog');
		$result['messages'] = $reader->readVector('message');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		$result['state'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.AvailableReactions
 */

final class AvailableReactionsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9f071957);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id Vector<botinlineresult> results int cache_time Vector<user> users true gallery string next_offset inlinebotswitchpm switch_pm inlinebotwebview switch_webview
 * @return messages.BotResults
 */

final class BotResults extends Instance {
	public function request(int $query_id,array $results,int $cache_time,array $users,null | bool $gallery = null,null | string $next_offset = null,null | object $switch_pm = null,null | object $switch_webview = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe021f2f6);
		$flags = 0;
		$flags |= $gallery ? (1 << 0) : 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 1);
		$flags |= is_null($switch_pm) ? 0 : (1 << 2);
		$flags |= is_null($switch_webview) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeLong($query_id);
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		if(is_null($switch_pm) === false):
			$writer->writeObject($switch_pm);
		endif;
		if(is_null($switch_webview) === false):
			$writer->writeObject($switch_webview);
		endif;
		$writer->writeVector($results,'botinlineresult');
		$writer->writeInt($cache_time);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['gallery'] = boolval($flags & (1 << 0));
		$result['query_id'] = $reader->readLong();
		if($flags & (1 << 1)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['switch_pm'] = $reader->readObject();
		else:
			$result['switch_pm'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['switch_webview'] = $reader->readObject();
		else:
			$result['switch_webview'] = null;
		endif;
		$result['results'] = $reader->readVector('botinlineresult');
		$result['cache_time'] = $reader->readInt();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param exportedchatinvite invite exportedchatinvite new_invite Vector<user> users
 * @return messages.ExportedChatInvite
 */

final class ExportedChatInviteReplaced extends Instance {
	public function request(object $invite,object $new_invite,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x222600ef);
		$writer->writeObject($invite);
		$writer->writeObject($new_invite);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['invite'] = $reader->readObject();
		$result['new_invite'] = $reader->readObject();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date encryptedfile file
 * @return messages.SentEncryptedMessage
 */

final class SentEncryptedFile extends Instance {
	public function request(int $date,object $file) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9493ff32);
		$writer->writeInt($date);
		$writer->writeObject($file);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['date'] = $reader->readInt();
		$result['file'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes random
 * @return messages.DhConfig
 */

final class DhConfigNotModified extends Instance {
	public function request(string $random) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc0e24635);
		$writer->writeBytes($random);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['random'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<saveddialog> dialogs Vector<message> messages Vector<chat> chats Vector<user> users
 * @return messages.SavedDialogs
 */

final class SavedDialogs extends Instance {
	public function request(array $dialogs,array $messages,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf83ae221);
		$writer->writeVector($dialogs,'saveddialog');
		$writer->writeVector($messages,'message');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['dialogs'] = $reader->readVector('saveddialog');
		$result['messages'] = $reader->readVector('message');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string confirm_text
 * @return messages.CheckedHistoryImportPeer
 */

final class CheckedHistoryImportPeer extends Instance {
	public function request(string $confirm_text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa24de717);
		$writer->writeBytes($confirm_text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['confirm_text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<stickersetcovered> sets
 * @return messages.MyStickers
 */

final class MyStickers extends Instance {
	public function request(int $count,array $sets) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfaff629d);
		$writer->writeInt($count);
		$writer->writeVector($sets,'stickersetcovered');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['sets'] = $reader->readVector('stickersetcovered');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.SponsoredMessages
 */

final class SponsoredMessagesEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1839490f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<int> dates Vector<chat> chats Vector<user> users
 * @return messages.InactiveChats
 */

final class InactiveChats extends Instance {
	public function request(array $dates,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa927fec5);
		$writer->writeVector($dates,'int');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['dates'] = $reader->readVector('int');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<document> stickers
 * @return messages.Stickers
 */

final class Stickers extends Instance {
	public function request(int $hash,array $stickers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x30a6ec7e);
		$writer->writeLong($hash);
		$writer->writeVector($stickers,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['stickers'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<message> messages Vector<forumtopic> topics Vector<chat> chats Vector<user> users true inexact int next_rate int offset_id_offset searchpostsflood search_flood
 * @return messages.Messages
 */

final class MessagesSlice extends Instance {
	public function request(int $count,array $messages,array $topics,array $chats,array $users,null | bool $inexact = null,null | int $next_rate = null,null | int $offset_id_offset = null,null | object $search_flood = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5f206716);
		$flags = 0;
		$flags |= $inexact ? (1 << 1) : 0;
		$flags |= is_null($next_rate) ? 0 : (1 << 0);
		$flags |= is_null($offset_id_offset) ? 0 : (1 << 2);
		$flags |= is_null($search_flood) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		if(is_null($next_rate) === false):
			$writer->writeInt($next_rate);
		endif;
		if(is_null($offset_id_offset) === false):
			$writer->writeInt($offset_id_offset);
		endif;
		if(is_null($search_flood) === false):
			$writer->writeObject($search_flood);
		endif;
		$writer->writeVector($messages,'message');
		$writer->writeVector($topics,'forumtopic');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['inexact'] = boolval($flags & (1 << 1));
		$result['count'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['next_rate'] = $reader->readInt();
		else:
			$result['next_rate'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['offset_id_offset'] = $reader->readInt();
		else:
			$result['offset_id_offset'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['search_flood'] = $reader->readObject();
		else:
			$result['search_flood'] = null;
		endif;
		$result['messages'] = $reader->readVector('message');
		$result['topics'] = $reader->readVector('forumtopic');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<reaction> reactions
 * @return messages.Reactions
 */

final class Reactions extends Instance {
	public function request(int $hash,array $reactions) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeafdf716);
		$writer->writeLong($hash);
		$writer->writeVector($reactions,'reaction');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['reactions'] = $reader->readVector('reaction');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param textwithentities result_text textwithentities diff_text
 * @return messages.ComposedMessageWithAI
 */

final class ComposedMessageWithAI extends Instance {
	public function request(object $result_text,null | object $diff_text = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x90d7adfa);
		$flags = 0;
		$flags |= is_null($diff_text) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($result_text);
		if(is_null($diff_text) === false):
			$writer->writeObject($diff_text);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['result_text'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['diff_text'] = $reader->readObject();
		else:
			$result['diff_text'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.AvailableEffects
 */

final class AvailableEffectsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd1ed9a5b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash int count Vector<stickersetcovered> sets Vector<long> unread true premium
 * @return messages.FeaturedStickers
 */

final class FeaturedStickers extends Instance {
	public function request(int $hash,int $count,array $sets,array $unread,null | bool $premium = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbe382906);
		$flags = 0;
		$flags |= $premium ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($hash);
		$writer->writeInt($count);
		$writer->writeVector($sets,'stickersetcovered');
		$writer->writeVector($unread,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['premium'] = boolval($flags & (1 << 0));
		$result['hash'] = $reader->readLong();
		$result['count'] = $reader->readInt();
		$result['sets'] = $reader->readVector('stickersetcovered');
		$result['unread'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int next_offset
 * @return messages.FoundStickers
 */

final class FoundStickersNotModified extends Instance {
	public function request(null | int $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6010c534);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($next_offset) === false):
			$writer->writeInt($next_offset);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readInt();
		else:
			$result['next_offset'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pts int count Vector<message> messages Vector<forumtopic> topics Vector<chat> chats Vector<user> users true inexact int offset_id_offset
 * @return messages.Messages
 */

final class ChannelMessages extends Instance {
	public function request(int $pts,int $count,array $messages,array $topics,array $chats,array $users,null | bool $inexact = null,null | int $offset_id_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc776ba4e);
		$flags = 0;
		$flags |= $inexact ? (1 << 1) : 0;
		$flags |= is_null($offset_id_offset) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeInt($pts);
		$writer->writeInt($count);
		if(is_null($offset_id_offset) === false):
			$writer->writeInt($offset_id_offset);
		endif;
		$writer->writeVector($messages,'message');
		$writer->writeVector($topics,'forumtopic');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['inexact'] = boolval($flags & (1 << 1));
		$result['pts'] = $reader->readInt();
		$result['count'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['offset_id_offset'] = $reader->readInt();
		else:
			$result['offset_id_offset'] = null;
		endif;
		$result['messages'] = $reader->readVector('message');
		$result['topics'] = $reader->readVector('forumtopic');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string game_hash long prev_stake int current_streak Vector<int> params int plays_left
 * @return messages.EmojiGameInfo
 */

final class EmojiGameDiceInfo extends Instance {
	public function request(string $game_hash,int $prev_stake,int $current_streak,array $params,null | int $plays_left = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x44e56023);
		$flags = 0;
		$flags |= is_null($plays_left) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($game_hash);
		$writer->writeLong($prev_stake);
		$writer->writeInt($current_streak);
		$writer->writeVector($params,'int');
		if(is_null($plays_left) === false):
			$writer->writeInt($plays_left);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['game_hash'] = $reader->readBytes();
		$result['prev_stake'] = $reader->readLong();
		$result['current_streak'] = $reader->readInt();
		$result['params'] = $reader->readVector('int');
		if($flags & (1 << 0)):
			$result['plays_left'] = $reader->readInt();
		else:
			$result['plays_left'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param updates updates
 * @return messages.ChatInviteJoinResult
 */

final class ChatInviteJoinResultOk extends Instance {
	public function request(object $updates) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x445663a7);
		$writer->writeObject($updates);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['updates'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count int min_date int min_msg_id Vector<searchresultscalendarperiod> periods Vector<message> messages Vector<chat> chats Vector<user> users true inexact int offset_id_offset
 * @return messages.SearchResultsCalendar
 */

final class SearchResultsCalendar extends Instance {
	public function request(int $count,int $min_date,int $min_msg_id,array $periods,array $messages,array $chats,array $users,null | bool $inexact = null,null | int $offset_id_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x147ee23c);
		$flags = 0;
		$flags |= $inexact ? (1 << 0) : 0;
		$flags |= is_null($offset_id_offset) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeInt($min_date);
		$writer->writeInt($min_msg_id);
		if(is_null($offset_id_offset) === false):
			$writer->writeInt($offset_id_offset);
		endif;
		$writer->writeVector($periods,'searchresultscalendarperiod');
		$writer->writeVector($messages,'message');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['inexact'] = boolval($flags & (1 << 0));
		$result['count'] = $reader->readInt();
		$result['min_date'] = $reader->readInt();
		$result['min_msg_id'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['offset_id_offset'] = $reader->readInt();
		else:
			$result['offset_id_offset'] = null;
		endif;
		$result['periods'] = $reader->readVector('searchresultscalendarperiod');
		$result['messages'] = $reader->readVector('message');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long transcription_id string text true pending int trial_remains_num int trial_remains_until_date
 * @return messages.TranscribedAudio
 */

final class TranscribedAudio extends Instance {
	public function request(int $transcription_id,string $text,null | bool $pending = null,null | int $trial_remains_num = null,null | int $trial_remains_until_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcfb9d957);
		$flags = 0;
		$flags |= $pending ? (1 << 0) : 0;
		$flags |= is_null($trial_remains_num) ? 0 : (1 << 1);
		$flags |= is_null($trial_remains_until_date) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($transcription_id);
		$writer->writeBytes($text);
		if(is_null($trial_remains_num) === false):
			$writer->writeInt($trial_remains_num);
		endif;
		if(is_null($trial_remains_until_date) === false):
			$writer->writeInt($trial_remains_until_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pending'] = boolval($flags & (1 << 0));
		$result['transcription_id'] = $reader->readLong();
		$result['text'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['trial_remains_num'] = $reader->readInt();
		else:
			$result['trial_remains_num'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['trial_remains_until_date'] = $reader->readInt();
		else:
			$result['trial_remains_until_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.EmojiGroups
 */

final class EmojiGroupsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6fb4ad87);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.EmojiGameInfo
 */

final class EmojiGameUnavailable extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x59e65335);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash Vector<availableeffect> effects Vector<document> documents
 * @return messages.AvailableEffects
 */

final class AvailableEffects extends Instance {
	public function request(int $hash,array $effects,array $documents) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbddb616e);
		$writer->writeInt($hash);
		$writer->writeVector($effects,'availableeffect');
		$writer->writeVector($documents,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readInt();
		$result['effects'] = $reader->readVector('availableeffect');
		$result['documents'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<dialog> dialogs Vector<message> messages Vector<chat> chats Vector<user> users
 * @return messages.Dialogs
 */

final class DialogsSlice extends Instance {
	public function request(int $count,array $dialogs,array $messages,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x71e094f3);
		$writer->writeInt($count);
		$writer->writeVector($dialogs,'dialog');
		$writer->writeVector($messages,'message');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['dialogs'] = $reader->readVector('dialog');
		$result['messages'] = $reader->readVector('message');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count
 * @return messages.FeaturedStickers
 */

final class FeaturedStickersNotModified extends Instance {
	public function request(int $count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc6dc0c66);
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<savedreactiontag> tags long hash
 * @return messages.SavedReactionTags
 */

final class SavedReactionTags extends Instance {
	public function request(array $tags,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3259950a);
		$writer->writeVector($tags,'savedreactiontag');
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['tags'] = $reader->readVector('savedreactiontag');
		$result['hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pts int pts_count int offset
 * @return messages.AffectedHistory
 */

final class AffectedHistory extends Instance {
	public function request(int $pts,int $pts_count,int $offset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb45c69d1);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		$writer->writeInt($offset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		$result['offset'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pts int pts_count int offset Vector<int> messages
 * @return messages.AffectedFoundMessages
 */

final class AffectedFoundMessages extends Instance {
	public function request(int $pts,int $pts_count,int $offset,array $messages) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xef8d3e6c);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		$writer->writeInt($offset);
		$writer->writeVector($messages,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		$result['offset'] = $reader->readInt();
		$result['messages'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes seed long stake_ton_amount long ton_amount
 * @return messages.EmojiGameOutcome
 */

final class EmojiGameOutcome extends Instance {
	public function request(string $seed,int $stake_ton_amount,int $ton_amount) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xda2ad647);
		$writer->writeBytes($seed);
		$writer->writeLong($stake_ton_amount);
		$writer->writeLong($ton_amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['seed'] = $reader->readBytes();
		$result['stake_ton_amount'] = $reader->readLong();
		$result['ton_amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<document> stickers int next_offset
 * @return messages.FoundStickers
 */

final class FoundStickers extends Instance {
	public function request(int $hash,array $stickers,null | int $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x82c9e290);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($next_offset) === false):
			$writer->writeInt($next_offset);
		endif;
		$writer->writeLong($hash);
		$writer->writeVector($stickers,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readInt();
		else:
			$result['next_offset'] = null;
		endif;
		$result['hash'] = $reader->readLong();
		$result['stickers'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.Stickers
 */

final class StickersNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf1749a22);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.StickerSet
 */

final class StickerSetNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd3f924eb);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<chatadminwithinvites> admins Vector<user> users
 * @return messages.ChatAdminsWithInvites
 */

final class ChatAdminsWithInvites extends Instance {
	public function request(array $admins,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb69b72d7);
		$writer->writeVector($admins,'chatadminwithinvites');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['admins'] = $reader->readVector('chatadminwithinvites');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<message> messages int unread_count Vector<chat> chats Vector<user> users int max_id int read_inbox_max_id int read_outbox_max_id
 * @return messages.DiscussionMessage
 */

final class DiscussionMessage extends Instance {
	public function request(array $messages,int $unread_count,array $chats,array $users,null | int $max_id = null,null | int $read_inbox_max_id = null,null | int $read_outbox_max_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa6341782);
		$flags = 0;
		$flags |= is_null($max_id) ? 0 : (1 << 0);
		$flags |= is_null($read_inbox_max_id) ? 0 : (1 << 1);
		$flags |= is_null($read_outbox_max_id) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeVector($messages,'message');
		if(is_null($max_id) === false):
			$writer->writeInt($max_id);
		endif;
		if(is_null($read_inbox_max_id) === false):
			$writer->writeInt($read_inbox_max_id);
		endif;
		if(is_null($read_outbox_max_id) === false):
			$writer->writeInt($read_outbox_max_id);
		endif;
		$writer->writeInt($unread_count);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['messages'] = $reader->readVector('message');
		if($flags & (1 << 0)):
			$result['max_id'] = $reader->readInt();
		else:
			$result['max_id'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['read_inbox_max_id'] = $reader->readInt();
		else:
			$result['read_inbox_max_id'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['read_outbox_max_id'] = $reader->readInt();
		else:
			$result['read_outbox_max_id'] = null;
		endif;
		$result['unread_count'] = $reader->readInt();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.AllStickers
 */

final class AllStickersNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe86602c3);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<forumtopic> topics Vector<message> messages Vector<chat> chats Vector<user> users int pts true order_by_create_date
 * @return messages.ForumTopics
 */

final class ForumTopics extends Instance {
	public function request(int $count,array $topics,array $messages,array $chats,array $users,int $pts,null | bool $order_by_create_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x367617d3);
		$flags = 0;
		$flags |= $order_by_create_date ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeVector($topics,'forumtopic');
		$writer->writeVector($messages,'message');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		$writer->writeInt($pts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['order_by_create_date'] = boolval($flags & (1 << 0));
		$result['count'] = $reader->readInt();
		$result['topics'] = $reader->readVector('forumtopic');
		$result['messages'] = $reader->readVector('message');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		$result['pts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash Vector<availablereaction> reactions
 * @return messages.AvailableReactions
 */

final class AvailableReactions extends Instance {
	public function request(int $hash,array $reactions) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x768e3aad);
		$writer->writeInt($hash);
		$writer->writeVector($reactions,'availablereaction');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readInt();
		$result['reactions'] = $reader->readVector('availablereaction');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pts int pts_count
 * @return messages.AffectedMessages
 */

final class AffectedMessages extends Instance {
	public function request(int $pts,int $pts_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x84d19185);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param exportedchatinvite invite Vector<user> users
 * @return messages.ExportedChatInvite
 */

final class ExportedChatInvite extends Instance {
	public function request(object $invite,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1871be50);
		$writer->writeObject($invite);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['invite'] = $reader->readObject();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<document> gifs
 * @return messages.SavedGifs
 */

final class SavedGifs extends Instance {
	public function request(int $hash,array $gifs) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x84a02a0d);
		$writer->writeLong($hash);
		$writer->writeVector($gifs,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['gifs'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param auth.sentcodetype type string phone_code_hash auth.codetype next_type int timeout
 * @return auth.SentCode
 */

final class SentCode extends Instance {
	public function request(object $type,string $phone_code_hash,null | object $next_type = null,null | int $timeout = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5e002502);
		$flags = 0;
		$flags |= is_null($next_type) ? 0 : (1 << 1);
		$flags |= is_null($timeout) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($type);
		$writer->writeBytes($phone_code_hash);
		if(is_null($next_type) === false):
			$writer->writeObject($next_type);
		endif;
		if(is_null($timeout) === false):
			$writer->writeInt($timeout);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['type'] = $reader->readObject();
		$result['phone_code_hash'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['next_type'] = $reader->readObject();
		else:
			$result['next_type'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['timeout'] = $reader->readInt();
		else:
			$result['timeout'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int length bytes nonce long play_integrity_project_id bytes play_integrity_nonce string receipt int push_timeout
 * @return auth.SentCodeType
 */

final class SentCodeTypeFirebaseSms extends Instance {
	public function request(int $length,null | string $nonce = null,null | int $play_integrity_project_id = null,null | string $play_integrity_nonce = null,null | string $receipt = null,null | int $push_timeout = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9fd736);
		$flags = 0;
		$flags |= is_null($nonce) ? 0 : (1 << 0);
		$flags |= is_null($play_integrity_project_id) ? 0 : (1 << 2);
		$flags |= is_null($play_integrity_nonce) ? 0 : (1 << 2);
		$flags |= is_null($receipt) ? 0 : (1 << 1);
		$flags |= is_null($push_timeout) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($nonce) === false):
			$writer->writeBytes($nonce);
		endif;
		if(is_null($play_integrity_project_id) === false):
			$writer->writeLong($play_integrity_project_id);
		endif;
		if(is_null($play_integrity_nonce) === false):
			$writer->writeBytes($play_integrity_nonce);
		endif;
		if(is_null($receipt) === false):
			$writer->writeBytes($receipt);
		endif;
		if(is_null($push_timeout) === false):
			$writer->writeInt($push_timeout);
		endif;
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['nonce'] = $reader->readBytes();
		else:
			$result['nonce'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['play_integrity_project_id'] = $reader->readLong();
		else:
			$result['play_integrity_project_id'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['play_integrity_nonce'] = $reader->readBytes();
		else:
			$result['play_integrity_nonce'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['receipt'] = $reader->readBytes();
		else:
			$result['receipt'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['push_timeout'] = $reader->readInt();
		else:
			$result['push_timeout'] = null;
		endif;
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string email_pattern int length true apple_signin_allowed true google_signin_allowed int reset_available_period int reset_pending_date
 * @return auth.SentCodeType
 */

final class SentCodeTypeEmailCode extends Instance {
	public function request(string $email_pattern,int $length,null | bool $apple_signin_allowed = null,null | bool $google_signin_allowed = null,null | int $reset_available_period = null,null | int $reset_pending_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf450f59b);
		$flags = 0;
		$flags |= $apple_signin_allowed ? (1 << 0) : 0;
		$flags |= $google_signin_allowed ? (1 << 1) : 0;
		$flags |= is_null($reset_available_period) ? 0 : (1 << 3);
		$flags |= is_null($reset_pending_date) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeBytes($email_pattern);
		$writer->writeInt($length);
		if(is_null($reset_available_period) === false):
			$writer->writeInt($reset_available_period);
		endif;
		if(is_null($reset_pending_date) === false):
			$writer->writeInt($reset_pending_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['apple_signin_allowed'] = boolval($flags & (1 << 0));
		$result['google_signin_allowed'] = boolval($flags & (1 << 1));
		$result['email_pattern'] = $reader->readBytes();
		$result['length'] = $reader->readInt();
		if($flags & (1 << 3)):
			$result['reset_available_period'] = $reader->readInt();
		else:
			$result['reset_available_period'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['reset_pending_date'] = $reader->readInt();
		else:
			$result['reset_pending_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson options
 * @return auth.PasskeyLoginOptions
 */

final class PasskeyLoginOptions extends Instance {
	public function request(object $options) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe2037789);
		$writer->writeObject($options);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['options'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return auth.CodeType
 */

final class CodeTypeSms extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x72a3158c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string email_pattern
 * @return auth.PasswordRecovery
 */

final class PasswordRecovery extends Instance {
	public function request(string $email_pattern) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x137948a5);
		$writer->writeBytes($email_pattern);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['email_pattern'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int length
 * @return auth.SentCodeType
 */

final class SentCodeTypeSms extends Instance {
	public function request(int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc000bba2);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return auth.CodeType
 */

final class CodeTypeCall extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x741cd3e3);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int dc_id bytes token
 * @return auth.LoginToken
 */

final class LoginTokenMigrateTo extends Instance {
	public function request(int $dc_id,string $token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x68e9916);
		$writer->writeInt($dc_id);
		$writer->writeBytes($token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['dc_id'] = $reader->readInt();
		$result['token'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int length
 * @return auth.SentCodeType
 */

final class SentCodeTypeApp extends Instance {
	public function request(int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3dbb5986);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true apple_signin_allowed true google_signin_allowed
 * @return auth.SentCodeType
 */

final class SentCodeTypeSetUpEmailRequired extends Instance {
	public function request(null | bool $apple_signin_allowed = null,null | bool $google_signin_allowed = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa5491dea);
		$flags = 0;
		$flags |= $apple_signin_allowed ? (1 << 0) : 0;
		$flags |= $google_signin_allowed ? (1 << 1) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['apple_signin_allowed'] = boolval($flags & (1 << 0));
		$result['google_signin_allowed'] = boolval($flags & (1 << 1));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param help.termsofservice terms_of_service
 * @return auth.Authorization
 */

final class AuthorizationSignUpRequired extends Instance {
	public function request(null | object $terms_of_service = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x44747e9a);
		$flags = 0;
		$flags |= is_null($terms_of_service) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($terms_of_service) === false):
			$writer->writeObject($terms_of_service);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['terms_of_service'] = $reader->readObject();
		else:
			$result['terms_of_service'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string prefix int length
 * @return auth.SentCodeType
 */

final class SentCodeTypeMissedCall extends Instance {
	public function request(string $prefix,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x82006484);
		$writer->writeBytes($prefix);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prefix'] = $reader->readBytes();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string store_product string phone_code_hash string support_email_address string support_email_subject int premium_days string currency long amount
 * @return auth.SentCode
 */

final class SentCodePaymentRequired extends Instance {
	public function request(string $store_product,string $phone_code_hash,string $support_email_address,string $support_email_subject,int $premium_days,string $currency,int $amount) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf8827ebf);
		$writer->writeBytes($store_product);
		$writer->writeBytes($phone_code_hash);
		$writer->writeBytes($support_email_address);
		$writer->writeBytes($support_email_subject);
		$writer->writeInt($premium_days);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['store_product'] = $reader->readBytes();
		$result['phone_code_hash'] = $reader->readBytes();
		$result['support_email_address'] = $reader->readBytes();
		$result['support_email_subject'] = $reader->readBytes();
		$result['premium_days'] = $reader->readInt();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param user user true setup_password_required int otherwise_relogin_days int tmp_sessions bytes future_auth_token
 * @return auth.Authorization
 */

final class Authorization extends Instance {
	public function request(object $user,null | bool $setup_password_required = null,null | int $otherwise_relogin_days = null,null | int $tmp_sessions = null,null | string $future_auth_token = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2ea2c0d4);
		$flags = 0;
		$flags |= $setup_password_required ? (1 << 1) : 0;
		$flags |= is_null($otherwise_relogin_days) ? 0 : (1 << 1);
		$flags |= is_null($tmp_sessions) ? 0 : (1 << 0);
		$flags |= is_null($future_auth_token) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($otherwise_relogin_days) === false):
			$writer->writeInt($otherwise_relogin_days);
		endif;
		if(is_null($tmp_sessions) === false):
			$writer->writeInt($tmp_sessions);
		endif;
		if(is_null($future_auth_token) === false):
			$writer->writeBytes($future_auth_token);
		endif;
		$writer->writeObject($user);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['setup_password_required'] = boolval($flags & (1 << 1));
		if($flags & (1 << 1)):
			$result['otherwise_relogin_days'] = $reader->readInt();
		else:
			$result['otherwise_relogin_days'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['tmp_sessions'] = $reader->readInt();
		else:
			$result['tmp_sessions'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['future_auth_token'] = $reader->readBytes();
		else:
			$result['future_auth_token'] = null;
		endif;
		$result['user'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int expires bytes token
 * @return auth.LoginToken
 */

final class LoginToken extends Instance {
	public function request(int $expires,string $token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x629f1980);
		$writer->writeInt($expires);
		$writer->writeBytes($token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['expires'] = $reader->readInt();
		$result['token'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string beginning
 * @return auth.SentCodeType
 */

final class SentCodeTypeSmsWord extends Instance {
	public function request(null | string $beginning = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa416ac81);
		$flags = 0;
		$flags |= is_null($beginning) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($beginning) === false):
			$writer->writeBytes($beginning);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['beginning'] = $reader->readBytes();
		else:
			$result['beginning'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return auth.CodeType
 */

final class CodeTypeMissedCall extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd61ad6ee);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return auth.CodeType
 */

final class CodeTypeFragmentSms extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6ed998c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param auth.authorization authorization
 * @return auth.LoginToken
 */

final class LoginTokenSuccess extends Instance {
	public function request(object $authorization) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x390d5c5e);
		$writer->writeObject($authorization);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['authorization'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string pattern
 * @return auth.SentCodeType
 */

final class SentCodeTypeFlashCall extends Instance {
	public function request(string $pattern) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xab03c6d9);
		$writer->writeBytes($pattern);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pattern'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes future_auth_token
 * @return auth.LoggedOut
 */

final class LoggedOut extends Instance {
	public function request(null | string $future_auth_token = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc3a2835f);
		$flags = 0;
		$flags |= is_null($future_auth_token) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($future_auth_token) === false):
			$writer->writeBytes($future_auth_token);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['future_auth_token'] = $reader->readBytes();
		else:
			$result['future_auth_token'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return auth.CodeType
 */

final class CodeTypeFlashCall extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x226ccefb);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id bytes bytes
 * @return auth.ExportedAuthorization
 */

final class ExportedAuthorization extends Instance {
	public function request(int $id,string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb434e2b8);
		$writer->writeLong($id);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['bytes'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string beginning
 * @return auth.SentCodeType
 */

final class SentCodeTypeSmsPhrase extends Instance {
	public function request(null | string $beginning = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb37794af);
		$flags = 0;
		$flags |= is_null($beginning) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($beginning) === false):
			$writer->writeBytes($beginning);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['beginning'] = $reader->readBytes();
		else:
			$result['beginning'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url int length
 * @return auth.SentCodeType
 */

final class SentCodeTypeFragmentSms extends Instance {
	public function request(string $url,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd9565c39);
		$writer->writeBytes($url);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int length
 * @return auth.SentCodeType
 */

final class SentCodeTypeCall extends Instance {
	public function request(int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5353e5a7);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param auth.authorization authorization
 * @return auth.SentCode
 */

final class SentCodeSuccess extends Instance {
	public function request(object $authorization) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2390fe44);
		$writer->writeObject($authorization);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['authorization'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<peer> missing_peers Vector<chat> chats Vector<user> users
 * @return chatlists.ChatlistUpdates
 */

final class ChatlistUpdates extends Instance {
	public function request(array $missing_peers,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x93bd878d);
		$writer->writeVector($missing_peers,'peer');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['missing_peers'] = $reader->readVector('peer');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param textwithentities title Vector<peer> peers Vector<chat> chats Vector<user> users true title_noanimate string emoticon
 * @return chatlists.ChatlistInvite
 */

final class ChatlistInvite extends Instance {
	public function request(object $title,array $peers,array $chats,array $users,null | bool $title_noanimate = null,null | string $emoticon = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf10ece2f);
		$flags = 0;
		$flags |= $title_noanimate ? (1 << 1) : 0;
		$flags |= is_null($emoticon) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($title);
		if(is_null($emoticon) === false):
			$writer->writeBytes($emoticon);
		endif;
		$writer->writeVector($peers,'peer');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['title_noanimate'] = boolval($flags & (1 << 1));
		$result['title'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['emoticon'] = $reader->readBytes();
		else:
			$result['emoticon'] = null;
		endif;
		$result['peers'] = $reader->readVector('peer');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param dialogfilter filter exportedchatlistinvite invite
 * @return chatlists.ExportedChatlistInvite
 */

final class ExportedChatlistInvite extends Instance {
	public function request(object $filter,object $invite) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x10e6e3a6);
		$writer->writeObject($filter);
		$writer->writeObject($invite);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['filter'] = $reader->readObject();
		$result['invite'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int filter_id Vector<peer> missing_peers Vector<peer> already_peers Vector<chat> chats Vector<user> users
 * @return chatlists.ChatlistInvite
 */

final class ChatlistInviteAlready extends Instance {
	public function request(int $filter_id,array $missing_peers,array $already_peers,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfa87f659);
		$writer->writeInt($filter_id);
		$writer->writeVector($missing_peers,'peer');
		$writer->writeVector($already_peers,'peer');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['filter_id'] = $reader->readInt();
		$result['missing_peers'] = $reader->readVector('peer');
		$result['already_peers'] = $reader->readVector('peer');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<exportedchatlistinvite> invites Vector<chat> chats Vector<user> users
 * @return chatlists.ExportedInvites
 */

final class ExportedInvites extends Instance {
	public function request(array $invites,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x10ab6dc7);
		$writer->writeVector($invites,'exportedchatlistinvite');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['invites'] = $reader->readVector('exportedchatlistinvite');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.TimezonesList
 */

final class TimezonesListNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x970708cc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int expires Vector<string> pending_suggestions Vector<string> dismissed_suggestions Vector<chat> chats Vector<user> users true proxy peer peer string psa_type string psa_message pendingsuggestion custom_pending_suggestion
 * @return help.PromoData
 */

final class PromoData extends Instance {
	public function request(int $expires,array $pending_suggestions,array $dismissed_suggestions,array $chats,array $users,null | bool $proxy = null,null | object $peer = null,null | string $psa_type = null,null | string $psa_message = null,null | object $custom_pending_suggestion = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8a4d87a);
		$flags = 0;
		$flags |= $proxy ? (1 << 0) : 0;
		$flags |= is_null($peer) ? 0 : (1 << 3);
		$flags |= is_null($psa_type) ? 0 : (1 << 1);
		$flags |= is_null($psa_message) ? 0 : (1 << 2);
		$flags |= is_null($custom_pending_suggestion) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeInt($expires);
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		if(is_null($psa_type) === false):
			$writer->writeBytes($psa_type);
		endif;
		if(is_null($psa_message) === false):
			$writer->writeBytes($psa_message);
		endif;
		$writer->writeVector($pending_suggestions,'string');
		$writer->writeVector($dismissed_suggestions,'string');
		if(is_null($custom_pending_suggestion) === false):
			$writer->writeObject($custom_pending_suggestion);
		endif;
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['proxy'] = boolval($flags & (1 << 0));
		$result['expires'] = $reader->readInt();
		if($flags & (1 << 3)):
			$result['peer'] = $reader->readObject();
		else:
			$result['peer'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['psa_type'] = $reader->readBytes();
		else:
			$result['psa_type'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['psa_message'] = $reader->readBytes();
		else:
			$result['psa_message'] = null;
		endif;
		$result['pending_suggestions'] = $reader->readVector('string');
		$result['dismissed_suggestions'] = $reader->readVector('string');
		if($flags & (1 << 4)):
			$result['custom_pending_suggestion'] = $reader->readObject();
		else:
			$result['custom_pending_suggestion'] = null;
		endif;
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int expires
 * @return help.TermsOfServiceUpdate
 */

final class TermsOfServiceUpdateEmpty extends Instance {
	public function request(int $expires) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe3309f7f);
		$writer->writeInt($expires);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['expires'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash datajson countries_langs
 * @return help.PassportConfig
 */

final class PassportConfig extends Instance {
	public function request(int $hash,object $countries_langs) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa098d6af);
		$writer->writeInt($hash);
		$writer->writeObject($countries_langs);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readInt();
		$result['countries_langs'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<int> palette_colors Vector<int> bg_colors Vector<int> story_colors
 * @return help.PeerColorSet
 */

final class PeerColorProfileSet extends Instance {
	public function request(array $palette_colors,array $bg_colors,array $story_colors) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x767d61eb);
		$writer->writeVector($palette_colors,'int');
		$writer->writeVector($bg_colors,'int');
		$writer->writeVector($story_colors,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['palette_colors'] = $reader->readVector('int');
		$result['bg_colors'] = $reader->readVector('int');
		$result['story_colors'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<timezone> timezones int hash
 * @return help.TimezonesList
 */

final class TimezonesList extends Instance {
	public function request(array $timezones,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7b74ed71);
		$writer->writeVector($timezones,'timezone');
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['timezones'] = $reader->readVector('timezone');
		$result['hash'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string country_code Vector<string> prefixes Vector<string> patterns
 * @return help.CountryCode
 */

final class CountryCode extends Instance {
	public function request(string $country_code,null | array $prefixes = null,null | array $patterns = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4203c5ef);
		$flags = 0;
		$flags |= is_null($prefixes) ? 0 : (1 << 0);
		$flags |= is_null($patterns) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($country_code);
		if(is_null($prefixes) === false):
			$writer->writeVector($prefixes,'string');
		endif;
		if(is_null($patterns) === false):
			$writer->writeVector($patterns,'string');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['country_code'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['prefixes'] = $reader->readVector('string');
		else:
			$result['prefixes'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['patterns'] = $reader->readVector('string');
		else:
			$result['patterns'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string iso2 string default_name Vector<help.countrycode> country_codes true hidden string name
 * @return help.Country
 */

final class Country extends Instance {
	public function request(string $iso2,string $default_name,array $country_codes,null | bool $hidden = null,null | string $name = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc3878e23);
		$flags = 0;
		$flags |= $hidden ? (1 << 0) : 0;
		$flags |= is_null($name) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($iso2);
		$writer->writeBytes($default_name);
		if(is_null($name) === false):
			$writer->writeBytes($name);
		endif;
		$writer->writeVector($country_codes,'help.countrycode');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['hidden'] = boolval($flags & (1 << 0));
		$result['iso2'] = $reader->readBytes();
		$result['default_name'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['name'] = $reader->readBytes();
		else:
			$result['name'] = null;
		endif;
		$result['country_codes'] = $reader->readVector('help.countrycode');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.AppUpdate
 */

final class NoAppUpdate extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc45a6536);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message Vector<messageentity> entities string author int date
 * @return help.UserInfo
 */

final class UserInfo extends Instance {
	public function request(string $message,array $entities,string $author,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1eb3758);
		$writer->writeBytes($message);
		$writer->writeVector($entities,'messageentity');
		$writer->writeBytes($author);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readBytes();
		$result['entities'] = $reader->readVector('messageentity');
		$result['author'] = $reader->readBytes();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.PeerColors
 */

final class PeerColorsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2ba1f5ce);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date int expires Vector<accesspointrule> rules
 * @return help.ConfigSimple
 */

final class ConfigSimple extends Instance {
	public function request(int $date,int $expires,array $rules) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5a592a6c);
		$writer->writeInt($date);
		$writer->writeInt($expires);
		$writer->writeVector($rules,'accesspointrule');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['date'] = $reader->readInt();
		$result['expires'] = $reader->readInt();
		$result['rules'] = $reader->readVector('accesspointrule');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<help.country> countries int hash
 * @return help.CountriesList
 */

final class CountriesList extends Instance {
	public function request(array $countries,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x87d0759e);
		$writer->writeVector($countries,'help.country');
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['countries'] = $reader->readVector('help.country');
		$result['hash'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message true update_app Vector<messageentity> entities
 * @return help.DeepLinkInfo
 */

final class DeepLinkInfo extends Instance {
	public function request(string $message,null | bool $update_app = null,null | array $entities = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6a4ee832);
		$flags = 0;
		$flags |= $update_app ? (1 << 0) : 0;
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['update_app'] = boolval($flags & (1 << 0));
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string status_text Vector<messageentity> status_entities Vector<string> video_sections Vector<document> videos Vector<premiumsubscriptionoption> period_options Vector<user> users
 * @return help.PremiumPromo
 */

final class PremiumPromo extends Instance {
	public function request(string $status_text,array $status_entities,array $video_sections,array $videos,array $period_options,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5334759c);
		$writer->writeBytes($status_text);
		$writer->writeVector($status_entities,'messageentity');
		$writer->writeVector($video_sections,'string');
		$writer->writeVector($videos,'document');
		$writer->writeVector($period_options,'premiumsubscriptionoption');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['status_text'] = $reader->readBytes();
		$result['status_entities'] = $reader->readVector('messageentity');
		$result['video_sections'] = $reader->readVector('string');
		$result['videos'] = $reader->readVector('document');
		$result['period_options'] = $reader->readVector('premiumsubscriptionoption');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.UserInfo
 */

final class UserInfoEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf3ae2eed);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<recentmeurl> urls Vector<chat> chats Vector<user> users
 * @return help.RecentMeUrls
 */

final class RecentMeUrls extends Instance {
	public function request(array $urls,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe0310d7);
		$writer->writeVector($urls,'recentmeurl');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['urls'] = $reader->readVector('recentmeurl');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash Vector<help.peercoloroption> colors
 * @return help.PeerColors
 */

final class PeerColors extends Instance {
	public function request(int $hash,array $colors) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf8ed08);
		$writer->writeInt($hash);
		$writer->writeVector($colors,'help.peercoloroption');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readInt();
		$result['colors'] = $reader->readVector('help.peercoloroption');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.AppConfig
 */

final class AppConfigNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7cde641d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message
 * @return help.InviteText
 */

final class InviteText extends Instance {
	public function request(string $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x18cb9f78);
		$writer->writeBytes($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int color_id true hidden help.peercolorset colors help.peercolorset dark_colors int channel_min_level int group_min_level
 * @return help.PeerColorOption
 */

final class PeerColorOption extends Instance {
	public function request(int $color_id,null | bool $hidden = null,null | object $colors = null,null | object $dark_colors = null,null | int $channel_min_level = null,null | int $group_min_level = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xadec6ebe);
		$flags = 0;
		$flags |= $hidden ? (1 << 0) : 0;
		$flags |= is_null($colors) ? 0 : (1 << 1);
		$flags |= is_null($dark_colors) ? 0 : (1 << 2);
		$flags |= is_null($channel_min_level) ? 0 : (1 << 3);
		$flags |= is_null($group_min_level) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeInt($color_id);
		if(is_null($colors) === false):
			$writer->writeObject($colors);
		endif;
		if(is_null($dark_colors) === false):
			$writer->writeObject($dark_colors);
		endif;
		if(is_null($channel_min_level) === false):
			$writer->writeInt($channel_min_level);
		endif;
		if(is_null($group_min_level) === false):
			$writer->writeInt($group_min_level);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['hidden'] = boolval($flags & (1 << 0));
		$result['color_id'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['colors'] = $reader->readObject();
		else:
			$result['colors'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['dark_colors'] = $reader->readObject();
		else:
			$result['dark_colors'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['channel_min_level'] = $reader->readInt();
		else:
			$result['channel_min_level'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['group_min_level'] = $reader->readInt();
		else:
			$result['group_min_level'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int expires
 * @return help.PromoData
 */

final class PromoDataEmpty extends Instance {
	public function request(int $expires) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x98f6ac75);
		$writer->writeInt($expires);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['expires'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number user user
 * @return help.Support
 */

final class Support extends Instance {
	public function request(string $phone_number,object $user) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x17c6b5f6);
		$writer->writeBytes($phone_number);
		$writer->writeObject($user);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone_number'] = $reader->readBytes();
		$result['user'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.PassportConfig
 */

final class PassportConfigNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbfb9f457);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.DeepLinkInfo
 */

final class DeepLinkInfoEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x66afa166);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string name
 * @return help.SupportName
 */

final class SupportName extends Instance {
	public function request(string $name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c05f1c9);
		$writer->writeBytes($name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson id string text Vector<messageentity> entities true popup int min_age_confirm
 * @return help.TermsOfService
 */

final class TermsOfService extends Instance {
	public function request(object $id,string $text,array $entities,null | bool $popup = null,null | int $min_age_confirm = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x780a0310);
		$flags = 0;
		$flags |= $popup ? (1 << 0) : 0;
		$flags |= is_null($min_age_confirm) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($id);
		$writer->writeBytes($text);
		$writer->writeVector($entities,'messageentity');
		if(is_null($min_age_confirm) === false):
			$writer->writeInt($min_age_confirm);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['popup'] = boolval($flags & (1 << 0));
		$result['id'] = $reader->readObject();
		$result['text'] = $reader->readBytes();
		$result['entities'] = $reader->readVector('messageentity');
		if($flags & (1 << 1)):
			$result['min_age_confirm'] = $reader->readInt();
		else:
			$result['min_age_confirm'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash jsonvalue config
 * @return help.AppConfig
 */

final class AppConfig extends Instance {
	public function request(int $hash,object $config) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdd18782e);
		$writer->writeInt($hash);
		$writer->writeObject($config);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readInt();
		$result['config'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id string version string text Vector<messageentity> entities true can_not_skip document document string url document sticker
 * @return help.AppUpdate
 */

final class AppUpdate extends Instance {
	public function request(int $id,string $version,string $text,array $entities,null | bool $can_not_skip = null,null | object $document = null,null | string $url = null,null | object $sticker = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xccbbce30);
		$flags = 0;
		$flags |= $can_not_skip ? (1 << 0) : 0;
		$flags |= is_null($document) ? 0 : (1 << 1);
		$flags |= is_null($url) ? 0 : (1 << 2);
		$flags |= is_null($sticker) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeBytes($version);
		$writer->writeBytes($text);
		$writer->writeVector($entities,'messageentity');
		if(is_null($document) === false):
			$writer->writeObject($document);
		endif;
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		if(is_null($sticker) === false):
			$writer->writeObject($sticker);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['can_not_skip'] = boolval($flags & (1 << 0));
		$result['id'] = $reader->readInt();
		$result['version'] = $reader->readBytes();
		$result['text'] = $reader->readBytes();
		$result['entities'] = $reader->readVector('messageentity');
		if($flags & (1 << 1)):
			$result['document'] = $reader->readObject();
		else:
			$result['document'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['url'] = $reader->readBytes();
		else:
			$result['url'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['sticker'] = $reader->readObject();
		else:
			$result['sticker'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int expires help.termsofservice terms_of_service
 * @return help.TermsOfServiceUpdate
 */

final class TermsOfServiceUpdate extends Instance {
	public function request(int $expires,object $terms_of_service) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x28ecf961);
		$writer->writeInt($expires);
		$writer->writeObject($terms_of_service);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['expires'] = $reader->readInt();
		$result['terms_of_service'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<int> colors
 * @return help.PeerColorSet
 */

final class PeerColorSet extends Instance {
	public function request(array $colors) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x26219a58);
		$writer->writeVector($colors,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['colors'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.CountriesList
 */

final class CountriesListNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x93cc1f32);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Photos;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<photo> photos Vector<user> users
 * @return photos.Photos
 */

final class Photos extends Instance {
	public function request(array $photos,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8dca6aa5);
		$writer->writeVector($photos,'photo');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['photos'] = $reader->readVector('photo');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Photos;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param photo photo Vector<user> users
 * @return photos.Photo
 */

final class Photo extends Instance {
	public function request(object $photo,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x20212ca8);
		$writer->writeObject($photo);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['photo'] = $reader->readObject();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Photos;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<photo> photos Vector<user> users
 * @return photos.Photos
 */

final class PhotosSlice extends Instance {
	public function request(int $count,array $photos,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x15051f54);
		$writer->writeInt($count);
		$writer->writeVector($photos,'photo');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['photos'] = $reader->readVector('photo');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Fragment;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int purchase_date string currency long amount string crypto_currency long crypto_amount string url
 * @return fragment.CollectibleInfo
 */

final class CollectibleInfo extends Instance {
	public function request(int $purchase_date,string $currency,int $amount,string $crypto_currency,int $crypto_amount,string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6ebdff91);
		$writer->writeInt($purchase_date);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		$writer->writeBytes($crypto_currency);
		$writer->writeLong($crypto_amount);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['purchase_date'] = $reader->readInt();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		$result['crypto_currency'] = $reader->readBytes();
		$result['crypto_amount'] = $reader->readLong();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<botpreviewmedia> media Vector<string> lang_codes
 * @return bots.PreviewInfo
 */

final class PreviewInfo extends Instance {
	public function request(array $media,array $lang_codes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xca71d64);
		$writer->writeVector($media,'botpreviewmedia');
		$writer->writeVector($lang_codes,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['media'] = $reader->readVector('botpreviewmedia');
		$result['lang_codes'] = $reader->readVector('string');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string token
 * @return bots.ExportedBotToken
 */

final class ExportedBotToken extends Instance {
	public function request(string $token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3c60b621);
		$writer->writeBytes($token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['token'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<user> users string next_offset
 * @return bots.PopularAppBots
 */

final class PopularAppBots extends Instance {
	public function request(array $users,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1991b13b);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true restricted Vector<user> add_users
 * @return bots.AccessSettings
 */

final class AccessSettings extends Instance {
	public function request(null | bool $restricted = null,null | array $add_users = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdd1fbf93);
		$flags = 0;
		$flags |= $restricted ? (1 << 0) : 0;
		$flags |= is_null($add_users) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($add_users) === false):
			$writer->writeVector($add_users,'user');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['restricted'] = boolval($flags & (1 << 0));
		if($flags & (1 << 1)):
			$result['add_users'] = $reader->readVector('user');
		else:
			$result['add_users'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string webapp_req_id
 * @return bots.RequestedButton
 */

final class RequestedButton extends Instance {
	public function request(string $webapp_req_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf13bbcd7);
		$writer->writeBytes($webapp_req_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['webapp_req_id'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string name string about string description
 * @return bots.BotInfo
 */

final class BotInfo extends Instance {
	public function request(string $name,string $about,string $description) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe8a775b0);
		$writer->writeBytes($name);
		$writer->writeBytes($about);
		$writer->writeBytes($description);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['name'] = $reader->readBytes();
		$result['about'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer Vector<chat> chats Vector<user> users
 * @return contacts.ResolvedPeer
 */

final class ResolvedPeer extends Instance {
	public function request(object $peer,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7f077ad9);
		$writer->writeObject($peer);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<sponsoredpeer> peers Vector<chat> chats Vector<user> users
 * @return contacts.SponsoredPeers
 */

final class SponsoredPeers extends Instance {
	public function request(array $peers,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeb032884);
		$writer->writeVector($peers,'sponsoredpeer');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peers'] = $reader->readVector('sponsoredpeer');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<contact> contacts int saved_count Vector<user> users
 * @return contacts.Contacts
 */

final class Contacts extends Instance {
	public function request(array $contacts,int $saved_count,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeae87e42);
		$writer->writeVector($contacts,'contact');
		$writer->writeInt($saved_count);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['contacts'] = $reader->readVector('contact');
		$result['saved_count'] = $reader->readInt();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<importedcontact> imported Vector<popularcontact> popular_invites Vector<long> retry_contacts Vector<user> users
 * @return contacts.ImportedContacts
 */

final class ImportedContacts extends Instance {
	public function request(array $imported,array $popular_invites,array $retry_contacts,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x77d01c3b);
		$writer->writeVector($imported,'importedcontact');
		$writer->writeVector($popular_invites,'popularcontact');
		$writer->writeVector($retry_contacts,'long');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['imported'] = $reader->readVector('importedcontact');
		$result['popular_invites'] = $reader->readVector('popularcontact');
		$result['retry_contacts'] = $reader->readVector('long');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return contacts.Contacts
 */

final class ContactsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb74ba9d2);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<peerblocked> blocked Vector<chat> chats Vector<user> users
 * @return contacts.Blocked
 */

final class Blocked extends Instance {
	public function request(array $blocked,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xade1591);
		$writer->writeVector($blocked,'peerblocked');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['blocked'] = $reader->readVector('peerblocked');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return contacts.TopPeers
 */

final class TopPeersNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xde266ef5);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<toppeercategorypeers> categories Vector<chat> chats Vector<user> users
 * @return contacts.TopPeers
 */

final class TopPeers extends Instance {
	public function request(array $categories,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x70b772a8);
		$writer->writeVector($categories,'toppeercategorypeers');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['categories'] = $reader->readVector('toppeercategorypeers');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return contacts.TopPeers
 */

final class TopPeersDisabled extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb52c939d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<contactbirthday> contacts Vector<user> users
 * @return contacts.ContactBirthdays
 */

final class ContactBirthdays extends Instance {
	public function request(array $contacts,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x114ff30d);
		$writer->writeVector($contacts,'contactbirthday');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['contacts'] = $reader->readVector('contactbirthday');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<peer> my_results Vector<peer> results Vector<chat> chats Vector<user> users
 * @return contacts.Found
 */

final class Found extends Instance {
	public function request(array $my_results,array $results,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb3134d9d);
		$writer->writeVector($my_results,'peer');
		$writer->writeVector($results,'peer');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['my_results'] = $reader->readVector('peer');
		$result['results'] = $reader->readVector('peer');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return contacts.SponsoredPeers
 */

final class SponsoredPeersEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xea32b4b1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<peerblocked> blocked Vector<chat> chats Vector<user> users
 * @return contacts.Blocked
 */

final class BlockedSlice extends Instance {
	public function request(int $count,array $blocked,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe1664194);
		$writer->writeInt($count);
		$writer->writeVector($blocked,'peerblocked');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['blocked'] = $reader->readVector('peerblocked');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<document> documents
 * @return users.SavedMusic
 */

final class SavedMusic extends Instance {
	public function request(int $count,array $documents) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x34a2f297);
		$writer->writeInt($count);
		$writer->writeVector($documents,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['documents'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count
 * @return users.SavedMusic
 */

final class SavedMusicNotModified extends Instance {
	public function request(int $count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe3878aa4);
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<user> users
 * @return users.Users
 */

final class Users extends Instance {
	public function request(array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x62d706b8);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<user> users
 * @return users.Users
 */

final class UsersSlice extends Instance {
	public function request(int $count,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x315a4974);
		$writer->writeInt($count);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param userfull full_user Vector<chat> chats Vector<user> users
 * @return users.UserFull
 */

final class UserFull extends Instance {
	public function request(object $full_user,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3b6d152e);
		$writer->writeObject($full_user);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['full_user'] = $reader->readObject();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return payments.StarsRevenueAdsAccountUrl
 */

final class StarsRevenueAdsAccountUrl extends Instance {
	public function request(string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x394e7f21);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return payments.CheckCanSendGiftResult
 */

final class CheckCanSendGiftResultOk extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x374fa7ad);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stargift gift Vector<chat> chats Vector<user> users
 * @return payments.UniqueStarGift
 */

final class UniqueStarGift extends Instance {
	public function request(object $gift,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x416c56e8);
		$writer->writeObject($gift);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['gift'] = $reader->readObject();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<stargiftcollection> collections
 * @return payments.StarGiftCollections
 */

final class StarGiftCollections extends Instance {
	public function request(array $collections) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8a2932f3);
		$writer->writeVector($collections,'stargiftcollection');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['collections'] = $reader->readVector('stargiftcollection');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string currency long value int initial_sale_date long initial_sale_stars long initial_sale_price true last_sale_on_fragment true value_is_average int last_sale_date long last_sale_price long floor_price long average_price int listed_count int fragment_listed_count string fragment_listed_url
 * @return payments.UniqueStarGiftValueInfo
 */

final class UniqueStarGiftValueInfo extends Instance {
	public function request(string $currency,int $value,int $initial_sale_date,int $initial_sale_stars,int $initial_sale_price,null | bool $last_sale_on_fragment = null,null | bool $value_is_average = null,null | int $last_sale_date = null,null | int $last_sale_price = null,null | int $floor_price = null,null | int $average_price = null,null | int $listed_count = null,null | int $fragment_listed_count = null,null | string $fragment_listed_url = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x512fe446);
		$flags = 0;
		$flags |= $last_sale_on_fragment ? (1 << 1) : 0;
		$flags |= $value_is_average ? (1 << 6) : 0;
		$flags |= is_null($last_sale_date) ? 0 : (1 << 0);
		$flags |= is_null($last_sale_price) ? 0 : (1 << 0);
		$flags |= is_null($floor_price) ? 0 : (1 << 2);
		$flags |= is_null($average_price) ? 0 : (1 << 3);
		$flags |= is_null($listed_count) ? 0 : (1 << 4);
		$flags |= is_null($fragment_listed_count) ? 0 : (1 << 5);
		$flags |= is_null($fragment_listed_url) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeBytes($currency);
		$writer->writeLong($value);
		$writer->writeInt($initial_sale_date);
		$writer->writeLong($initial_sale_stars);
		$writer->writeLong($initial_sale_price);
		if(is_null($last_sale_date) === false):
			$writer->writeInt($last_sale_date);
		endif;
		if(is_null($last_sale_price) === false):
			$writer->writeLong($last_sale_price);
		endif;
		if(is_null($floor_price) === false):
			$writer->writeLong($floor_price);
		endif;
		if(is_null($average_price) === false):
			$writer->writeLong($average_price);
		endif;
		if(is_null($listed_count) === false):
			$writer->writeInt($listed_count);
		endif;
		if(is_null($fragment_listed_count) === false):
			$writer->writeInt($fragment_listed_count);
		endif;
		if(is_null($fragment_listed_url) === false):
			$writer->writeBytes($fragment_listed_url);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['last_sale_on_fragment'] = boolval($flags & (1 << 1));
		$result['value_is_average'] = boolval($flags & (1 << 6));
		$result['currency'] = $reader->readBytes();
		$result['value'] = $reader->readLong();
		$result['initial_sale_date'] = $reader->readInt();
		$result['initial_sale_stars'] = $reader->readLong();
		$result['initial_sale_price'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['last_sale_date'] = $reader->readInt();
		else:
			$result['last_sale_date'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['last_sale_price'] = $reader->readLong();
		else:
			$result['last_sale_price'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['floor_price'] = $reader->readLong();
		else:
			$result['floor_price'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['average_price'] = $reader->readLong();
		else:
			$result['average_price'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['listed_count'] = $reader->readInt();
		else:
			$result['listed_count'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['fragment_listed_count'] = $reader->readInt();
		else:
			$result['fragment_listed_count'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['fragment_listed_url'] = $reader->readBytes();
		else:
			$result['fragment_listed_url'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date long bot_id long provider_id string title string description invoice invoice string currency long total_amount string credentials_title Vector<user> users webdocument photo paymentrequestedinfo info shippingoption shipping long tip_amount
 * @return payments.PaymentReceipt
 */

final class PaymentReceipt extends Instance {
	public function request(int $date,int $bot_id,int $provider_id,string $title,string $description,object $invoice,string $currency,int $total_amount,string $credentials_title,array $users,null | object $photo = null,null | object $info = null,null | object $shipping = null,null | int $tip_amount = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x70c4fe03);
		$flags = 0;
		$flags |= is_null($photo) ? 0 : (1 << 2);
		$flags |= is_null($info) ? 0 : (1 << 0);
		$flags |= is_null($shipping) ? 0 : (1 << 1);
		$flags |= is_null($tip_amount) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeInt($date);
		$writer->writeLong($bot_id);
		$writer->writeLong($provider_id);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		$writer->writeObject($invoice);
		if(is_null($info) === false):
			$writer->writeObject($info);
		endif;
		if(is_null($shipping) === false):
			$writer->writeObject($shipping);
		endif;
		if(is_null($tip_amount) === false):
			$writer->writeLong($tip_amount);
		endif;
		$writer->writeBytes($currency);
		$writer->writeLong($total_amount);
		$writer->writeBytes($credentials_title);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['bot_id'] = $reader->readLong();
		$result['provider_id'] = $reader->readLong();
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		$result['invoice'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['info'] = $reader->readObject();
		else:
			$result['info'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['shipping'] = $reader->readObject();
		else:
			$result['shipping'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['tip_amount'] = $reader->readLong();
		else:
			$result['tip_amount'] = null;
		endif;
		$result['currency'] = $reader->readBytes();
		$result['total_amount'] = $reader->readLong();
		$result['credentials_title'] = $reader->readBytes();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param statsgraph revenue_graph starsrevenuestatus status double usd_rate statsgraph top_hours_graph
 * @return payments.StarsRevenueStats
 */

final class StarsRevenueStats extends Instance {
	public function request(object $revenue_graph,object $status,float $usd_rate,null | object $top_hours_graph = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c207376);
		$flags = 0;
		$flags |= is_null($top_hours_graph) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($top_hours_graph) === false):
			$writer->writeObject($top_hours_graph);
		endif;
		$writer->writeObject($revenue_graph);
		$writer->writeObject($status);
		$writer->writeDouble($usd_rate);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['top_hours_graph'] = $reader->readObject();
		else:
			$result['top_hours_graph'] = null;
		endif;
		$result['revenue_graph'] = $reader->readObject();
		$result['status'] = $reader->readObject();
		$result['usd_rate'] = $reader->readDouble();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long form_id long bot_id string title string description invoice invoice long provider_id string url Vector<user> users true can_save_credentials true password_missing webdocument photo string native_provider datajson native_params Vector<paymentformmethod> additional_methods paymentrequestedinfo saved_info Vector<paymentsavedcredentials> saved_credentials
 * @return payments.PaymentForm
 */

final class PaymentForm extends Instance {
	public function request(int $form_id,int $bot_id,string $title,string $description,object $invoice,int $provider_id,string $url,array $users,null | bool $can_save_credentials = null,null | bool $password_missing = null,null | object $photo = null,null | string $native_provider = null,null | object $native_params = null,null | array $additional_methods = null,null | object $saved_info = null,null | array $saved_credentials = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa0058751);
		$flags = 0;
		$flags |= $can_save_credentials ? (1 << 2) : 0;
		$flags |= $password_missing ? (1 << 3) : 0;
		$flags |= is_null($photo) ? 0 : (1 << 5);
		$flags |= is_null($native_provider) ? 0 : (1 << 4);
		$flags |= is_null($native_params) ? 0 : (1 << 4);
		$flags |= is_null($additional_methods) ? 0 : (1 << 6);
		$flags |= is_null($saved_info) ? 0 : (1 << 0);
		$flags |= is_null($saved_credentials) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($form_id);
		$writer->writeLong($bot_id);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		$writer->writeObject($invoice);
		$writer->writeLong($provider_id);
		$writer->writeBytes($url);
		if(is_null($native_provider) === false):
			$writer->writeBytes($native_provider);
		endif;
		if(is_null($native_params) === false):
			$writer->writeObject($native_params);
		endif;
		if(is_null($additional_methods) === false):
			$writer->writeVector($additional_methods,'paymentformmethod');
		endif;
		if(is_null($saved_info) === false):
			$writer->writeObject($saved_info);
		endif;
		if(is_null($saved_credentials) === false):
			$writer->writeVector($saved_credentials,'paymentsavedcredentials');
		endif;
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['can_save_credentials'] = boolval($flags & (1 << 2));
		$result['password_missing'] = boolval($flags & (1 << 3));
		$result['form_id'] = $reader->readLong();
		$result['bot_id'] = $reader->readLong();
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		if($flags & (1 << 5)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		$result['invoice'] = $reader->readObject();
		$result['provider_id'] = $reader->readLong();
		$result['url'] = $reader->readBytes();
		if($flags & (1 << 4)):
			$result['native_provider'] = $reader->readBytes();
		else:
			$result['native_provider'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['native_params'] = $reader->readObject();
		else:
			$result['native_params'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['additional_methods'] = $reader->readVector('paymentformmethod');
		else:
			$result['additional_methods'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['saved_info'] = $reader->readObject();
		else:
			$result['saved_info'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['saved_credentials'] = $reader->readVector('paymentsavedcredentials');
		else:
			$result['saved_credentials'] = null;
		endif;
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true has_saved_credentials paymentrequestedinfo saved_info
 * @return payments.SavedInfo
 */

final class SavedInfo extends Instance {
	public function request(null | bool $has_saved_credentials = null,null | object $saved_info = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfb8fe43c);
		$flags = 0;
		$flags |= $has_saved_credentials ? (1 << 1) : 0;
		$flags |= is_null($saved_info) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($saved_info) === false):
			$writer->writeObject($saved_info);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['has_saved_credentials'] = boolval($flags & (1 << 1));
		if($flags & (1 << 0)):
			$result['saved_info'] = $reader->readObject();
		else:
			$result['saved_info'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return payments.StarGiftActiveAuctions
 */

final class StarGiftActiveAuctionsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdb33dad0);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<stargiftattribute> attributes
 * @return payments.StarGiftUpgradeAttributes
 */

final class StarGiftUpgradeAttributes extends Instance {
	public function request(array $attributes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x46c6e36f);
		$writer->writeVector($attributes,'stargiftattribute');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['attributes'] = $reader->readVector('stargiftattribute');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return payments.ExportedInvoice
 */

final class ExportedInvoice extends Instance {
	public function request(string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaed0cbd9);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date long bot_id string title string description invoice invoice string currency long total_amount string transaction_id Vector<user> users webdocument photo
 * @return payments.PaymentReceipt
 */

final class PaymentReceiptStars extends Instance {
	public function request(int $date,int $bot_id,string $title,string $description,object $invoice,string $currency,int $total_amount,string $transaction_id,array $users,null | object $photo = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdabbf83a);
		$flags = 0;
		$flags |= is_null($photo) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeInt($date);
		$writer->writeLong($bot_id);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		$writer->writeObject($invoice);
		$writer->writeBytes($currency);
		$writer->writeLong($total_amount);
		$writer->writeBytes($transaction_id);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['bot_id'] = $reader->readLong();
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		$result['invoice'] = $reader->readObject();
		$result['currency'] = $reader->readBytes();
		$result['total_amount'] = $reader->readLong();
		$result['transaction_id'] = $reader->readBytes();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return payments.StarsRevenueWithdrawalUrl
 */

final class StarsRevenueWithdrawalUrl extends Instance {
	public function request(string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1dab80b7);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stargift gift stargiftauctionstate state stargiftauctionuserstate user_state int timeout Vector<user> users Vector<chat> chats
 * @return payments.StarGiftAuctionState
 */

final class StarGiftAuctionState extends Instance {
	public function request(object $gift,object $state,object $user_state,int $timeout,array $users,array $chats) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6b39f4ec);
		$writer->writeObject($gift);
		$writer->writeObject($state);
		$writer->writeObject($user_state);
		$writer->writeInt($timeout);
		$writer->writeVector($users,'user');
		$writer->writeVector($chats,'chat');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['gift'] = $reader->readObject();
		$result['state'] = $reader->readObject();
		$result['user_state'] = $reader->readObject();
		$result['timeout'] = $reader->readInt();
		$result['users'] = $reader->readVector('user');
		$result['chats'] = $reader->readVector('chat');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param textwithentities reason
 * @return payments.CheckCanSendGiftResult
 */

final class CheckCanSendGiftResultFail extends Instance {
	public function request(object $reason) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd5e58274);
		$writer->writeObject($reason);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['reason'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<stargiftauctionacquiredgift> gifts Vector<user> users Vector<chat> chats
 * @return payments.StarGiftAuctionAcquiredGifts
 */

final class StarGiftAuctionAcquiredGifts extends Instance {
	public function request(array $gifts,array $users,array $chats) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7d5bd1f0);
		$writer->writeVector($gifts,'stargiftauctionacquiredgift');
		$writer->writeVector($users,'user');
		$writer->writeVector($chats,'chat');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['gifts'] = $reader->readVector('stargiftauctionacquiredgift');
		$result['users'] = $reader->readVector('user');
		$result['chats'] = $reader->readVector('chat');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id Vector<shippingoption> shipping_options
 * @return payments.ValidatedRequestedInfo
 */

final class ValidatedRequestedInfo extends Instance {
	public function request(null | string $id = null,null | array $shipping_options = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd1451883);
		$flags = 0;
		$flags |= is_null($id) ? 0 : (1 << 0);
		$flags |= is_null($shipping_options) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($id) === false):
			$writer->writeBytes($id);
		endif;
		if(is_null($shipping_options) === false):
			$writer->writeVector($shipping_options,'shippingoption');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['id'] = $reader->readBytes();
		else:
			$result['id'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['shipping_options'] = $reader->readVector('shippingoption');
		else:
			$result['shipping_options'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param starsamount balance Vector<chat> chats Vector<user> users Vector<starssubscription> subscriptions string subscriptions_next_offset long subscriptions_missing_balance Vector<starstransaction> history string next_offset
 * @return payments.StarsStatus
 */

final class StarsStatus extends Instance {
	public function request(object $balance,array $chats,array $users,null | array $subscriptions = null,null | string $subscriptions_next_offset = null,null | int $subscriptions_missing_balance = null,null | array $history = null,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c9ce8ed);
		$flags = 0;
		$flags |= is_null($subscriptions) ? 0 : (1 << 1);
		$flags |= is_null($subscriptions_next_offset) ? 0 : (1 << 2);
		$flags |= is_null($subscriptions_missing_balance) ? 0 : (1 << 4);
		$flags |= is_null($history) ? 0 : (1 << 3);
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($balance);
		if(is_null($subscriptions) === false):
			$writer->writeVector($subscriptions,'starssubscription');
		endif;
		if(is_null($subscriptions_next_offset) === false):
			$writer->writeBytes($subscriptions_next_offset);
		endif;
		if(is_null($subscriptions_missing_balance) === false):
			$writer->writeLong($subscriptions_missing_balance);
		endif;
		if(is_null($history) === false):
			$writer->writeVector($history,'starstransaction');
		endif;
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['balance'] = $reader->readObject();
		if($flags & (1 << 1)):
			$result['subscriptions'] = $reader->readVector('starssubscription');
		else:
			$result['subscriptions'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['subscriptions_next_offset'] = $reader->readBytes();
		else:
			$result['subscriptions_next_offset'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['subscriptions_missing_balance'] = $reader->readLong();
		else:
			$result['subscriptions_missing_balance'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['history'] = $reader->readVector('starstransaction');
		else:
			$result['history'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash Vector<stargift> gifts Vector<chat> chats Vector<user> users
 * @return payments.StarGifts
 */

final class StarGifts extends Instance {
	public function request(int $hash,array $gifts,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2ed82995);
		$writer->writeInt($hash);
		$writer->writeVector($gifts,'stargift');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readInt();
		$result['gifts'] = $reader->readVector('stargift');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return payments.StarGiftWithdrawalUrl
 */

final class StarGiftWithdrawalUrl extends Instance {
	public function request(string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x84aa3a9c);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<stargift> gifts Vector<chat> chats Vector<user> users string next_offset Vector<stargiftattribute> attributes long attributes_hash Vector<stargiftattributecounter> counters
 * @return payments.ResaleStarGifts
 */

final class ResaleStarGifts extends Instance {
	public function request(int $count,array $gifts,array $chats,array $users,null | string $next_offset = null,null | array $attributes = null,null | int $attributes_hash = null,null | array $counters = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x947a12df);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$flags |= is_null($attributes) ? 0 : (1 << 1);
		$flags |= is_null($attributes_hash) ? 0 : (1 << 1);
		$flags |= is_null($counters) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeVector($gifts,'stargift');
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		if(is_null($attributes) === false):
			$writer->writeVector($attributes,'stargiftattribute');
		endif;
		if(is_null($attributes_hash) === false):
			$writer->writeLong($attributes_hash);
		endif;
		$writer->writeVector($chats,'chat');
		if(is_null($counters) === false):
			$writer->writeVector($counters,'stargiftattributecounter');
		endif;
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['count'] = $reader->readInt();
		$result['gifts'] = $reader->readVector('stargift');
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['attributes'] = $reader->readVector('stargiftattribute');
		else:
			$result['attributes'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['attributes_hash'] = $reader->readLong();
		else:
			$result['attributes_hash'] = null;
		endif;
		$result['chats'] = $reader->readVector('chat');
		if($flags & (1 << 2)):
			$result['counters'] = $reader->readVector('stargiftattributecounter');
		else:
			$result['counters'] = null;
		endif;
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<connectedbotstarref> connected_bots Vector<user> users
 * @return payments.ConnectedStarRefBots
 */

final class ConnectedStarRefBots extends Instance {
	public function request(int $count,array $connected_bots,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x98d5ea1d);
		$writer->writeInt($count);
		$writer->writeVector($connected_bots,'connectedbotstarref');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['connected_bots'] = $reader->readVector('connectedbotstarref');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<starrefprogram> suggested_bots Vector<user> users string next_offset
 * @return payments.SuggestedStarRefBots
 */

final class SuggestedStarRefBots extends Instance {
	public function request(int $count,array $suggested_bots,array $users,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb4d5d859);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeVector($suggested_bots,'starrefprogram');
		$writer->writeVector($users,'user');
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['count'] = $reader->readInt();
		$result['suggested_bots'] = $reader->readVector('starrefprogram');
		$result['users'] = $reader->readVector('user');
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title Vector<bankcardopenurl> open_urls
 * @return payments.BankCardData
 */

final class BankCardData extends Instance {
	public function request(string $title,array $open_urls) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e24e573);
		$writer->writeBytes($title);
		$writer->writeVector($open_urls,'bankcardopenurl');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readBytes();
		$result['open_urls'] = $reader->readVector('bankcardopenurl');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<stargiftattribute> sample_attributes Vector<stargiftupgradeprice> prices Vector<stargiftupgradeprice> next_prices
 * @return payments.StarGiftUpgradePreview
 */

final class StarGiftUpgradePreview extends Instance {
	public function request(array $sample_attributes,array $prices,array $next_prices) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3de1dfed);
		$writer->writeVector($sample_attributes,'stargiftattribute');
		$writer->writeVector($prices,'stargiftupgradeprice');
		$writer->writeVector($next_prices,'stargiftupgradeprice');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['sample_attributes'] = $reader->readVector('stargiftattribute');
		$result['prices'] = $reader->readVector('stargiftupgradeprice');
		$result['next_prices'] = $reader->readVector('stargiftupgradeprice');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int start_date int finish_date int winners_count true winner true refunded string gift_code_slug long stars_prize int activated_count
 * @return payments.GiveawayInfo
 */

final class GiveawayInfoResults extends Instance {
	public function request(int $start_date,int $finish_date,int $winners_count,null | bool $winner = null,null | bool $refunded = null,null | string $gift_code_slug = null,null | int $stars_prize = null,null | int $activated_count = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe175e66f);
		$flags = 0;
		$flags |= $winner ? (1 << 0) : 0;
		$flags |= $refunded ? (1 << 1) : 0;
		$flags |= is_null($gift_code_slug) ? 0 : (1 << 3);
		$flags |= is_null($stars_prize) ? 0 : (1 << 4);
		$flags |= is_null($activated_count) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeInt($start_date);
		if(is_null($gift_code_slug) === false):
			$writer->writeBytes($gift_code_slug);
		endif;
		if(is_null($stars_prize) === false):
			$writer->writeLong($stars_prize);
		endif;
		$writer->writeInt($finish_date);
		$writer->writeInt($winners_count);
		if(is_null($activated_count) === false):
			$writer->writeInt($activated_count);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['winner'] = boolval($flags & (1 << 0));
		$result['refunded'] = boolval($flags & (1 << 1));
		$result['start_date'] = $reader->readInt();
		if($flags & (1 << 3)):
			$result['gift_code_slug'] = $reader->readBytes();
		else:
			$result['gift_code_slug'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['stars_prize'] = $reader->readLong();
		else:
			$result['stars_prize'] = null;
		endif;
		$result['finish_date'] = $reader->readInt();
		$result['winners_count'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['activated_count'] = $reader->readInt();
		else:
			$result['activated_count'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int start_date true participating true preparing_results int joined_too_early_date long admin_disallowed_chat_id string disallowed_country
 * @return payments.GiveawayInfo
 */

final class GiveawayInfo extends Instance {
	public function request(int $start_date,null | bool $participating = null,null | bool $preparing_results = null,null | int $joined_too_early_date = null,null | int $admin_disallowed_chat_id = null,null | string $disallowed_country = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4367daa0);
		$flags = 0;
		$flags |= $participating ? (1 << 0) : 0;
		$flags |= $preparing_results ? (1 << 3) : 0;
		$flags |= is_null($joined_too_early_date) ? 0 : (1 << 1);
		$flags |= is_null($admin_disallowed_chat_id) ? 0 : (1 << 2);
		$flags |= is_null($disallowed_country) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeInt($start_date);
		if(is_null($joined_too_early_date) === false):
			$writer->writeInt($joined_too_early_date);
		endif;
		if(is_null($admin_disallowed_chat_id) === false):
			$writer->writeLong($admin_disallowed_chat_id);
		endif;
		if(is_null($disallowed_country) === false):
			$writer->writeBytes($disallowed_country);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['participating'] = boolval($flags & (1 << 0));
		$result['preparing_results'] = boolval($flags & (1 << 3));
		$result['start_date'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['joined_too_early_date'] = $reader->readInt();
		else:
			$result['joined_too_early_date'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['admin_disallowed_chat_id'] = $reader->readLong();
		else:
			$result['admin_disallowed_chat_id'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['disallowed_country'] = $reader->readBytes();
		else:
			$result['disallowed_country'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<stargiftactiveauctionstate> auctions Vector<user> users Vector<chat> chats
 * @return payments.StarGiftActiveAuctions
 */

final class StarGiftActiveAuctions extends Instance {
	public function request(array $auctions,array $users,array $chats) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaef6abbc);
		$writer->writeVector($auctions,'stargiftactiveauctionstate');
		$writer->writeVector($users,'user');
		$writer->writeVector($chats,'chat');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['auctions'] = $reader->readVector('stargiftactiveauctionstate');
		$result['users'] = $reader->readVector('user');
		$result['chats'] = $reader->readVector('chat');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long form_id invoice invoice
 * @return payments.PaymentForm
 */

final class PaymentFormStarGift extends Instance {
	public function request(int $form_id,object $invoice) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb425cfe1);
		$writer->writeLong($form_id);
		$writer->writeObject($invoice);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['form_id'] = $reader->readLong();
		$result['invoice'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<savedstargift> gifts Vector<chat> chats Vector<user> users bool chat_notifications_enabled string next_offset
 * @return payments.SavedStarGifts
 */

final class SavedStarGifts extends Instance {
	public function request(int $count,array $gifts,array $chats,array $users,null | bool $chat_notifications_enabled = null,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x95f389b1);
		$flags = 0;
		$flags |= is_null($chat_notifications_enabled) ? 0 : (1 << 1);
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		if(is_null($chat_notifications_enabled) === false):
			$writer->writeBool($chat_notifications_enabled);
		endif;
		$writer->writeVector($gifts,'savedstargift');
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['count'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['chat_notifications_enabled'] = $reader->readBool();
		else:
			$result['chat_notifications_enabled'] = null;
		endif;
		$result['gifts'] = $reader->readVector('savedstargift');
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return payments.StarGiftCollections
 */

final class StarGiftCollectionsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa0ba4f17);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long form_id long bot_id string title string description invoice invoice Vector<user> users webdocument photo
 * @return payments.PaymentForm
 */

final class PaymentFormStars extends Instance {
	public function request(int $form_id,int $bot_id,string $title,string $description,object $invoice,array $users,null | object $photo = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7bf6b15c);
		$flags = 0;
		$flags |= is_null($photo) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeLong($form_id);
		$writer->writeLong($bot_id);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		$writer->writeObject($invoice);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['form_id'] = $reader->readLong();
		$result['bot_id'] = $reader->readLong();
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		if($flags & (1 << 5)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		$result['invoice'] = $reader->readObject();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date int days Vector<chat> chats Vector<user> users true via_giveaway peer from_id int giveaway_msg_id long to_id int used_date
 * @return payments.CheckedGiftCode
 */

final class CheckedGiftCode extends Instance {
	public function request(int $date,int $days,array $chats,array $users,null | bool $via_giveaway = null,null | object $from_id = null,null | int $giveaway_msg_id = null,null | int $to_id = null,null | int $used_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeb983f8f);
		$flags = 0;
		$flags |= $via_giveaway ? (1 << 2) : 0;
		$flags |= is_null($from_id) ? 0 : (1 << 4);
		$flags |= is_null($giveaway_msg_id) ? 0 : (1 << 3);
		$flags |= is_null($to_id) ? 0 : (1 << 0);
		$flags |= is_null($used_date) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($from_id) === false):
			$writer->writeObject($from_id);
		endif;
		if(is_null($giveaway_msg_id) === false):
			$writer->writeInt($giveaway_msg_id);
		endif;
		if(is_null($to_id) === false):
			$writer->writeLong($to_id);
		endif;
		$writer->writeInt($date);
		$writer->writeInt($days);
		if(is_null($used_date) === false):
			$writer->writeInt($used_date);
		endif;
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['via_giveaway'] = boolval($flags & (1 << 2));
		if($flags & (1 << 4)):
			$result['from_id'] = $reader->readObject();
		else:
			$result['from_id'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['giveaway_msg_id'] = $reader->readInt();
		else:
			$result['giveaway_msg_id'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['to_id'] = $reader->readLong();
		else:
			$result['to_id'] = null;
		endif;
		$result['date'] = $reader->readInt();
		$result['days'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['used_date'] = $reader->readInt();
		else:
			$result['used_date'] = null;
		endif;
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return payments.PaymentResult
 */

final class PaymentVerificationNeeded extends Instance {
	public function request(string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd8411139);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param updates updates
 * @return payments.PaymentResult
 */

final class PaymentResult extends Instance {
	public function request(object $updates) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4e5f810d);
		$writer->writeObject($updates);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['updates'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return payments.StarGifts
 */

final class StarGiftsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa388a368);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<document> ringtones
 * @return account.SavedRingtones
 */

final class SavedRingtones extends Instance {
	public function request(int $hash,array $ringtones) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc1e92cc5);
		$writer->writeLong($hash);
		$writer->writeVector($ringtones,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['ringtones'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true sensitive_enabled true sensitive_can_change
 * @return account.ContentSettings
 */

final class ContentSettings extends Instance {
	public function request(null | bool $sensitive_enabled = null,null | bool $sensitive_can_change = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x57e28221);
		$flags = 0;
		$flags |= $sensitive_enabled ? (1 << 0) : 0;
		$flags |= $sensitive_can_change ? (1 << 1) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['sensitive_enabled'] = boolval($flags & (1 << 0));
		$result['sensitive_can_change'] = boolval($flags & (1 << 1));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<webdomainexception> external_exceptions Vector<webdomainexception> inapp_exceptions long hash true open_external_browser true display_close_button
 * @return account.WebBrowserSettings
 */

final class WebBrowserSettings extends Instance {
	public function request(array $external_exceptions,array $inapp_exceptions,int $hash,null | bool $open_external_browser = null,null | bool $display_close_button = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x79eb8cb3);
		$flags = 0;
		$flags |= $open_external_browser ? (1 << 0) : 0;
		$flags |= $display_close_button ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($external_exceptions,'webdomainexception');
		$writer->writeVector($inapp_exceptions,'webdomainexception');
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['open_external_browser'] = boolval($flags & (1 << 0));
		$result['display_close_button'] = boolval($flags & (1 << 1));
		$result['external_exceptions'] = $reader->readVector('webdomainexception');
		$result['inapp_exceptions'] = $reader->readVector('webdomainexception');
		$result['hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string email auth.sentcode sent_code
 * @return account.EmailVerified
 */

final class EmailVerifiedLogin extends Instance {
	public function request(string $email,object $sent_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe1bb0d61);
		$writer->writeBytes($email);
		$writer->writeObject($sent_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['email'] = $reader->readBytes();
		$result['sent_code'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.SavedRingtones
 */

final class SavedRingtonesNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfbf6e8b1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<theme> themes
 * @return account.Themes
 */

final class Themes extends Instance {
	public function request(int $hash,array $themes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9a3d8c6d);
		$writer->writeLong($hash);
		$writer->writeVector($themes,'theme');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['themes'] = $reader->readVector('theme');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.Themes
 */

final class ThemesNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf41eb622);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<securerequiredtype> required_types Vector<securevalue> values Vector<securevalueerror> errors Vector<user> users string privacy_policy_url
 * @return account.AuthorizationForm
 */

final class AuthorizationForm extends Instance {
	public function request(array $required_types,array $values,array $errors,array $users,null | string $privacy_policy_url = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xad2e1cd8);
		$flags = 0;
		$flags |= is_null($privacy_policy_url) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeVector($required_types,'securerequiredtype');
		$writer->writeVector($values,'securevalue');
		$writer->writeVector($errors,'securevalueerror');
		$writer->writeVector($users,'user');
		if(is_null($privacy_policy_url) === false):
			$writer->writeBytes($privacy_policy_url);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['required_types'] = $reader->readVector('securerequiredtype');
		$result['values'] = $reader->readVector('securevalue');
		$result['errors'] = $reader->readVector('securevalueerror');
		$result['users'] = $reader->readVector('user');
		if($flags & (1 << 0)):
			$result['privacy_policy_url'] = $reader->readBytes();
		else:
			$result['privacy_policy_url'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.ChatThemes
 */

final class ChatThemesNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe011e1c4);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param autodownloadsettings low autodownloadsettings medium autodownloadsettings high
 * @return account.AutoDownloadSettings
 */

final class AutoDownloadSettings extends Instance {
	public function request(object $low,object $medium,object $high) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x63cacf26);
		$writer->writeObject($low);
		$writer->writeObject($medium);
		$writer->writeObject($high);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['low'] = $reader->readObject();
		$result['medium'] = $reader->readObject();
		$result['high'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.SavedMusicIds
 */

final class SavedMusicIdsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4fc81d6e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<passkey> passkeys
 * @return account.Passkeys
 */

final class Passkeys extends Instance {
	public function request(array $passkeys) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf8e0aa1c);
		$writer->writeVector($passkeys,'passkey');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['passkeys'] = $reader->readVector('passkey');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string email_pattern int length
 * @return account.SentEmailCode
 */

final class SentEmailCode extends Instance {
	public function request(string $email_pattern,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x811f854f);
		$writer->writeBytes($email_pattern);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['email_pattern'] = $reader->readBytes();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.SavedRingtone
 */

final class SavedRingtone extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb7263f6d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<emojistatus> statuses
 * @return account.EmojiStatuses
 */

final class EmojiStatuses extends Instance {
	public function request(int $hash,array $statuses) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x90c467d1);
		$writer->writeLong($hash);
		$writer->writeVector($statuses,'emojistatus');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['statuses'] = $reader->readVector('emojistatus');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int retry_date
 * @return account.ResetPasswordResult
 */

final class ResetPasswordFailedWait extends Instance {
	public function request(int $retry_date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe3779861);
		$writer->writeInt($retry_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['retry_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.WallPapers
 */

final class WallPapersNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1c199183);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param autosavesettings users_settings autosavesettings chats_settings autosavesettings broadcasts_settings Vector<autosaveexception> exceptions Vector<chat> chats Vector<user> users
 * @return account.AutoSaveSettings
 */

final class AutoSaveSettings extends Instance {
	public function request(object $users_settings,object $chats_settings,object $broadcasts_settings,array $exceptions,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4c3e069d);
		$writer->writeObject($users_settings);
		$writer->writeObject($chats_settings);
		$writer->writeObject($broadcasts_settings);
		$writer->writeVector($exceptions,'autosaveexception');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['users_settings'] = $reader->readObject();
		$result['chats_settings'] = $reader->readObject();
		$result['broadcasts_settings'] = $reader->readObject();
		$result['exceptions'] = $reader->readVector('autosaveexception');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> ids
 * @return account.SavedMusicIds
 */

final class SavedMusicIds extends Instance {
	public function request(array $ids) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x998d6636);
		$writer->writeVector($ids,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['ids'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<connectedbot> connected_bots Vector<user> users
 * @return account.ConnectedBots
 */

final class ConnectedBots extends Instance {
	public function request(array $connected_bots,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x17d7f87b);
		$writer->writeVector($connected_bots,'connectedbot');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['connected_bots'] = $reader->readVector('connectedbot');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string email securesecretsettings secure_settings
 * @return account.PasswordSettings
 */

final class PasswordSettings extends Instance {
	public function request(null | string $email = null,null | object $secure_settings = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9a5c33e5);
		$flags = 0;
		$flags |= is_null($email) ? 0 : (1 << 0);
		$flags |= is_null($secure_settings) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($email) === false):
			$writer->writeBytes($email);
		endif;
		if(is_null($secure_settings) === false):
			$writer->writeObject($secure_settings);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['email'] = $reader->readBytes();
		else:
			$result['email'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['secure_settings'] = $reader->readObject();
		else:
			$result['secure_settings'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<privacyrule> rules Vector<chat> chats Vector<user> users
 * @return account.PrivacyRules
 */

final class PrivacyRules extends Instance {
	public function request(array $rules,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x50a04e45);
		$writer->writeVector($rules,'privacyrule');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['rules'] = $reader->readVector('privacyrule');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer string message Vector<chat> chats Vector<user> users Vector<messageentity> entities
 * @return account.ResolvedBusinessChatLinks
 */

final class ResolvedBusinessChatLinks extends Instance {
	public function request(object $peer,string $message,array $chats,array $users,null | array $entities = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9a23af21);
		$flags = 0;
		$flags |= is_null($entities) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['peer'] = $reader->readObject();
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int until_date
 * @return account.ResetPasswordResult
 */

final class ResetPasswordRequestedWait extends Instance {
	public function request(int $until_date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe9effc7d);
		$writer->writeInt($until_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['until_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.EmojiStatuses
 */

final class EmojiStatusesNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd08ce645);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes tmp_password int valid_until
 * @return account.TmpPassword
 */

final class TmpPassword extends Instance {
	public function request(string $tmp_password,int $valid_until) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdb64fd34);
		$writer->writeBytes($tmp_password);
		$writer->writeInt($valid_until);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['tmp_password'] = $reader->readBytes();
		$result['valid_until'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string email
 * @return account.EmailVerified
 */

final class EmailVerified extends Instance {
	public function request(string $email) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2b96cd1b);
		$writer->writeBytes($email);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['email'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars_amount
 * @return account.PaidMessagesRevenue
 */

final class PaidMessagesRevenue extends Instance {
	public function request(int $stars_amount) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1e109708);
		$writer->writeLong($stars_amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['stars_amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<webauthorization> authorizations Vector<user> users
 * @return account.WebAuthorizations
 */

final class WebAuthorizations extends Instance {
	public function request(array $authorizations,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xed56c9fc);
		$writer->writeVector($authorizations,'webauthorization');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['authorizations'] = $reader->readVector('webauthorization');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson options
 * @return account.PasskeyRegistrationOptions
 */

final class PasskeyRegistrationOptions extends Instance {
	public function request(object $options) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe16b5ce1);
		$writer->writeObject($options);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['options'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<chattheme> themes Vector<chat> chats Vector<user> users string next_offset
 * @return account.ChatThemes
 */

final class ChatThemes extends Instance {
	public function request(int $hash,array $themes,array $chats,array $users,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbe098173);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($hash);
		$writer->writeVector($themes,'chattheme');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['hash'] = $reader->readLong();
		$result['themes'] = $reader->readVector('chattheme');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<wallpaper> wallpapers
 * @return account.WallPapers
 */

final class WallPapers extends Instance {
	public function request(int $hash,array $wallpapers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcdc3858c);
		$writer->writeLong($hash);
		$writer->writeVector($wallpapers,'wallpaper');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['wallpapers'] = $reader->readVector('wallpaper');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<businesschatlink> links Vector<chat> chats Vector<user> users
 * @return account.BusinessChatLinks
 */

final class BusinessChatLinks extends Instance {
	public function request(array $links,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xec43a2d1);
		$writer->writeVector($links,'businesschatlink');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['links'] = $reader->readVector('businesschatlink');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param passwordkdfalgo new_algo bytes new_password_hash string hint string email securesecretsettings new_secure_settings
 * @return account.PasswordInputSettings
 */

final class PasswordInputSettings extends Instance {
	public function request(null | object $new_algo = null,null | string $new_password_hash = null,null | string $hint = null,null | string $email = null,null | object $new_secure_settings = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc23727c9);
		$flags = 0;
		$flags |= is_null($new_algo) ? 0 : (1 << 0);
		$flags |= is_null($new_password_hash) ? 0 : (1 << 0);
		$flags |= is_null($hint) ? 0 : (1 << 0);
		$flags |= is_null($email) ? 0 : (1 << 1);
		$flags |= is_null($new_secure_settings) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($new_algo) === false):
			$writer->writeObject($new_algo);
		endif;
		if(is_null($new_password_hash) === false):
			$writer->writeBytes($new_password_hash);
		endif;
		if(is_null($hint) === false):
			$writer->writeBytes($hint);
		endif;
		if(is_null($email) === false):
			$writer->writeBytes($email);
		endif;
		if(is_null($new_secure_settings) === false):
			$writer->writeObject($new_secure_settings);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['new_algo'] = $reader->readObject();
		else:
			$result['new_algo'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['new_password_hash'] = $reader->readBytes();
		else:
			$result['new_password_hash'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['hint'] = $reader->readBytes();
		else:
			$result['hint'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['email'] = $reader->readBytes();
		else:
			$result['email'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['new_secure_settings'] = $reader->readObject();
		else:
			$result['new_secure_settings'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id
 * @return account.Takeout
 */

final class Takeout extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4dba4501);
		$writer->writeLong($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.WebBrowserSettings
 */

final class WebBrowserSettingsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc31c8f4e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int authorization_ttl_days Vector<authorization> authorizations
 * @return account.Authorizations
 */

final class Authorizations extends Instance {
	public function request(int $authorization_ttl_days,array $authorizations) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4bff8ea0);
		$writer->writeInt($authorization_ttl_days);
		$writer->writeVector($authorizations,'authorization');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['authorization_ttl_days'] = $reader->readInt();
		$result['authorizations'] = $reader->readVector('authorization');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param passwordkdfalgo new_algo securepasswordkdfalgo new_secure_algo bytes secure_random true has_recovery true has_secure_values true has_password passwordkdfalgo current_algo bytes srp_B long srp_id string hint string email_unconfirmed_pattern int pending_reset_date string login_email_pattern
 * @return account.Password
 */

final class Password extends Instance {
	public function request(object $new_algo,object $new_secure_algo,string $secure_random,null | bool $has_recovery = null,null | bool $has_secure_values = null,null | bool $has_password = null,null | object $current_algo = null,null | string $srp_B = null,null | int $srp_id = null,null | string $hint = null,null | string $email_unconfirmed_pattern = null,null | int $pending_reset_date = null,null | string $login_email_pattern = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x957b50fb);
		$flags = 0;
		$flags |= $has_recovery ? (1 << 0) : 0;
		$flags |= $has_secure_values ? (1 << 1) : 0;
		$flags |= $has_password ? (1 << 2) : 0;
		$flags |= is_null($current_algo) ? 0 : (1 << 2);
		$flags |= is_null($srp_B) ? 0 : (1 << 2);
		$flags |= is_null($srp_id) ? 0 : (1 << 2);
		$flags |= is_null($hint) ? 0 : (1 << 3);
		$flags |= is_null($email_unconfirmed_pattern) ? 0 : (1 << 4);
		$flags |= is_null($pending_reset_date) ? 0 : (1 << 5);
		$flags |= is_null($login_email_pattern) ? 0 : (1 << 6);
		$writer->writeInt($flags);
		if(is_null($current_algo) === false):
			$writer->writeObject($current_algo);
		endif;
		if(is_null($srp_B) === false):
			$writer->writeBytes($srp_B);
		endif;
		if(is_null($srp_id) === false):
			$writer->writeLong($srp_id);
		endif;
		if(is_null($hint) === false):
			$writer->writeBytes($hint);
		endif;
		if(is_null($email_unconfirmed_pattern) === false):
			$writer->writeBytes($email_unconfirmed_pattern);
		endif;
		$writer->writeObject($new_algo);
		$writer->writeObject($new_secure_algo);
		$writer->writeBytes($secure_random);
		if(is_null($pending_reset_date) === false):
			$writer->writeInt($pending_reset_date);
		endif;
		if(is_null($login_email_pattern) === false):
			$writer->writeBytes($login_email_pattern);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['has_recovery'] = boolval($flags & (1 << 0));
		$result['has_secure_values'] = boolval($flags & (1 << 1));
		$result['has_password'] = boolval($flags & (1 << 2));
		if($flags & (1 << 2)):
			$result['current_algo'] = $reader->readObject();
		else:
			$result['current_algo'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['srp_B'] = $reader->readBytes();
		else:
			$result['srp_B'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['srp_id'] = $reader->readLong();
		else:
			$result['srp_id'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['hint'] = $reader->readBytes();
		else:
			$result['hint'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['email_unconfirmed_pattern'] = $reader->readBytes();
		else:
			$result['email_unconfirmed_pattern'] = null;
		endif;
		$result['new_algo'] = $reader->readObject();
		$result['new_secure_algo'] = $reader->readObject();
		$result['secure_random'] = $reader->readBytes();
		if($flags & (1 << 5)):
			$result['pending_reset_date'] = $reader->readInt();
		else:
			$result['pending_reset_date'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['login_email_pattern'] = $reader->readBytes();
		else:
			$result['login_email_pattern'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.ResetPasswordResult
 */

final class ResetPasswordOk extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe926d63e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param document document
 * @return account.SavedRingtone
 */

final class SavedRingtoneConverted extends Instance {
	public function request(object $document) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1f307eb7);
		$writer->writeObject($document);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['document'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Updates;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pts int qts int date int seq int unread_count
 * @return updates.State
 */

final class State extends Instance {
	public function request(int $pts,int $qts,int $date,int $seq,int $unread_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa56c2a3e);
		$writer->writeInt($pts);
		$writer->writeInt($qts);
		$writer->writeInt($date);
		$writer->writeInt($seq);
		$writer->writeInt($unread_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pts'] = $reader->readInt();
		$result['qts'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['seq'] = $reader->readInt();
		$result['unread_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Updates;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pts Vector<message> new_messages Vector<update> other_updates Vector<chat> chats Vector<user> users true final int timeout
 * @return updates.ChannelDifference
 */

final class ChannelDifference extends Instance {
	public function request(int $pts,array $new_messages,array $other_updates,array $chats,array $users,null | bool $final = null,null | int $timeout = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2064674e);
		$flags = 0;
		$flags |= $final ? (1 << 0) : 0;
		$flags |= is_null($timeout) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeInt($pts);
		if(is_null($timeout) === false):
			$writer->writeInt($timeout);
		endif;
		$writer->writeVector($new_messages,'message');
		$writer->writeVector($other_updates,'update');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['final'] = boolval($flags & (1 << 0));
		$result['pts'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['timeout'] = $reader->readInt();
		else:
			$result['timeout'] = null;
		endif;
		$result['new_messages'] = $reader->readVector('message');
		$result['other_updates'] = $reader->readVector('update');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Updates;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pts true final int timeout
 * @return updates.ChannelDifference
 */

final class ChannelDifferenceEmpty extends Instance {
	public function request(int $pts,null | bool $final = null,null | int $timeout = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e11affb);
		$flags = 0;
		$flags |= $final ? (1 << 0) : 0;
		$flags |= is_null($timeout) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeInt($pts);
		if(is_null($timeout) === false):
			$writer->writeInt($timeout);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['final'] = boolval($flags & (1 << 0));
		$result['pts'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['timeout'] = $reader->readInt();
		else:
			$result['timeout'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Updates;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pts
 * @return updates.Difference
 */

final class DifferenceTooLong extends Instance {
	public function request(int $pts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4afe8f6d);
		$writer->writeInt($pts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Updates;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date int seq
 * @return updates.Difference
 */

final class DifferenceEmpty extends Instance {
	public function request(int $date,int $seq) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5d75a138);
		$writer->writeInt($date);
		$writer->writeInt($seq);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['date'] = $reader->readInt();
		$result['seq'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Updates;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param dialog dialog Vector<message> messages Vector<chat> chats Vector<user> users true final int timeout
 * @return updates.ChannelDifference
 */

final class ChannelDifferenceTooLong extends Instance {
	public function request(object $dialog,array $messages,array $chats,array $users,null | bool $final = null,null | int $timeout = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa4bcc6fe);
		$flags = 0;
		$flags |= $final ? (1 << 0) : 0;
		$flags |= is_null($timeout) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($timeout) === false):
			$writer->writeInt($timeout);
		endif;
		$writer->writeObject($dialog);
		$writer->writeVector($messages,'message');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['final'] = boolval($flags & (1 << 0));
		if($flags & (1 << 1)):
			$result['timeout'] = $reader->readInt();
		else:
			$result['timeout'] = null;
		endif;
		$result['dialog'] = $reader->readObject();
		$result['messages'] = $reader->readVector('message');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Updates;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<message> new_messages Vector<encryptedmessage> new_encrypted_messages Vector<update> other_updates Vector<chat> chats Vector<user> users updates.state state
 * @return updates.Difference
 */

final class Difference extends Instance {
	public function request(array $new_messages,array $new_encrypted_messages,array $other_updates,array $chats,array $users,object $state) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf49ca0);
		$writer->writeVector($new_messages,'message');
		$writer->writeVector($new_encrypted_messages,'encryptedmessage');
		$writer->writeVector($other_updates,'update');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		$writer->writeObject($state);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_messages'] = $reader->readVector('message');
		$result['new_encrypted_messages'] = $reader->readVector('encryptedmessage');
		$result['other_updates'] = $reader->readVector('update');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		$result['state'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Updates;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<message> new_messages Vector<encryptedmessage> new_encrypted_messages Vector<update> other_updates Vector<chat> chats Vector<user> users updates.state intermediate_state
 * @return updates.Difference
 */

final class DifferenceSlice extends Instance {
	public function request(array $new_messages,array $new_encrypted_messages,array $other_updates,array $chats,array $users,object $intermediate_state) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa8fb1981);
		$writer->writeVector($new_messages,'message');
		$writer->writeVector($new_encrypted_messages,'encryptedmessage');
		$writer->writeVector($other_updates,'update');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		$writer->writeObject($intermediate_state);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_messages'] = $reader->readVector('message');
		$result['new_encrypted_messages'] = $reader->readVector('encryptedmessage');
		$result['other_updates'] = $reader->readVector('update');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		$result['intermediate_state'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Smsjobs;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string terms_url int monthly_sent_sms
 * @return smsjobs.EligibilityToJoin
 */

final class EligibleToJoin extends Instance {
	public function request(string $terms_url,int $monthly_sent_sms) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdc8b44cf);
		$writer->writeBytes($terms_url);
		$writer->writeInt($monthly_sent_sms);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['terms_url'] = $reader->readBytes();
		$result['monthly_sent_sms'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Smsjobs;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int recent_sent int recent_since int recent_remains int total_sent int total_since string terms_url true allow_international string last_gift_slug
 * @return smsjobs.Status
 */

final class Status extends Instance {
	public function request(int $recent_sent,int $recent_since,int $recent_remains,int $total_sent,int $total_since,string $terms_url,null | bool $allow_international = null,null | string $last_gift_slug = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2aee9191);
		$flags = 0;
		$flags |= $allow_international ? (1 << 0) : 0;
		$flags |= is_null($last_gift_slug) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeInt($recent_sent);
		$writer->writeInt($recent_since);
		$writer->writeInt($recent_remains);
		$writer->writeInt($total_sent);
		$writer->writeInt($total_since);
		if(is_null($last_gift_slug) === false):
			$writer->writeBytes($last_gift_slug);
		endif;
		$writer->writeBytes($terms_url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['allow_international'] = boolval($flags & (1 << 0));
		$result['recent_sent'] = $reader->readInt();
		$result['recent_since'] = $reader->readInt();
		$result['recent_remains'] = $reader->readInt();
		$result['total_sent'] = $reader->readInt();
		$result['total_since'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['last_gift_slug'] = $reader->readBytes();
		else:
			$result['last_gift_slug'] = null;
		endif;
		$result['terms_url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Premium;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int level int current_level_boosts int boosts string boost_url true my_boost int gift_boosts int next_level_boosts statspercentvalue premium_audience Vector<prepaidgiveaway> prepaid_giveaways Vector<int> my_boost_slots
 * @return premium.BoostsStatus
 */

final class BoostsStatus extends Instance {
	public function request(int $level,int $current_level_boosts,int $boosts,string $boost_url,null | bool $my_boost = null,null | int $gift_boosts = null,null | int $next_level_boosts = null,null | object $premium_audience = null,null | array $prepaid_giveaways = null,null | array $my_boost_slots = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4959427a);
		$flags = 0;
		$flags |= $my_boost ? (1 << 2) : 0;
		$flags |= is_null($gift_boosts) ? 0 : (1 << 4);
		$flags |= is_null($next_level_boosts) ? 0 : (1 << 0);
		$flags |= is_null($premium_audience) ? 0 : (1 << 1);
		$flags |= is_null($prepaid_giveaways) ? 0 : (1 << 3);
		$flags |= is_null($my_boost_slots) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeInt($level);
		$writer->writeInt($current_level_boosts);
		$writer->writeInt($boosts);
		if(is_null($gift_boosts) === false):
			$writer->writeInt($gift_boosts);
		endif;
		if(is_null($next_level_boosts) === false):
			$writer->writeInt($next_level_boosts);
		endif;
		if(is_null($premium_audience) === false):
			$writer->writeObject($premium_audience);
		endif;
		$writer->writeBytes($boost_url);
		if(is_null($prepaid_giveaways) === false):
			$writer->writeVector($prepaid_giveaways,'prepaidgiveaway');
		endif;
		if(is_null($my_boost_slots) === false):
			$writer->writeVector($my_boost_slots,'int');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['my_boost'] = boolval($flags & (1 << 2));
		$result['level'] = $reader->readInt();
		$result['current_level_boosts'] = $reader->readInt();
		$result['boosts'] = $reader->readInt();
		if($flags & (1 << 4)):
			$result['gift_boosts'] = $reader->readInt();
		else:
			$result['gift_boosts'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['next_level_boosts'] = $reader->readInt();
		else:
			$result['next_level_boosts'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['premium_audience'] = $reader->readObject();
		else:
			$result['premium_audience'] = null;
		endif;
		$result['boost_url'] = $reader->readBytes();
		if($flags & (1 << 3)):
			$result['prepaid_giveaways'] = $reader->readVector('prepaidgiveaway');
		else:
			$result['prepaid_giveaways'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['my_boost_slots'] = $reader->readVector('int');
		else:
			$result['my_boost_slots'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Premium;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<myboost> my_boosts Vector<chat> chats Vector<user> users
 * @return premium.MyBoosts
 */

final class MyBoosts extends Instance {
	public function request(array $my_boosts,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9ae228e2);
		$writer->writeVector($my_boosts,'myboost');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['my_boosts'] = $reader->readVector('myboost');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Premium;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<boost> boosts Vector<user> users string next_offset
 * @return premium.BoostsList
 */

final class BoostsList extends Instance {
	public function request(int $count,array $boosts,array $users,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x86f8613c);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeVector($boosts,'boost');
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['count'] = $reader->readInt();
		$result['boosts'] = $reader->readVector('boost');
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url string key
 * @return phone.GroupCallStreamRtmpUrl
 */

final class GroupCallStreamRtmpUrl extends Instance {
	public function request(string $url,string $key) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2dbf3432);
		$writer->writeBytes($url);
		$writer->writeBytes($key);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['key'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<peer> peers Vector<chat> chats Vector<user> users
 * @return phone.JoinAsPeers
 */

final class JoinAsPeers extends Instance {
	public function request(array $peers,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xafe5623f);
		$writer->writeVector($peers,'peer');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peers'] = $reader->readVector('peer');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param groupcall call Vector<groupcallparticipant> participants string participants_next_offset Vector<chat> chats Vector<user> users
 * @return phone.GroupCall
 */

final class GroupCall extends Instance {
	public function request(object $call,array $participants,string $participants_next_offset,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9e727aad);
		$writer->writeObject($call);
		$writer->writeVector($participants,'groupcallparticipant');
		$writer->writeBytes($participants_next_offset);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['call'] = $reader->readObject();
		$result['participants'] = $reader->readVector('groupcallparticipant');
		$result['participants_next_offset'] = $reader->readBytes();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long total_stars Vector<groupcalldonor> top_donors Vector<chat> chats Vector<user> users
 * @return phone.GroupCallStars
 */

final class GroupCallStars extends Instance {
	public function request(int $total_stars,array $top_donors,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9d1dbd26);
		$writer->writeLong($total_stars);
		$writer->writeVector($top_donors,'groupcalldonor');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['total_stars'] = $reader->readLong();
		$result['top_donors'] = $reader->readVector('groupcalldonor');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<groupcallstreamchannel> channels
 * @return phone.GroupCallStreamChannels
 */

final class GroupCallStreamChannels extends Instance {
	public function request(array $channels) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd0e482b2);
		$writer->writeVector($channels,'groupcallstreamchannel');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channels'] = $reader->readVector('groupcallstreamchannel');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<groupcallparticipant> participants string next_offset Vector<chat> chats Vector<user> users int version
 * @return phone.GroupParticipants
 */

final class GroupParticipants extends Instance {
	public function request(int $count,array $participants,string $next_offset,array $chats,array $users,int $version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf47751b6);
		$writer->writeInt($count);
		$writer->writeVector($participants,'groupcallparticipant');
		$writer->writeBytes($next_offset);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		$writer->writeInt($version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['participants'] = $reader->readVector('groupcallparticipant');
		$result['next_offset'] = $reader->readBytes();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		$result['version'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param phonecall phone_call Vector<user> users
 * @return phone.PhoneCall
 */

final class PhoneCall extends Instance {
	public function request(object $phone_call,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xec82e140);
		$writer->writeObject($phone_call);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone_call'] = $reader->readObject();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string link
 * @return phone.ExportedGroupCallInvite
 */

final class ExportedGroupCallInvite extends Instance {
	public function request(string $link) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x204bd158);
		$writer->writeBytes($link);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['link'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Aicompose;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<aicomposetone> tones Vector<user> users
 * @return aicompose.Tones
 */

final class Tones extends Instance {
	public function request(int $hash,array $tones,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c9d0efe);
		$writer->writeLong($hash);
		$writer->writeVector($tones,'aicomposetone');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['tones'] = $reader->readVector('aicomposetone');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Aicompose;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return aicompose.Tones
 */

final class TonesNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc1f46103);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Storage;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return storage.FileType
 */

final class FilePartial extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x40bc6f52);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Storage;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return storage.FileType
 */

final class FileGif extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcae1aadf);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Storage;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return storage.FileType
 */

final class FilePng extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa4f63c0);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Storage;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return storage.FileType
 */

final class FileMp4 extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb3cea0e4);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Storage;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return storage.FileType
 */

final class FilePdf extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xae1e508d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Storage;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return storage.FileType
 */

final class FileJpeg extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7efe0e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Storage;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return storage.FileType
 */

final class FileMov extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4b09ebbc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Storage;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return storage.FileType
 */

final class FileWebp extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1081464c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Storage;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return storage.FileType
 */

final class FileMp3 extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x528a0677);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Storage;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return storage.FileType
 */

final class FileUnknown extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaa963b05);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param storage.filetype type int mtime bytes bytes
 * @return upload.File
 */

final class File extends Instance {
	public function request(object $type,int $mtime,string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x96a18d5);
		$writer->writeObject($type);
		$writer->writeInt($mtime);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readObject();
		$result['mtime'] = $reader->readInt();
		$result['bytes'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes request_token
 * @return upload.CdnFile
 */

final class CdnFileReuploadNeeded extends Instance {
	public function request(string $request_token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeea8e46e);
		$writer->writeBytes($request_token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['request_token'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int size string mime_type storage.filetype file_type int mtime bytes bytes
 * @return upload.WebFile
 */

final class WebFile extends Instance {
	public function request(int $size,string $mime_type,object $file_type,int $mtime,string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x21e753bc);
		$writer->writeInt($size);
		$writer->writeBytes($mime_type);
		$writer->writeObject($file_type);
		$writer->writeInt($mtime);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['size'] = $reader->readInt();
		$result['mime_type'] = $reader->readBytes();
		$result['file_type'] = $reader->readObject();
		$result['mtime'] = $reader->readInt();
		$result['bytes'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes bytes
 * @return upload.CdnFile
 */

final class CdnFile extends Instance {
	public function request(string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa99fca4f);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['bytes'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int dc_id bytes file_token bytes encryption_key bytes encryption_iv Vector<filehash> file_hashes
 * @return upload.File
 */

final class FileCdnRedirect extends Instance {
	public function request(int $dc_id,string $file_token,string $encryption_key,string $encryption_iv,array $file_hashes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf18cda44);
		$writer->writeInt($dc_id);
		$writer->writeBytes($file_token);
		$writer->writeBytes($encryption_key);
		$writer->writeBytes($encryption_iv);
		$writer->writeVector($file_hashes,'filehash');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['dc_id'] = $reader->readInt();
		$result['file_token'] = $reader->readBytes();
		$result['encryption_key'] = $reader->readBytes();
		$result['encryption_iv'] = $reader->readBytes();
		$result['file_hashes'] = $reader->readVector('filehash');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageUploadVideoAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x92042ff7);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long exchange_id bytes g_a
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionRequestKey extends Instance {
	public function request(int $exchange_id,string $g_a) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf3c9611b);
		$writer->writeLong($exchange_id);
		$writer->writeBytes($g_a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['exchange_id'] = $reader->readLong();
		$result['g_a'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param double lat double long
 * @return secret.DecryptedMessageMedia
 */

final class DecryptedMessageMediaGeoPoint extends Instance {
	public function request(float $lat,float $long) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x35480a59);
		$writer->writeDouble($lat);
		$writer->writeDouble($long);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['lat'] = $reader->readDouble();
		$result['long'] = $reader->readDouble();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int duration int w int h true round_message
 * @return secret.DocumentAttribute
 */

final class DocumentAttributeVideo extends Instance {
	public function request(int $duration,int $w,int $h,null | bool $round_message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xef02ce6);
		$flags = 0;
		$flags |= $round_message ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($duration);
		$writer->writeInt($w);
		$writer->writeInt($h);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['round_message'] = boolval($flags & (1 << 0));
		$result['duration'] = $reader->readInt();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionNoop extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa82fdd63);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageGeoLocationAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x176f8ba1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes random_bytes int layer int in_seq_no int out_seq_no decryptedmessage message
 * @return secret.DecryptedMessageLayer
 */

final class DecryptedMessageLayer extends Instance {
	public function request(string $random_bytes,int $layer,int $in_seq_no,int $out_seq_no,object $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1be31789);
		$writer->writeBytes($random_bytes);
		$writer->writeInt($layer);
		$writer->writeInt($in_seq_no);
		$writer->writeInt($out_seq_no);
		$writer->writeObject($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['random_bytes'] = $reader->readBytes();
		$result['layer'] = $reader->readInt();
		$result['in_seq_no'] = $reader->readInt();
		$result['out_seq_no'] = $reader->readInt();
		$result['message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes thumb int thumb_w int thumb_h int w int h int size bytes key bytes iv string caption
 * @return secret.DecryptedMessageMedia
 */

final class DecryptedMessageMediaPhoto extends Instance {
	public function request(string $thumb,int $thumb_w,int $thumb_h,int $w,int $h,int $size,string $key,string $iv,string $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf1fa8d78);
		$writer->writeBytes($thumb);
		$writer->writeInt($thumb_w);
		$writer->writeInt($thumb_h);
		$writer->writeInt($w);
		$writer->writeInt($h);
		$writer->writeInt($size);
		$writer->writeBytes($key);
		$writer->writeBytes($iv);
		$writer->writeBytes($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['thumb'] = $reader->readBytes();
		$result['thumb_w'] = $reader->readInt();
		$result['thumb_h'] = $reader->readInt();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		$result['size'] = $reader->readInt();
		$result['key'] = $reader->readBytes();
		$result['iv'] = $reader->readBytes();
		$result['caption'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long exchange_id bytes g_b long key_fingerprint
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionAcceptKey extends Instance {
	public function request(int $exchange_id,string $g_b,int $key_fingerprint) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6fe1735b);
		$writer->writeLong($exchange_id);
		$writer->writeBytes($g_b);
		$writer->writeLong($key_fingerprint);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['exchange_id'] = $reader->readLong();
		$result['g_b'] = $reader->readBytes();
		$result['key_fingerprint'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int w int h
 * @return secret.DocumentAttribute
 */

final class DocumentAttributeImageSize extends Instance {
	public function request(int $w,int $h) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c37c15c);
		$writer->writeInt($w);
		$writer->writeInt($h);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityItalic extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x826f8b60);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length string url
 * @return secret.MessageEntity
 */

final class MessageEntityTextUrl extends Instance {
	public function request(int $offset,int $length,string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x76a6d327);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityStrike extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbf0693d4);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long random_id decryptedmessageaction action
 * @return secret.DecryptedMessage
 */

final class DecryptedMessageService extends Instance {
	public function request(int $random_id,object $action) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x73164160);
		$writer->writeLong($random_id);
		$writer->writeObject($action);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['random_id'] = $reader->readLong();
		$result['action'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int ttl_seconds
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionSetMessageTTL extends Instance {
	public function request(int $ttl_seconds) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa1733aec);
		$writer->writeInt($ttl_seconds);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['ttl_seconds'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int start_seq_no int end_seq_no
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionResend extends Instance {
	public function request(int $start_seq_no,int $end_seq_no) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x511110b0);
		$writer->writeInt($start_seq_no);
		$writer->writeInt($end_seq_no);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['start_seq_no'] = $reader->readInt();
		$result['end_seq_no'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageUploadRoundAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbb718624);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param double lat double long string title string address string provider string venue_id
 * @return secret.DecryptedMessageMedia
 */

final class DecryptedMessageMediaVenue extends Instance {
	public function request(float $lat,float $long,string $title,string $address,string $provider,string $venue_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8a0df56f);
		$writer->writeDouble($lat);
		$writer->writeDouble($long);
		$writer->writeBytes($title);
		$writer->writeBytes($address);
		$writer->writeBytes($provider);
		$writer->writeBytes($venue_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['lat'] = $reader->readDouble();
		$result['long'] = $reader->readDouble();
		$result['title'] = $reader->readBytes();
		$result['address'] = $reader->readBytes();
		$result['provider'] = $reader->readBytes();
		$result['venue_id'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string first_name string last_name int user_id
 * @return secret.DecryptedMessageMedia
 */

final class DecryptedMessageMediaContact extends Instance {
	public function request(string $phone_number,string $first_name,string $last_name,int $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x588a0a97);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($first_name);
		$writer->writeBytes($last_name);
		$writer->writeInt($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone_number'] = $reader->readBytes();
		$result['first_name'] = $reader->readBytes();
		$result['last_name'] = $reader->readBytes();
		$result['user_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityHashtag extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6f635b0d);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageUploadDocumentAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8faee98e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> random_ids
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionReadMessages extends Instance {
	public function request(array $random_ids) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc4f40be);
		$writer->writeVector($random_ids,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['random_ids'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> random_ids
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionScreenshotMessages extends Instance {
	public function request(array $random_ids) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ac1f475);
		$writer->writeVector($random_ids,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['random_ids'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageRecordVideoAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa187d66f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string type filelocation location int w int h bytes bytes
 * @return secret.PhotoSize
 */

final class PhotoCachedSize extends Instance {
	public function request(string $type,object $location,int $w,int $h,string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe9a734fa);
		$writer->writeBytes($type);
		$writer->writeObject($location);
		$writer->writeInt($w);
		$writer->writeInt($h);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readBytes();
		$result['location'] = $reader->readObject();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		$result['bytes'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityBlockquote extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x20df5d0);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityUrl extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6ed02538);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long volume_id int local_id long secret
 * @return secret.FileLocation
 */

final class FileLocationUnavailable extends Instance {
	public function request(int $volume_id,int $local_id,int $secret) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7c596b46);
		$writer->writeLong($volume_id);
		$writer->writeInt($local_id);
		$writer->writeLong($secret);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['volume_id'] = $reader->readLong();
		$result['local_id'] = $reader->readInt();
		$result['secret'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long exchange_id long key_fingerprint
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionCommitKey extends Instance {
	public function request(int $exchange_id,int $key_fingerprint) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xec2e0b9b);
		$writer->writeLong($exchange_id);
		$writer->writeLong($key_fingerprint);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['exchange_id'] = $reader->readLong();
		$result['key_fingerprint'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string type
 * @return secret.PhotoSize
 */

final class PhotoSizeEmpty extends Instance {
	public function request(string $type) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe17e23c);
		$writer->writeBytes($type);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return secret.DecryptedMessageMedia
 */

final class DecryptedMessageMediaWebPage extends Instance {
	public function request(string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe50511d8);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityCode extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x28a20571);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageUploadPhotoAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x990a3c1a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string file_name
 * @return secret.DocumentAttribute
 */

final class DocumentAttributeFilename extends Instance {
	public function request(string $file_name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x15590068);
		$writer->writeBytes($file_name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['file_name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityBotCommand extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6cef8ac7);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string short_name
 * @return secret.InputStickerSet
 */

final class InputStickerSetShortName extends Instance {
	public function request(string $short_name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x861cc8a0);
		$writer->writeBytes($short_name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['short_name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageCancelAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfd5ec8f5);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionFlushHistory extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6719e45c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length string language
 * @return secret.MessageEntity
 */

final class MessageEntityPre extends Instance {
	public function request(int $offset,int $length,string $language) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x73924be0);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		$writer->writeBytes($language);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		$result['language'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageChooseContactAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x628cbc6f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityEmail extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x64e475c2);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityUnknown extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbb92ba95);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageRecordAudioAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd52f73f7);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageUploadAudioAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe6ac8a6f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long random_id int ttl string message true no_webpage true silent decryptedmessagemedia media Vector<messageentity> entities string via_bot_name long reply_to_random_id long grouped_id
 * @return secret.DecryptedMessage
 */

final class DecryptedMessage extends Instance {
	public function request(int $random_id,int $ttl,string $message,null | bool $no_webpage = null,null | bool $silent = null,null | object $media = null,null | array $entities = null,null | string $via_bot_name = null,null | int $reply_to_random_id = null,null | int $grouped_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x91cc4674);
		$flags = 0;
		$flags |= $no_webpage ? (1 << 1) : 0;
		$flags |= $silent ? (1 << 5) : 0;
		$flags |= is_null($media) ? 0 : (1 << 9);
		$flags |= is_null($entities) ? 0 : (1 << 7);
		$flags |= is_null($via_bot_name) ? 0 : (1 << 11);
		$flags |= is_null($reply_to_random_id) ? 0 : (1 << 3);
		$flags |= is_null($grouped_id) ? 0 : (1 << 17);
		$writer->writeInt($flags);
		$writer->writeLong($random_id);
		$writer->writeInt($ttl);
		$writer->writeBytes($message);
		if(is_null($media) === false):
			$writer->writeObject($media);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($via_bot_name) === false):
			$writer->writeBytes($via_bot_name);
		endif;
		if(is_null($reply_to_random_id) === false):
			$writer->writeLong($reply_to_random_id);
		endif;
		if(is_null($grouped_id) === false):
			$writer->writeLong($grouped_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['no_webpage'] = boolval($flags & (1 << 1));
		$result['silent'] = boolval($flags & (1 << 5));
		$result['random_id'] = $reader->readLong();
		$result['ttl'] = $reader->readInt();
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 9)):
			$result['media'] = $reader->readObject();
		else:
			$result['media'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['via_bot_name'] = $reader->readBytes();
		else:
			$result['via_bot_name'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['reply_to_random_id'] = $reader->readLong();
		else:
			$result['reply_to_random_id'] = null;
		endif;
		if($flags & (1 << 17)):
			$result['grouped_id'] = $reader->readLong();
		else:
			$result['grouped_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.DecryptedMessageMedia
 */

final class DecryptedMessageMediaEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x89f5c4a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length long document_id
 * @return secret.MessageEntity
 */

final class MessageEntityCustomEmoji extends Instance {
	public function request(int $offset,int $length,int $document_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc8cf05f8);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		$writer->writeLong($document_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		$result['document_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageTypingAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x16bf744e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int layer
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionNotifyLayer extends Instance {
	public function request(int $layer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf3048883);
		$writer->writeInt($layer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['layer'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntitySpoiler extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x32ca960f);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityUnderline extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9c4e7e8b);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int duration true voice string title string performer bytes waveform
 * @return secret.DocumentAttribute
 */

final class DocumentAttributeAudio extends Instance {
	public function request(int $duration,null | bool $voice = null,null | string $title = null,null | string $performer = null,null | string $waveform = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9852f9c6);
		$flags = 0;
		$flags |= $voice ? (1 << 10) : 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$flags |= is_null($performer) ? 0 : (1 << 1);
		$flags |= is_null($waveform) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeInt($duration);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($performer) === false):
			$writer->writeBytes($performer);
		endif;
		if(is_null($waveform) === false):
			$writer->writeBytes($waveform);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['voice'] = boolval($flags & (1 << 10));
		$result['duration'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['performer'] = $reader->readBytes();
		else:
			$result['performer'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['waveform'] = $reader->readBytes();
		else:
			$result['waveform'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes thumb int thumb_w int thumb_h int duration string mime_type int w int h int size bytes key bytes iv string caption
 * @return secret.DecryptedMessageMedia
 */

final class DecryptedMessageMediaVideo extends Instance {
	public function request(string $thumb,int $thumb_w,int $thumb_h,int $duration,string $mime_type,int $w,int $h,int $size,string $key,string $iv,string $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x970c8c0e);
		$writer->writeBytes($thumb);
		$writer->writeInt($thumb_w);
		$writer->writeInt($thumb_h);
		$writer->writeInt($duration);
		$writer->writeBytes($mime_type);
		$writer->writeInt($w);
		$writer->writeInt($h);
		$writer->writeInt($size);
		$writer->writeBytes($key);
		$writer->writeBytes($iv);
		$writer->writeBytes($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['thumb'] = $reader->readBytes();
		$result['thumb_w'] = $reader->readInt();
		$result['thumb_h'] = $reader->readInt();
		$result['duration'] = $reader->readInt();
		$result['mime_type'] = $reader->readBytes();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		$result['size'] = $reader->readInt();
		$result['key'] = $reader->readBytes();
		$result['iv'] = $reader->readBytes();
		$result['caption'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int duration string mime_type int size bytes key bytes iv
 * @return secret.DecryptedMessageMedia
 */

final class DecryptedMessageMediaAudio extends Instance {
	public function request(int $duration,string $mime_type,int $size,string $key,string $iv) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x57e0a9cb);
		$writer->writeInt($duration);
		$writer->writeBytes($mime_type);
		$writer->writeInt($size);
		$writer->writeBytes($key);
		$writer->writeBytes($iv);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['duration'] = $reader->readInt();
		$result['mime_type'] = $reader->readBytes();
		$result['size'] = $reader->readInt();
		$result['key'] = $reader->readBytes();
		$result['iv'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long exchange_id
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionAbortKey extends Instance {
	public function request(int $exchange_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdd05ec6b);
		$writer->writeLong($exchange_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['exchange_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string alt inputstickerset stickerset
 * @return secret.DocumentAttribute
 */

final class DocumentAttributeSticker extends Instance {
	public function request(string $alt,object $stickerset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3a556302);
		$writer->writeBytes($alt);
		$writer->writeObject($stickerset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['alt'] = $reader->readBytes();
		$result['stickerset'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.InputStickerSet
 */

final class InputStickerSetEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xffb62b95);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityMention extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfa04579d);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.SendMessageAction
 */

final class SendMessageRecordRoundAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x88f27fbc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param sendmessageaction action
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionTyping extends Instance {
	public function request(object $action) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xccb27641);
		$writer->writeObject($action);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['action'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return secret.DocumentAttribute
 */

final class DocumentAttributeAnimated extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x11b58939);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> random_ids
 * @return secret.DecryptedMessageAction
 */

final class DecryptedMessageActionDeleteMessages extends Instance {
	public function request(array $random_ids) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x65614304);
		$writer->writeVector($random_ids,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['random_ids'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int dc_id long volume_id int local_id long secret
 * @return secret.FileLocation
 */

final class FileLocation extends Instance {
	public function request(int $dc_id,int $volume_id,int $local_id,int $secret) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x53d69076);
		$writer->writeInt($dc_id);
		$writer->writeLong($volume_id);
		$writer->writeInt($local_id);
		$writer->writeLong($secret);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['dc_id'] = $reader->readInt();
		$result['volume_id'] = $reader->readLong();
		$result['local_id'] = $reader->readInt();
		$result['secret'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return secret.MessageEntity
 */

final class MessageEntityBold extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd610bc9);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes thumb int thumb_w int thumb_h string mime_type long size bytes key bytes iv Vector<documentattribute> attributes string caption
 * @return secret.DecryptedMessageMedia
 */

final class DecryptedMessageMediaDocument extends Instance {
	public function request(string $thumb,int $thumb_w,int $thumb_h,string $mime_type,int $size,string $key,string $iv,array $attributes,string $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6abd9782);
		$writer->writeBytes($thumb);
		$writer->writeInt($thumb_w);
		$writer->writeInt($thumb_h);
		$writer->writeBytes($mime_type);
		$writer->writeLong($size);
		$writer->writeBytes($key);
		$writer->writeBytes($iv);
		$writer->writeVector($attributes,'documentattribute');
		$writer->writeBytes($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['thumb'] = $reader->readBytes();
		$result['thumb_w'] = $reader->readInt();
		$result['thumb_h'] = $reader->readInt();
		$result['mime_type'] = $reader->readBytes();
		$result['size'] = $reader->readLong();
		$result['key'] = $reader->readBytes();
		$result['iv'] = $reader->readBytes();
		$result['attributes'] = $reader->readVector('documentattribute');
		$result['caption'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash int date string mime_type int size photosize thumb int dc_id Vector<documentattribute> attributes
 * @return secret.DecryptedMessageMedia
 */

final class DecryptedMessageMediaExternalDocument extends Instance {
	public function request(int $id,int $access_hash,int $date,string $mime_type,int $size,object $thumb,int $dc_id,array $attributes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfa95b0dd);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeInt($date);
		$writer->writeBytes($mime_type);
		$writer->writeInt($size);
		$writer->writeObject($thumb);
		$writer->writeInt($dc_id);
		$writer->writeVector($attributes,'documentattribute');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['mime_type'] = $reader->readBytes();
		$result['size'] = $reader->readInt();
		$result['thumb'] = $reader->readObject();
		$result['dc_id'] = $reader->readInt();
		$result['attributes'] = $reader->readVector('documentattribute');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Secret;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string type filelocation location int w int h int size
 * @return secret.PhotoSize
 */

final class PhotoSize extends Instance {
	public function request(string $type,object $location,int $w,int $h,int $size) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x77bfb61b);
		$writer->writeBytes($type);
		$writer->writeObject($location);
		$writer->writeInt($w);
		$writer->writeInt($h);
		$writer->writeInt($size);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readBytes();
		$result['location'] = $reader->readObject();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		$result['size'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputsavedstargift stargift true keep_original_details
 * @return InputInvoice
 */

final class InputInvoiceStarGiftUpgrade extends Instance {
	public function request(object $stargift,null | bool $keep_original_details = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4d818d5d);
		$flags = 0;
		$flags |= $keep_original_details ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($stargift);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['keep_original_details'] = boolval($flags & (1 << 0));
		$result['stargift'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string prev_value string new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeTitle extends Instance {
	public function request(string $prev_value,string $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe6dfb825);
		$writer->writeBytes($prev_value);
		$writer->writeBytes($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readBytes();
		$result['new_value'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string key jsonvalue value
 * @return JSONObjectValue
 */

final class JsonObjectValue extends Instance {
	public function request(string $key,object $value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc0de1bd9);
		$writer->writeBytes($key);
		$writer->writeObject($value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['key'] = $reader->readBytes();
		$result['value'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param channelparticipant participant
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantInvite extends Instance {
	public function request(object $participant) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe31c34d8);
		$writer->writeObject($participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['participant'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputStickerSet
 */

final class InputStickerSetAnimatedEmoji extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x28703c8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyProfilePhoto extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5719bacc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyStatusTimestamp extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4f96cb18);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson client_data bytes attestation_data
 * @return InputPasskeyResponse
 */

final class InputPasskeyResponseRegister extends Instance {
	public function request(object $client_data,string $attestation_data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e63935c);
		$writer->writeObject($client_data);
		$writer->writeBytes($attestation_data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['client_data'] = $reader->readObject();
		$result['attestation_data'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int progress
 * @return SendMessageAction
 */

final class SendMessageUploadVideoAction extends Instance {
	public function request(int $progress) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe9763aec);
		$writer->writeInt($progress);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['progress'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockKicker extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1e148390);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes random_id string url string title string message string button_text true recommended true can_report Vector<messageentity> entities photo photo messagemedia media peercolor color string sponsor_info string additional_info int min_display_duration int max_display_duration
 * @return SponsoredMessage
 */

final class SponsoredMessage extends Instance {
	public function request(string $random_id,string $url,string $title,string $message,string $button_text,null | bool $recommended = null,null | bool $can_report = null,null | array $entities = null,null | object $photo = null,null | object $media = null,null | object $color = null,null | string $sponsor_info = null,null | string $additional_info = null,null | int $min_display_duration = null,null | int $max_display_duration = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7dbf8673);
		$flags = 0;
		$flags |= $recommended ? (1 << 5) : 0;
		$flags |= $can_report ? (1 << 12) : 0;
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$flags |= is_null($photo) ? 0 : (1 << 6);
		$flags |= is_null($media) ? 0 : (1 << 14);
		$flags |= is_null($color) ? 0 : (1 << 13);
		$flags |= is_null($sponsor_info) ? 0 : (1 << 7);
		$flags |= is_null($additional_info) ? 0 : (1 << 8);
		$flags |= is_null($min_display_duration) ? 0 : (1 << 15);
		$flags |= is_null($max_display_duration) ? 0 : (1 << 15);
		$writer->writeInt($flags);
		$writer->writeBytes($random_id);
		$writer->writeBytes($url);
		$writer->writeBytes($title);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		if(is_null($media) === false):
			$writer->writeObject($media);
		endif;
		if(is_null($color) === false):
			$writer->writeObject($color);
		endif;
		$writer->writeBytes($button_text);
		if(is_null($sponsor_info) === false):
			$writer->writeBytes($sponsor_info);
		endif;
		if(is_null($additional_info) === false):
			$writer->writeBytes($additional_info);
		endif;
		if(is_null($min_display_duration) === false):
			$writer->writeInt($min_display_duration);
		endif;
		if(is_null($max_display_duration) === false):
			$writer->writeInt($max_display_duration);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['recommended'] = boolval($flags & (1 << 5));
		$result['can_report'] = boolval($flags & (1 << 12));
		$result['random_id'] = $reader->readBytes();
		$result['url'] = $reader->readBytes();
		$result['title'] = $reader->readBytes();
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['media'] = $reader->readObject();
		else:
			$result['media'] = null;
		endif;
		if($flags & (1 << 13)):
			$result['color'] = $reader->readObject();
		else:
			$result['color'] = null;
		endif;
		$result['button_text'] = $reader->readBytes();
		if($flags & (1 << 7)):
			$result['sponsor_info'] = $reader->readBytes();
		else:
			$result['sponsor_info'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['additional_info'] = $reader->readBytes();
		else:
			$result['additional_info'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['min_display_duration'] = $reader->readInt();
		else:
			$result['min_display_duration'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['max_display_duration'] = $reader->readInt();
		else:
			$result['max_display_duration'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputFileLocation
 */

final class InputEncryptedFileLocation extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf5235d55);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param double part double total
 * @return StatsPercentValue
 */

final class StatsPercentValue extends Instance {
	public function request(float $part,float $total) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcbce2fe0);
		$writer->writeDouble($part);
		$writer->writeDouble($total);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['part'] = $reader->readDouble();
		$result['total'] = $reader->readDouble();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int dc_id long id long access_hash
 * @return InputBotInlineMessageID
 */

final class InputBotInlineMessageID extends Instance {
	public function request(int $dc_id,int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x890c3d89);
		$writer->writeInt($dc_id);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['dc_id'] = $reader->readInt();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int channel int scale long last_timestamp_ms
 * @return GroupCallStreamChannel
 */

final class GroupCallStreamChannel extends Instance {
	public function request(int $channel,int $scale,int $last_timestamp_ms) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x80eb48af);
		$writer->writeInt($channel);
		$writer->writeInt($scale);
		$writer->writeLong($last_timestamp_ms);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel'] = $reader->readInt();
		$result['scale'] = $reader->readInt();
		$result['last_timestamp_ms'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce int128 server_nonce int g string dh_prime string g_a int server_time
 * @return Server_DH_inner_data
 */

final class ServerDHInnerData extends Instance {
	public function request(int | string $nonce,int | string $server_nonce,int $g,string $dh_prime,string $g_a,int $server_time) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb5890dba);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeInt($g);
		$writer->writeBytes($dh_prime);
		$writer->writeBytes($g_a);
		$writer->writeInt($server_time);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['g'] = $reader->readInt();
		$result['dh_prime'] = $reader->readBytes();
		$result['g_a'] = $reader->readBytes();
		$result['server_time'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgeopoint geo_point int heading int period int proximity_notification_radius replymarkup reply_markup
 * @return InputBotInlineMessage
 */

final class InputBotInlineMessageMediaGeo extends Instance {
	public function request(object $geo_point,null | int $heading = null,null | int $period = null,null | int $proximity_notification_radius = null,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x96929a85);
		$flags = 0;
		$flags |= is_null($heading) ? 0 : (1 << 0);
		$flags |= is_null($period) ? 0 : (1 << 1);
		$flags |= is_null($proximity_notification_radius) ? 0 : (1 << 3);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($geo_point);
		if(is_null($heading) === false):
			$writer->writeInt($heading);
		endif;
		if(is_null($period) === false):
			$writer->writeInt($period);
		endif;
		if(is_null($proximity_notification_radius) === false):
			$writer->writeInt($proximity_notification_radius);
		endif;
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['geo_point'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['heading'] = $reader->readInt();
		else:
			$result['heading'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['period'] = $reader->readInt();
		else:
			$result['period'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['proximity_notification_radius'] = $reader->readInt();
		else:
			$result['proximity_notification_radius'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputBotApp
 */

final class InputBotAppID extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa920bd7a);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id int date true requested true via_chatlist string about long approved_by
 * @return ChatInviteImporter
 */

final class ChatInviteImporter extends Instance {
	public function request(int $user_id,int $date,null | bool $requested = null,null | bool $via_chatlist = null,null | string $about = null,null | int $approved_by = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c5adfd9);
		$flags = 0;
		$flags |= $requested ? (1 << 0) : 0;
		$flags |= $via_chatlist ? (1 << 3) : 0;
		$flags |= is_null($about) ? 0 : (1 << 2);
		$flags |= is_null($approved_by) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		$writer->writeInt($date);
		if(is_null($about) === false):
			$writer->writeBytes($about);
		endif;
		if(is_null($approved_by) === false):
			$writer->writeLong($approved_by);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['requested'] = boolval($flags & (1 << 0));
		$result['via_chatlist'] = boolval($flags & (1 << 3));
		$result['user_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['about'] = $reader->readBytes();
		else:
			$result['about'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['approved_by'] = $reader->readLong();
		else:
			$result['approved_by'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long new_creator_id
 * @return MessageAction
 */

final class MessageActionNewCreatorPending extends Instance {
	public function request(int $new_creator_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb07ed085);
		$writer->writeLong($new_creator_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_creator_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param webpage webpage int pts int pts_count
 * @return Update
 */

final class UpdateWebPage extends Instance {
	public function request(object $webpage,int $pts,int $pts_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7f891213);
		$writer->writeObject($webpage);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['webpage'] = $reader->readObject();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long session_id
 * @return DestroySessionRes
 */

final class DestroySessionOk extends Instance {
	public function request(int $session_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe22045fc);
		$writer->writeLong($session_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['session_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int folder_id
 * @return DialogPeer
 */

final class DialogPeerFolder extends Instance {
	public function request(int $folder_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x514519e2);
		$writer->writeInt($folder_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['folder_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityBankCard extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x761e6af4);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessageAction
 */

final class MessageActionPinMessage extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x94bd38ed);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash bytes file_reference string thumb_size
 * @return InputFileLocation
 */

final class InputDocumentFileLocation extends Instance {
	public function request(int $id,int $access_hash,string $file_reference,string $thumb_size) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbad07584);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($file_reference);
		$writer->writeBytes($thumb_size);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['file_reference'] = $reader->readBytes();
		$result['thumb_size'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce int128 server_nonce string pq Vector<long> server_public_key_fingerprints
 * @return ResPQ
 */

final class ResPQ extends Instance {
	public function request(int | string $nonce,int | string $server_nonce,string $pq,array $server_public_key_fingerprints) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5162463);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeBytes($pq);
		$writer->writeVector($server_public_key_fingerprints,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['pq'] = $reader->readBytes();
		$result['server_public_key_fingerprints'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int folder_id Vector<dialogpeer> order
 * @return Update
 */

final class UpdatePinnedDialogs extends Instance {
	public function request(null | int $folder_id = null,null | array $order = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfa0f3ca2);
		$flags = 0;
		$flags |= is_null($folder_id) ? 0 : (1 << 1);
		$flags |= is_null($order) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($folder_id) === false):
			$writer->writeInt($folder_id);
		endif;
		if(is_null($order) === false):
			$writer->writeVector($order,'dialogpeer');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 1)):
			$result['folder_id'] = $reader->readInt();
		else:
			$result['folder_id'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['order'] = $reader->readVector('dialogpeer');
		else:
			$result['order'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int dc_id long owner_id int id long access_hash
 * @return InputBotInlineMessageID
 */

final class InputBotInlineMessageID64 extends Instance {
	public function request(int $dc_id,int $owner_id,int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb6d915d7);
		$writer->writeInt($dc_id);
		$writer->writeLong($owner_id);
		$writer->writeInt($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['dc_id'] = $reader->readInt();
		$result['owner_id'] = $reader->readLong();
		$result['id'] = $reader->readInt();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars_amount Vector<messageextendedmedia> extended_media
 * @return MessageMedia
 */

final class MessageMediaPaidMedia extends Instance {
	public function request(int $stars_amount,array $extended_media) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa8852491);
		$writer->writeLong($stars_amount);
		$writer->writeVector($extended_media,'messageextendedmedia');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['stars_amount'] = $reader->readLong();
		$result['extended_media'] = $reader->readVector('messageextendedmedia');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param double duration int w int h true round_message true supports_streaming true nosound int preload_prefix_size double video_start_ts string video_codec
 * @return DocumentAttribute
 */

final class DocumentAttributeVideo extends Instance {
	public function request(float $duration,int $w,int $h,null | bool $round_message = null,null | bool $supports_streaming = null,null | bool $nosound = null,null | int $preload_prefix_size = null,null | float $video_start_ts = null,null | string $video_codec = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x43c57c48);
		$flags = 0;
		$flags |= $round_message ? (1 << 0) : 0;
		$flags |= $supports_streaming ? (1 << 1) : 0;
		$flags |= $nosound ? (1 << 3) : 0;
		$flags |= is_null($preload_prefix_size) ? 0 : (1 << 2);
		$flags |= is_null($video_start_ts) ? 0 : (1 << 4);
		$flags |= is_null($video_codec) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeDouble($duration);
		$writer->writeInt($w);
		$writer->writeInt($h);
		if(is_null($preload_prefix_size) === false):
			$writer->writeInt($preload_prefix_size);
		endif;
		if(is_null($video_start_ts) === false):
			$writer->writeDouble($video_start_ts);
		endif;
		if(is_null($video_codec) === false):
			$writer->writeBytes($video_codec);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['round_message'] = boolval($flags & (1 << 0));
		$result['supports_streaming'] = boolval($flags & (1 << 1));
		$result['nosound'] = boolval($flags & (1 << 3));
		$result['duration'] = $reader->readDouble();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['preload_prefix_size'] = $reader->readInt();
		else:
			$result['preload_prefix_size'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['video_start_ts'] = $reader->readDouble();
		else:
			$result['video_start_ts'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['video_codec'] = $reader->readBytes();
		else:
			$result['video_codec'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id peer peer int until_date starssubscriptionpricing pricing true canceled true can_refulfill true missing_balance true bot_canceled string chat_invite_hash string title webdocument photo string invoice_slug
 * @return StarsSubscription
 */

final class StarsSubscription extends Instance {
	public function request(string $id,object $peer,int $until_date,object $pricing,null | bool $canceled = null,null | bool $can_refulfill = null,null | bool $missing_balance = null,null | bool $bot_canceled = null,null | string $chat_invite_hash = null,null | string $title = null,null | object $photo = null,null | string $invoice_slug = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2e6eab1a);
		$flags = 0;
		$flags |= $canceled ? (1 << 0) : 0;
		$flags |= $can_refulfill ? (1 << 1) : 0;
		$flags |= $missing_balance ? (1 << 2) : 0;
		$flags |= $bot_canceled ? (1 << 7) : 0;
		$flags |= is_null($chat_invite_hash) ? 0 : (1 << 3);
		$flags |= is_null($title) ? 0 : (1 << 4);
		$flags |= is_null($photo) ? 0 : (1 << 5);
		$flags |= is_null($invoice_slug) ? 0 : (1 << 6);
		$writer->writeInt($flags);
		$writer->writeBytes($id);
		$writer->writeObject($peer);
		$writer->writeInt($until_date);
		$writer->writeObject($pricing);
		if(is_null($chat_invite_hash) === false):
			$writer->writeBytes($chat_invite_hash);
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		if(is_null($invoice_slug) === false):
			$writer->writeBytes($invoice_slug);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['canceled'] = boolval($flags & (1 << 0));
		$result['can_refulfill'] = boolval($flags & (1 << 1));
		$result['missing_balance'] = boolval($flags & (1 << 2));
		$result['bot_canceled'] = boolval($flags & (1 << 7));
		$result['id'] = $reader->readBytes();
		$result['peer'] = $reader->readObject();
		$result['until_date'] = $reader->readInt();
		$result['pricing'] = $reader->readObject();
		if($flags & (1 << 3)):
			$result['chat_invite_hash'] = $reader->readBytes();
		else:
			$result['chat_invite_hash'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['invoice_slug'] = $reader->readBytes();
		else:
			$result['invoice_slug'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long client_id string phone string first_name string last_name textwithentities note
 * @return InputContact
 */

final class InputPhoneContact extends Instance {
	public function request(int $client_id,string $phone,string $first_name,string $last_name,null | object $note = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6a1dc4be);
		$flags = 0;
		$flags |= is_null($note) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($client_id);
		$writer->writeBytes($phone);
		$writer->writeBytes($first_name);
		$writer->writeBytes($last_name);
		if(is_null($note) === false):
			$writer->writeObject($note);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['client_id'] = $reader->readLong();
		$result['phone'] = $reader->readBytes();
		$result['first_name'] = $reader->readBytes();
		$result['last_name'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['note'] = $reader->readObject();
		else:
			$result['note'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id userstatus status
 * @return Update
 */

final class UpdateUserStatus extends Instance {
	public function request(int $user_id,object $status) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe5bdf8de);
		$writer->writeLong($user_id);
		$writer->writeObject($status);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['status'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int views_count true has_viewers int forwards_count Vector<reactioncount> reactions int reactions_count Vector<long> recent_viewers
 * @return StoryViews
 */

final class StoryViews extends Instance {
	public function request(int $views_count,null | bool $has_viewers = null,null | int $forwards_count = null,null | array $reactions = null,null | int $reactions_count = null,null | array $recent_viewers = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8d595cd6);
		$flags = 0;
		$flags |= $has_viewers ? (1 << 1) : 0;
		$flags |= is_null($forwards_count) ? 0 : (1 << 2);
		$flags |= is_null($reactions) ? 0 : (1 << 3);
		$flags |= is_null($reactions_count) ? 0 : (1 << 4);
		$flags |= is_null($recent_viewers) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($views_count);
		if(is_null($forwards_count) === false):
			$writer->writeInt($forwards_count);
		endif;
		if(is_null($reactions) === false):
			$writer->writeVector($reactions,'reactioncount');
		endif;
		if(is_null($reactions_count) === false):
			$writer->writeInt($reactions_count);
		endif;
		if(is_null($recent_viewers) === false):
			$writer->writeVector($recent_viewers,'long');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['has_viewers'] = boolval($flags & (1 << 1));
		$result['views_count'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['forwards_count'] = $reader->readInt();
		else:
			$result['forwards_count'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['reactions'] = $reader->readVector('reactioncount');
		else:
			$result['reactions'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['reactions_count'] = $reader->readInt();
		else:
			$result['reactions_count'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['recent_viewers'] = $reader->readVector('long');
		else:
			$result['recent_viewers'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url int size string mime_type Vector<documentattribute> attributes
 * @return InputWebDocument
 */

final class InputWebDocument extends Instance {
	public function request(string $url,int $size,string $mime_type,array $attributes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9bed434d);
		$writer->writeBytes($url);
		$writer->writeInt($size);
		$writer->writeBytes($mime_type);
		$writer->writeVector($attributes,'documentattribute');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['size'] = $reader->readInt();
		$result['mime_type'] = $reader->readBytes();
		$result['attributes'] = $reader->readVector('documentattribute');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id string about int read_inbox_max_id int read_outbox_max_id int unread_count photo chat_photo peernotifysettings notify_settings Vector<botinfo> bot_info int pts true can_view_participants true can_set_username true can_set_stickers true hidden_prehistory true can_set_location true has_scheduled true can_view_stats true blocked true can_delete_channel true antispam true participants_hidden true translations_disabled true stories_pinned_available true view_forum_as_messages true restricted_sponsored true can_view_revenue true paid_media_allowed true can_view_stars_revenue true paid_reactions_available true stargifts_available true paid_messages_available int participants_count int admins_count int kicked_count int banned_count int online_count exportedchatinvite exported_invite long migrated_from_chat_id int migrated_from_max_id int pinned_msg_id stickerset stickerset int available_min_id int folder_id long linked_chat_id channellocation location int slowmode_seconds int slowmode_next_send_date int stats_dc inputgroupcall call int ttl_period Vector<string> pending_suggestions peer groupcall_default_join_as string theme_emoticon int requests_pending Vector<long> recent_requesters peer default_send_as chatreactions available_reactions int reactions_limit peerstories stories wallpaper wallpaper int boosts_applied int boosts_unrestrict stickerset emojiset botverification bot_verification int stargifts_count long send_paid_messages_stars profiletab main_tab long guard_bot_id
 * @return ChatFull
 */

final class ChannelFull extends Instance {
	public function request(int $id,string $about,int $read_inbox_max_id,int $read_outbox_max_id,int $unread_count,object $chat_photo,object $notify_settings,array $bot_info,int $pts,null | bool $can_view_participants = null,null | bool $can_set_username = null,null | bool $can_set_stickers = null,null | bool $hidden_prehistory = null,null | bool $can_set_location = null,null | bool $has_scheduled = null,null | bool $can_view_stats = null,null | bool $blocked = null,null | bool $can_delete_channel = null,null | bool $antispam = null,null | bool $participants_hidden = null,null | bool $translations_disabled = null,null | bool $stories_pinned_available = null,null | bool $view_forum_as_messages = null,null | bool $restricted_sponsored = null,null | bool $can_view_revenue = null,null | bool $paid_media_allowed = null,null | bool $can_view_stars_revenue = null,null | bool $paid_reactions_available = null,null | bool $stargifts_available = null,null | bool $paid_messages_available = null,null | int $participants_count = null,null | int $admins_count = null,null | int $kicked_count = null,null | int $banned_count = null,null | int $online_count = null,null | object $exported_invite = null,null | int $migrated_from_chat_id = null,null | int $migrated_from_max_id = null,null | int $pinned_msg_id = null,null | object $stickerset = null,null | int $available_min_id = null,null | int $folder_id = null,null | int $linked_chat_id = null,null | object $location = null,null | int $slowmode_seconds = null,null | int $slowmode_next_send_date = null,null | int $stats_dc = null,null | object $call = null,null | int $ttl_period = null,null | array $pending_suggestions = null,null | object $groupcall_default_join_as = null,null | string $theme_emoticon = null,null | int $requests_pending = null,null | array $recent_requesters = null,null | object $default_send_as = null,null | object $available_reactions = null,null | int $reactions_limit = null,null | object $stories = null,null | object $wallpaper = null,null | int $boosts_applied = null,null | int $boosts_unrestrict = null,null | object $emojiset = null,null | object $bot_verification = null,null | int $stargifts_count = null,null | int $send_paid_messages_stars = null,null | object $main_tab = null,null | int $guard_bot_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa04e8d3a);
		$flags = 0;
		$flags |= $can_view_participants ? (1 << 3) : 0;
		$flags |= $can_set_username ? (1 << 6) : 0;
		$flags |= $can_set_stickers ? (1 << 7) : 0;
		$flags |= $hidden_prehistory ? (1 << 10) : 0;
		$flags |= $can_set_location ? (1 << 16) : 0;
		$flags |= $has_scheduled ? (1 << 19) : 0;
		$flags |= $can_view_stats ? (1 << 20) : 0;
		$flags |= $blocked ? (1 << 22) : 0;
		$flags |= is_null($participants_count) ? 0 : (1 << 0);
		$flags |= is_null($admins_count) ? 0 : (1 << 1);
		$flags |= is_null($kicked_count) ? 0 : (1 << 2);
		$flags |= is_null($banned_count) ? 0 : (1 << 2);
		$flags |= is_null($online_count) ? 0 : (1 << 13);
		$flags |= is_null($exported_invite) ? 0 : (1 << 23);
		$flags |= is_null($migrated_from_chat_id) ? 0 : (1 << 4);
		$flags |= is_null($migrated_from_max_id) ? 0 : (1 << 4);
		$flags |= is_null($pinned_msg_id) ? 0 : (1 << 5);
		$flags |= is_null($stickerset) ? 0 : (1 << 8);
		$flags |= is_null($available_min_id) ? 0 : (1 << 9);
		$flags |= is_null($folder_id) ? 0 : (1 << 11);
		$flags |= is_null($linked_chat_id) ? 0 : (1 << 14);
		$flags |= is_null($location) ? 0 : (1 << 15);
		$flags |= is_null($slowmode_seconds) ? 0 : (1 << 17);
		$flags |= is_null($slowmode_next_send_date) ? 0 : (1 << 18);
		$flags |= is_null($stats_dc) ? 0 : (1 << 12);
		$flags |= is_null($call) ? 0 : (1 << 21);
		$flags |= is_null($ttl_period) ? 0 : (1 << 24);
		$flags |= is_null($pending_suggestions) ? 0 : (1 << 25);
		$flags |= is_null($groupcall_default_join_as) ? 0 : (1 << 26);
		$flags |= is_null($theme_emoticon) ? 0 : (1 << 27);
		$flags |= is_null($requests_pending) ? 0 : (1 << 28);
		$flags |= is_null($recent_requesters) ? 0 : (1 << 28);
		$flags |= is_null($default_send_as) ? 0 : (1 << 29);
		$flags |= is_null($available_reactions) ? 0 : (1 << 30);
		$writer->writeInt($flags);
		$flags2 = 0;
		$flags2 |= $can_delete_channel ? (1 << 0) : 0;
		$flags2 |= $antispam ? (1 << 1) : 0;
		$flags2 |= $participants_hidden ? (1 << 2) : 0;
		$flags2 |= $translations_disabled ? (1 << 3) : 0;
		$flags2 |= $stories_pinned_available ? (1 << 5) : 0;
		$flags2 |= $view_forum_as_messages ? (1 << 6) : 0;
		$flags2 |= $restricted_sponsored ? (1 << 11) : 0;
		$flags2 |= $can_view_revenue ? (1 << 12) : 0;
		$flags2 |= $paid_media_allowed ? (1 << 14) : 0;
		$flags2 |= $can_view_stars_revenue ? (1 << 15) : 0;
		$flags2 |= $paid_reactions_available ? (1 << 16) : 0;
		$flags2 |= $stargifts_available ? (1 << 19) : 0;
		$flags2 |= $paid_messages_available ? (1 << 20) : 0;
		$flags2 |= is_null($reactions_limit) ? 0 : (1 << 13);
		$flags2 |= is_null($stories) ? 0 : (1 << 4);
		$flags2 |= is_null($wallpaper) ? 0 : (1 << 7);
		$flags2 |= is_null($boosts_applied) ? 0 : (1 << 8);
		$flags2 |= is_null($boosts_unrestrict) ? 0 : (1 << 9);
		$flags2 |= is_null($emojiset) ? 0 : (1 << 10);
		$flags2 |= is_null($bot_verification) ? 0 : (1 << 17);
		$flags2 |= is_null($stargifts_count) ? 0 : (1 << 18);
		$flags2 |= is_null($send_paid_messages_stars) ? 0 : (1 << 21);
		$flags2 |= is_null($main_tab) ? 0 : (1 << 22);
		$flags2 |= is_null($guard_bot_id) ? 0 : (1 << 23);
		$writer->writeInt($flags2);
		$writer->writeLong($id);
		$writer->writeBytes($about);
		if(is_null($participants_count) === false):
			$writer->writeInt($participants_count);
		endif;
		if(is_null($admins_count) === false):
			$writer->writeInt($admins_count);
		endif;
		if(is_null($kicked_count) === false):
			$writer->writeInt($kicked_count);
		endif;
		if(is_null($banned_count) === false):
			$writer->writeInt($banned_count);
		endif;
		if(is_null($online_count) === false):
			$writer->writeInt($online_count);
		endif;
		$writer->writeInt($read_inbox_max_id);
		$writer->writeInt($read_outbox_max_id);
		$writer->writeInt($unread_count);
		$writer->writeObject($chat_photo);
		$writer->writeObject($notify_settings);
		if(is_null($exported_invite) === false):
			$writer->writeObject($exported_invite);
		endif;
		$writer->writeVector($bot_info,'botinfo');
		if(is_null($migrated_from_chat_id) === false):
			$writer->writeLong($migrated_from_chat_id);
		endif;
		if(is_null($migrated_from_max_id) === false):
			$writer->writeInt($migrated_from_max_id);
		endif;
		if(is_null($pinned_msg_id) === false):
			$writer->writeInt($pinned_msg_id);
		endif;
		if(is_null($stickerset) === false):
			$writer->writeObject($stickerset);
		endif;
		if(is_null($available_min_id) === false):
			$writer->writeInt($available_min_id);
		endif;
		if(is_null($folder_id) === false):
			$writer->writeInt($folder_id);
		endif;
		if(is_null($linked_chat_id) === false):
			$writer->writeLong($linked_chat_id);
		endif;
		if(is_null($location) === false):
			$writer->writeObject($location);
		endif;
		if(is_null($slowmode_seconds) === false):
			$writer->writeInt($slowmode_seconds);
		endif;
		if(is_null($slowmode_next_send_date) === false):
			$writer->writeInt($slowmode_next_send_date);
		endif;
		if(is_null($stats_dc) === false):
			$writer->writeInt($stats_dc);
		endif;
		$writer->writeInt($pts);
		if(is_null($call) === false):
			$writer->writeObject($call);
		endif;
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		if(is_null($pending_suggestions) === false):
			$writer->writeVector($pending_suggestions,'string');
		endif;
		if(is_null($groupcall_default_join_as) === false):
			$writer->writeObject($groupcall_default_join_as);
		endif;
		if(is_null($theme_emoticon) === false):
			$writer->writeBytes($theme_emoticon);
		endif;
		if(is_null($requests_pending) === false):
			$writer->writeInt($requests_pending);
		endif;
		if(is_null($recent_requesters) === false):
			$writer->writeVector($recent_requesters,'long');
		endif;
		if(is_null($default_send_as) === false):
			$writer->writeObject($default_send_as);
		endif;
		if(is_null($available_reactions) === false):
			$writer->writeObject($available_reactions);
		endif;
		if(is_null($reactions_limit) === false):
			$writer->writeInt($reactions_limit);
		endif;
		if(is_null($stories) === false):
			$writer->writeObject($stories);
		endif;
		if(is_null($wallpaper) === false):
			$writer->writeObject($wallpaper);
		endif;
		if(is_null($boosts_applied) === false):
			$writer->writeInt($boosts_applied);
		endif;
		if(is_null($boosts_unrestrict) === false):
			$writer->writeInt($boosts_unrestrict);
		endif;
		if(is_null($emojiset) === false):
			$writer->writeObject($emojiset);
		endif;
		if(is_null($bot_verification) === false):
			$writer->writeObject($bot_verification);
		endif;
		if(is_null($stargifts_count) === false):
			$writer->writeInt($stargifts_count);
		endif;
		if(is_null($send_paid_messages_stars) === false):
			$writer->writeLong($send_paid_messages_stars);
		endif;
		if(is_null($main_tab) === false):
			$writer->writeObject($main_tab);
		endif;
		if(is_null($guard_bot_id) === false):
			$writer->writeLong($guard_bot_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['can_view_participants'] = boolval($flags & (1 << 3));
		$result['can_set_username'] = boolval($flags & (1 << 6));
		$result['can_set_stickers'] = boolval($flags & (1 << 7));
		$result['hidden_prehistory'] = boolval($flags & (1 << 10));
		$result['can_set_location'] = boolval($flags & (1 << 16));
		$result['has_scheduled'] = boolval($flags & (1 << 19));
		$result['can_view_stats'] = boolval($flags & (1 << 20));
		$result['blocked'] = boolval($flags & (1 << 22));
		$flags2 = $reader->readInt();
		$result['can_delete_channel'] = boolval($flags2 & (1 << 0));
		$result['antispam'] = boolval($flags2 & (1 << 1));
		$result['participants_hidden'] = boolval($flags2 & (1 << 2));
		$result['translations_disabled'] = boolval($flags2 & (1 << 3));
		$result['stories_pinned_available'] = boolval($flags2 & (1 << 5));
		$result['view_forum_as_messages'] = boolval($flags2 & (1 << 6));
		$result['restricted_sponsored'] = boolval($flags2 & (1 << 11));
		$result['can_view_revenue'] = boolval($flags2 & (1 << 12));
		$result['paid_media_allowed'] = boolval($flags2 & (1 << 14));
		$result['can_view_stars_revenue'] = boolval($flags2 & (1 << 15));
		$result['paid_reactions_available'] = boolval($flags2 & (1 << 16));
		$result['stargifts_available'] = boolval($flags2 & (1 << 19));
		$result['paid_messages_available'] = boolval($flags2 & (1 << 20));
		$result['id'] = $reader->readLong();
		$result['about'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['participants_count'] = $reader->readInt();
		else:
			$result['participants_count'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['admins_count'] = $reader->readInt();
		else:
			$result['admins_count'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['kicked_count'] = $reader->readInt();
		else:
			$result['kicked_count'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['banned_count'] = $reader->readInt();
		else:
			$result['banned_count'] = null;
		endif;
		if($flags & (1 << 13)):
			$result['online_count'] = $reader->readInt();
		else:
			$result['online_count'] = null;
		endif;
		$result['read_inbox_max_id'] = $reader->readInt();
		$result['read_outbox_max_id'] = $reader->readInt();
		$result['unread_count'] = $reader->readInt();
		$result['chat_photo'] = $reader->readObject();
		$result['notify_settings'] = $reader->readObject();
		if($flags & (1 << 23)):
			$result['exported_invite'] = $reader->readObject();
		else:
			$result['exported_invite'] = null;
		endif;
		$result['bot_info'] = $reader->readVector('botinfo');
		if($flags & (1 << 4)):
			$result['migrated_from_chat_id'] = $reader->readLong();
		else:
			$result['migrated_from_chat_id'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['migrated_from_max_id'] = $reader->readInt();
		else:
			$result['migrated_from_max_id'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['pinned_msg_id'] = $reader->readInt();
		else:
			$result['pinned_msg_id'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['stickerset'] = $reader->readObject();
		else:
			$result['stickerset'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['available_min_id'] = $reader->readInt();
		else:
			$result['available_min_id'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['folder_id'] = $reader->readInt();
		else:
			$result['folder_id'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['linked_chat_id'] = $reader->readLong();
		else:
			$result['linked_chat_id'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['location'] = $reader->readObject();
		else:
			$result['location'] = null;
		endif;
		if($flags & (1 << 17)):
			$result['slowmode_seconds'] = $reader->readInt();
		else:
			$result['slowmode_seconds'] = null;
		endif;
		if($flags & (1 << 18)):
			$result['slowmode_next_send_date'] = $reader->readInt();
		else:
			$result['slowmode_next_send_date'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['stats_dc'] = $reader->readInt();
		else:
			$result['stats_dc'] = null;
		endif;
		$result['pts'] = $reader->readInt();
		if($flags & (1 << 21)):
			$result['call'] = $reader->readObject();
		else:
			$result['call'] = null;
		endif;
		if($flags & (1 << 24)):
			$result['ttl_period'] = $reader->readInt();
		else:
			$result['ttl_period'] = null;
		endif;
		if($flags & (1 << 25)):
			$result['pending_suggestions'] = $reader->readVector('string');
		else:
			$result['pending_suggestions'] = null;
		endif;
		if($flags & (1 << 26)):
			$result['groupcall_default_join_as'] = $reader->readObject();
		else:
			$result['groupcall_default_join_as'] = null;
		endif;
		if($flags & (1 << 27)):
			$result['theme_emoticon'] = $reader->readBytes();
		else:
			$result['theme_emoticon'] = null;
		endif;
		if($flags & (1 << 28)):
			$result['requests_pending'] = $reader->readInt();
		else:
			$result['requests_pending'] = null;
		endif;
		if($flags & (1 << 28)):
			$result['recent_requesters'] = $reader->readVector('long');
		else:
			$result['recent_requesters'] = null;
		endif;
		if($flags & (1 << 29)):
			$result['default_send_as'] = $reader->readObject();
		else:
			$result['default_send_as'] = null;
		endif;
		if($flags & (1 << 30)):
			$result['available_reactions'] = $reader->readObject();
		else:
			$result['available_reactions'] = null;
		endif;
		if($flags2 & (1 << 13)):
			$result['reactions_limit'] = $reader->readInt();
		else:
			$result['reactions_limit'] = null;
		endif;
		if($flags2 & (1 << 4)):
			$result['stories'] = $reader->readObject();
		else:
			$result['stories'] = null;
		endif;
		if($flags2 & (1 << 7)):
			$result['wallpaper'] = $reader->readObject();
		else:
			$result['wallpaper'] = null;
		endif;
		if($flags2 & (1 << 8)):
			$result['boosts_applied'] = $reader->readInt();
		else:
			$result['boosts_applied'] = null;
		endif;
		if($flags2 & (1 << 9)):
			$result['boosts_unrestrict'] = $reader->readInt();
		else:
			$result['boosts_unrestrict'] = null;
		endif;
		if($flags2 & (1 << 10)):
			$result['emojiset'] = $reader->readObject();
		else:
			$result['emojiset'] = null;
		endif;
		if($flags2 & (1 << 17)):
			$result['bot_verification'] = $reader->readObject();
		else:
			$result['bot_verification'] = null;
		endif;
		if($flags2 & (1 << 18)):
			$result['stargifts_count'] = $reader->readInt();
		else:
			$result['stargifts_count'] = null;
		endif;
		if($flags2 & (1 << 21)):
			$result['send_paid_messages_stars'] = $reader->readLong();
		else:
			$result['send_paid_messages_stars'] = null;
		endif;
		if($flags2 & (1 << 22)):
			$result['main_tab'] = $reader->readObject();
		else:
			$result['main_tab'] = null;
		endif;
		if($flags2 & (1 << 23)):
			$result['guard_bot_id'] = $reader->readLong();
		else:
			$result['guard_bot_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id string rank
 * @return ChatParticipant
 */

final class ChatParticipantCreator extends Instance {
	public function request(int $user_id,null | string $rank = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe1f867b8);
		$flags = 0;
		$flags |= is_null($rank) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		if(is_null($rank) === false):
			$writer->writeBytes($rank);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['rank'] = $reader->readBytes();
		else:
			$result['rank'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long collectible_id long gift_emoji_id long background_emoji_id int accent_color Vector<int> colors int dark_accent_color Vector<int> dark_colors
 * @return PeerColor
 */

final class PeerColorCollectible extends Instance {
	public function request(int $collectible_id,int $gift_emoji_id,int $background_emoji_id,int $accent_color,array $colors,null | int $dark_accent_color = null,null | array $dark_colors = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb9c0639a);
		$flags = 0;
		$flags |= is_null($dark_accent_color) ? 0 : (1 << 0);
		$flags |= is_null($dark_colors) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($collectible_id);
		$writer->writeLong($gift_emoji_id);
		$writer->writeLong($background_emoji_id);
		$writer->writeInt($accent_color);
		$writer->writeVector($colors,'int');
		if(is_null($dark_accent_color) === false):
			$writer->writeInt($dark_accent_color);
		endif;
		if(is_null($dark_colors) === false):
			$writer->writeVector($dark_colors,'int');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['collectible_id'] = $reader->readLong();
		$result['gift_emoji_id'] = $reader->readLong();
		$result['background_emoji_id'] = $reader->readLong();
		$result['accent_color'] = $reader->readInt();
		$result['colors'] = $reader->readVector('int');
		if($flags & (1 << 0)):
			$result['dark_accent_color'] = $reader->readInt();
		else:
			$result['dark_accent_color'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['dark_colors'] = $reader->readVector('int');
		else:
			$result['dark_colors'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stickerset set Vector<stickerpack> packs Vector<stickerkeyword> keywords Vector<document> documents
 * @return StickerSetCovered
 */

final class StickerSetFullCovered extends Instance {
	public function request(object $set,array $packs,array $keywords,array $documents) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x40d13c0e);
		$writer->writeObject($set);
		$writer->writeVector($packs,'stickerpack');
		$writer->writeVector($keywords,'stickerkeyword');
		$writer->writeVector($documents,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['set'] = $reader->readObject();
		$result['packs'] = $reader->readVector('stickerpack');
		$result['keywords'] = $reader->readVector('stickerkeyword');
		$result['documents'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id
 * @return Peer
 */

final class PeerUser extends Instance {
	public function request(int $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x59511722);
		$writer->writeLong($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyPhoneNumber extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd19ae46d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string link long admin_id int date true revoked true permanent true request_needed int start_date int expire_date int usage_limit int usage int requested int subscription_expired string title starssubscriptionpricing subscription_pricing
 * @return ExportedChatInvite
 */

final class ChatInviteExported extends Instance {
	public function request(string $link,int $admin_id,int $date,null | bool $revoked = null,null | bool $permanent = null,null | bool $request_needed = null,null | int $start_date = null,null | int $expire_date = null,null | int $usage_limit = null,null | int $usage = null,null | int $requested = null,null | int $subscription_expired = null,null | string $title = null,null | object $subscription_pricing = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa22cbd96);
		$flags = 0;
		$flags |= $revoked ? (1 << 0) : 0;
		$flags |= $permanent ? (1 << 5) : 0;
		$flags |= $request_needed ? (1 << 6) : 0;
		$flags |= is_null($start_date) ? 0 : (1 << 4);
		$flags |= is_null($expire_date) ? 0 : (1 << 1);
		$flags |= is_null($usage_limit) ? 0 : (1 << 2);
		$flags |= is_null($usage) ? 0 : (1 << 3);
		$flags |= is_null($requested) ? 0 : (1 << 7);
		$flags |= is_null($subscription_expired) ? 0 : (1 << 10);
		$flags |= is_null($title) ? 0 : (1 << 8);
		$flags |= is_null($subscription_pricing) ? 0 : (1 << 9);
		$writer->writeInt($flags);
		$writer->writeBytes($link);
		$writer->writeLong($admin_id);
		$writer->writeInt($date);
		if(is_null($start_date) === false):
			$writer->writeInt($start_date);
		endif;
		if(is_null($expire_date) === false):
			$writer->writeInt($expire_date);
		endif;
		if(is_null($usage_limit) === false):
			$writer->writeInt($usage_limit);
		endif;
		if(is_null($usage) === false):
			$writer->writeInt($usage);
		endif;
		if(is_null($requested) === false):
			$writer->writeInt($requested);
		endif;
		if(is_null($subscription_expired) === false):
			$writer->writeInt($subscription_expired);
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($subscription_pricing) === false):
			$writer->writeObject($subscription_pricing);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['revoked'] = boolval($flags & (1 << 0));
		$result['permanent'] = boolval($flags & (1 << 5));
		$result['request_needed'] = boolval($flags & (1 << 6));
		$result['link'] = $reader->readBytes();
		$result['admin_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 4)):
			$result['start_date'] = $reader->readInt();
		else:
			$result['start_date'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['expire_date'] = $reader->readInt();
		else:
			$result['expire_date'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['usage_limit'] = $reader->readInt();
		else:
			$result['usage_limit'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['usage'] = $reader->readInt();
		else:
			$result['usage'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['requested'] = $reader->readInt();
		else:
			$result['requested'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['subscription_expired'] = $reader->readInt();
		else:
			$result['subscription_expired'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['subscription_pricing'] = $reader->readObject();
		else:
			$result['subscription_pricing'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string domain string url string title long favicon
 * @return WebDomainException
 */

final class WebDomainException extends Instance {
	public function request(string $domain,string $url,string $title,null | int $favicon = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x933ca597);
		$flags = 0;
		$flags |= is_null($favicon) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($domain);
		$writer->writeBytes($url);
		$writer->writeBytes($title);
		if(is_null($favicon) === false):
			$writer->writeLong($favicon);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['domain'] = $reader->readBytes();
		$result['url'] = $reader->readBytes();
		$result['title'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['favicon'] = $reader->readLong();
		else:
			$result['favicon'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputStickerSet
 */

final class InputStickerSetEmojiDefaultStatuses extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x29d0f5ee);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q
 * @return ChannelParticipantsFilter
 */

final class ChannelParticipantsKicked extends Instance {
	public function request(string $q) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa3b54985);
		$writer->writeBytes($q);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['q'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterVideo extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9fc00e65);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string currency Vector<labeledprice> prices true test true name_requested true phone_requested true email_requested true shipping_address_requested true flexible true phone_to_provider true email_to_provider true recurring long max_tip_amount Vector<long> suggested_tip_amounts string terms_url int subscription_period
 * @return Invoice
 */

final class Invoice extends Instance {
	public function request(string $currency,array $prices,null | bool $test = null,null | bool $name_requested = null,null | bool $phone_requested = null,null | bool $email_requested = null,null | bool $shipping_address_requested = null,null | bool $flexible = null,null | bool $phone_to_provider = null,null | bool $email_to_provider = null,null | bool $recurring = null,null | int $max_tip_amount = null,null | array $suggested_tip_amounts = null,null | string $terms_url = null,null | int $subscription_period = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x49ee584);
		$flags = 0;
		$flags |= $test ? (1 << 0) : 0;
		$flags |= $name_requested ? (1 << 1) : 0;
		$flags |= $phone_requested ? (1 << 2) : 0;
		$flags |= $email_requested ? (1 << 3) : 0;
		$flags |= $shipping_address_requested ? (1 << 4) : 0;
		$flags |= $flexible ? (1 << 5) : 0;
		$flags |= $phone_to_provider ? (1 << 6) : 0;
		$flags |= $email_to_provider ? (1 << 7) : 0;
		$flags |= $recurring ? (1 << 9) : 0;
		$flags |= is_null($max_tip_amount) ? 0 : (1 << 8);
		$flags |= is_null($suggested_tip_amounts) ? 0 : (1 << 8);
		$flags |= is_null($terms_url) ? 0 : (1 << 10);
		$flags |= is_null($subscription_period) ? 0 : (1 << 11);
		$writer->writeInt($flags);
		$writer->writeBytes($currency);
		$writer->writeVector($prices,'labeledprice');
		if(is_null($max_tip_amount) === false):
			$writer->writeLong($max_tip_amount);
		endif;
		if(is_null($suggested_tip_amounts) === false):
			$writer->writeVector($suggested_tip_amounts,'long');
		endif;
		if(is_null($terms_url) === false):
			$writer->writeBytes($terms_url);
		endif;
		if(is_null($subscription_period) === false):
			$writer->writeInt($subscription_period);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['test'] = boolval($flags & (1 << 0));
		$result['name_requested'] = boolval($flags & (1 << 1));
		$result['phone_requested'] = boolval($flags & (1 << 2));
		$result['email_requested'] = boolval($flags & (1 << 3));
		$result['shipping_address_requested'] = boolval($flags & (1 << 4));
		$result['flexible'] = boolval($flags & (1 << 5));
		$result['phone_to_provider'] = boolval($flags & (1 << 6));
		$result['email_to_provider'] = boolval($flags & (1 << 7));
		$result['recurring'] = boolval($flags & (1 << 9));
		$result['currency'] = $reader->readBytes();
		$result['prices'] = $reader->readVector('labeledprice');
		if($flags & (1 << 8)):
			$result['max_tip_amount'] = $reader->readLong();
		else:
			$result['max_tip_amount'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['suggested_tip_amounts'] = $reader->readVector('long');
		else:
			$result['suggested_tip_amounts'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['terms_url'] = $reader->readBytes();
		else:
			$result['terms_url'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['subscription_period'] = $reader->readInt();
		else:
			$result['subscription_period'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long video_id pagecaption caption true autoplay true loop true spoiler
 * @return PageBlock
 */

final class PageBlockVideo extends Instance {
	public function request(int $video_id,object $caption,null | bool $autoplay = null,null | bool $loop = null,null | bool $spoiler = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7c8fe7b6);
		$flags = 0;
		$flags |= $autoplay ? (1 << 0) : 0;
		$flags |= $loop ? (1 << 1) : 0;
		$flags |= $spoiler ? (1 << 2) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($video_id);
		$writer->writeObject($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['autoplay'] = boolval($flags & (1 << 0));
		$result['loop'] = boolval($flags & (1 << 1));
		$result['spoiler'] = boolval($flags & (1 << 2));
		$result['video_id'] = $reader->readLong();
		$result['caption'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long document_id Vector<string> keyword
 * @return StickerKeyword
 */

final class StickerKeyword extends Instance {
	public function request(int $document_id,array $keyword) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfcfeb29c);
		$writer->writeLong($document_id);
		$writer->writeVector($keyword,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['document_id'] = $reader->readLong();
		$result['keyword'] = $reader->readVector('string');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title Vector<long> users
 * @return MessageAction
 */

final class MessageActionChatCreate extends Instance {
	public function request(string $title,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd47cbad);
		$writer->writeBytes($title);
		$writer->writeVector($users,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readBytes();
		$result['users'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id long query_id
 * @return InputMessage
 */

final class InputMessageCallbackQuery extends Instance {
	public function request(int $id,int $query_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xacfa1a7e);
		$writer->writeInt($id);
		$writer->writeLong($query_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		$result['query_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true missed
 * @return MessagesFilter
 */

final class InputMessagesFilterPhoneCalls extends Instance {
	public function request(null | bool $missed = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x80c99768);
		$flags = 0;
		$flags |= $missed ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['missed'] = boolval($flags & (1 << 0));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param exportedchatinvite invite
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionExportedInviteRevoke extends Instance {
	public function request(object $invite) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x410a134e);
		$writer->writeObject($invite);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['invite'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text string url inputuser bot true request_write_access keyboardbuttonstyle style string fwd_text
 * @return KeyboardButton
 */

final class InputKeyboardButtonUrlAuth extends Instance {
	public function request(string $text,string $url,object $bot,null | bool $request_write_access = null,null | object $style = null,null | string $fwd_text = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x68013e72);
		$flags = 0;
		$flags |= $request_write_access ? (1 << 0) : 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$flags |= is_null($fwd_text) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		if(is_null($fwd_text) === false):
			$writer->writeBytes($fwd_text);
		endif;
		$writer->writeBytes($url);
		$writer->writeObject($bot);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['request_write_access'] = boolval($flags & (1 << 0));
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['fwd_text'] = $reader->readBytes();
		else:
			$result['fwd_text'] = null;
		endif;
		$result['url'] = $reader->readBytes();
		$result['bot'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BotMenuButton
 */

final class BotMenuButtonCommands extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4258c205);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash long bot_id string domain string browser string platform int date_created int date_active string ip string region
 * @return WebAuthorization
 */

final class WebAuthorization extends Instance {
	public function request(int $hash,int $bot_id,string $domain,string $browser,string $platform,int $date_created,int $date_active,string $ip,string $region) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa6f8f452);
		$writer->writeLong($hash);
		$writer->writeLong($bot_id);
		$writer->writeBytes($domain);
		$writer->writeBytes($browser);
		$writer->writeBytes($platform);
		$writer->writeInt($date_created);
		$writer->writeInt($date_active);
		$writer->writeBytes($ip);
		$writer->writeBytes($region);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['bot_id'] = $reader->readLong();
		$result['domain'] = $reader->readBytes();
		$result['browser'] = $reader->readBytes();
		$result['platform'] = $reader->readBytes();
		$result['date_created'] = $reader->readInt();
		$result['date_active'] = $reader->readInt();
		$result['ip'] = $reader->readBytes();
		$result['region'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyRule
 */

final class PrivacyValueDisallowBots extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf6a5f82f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date messagemedia media
 * @return BotPreviewMedia
 */

final class BotPreviewMedia extends Instance {
	public function request(int $date,object $media) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x23e91ba3);
		$writer->writeInt($date);
		$writer->writeObject($media);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['date'] = $reader->readInt();
		$result['media'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true min true has_unread_votes true can_view_stats Vector<pollanswervoters> results int total_voters Vector<peer> recent_voters string solution Vector<messageentity> solution_entities messagemedia solution_media
 * @return PollResults
 */

final class PollResults extends Instance {
	public function request(null | bool $min = null,null | bool $has_unread_votes = null,null | bool $can_view_stats = null,null | array $results = null,null | int $total_voters = null,null | array $recent_voters = null,null | string $solution = null,null | array $solution_entities = null,null | object $solution_media = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xba7bb15e);
		$flags = 0;
		$flags |= $min ? (1 << 0) : 0;
		$flags |= $has_unread_votes ? (1 << 6) : 0;
		$flags |= $can_view_stats ? (1 << 7) : 0;
		$flags |= is_null($results) ? 0 : (1 << 1);
		$flags |= is_null($total_voters) ? 0 : (1 << 2);
		$flags |= is_null($recent_voters) ? 0 : (1 << 3);
		$flags |= is_null($solution) ? 0 : (1 << 4);
		$flags |= is_null($solution_entities) ? 0 : (1 << 4);
		$flags |= is_null($solution_media) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		if(is_null($results) === false):
			$writer->writeVector($results,'pollanswervoters');
		endif;
		if(is_null($total_voters) === false):
			$writer->writeInt($total_voters);
		endif;
		if(is_null($recent_voters) === false):
			$writer->writeVector($recent_voters,'peer');
		endif;
		if(is_null($solution) === false):
			$writer->writeBytes($solution);
		endif;
		if(is_null($solution_entities) === false):
			$writer->writeVector($solution_entities,'messageentity');
		endif;
		if(is_null($solution_media) === false):
			$writer->writeObject($solution_media);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['min'] = boolval($flags & (1 << 0));
		$result['has_unread_votes'] = boolval($flags & (1 << 6));
		$result['can_view_stats'] = boolval($flags & (1 << 7));
		if($flags & (1 << 1)):
			$result['results'] = $reader->readVector('pollanswervoters');
		else:
			$result['results'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['total_voters'] = $reader->readInt();
		else:
			$result['total_voters'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['recent_voters'] = $reader->readVector('peer');
		else:
			$result['recent_voters'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['solution'] = $reader->readBytes();
		else:
			$result['solution'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['solution_entities'] = $reader->readVector('messageentity');
		else:
			$result['solution_entities'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['solution_media'] = $reader->readObject();
		else:
			$result['solution_media'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true existing_chats true new_chats true contacts true non_contacts true exclude_selected Vector<long> users
 * @return BusinessRecipients
 */

final class BusinessRecipients extends Instance {
	public function request(null | bool $existing_chats = null,null | bool $new_chats = null,null | bool $contacts = null,null | bool $non_contacts = null,null | bool $exclude_selected = null,null | array $users = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x21108ff7);
		$flags = 0;
		$flags |= $existing_chats ? (1 << 0) : 0;
		$flags |= $new_chats ? (1 << 1) : 0;
		$flags |= $contacts ? (1 << 2) : 0;
		$flags |= $non_contacts ? (1 << 3) : 0;
		$flags |= $exclude_selected ? (1 << 5) : 0;
		$flags |= is_null($users) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		if(is_null($users) === false):
			$writer->writeVector($users,'long');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['existing_chats'] = boolval($flags & (1 << 0));
		$result['new_chats'] = boolval($flags & (1 << 1));
		$result['contacts'] = boolval($flags & (1 << 2));
		$result['non_contacts'] = boolval($flags & (1 << 3));
		$result['exclude_selected'] = boolval($flags & (1 << 5));
		if($flags & (1 << 4)):
			$result['users'] = $reader->readVector('long');
		else:
			$result['users'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int date long user_id string about exportedchatinvite invite int qts long query_id
 * @return Update
 */

final class UpdateBotChatInviteRequester extends Instance {
	public function request(object $peer,int $date,int $user_id,string $about,object $invite,int $qts,null | int $query_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7cb34d79);
		$flags = 0;
		$flags |= is_null($query_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($date);
		$writer->writeLong($user_id);
		$writer->writeBytes($about);
		$writer->writeObject($invite);
		$writer->writeInt($qts);
		if(is_null($query_id) === false):
			$writer->writeLong($query_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['peer'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		$result['about'] = $reader->readBytes();
		$result['invite'] = $reader->readObject();
		$result['qts'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['query_id'] = $reader->readLong();
		else:
			$result['query_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param double x double y double w double h double rotation double radius
 * @return MediaAreaCoordinates
 */

final class MediaAreaCoordinates extends Instance {
	public function request(float $x,float $y,float $w,float $h,float $rotation,null | float $radius = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcfc9e002);
		$flags = 0;
		$flags |= is_null($radius) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeDouble($x);
		$writer->writeDouble($y);
		$writer->writeDouble($w);
		$writer->writeDouble($h);
		$writer->writeDouble($rotation);
		if(is_null($radius) === false):
			$writer->writeDouble($radius);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['x'] = $reader->readDouble();
		$result['y'] = $reader->readDouble();
		$result['w'] = $reader->readDouble();
		$result['h'] = $reader->readDouble();
		$result['rotation'] = $reader->readDouble();
		if($flags & (1 << 0)):
			$result['radius'] = $reader->readDouble();
		else:
			$result['radius'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SendMessageAction
 */

final class SendMessageGeoLocationAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x176f8ba1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q
 * @return ChannelParticipantsFilter
 */

final class ChannelParticipantsContacts extends Instance {
	public function request(string $q) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbb6ae88d);
		$writer->writeBytes($q);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['q'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id starsamount amount int date starstransactionpeer peer true refund true pending true failed true gift true reaction true stargift_upgrade true business_transfer true stargift_resale true posts_search true stargift_prepaid_upgrade true stargift_drop_original_details true phonegroup_message true stargift_auction_bid true offer string title string description webdocument photo int transaction_date string transaction_url bytes bot_payload int msg_id Vector<messagemedia> extended_media int subscription_period int giveaway_post_id stargift stargift int floodskip_number int starref_commission_permille peer starref_peer starsamount starref_amount int paid_messages int premium_gift_months int ads_proceeds_from_date int ads_proceeds_to_date
 * @return StarsTransaction
 */

final class StarsTransaction extends Instance {
	public function request(string $id,object $amount,int $date,object $peer,null | bool $refund = null,null | bool $pending = null,null | bool $failed = null,null | bool $gift = null,null | bool $reaction = null,null | bool $stargift_upgrade = null,null | bool $business_transfer = null,null | bool $stargift_resale = null,null | bool $posts_search = null,null | bool $stargift_prepaid_upgrade = null,null | bool $stargift_drop_original_details = null,null | bool $phonegroup_message = null,null | bool $stargift_auction_bid = null,null | bool $offer = null,null | string $title = null,null | string $description = null,null | object $photo = null,null | int $transaction_date = null,null | string $transaction_url = null,null | string $bot_payload = null,null | int $msg_id = null,null | array $extended_media = null,null | int $subscription_period = null,null | int $giveaway_post_id = null,null | object $stargift = null,null | int $floodskip_number = null,null | int $starref_commission_permille = null,null | object $starref_peer = null,null | object $starref_amount = null,null | int $paid_messages = null,null | int $premium_gift_months = null,null | int $ads_proceeds_from_date = null,null | int $ads_proceeds_to_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x13659eb0);
		$flags = 0;
		$flags |= $refund ? (1 << 3) : 0;
		$flags |= $pending ? (1 << 4) : 0;
		$flags |= $failed ? (1 << 6) : 0;
		$flags |= $gift ? (1 << 10) : 0;
		$flags |= $reaction ? (1 << 11) : 0;
		$flags |= $stargift_upgrade ? (1 << 18) : 0;
		$flags |= $business_transfer ? (1 << 21) : 0;
		$flags |= $stargift_resale ? (1 << 22) : 0;
		$flags |= $posts_search ? (1 << 24) : 0;
		$flags |= $stargift_prepaid_upgrade ? (1 << 25) : 0;
		$flags |= $stargift_drop_original_details ? (1 << 26) : 0;
		$flags |= $phonegroup_message ? (1 << 27) : 0;
		$flags |= $stargift_auction_bid ? (1 << 28) : 0;
		$flags |= $offer ? (1 << 29) : 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$flags |= is_null($description) ? 0 : (1 << 1);
		$flags |= is_null($photo) ? 0 : (1 << 2);
		$flags |= is_null($transaction_date) ? 0 : (1 << 5);
		$flags |= is_null($transaction_url) ? 0 : (1 << 5);
		$flags |= is_null($bot_payload) ? 0 : (1 << 7);
		$flags |= is_null($msg_id) ? 0 : (1 << 8);
		$flags |= is_null($extended_media) ? 0 : (1 << 9);
		$flags |= is_null($subscription_period) ? 0 : (1 << 12);
		$flags |= is_null($giveaway_post_id) ? 0 : (1 << 13);
		$flags |= is_null($stargift) ? 0 : (1 << 14);
		$flags |= is_null($floodskip_number) ? 0 : (1 << 15);
		$flags |= is_null($starref_commission_permille) ? 0 : (1 << 16);
		$flags |= is_null($starref_peer) ? 0 : (1 << 17);
		$flags |= is_null($starref_amount) ? 0 : (1 << 17);
		$flags |= is_null($paid_messages) ? 0 : (1 << 19);
		$flags |= is_null($premium_gift_months) ? 0 : (1 << 20);
		$flags |= is_null($ads_proceeds_from_date) ? 0 : (1 << 23);
		$flags |= is_null($ads_proceeds_to_date) ? 0 : (1 << 23);
		$writer->writeInt($flags);
		$writer->writeBytes($id);
		$writer->writeObject($amount);
		$writer->writeInt($date);
		$writer->writeObject($peer);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($description) === false):
			$writer->writeBytes($description);
		endif;
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		if(is_null($transaction_date) === false):
			$writer->writeInt($transaction_date);
		endif;
		if(is_null($transaction_url) === false):
			$writer->writeBytes($transaction_url);
		endif;
		if(is_null($bot_payload) === false):
			$writer->writeBytes($bot_payload);
		endif;
		if(is_null($msg_id) === false):
			$writer->writeInt($msg_id);
		endif;
		if(is_null($extended_media) === false):
			$writer->writeVector($extended_media,'messagemedia');
		endif;
		if(is_null($subscription_period) === false):
			$writer->writeInt($subscription_period);
		endif;
		if(is_null($giveaway_post_id) === false):
			$writer->writeInt($giveaway_post_id);
		endif;
		if(is_null($stargift) === false):
			$writer->writeObject($stargift);
		endif;
		if(is_null($floodskip_number) === false):
			$writer->writeInt($floodskip_number);
		endif;
		if(is_null($starref_commission_permille) === false):
			$writer->writeInt($starref_commission_permille);
		endif;
		if(is_null($starref_peer) === false):
			$writer->writeObject($starref_peer);
		endif;
		if(is_null($starref_amount) === false):
			$writer->writeObject($starref_amount);
		endif;
		if(is_null($paid_messages) === false):
			$writer->writeInt($paid_messages);
		endif;
		if(is_null($premium_gift_months) === false):
			$writer->writeInt($premium_gift_months);
		endif;
		if(is_null($ads_proceeds_from_date) === false):
			$writer->writeInt($ads_proceeds_from_date);
		endif;
		if(is_null($ads_proceeds_to_date) === false):
			$writer->writeInt($ads_proceeds_to_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['refund'] = boolval($flags & (1 << 3));
		$result['pending'] = boolval($flags & (1 << 4));
		$result['failed'] = boolval($flags & (1 << 6));
		$result['gift'] = boolval($flags & (1 << 10));
		$result['reaction'] = boolval($flags & (1 << 11));
		$result['stargift_upgrade'] = boolval($flags & (1 << 18));
		$result['business_transfer'] = boolval($flags & (1 << 21));
		$result['stargift_resale'] = boolval($flags & (1 << 22));
		$result['posts_search'] = boolval($flags & (1 << 24));
		$result['stargift_prepaid_upgrade'] = boolval($flags & (1 << 25));
		$result['stargift_drop_original_details'] = boolval($flags & (1 << 26));
		$result['phonegroup_message'] = boolval($flags & (1 << 27));
		$result['stargift_auction_bid'] = boolval($flags & (1 << 28));
		$result['offer'] = boolval($flags & (1 << 29));
		$result['id'] = $reader->readBytes();
		$result['amount'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		$result['peer'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['description'] = $reader->readBytes();
		else:
			$result['description'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['transaction_date'] = $reader->readInt();
		else:
			$result['transaction_date'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['transaction_url'] = $reader->readBytes();
		else:
			$result['transaction_url'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['bot_payload'] = $reader->readBytes();
		else:
			$result['bot_payload'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['msg_id'] = $reader->readInt();
		else:
			$result['msg_id'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['extended_media'] = $reader->readVector('messagemedia');
		else:
			$result['extended_media'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['subscription_period'] = $reader->readInt();
		else:
			$result['subscription_period'] = null;
		endif;
		if($flags & (1 << 13)):
			$result['giveaway_post_id'] = $reader->readInt();
		else:
			$result['giveaway_post_id'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['stargift'] = $reader->readObject();
		else:
			$result['stargift'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['floodskip_number'] = $reader->readInt();
		else:
			$result['floodskip_number'] = null;
		endif;
		if($flags & (1 << 16)):
			$result['starref_commission_permille'] = $reader->readInt();
		else:
			$result['starref_commission_permille'] = null;
		endif;
		if($flags & (1 << 17)):
			$result['starref_peer'] = $reader->readObject();
		else:
			$result['starref_peer'] = null;
		endif;
		if($flags & (1 << 17)):
			$result['starref_amount'] = $reader->readObject();
		else:
			$result['starref_amount'] = null;
		endif;
		if($flags & (1 << 19)):
			$result['paid_messages'] = $reader->readInt();
		else:
			$result['paid_messages'] = null;
		endif;
		if($flags & (1 << 20)):
			$result['premium_gift_months'] = $reader->readInt();
		else:
			$result['premium_gift_months'] = null;
		endif;
		if($flags & (1 << 23)):
			$result['ads_proceeds_from_date'] = $reader->readInt();
		else:
			$result['ads_proceeds_from_date'] = null;
		endif;
		if($flags & (1 << 23)):
			$result['ads_proceeds_to_date'] = $reader->readInt();
		else:
			$result['ads_proceeds_to_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int id true via_mention storyitem story
 * @return MessageMedia
 */

final class MessageMediaStory extends Instance {
	public function request(object $peer,int $id,null | bool $via_mention = null,null | object $story = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x68cb6283);
		$flags = 0;
		$flags |= $via_mention ? (1 << 1) : 0;
		$flags |= is_null($story) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		if(is_null($story) === false):
			$writer->writeObject($story);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['via_mention'] = boolval($flags & (1 << 1));
		$result['peer'] = $reader->readObject();
		$result['id'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['story'] = $reader->readObject();
		else:
			$result['story'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string emoticon
 * @return SendMessageAction
 */

final class SendMessageEmojiInteractionSeen extends Instance {
	public function request(string $emoticon) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb665902e);
		$writer->writeBytes($emoticon);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['emoticon'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id long channel_id
 * @return InputChannel
 */

final class InputChannelFromMessage extends Instance {
	public function request(object $peer,int $msg_id,int $channel_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5b934f9d);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeLong($channel_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		$result['channel_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param chattheme theme
 * @return MessageAction
 */

final class MessageActionSetChatTheme extends Instance {
	public function request(object $theme) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb91bbd3a);
		$writer->writeObject($theme);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['theme'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateSavedRingtones extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x74d8be99);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true existing_chats true new_chats true contacts true non_contacts true exclude_selected Vector<inputuser> users Vector<inputuser> exclude_users
 * @return InputBusinessBotRecipients
 */

final class InputBusinessBotRecipients extends Instance {
	public function request(null | bool $existing_chats = null,null | bool $new_chats = null,null | bool $contacts = null,null | bool $non_contacts = null,null | bool $exclude_selected = null,null | array $users = null,null | array $exclude_users = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc4e5921e);
		$flags = 0;
		$flags |= $existing_chats ? (1 << 0) : 0;
		$flags |= $new_chats ? (1 << 1) : 0;
		$flags |= $contacts ? (1 << 2) : 0;
		$flags |= $non_contacts ? (1 << 3) : 0;
		$flags |= $exclude_selected ? (1 << 5) : 0;
		$flags |= is_null($users) ? 0 : (1 << 4);
		$flags |= is_null($exclude_users) ? 0 : (1 << 6);
		$writer->writeInt($flags);
		if(is_null($users) === false):
			$writer->writeVector($users,'inputuser');
		endif;
		if(is_null($exclude_users) === false):
			$writer->writeVector($exclude_users,'inputuser');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['existing_chats'] = boolval($flags & (1 << 0));
		$result['new_chats'] = boolval($flags & (1 << 1));
		$result['contacts'] = boolval($flags & (1 << 2));
		$result['non_contacts'] = boolval($flags & (1 << 3));
		$result['exclude_selected'] = boolval($flags & (1 << 5));
		if($flags & (1 << 4)):
			$result['users'] = $reader->readVector('inputuser');
		else:
			$result['users'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['exclude_users'] = $reader->readVector('inputuser');
		else:
			$result['exclude_users'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ProfileTab
 */

final class ProfileTabLinks extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd3656499);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string type bytes bytes
 * @return PhotoSize
 */

final class PhotoPathSize extends Instance {
	public function request(string $type,string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd8214d41);
		$writer->writeBytes($type);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readBytes();
		$result['bytes'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long call_id true video phonecalldiscardreason reason int duration
 * @return MessageAction
 */

final class MessageActionPhoneCall extends Instance {
	public function request(int $call_id,null | bool $video = null,null | object $reason = null,null | int $duration = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x80e11a7f);
		$flags = 0;
		$flags |= $video ? (1 << 2) : 0;
		$flags |= is_null($reason) ? 0 : (1 << 0);
		$flags |= is_null($duration) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($call_id);
		if(is_null($reason) === false):
			$writer->writeObject($reason);
		endif;
		if(is_null($duration) === false):
			$writer->writeInt($duration);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['video'] = boolval($flags & (1 << 2));
		$result['call_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['reason'] = $reader->readObject();
		else:
			$result['reason'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['duration'] = $reader->readInt();
		else:
			$result['duration'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BotMenuButton
 */

final class BotMenuButtonDefault extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7533a588);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id
 * @return Update
 */

final class UpdateWebViewResultSent extends Instance {
	public function request(int $query_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1592b79d);
		$writer->writeLong($query_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['query_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peercolor prev_value peercolor new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangePeerColor extends Instance {
	public function request(object $prev_value,object $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5796e780);
		$writer->writeObject($prev_value);
		$writer->writeObject($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readObject();
		$result['new_value'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int prev_value int new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionToggleSlowMode extends Instance {
	public function request(int $prev_value,int $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x53909779);
		$writer->writeInt($prev_value);
		$writer->writeInt($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readInt();
		$result['new_value'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReportResult
 */

final class ReportResultReported extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8db33c4b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string type string message messagemedia media Vector<messageentity> entities true popup true invert_media int inbox_date
 * @return Update
 */

final class UpdateServiceNotification extends Instance {
	public function request(string $type,string $message,object $media,array $entities,null | bool $popup = null,null | bool $invert_media = null,null | int $inbox_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xebe46819);
		$flags = 0;
		$flags |= $popup ? (1 << 0) : 0;
		$flags |= $invert_media ? (1 << 2) : 0;
		$flags |= is_null($inbox_date) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($inbox_date) === false):
			$writer->writeInt($inbox_date);
		endif;
		$writer->writeBytes($type);
		$writer->writeBytes($message);
		$writer->writeObject($media);
		$writer->writeVector($entities,'messageentity');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['popup'] = boolval($flags & (1 << 0));
		$result['invert_media'] = boolval($flags & (1 << 2));
		if($flags & (1 << 1)):
			$result['inbox_date'] = $reader->readInt();
		else:
			$result['inbox_date'] = null;
		endif;
		$result['type'] = $reader->readBytes();
		$result['message'] = $reader->readBytes();
		$result['media'] = $reader->readObject();
		$result['entities'] = $reader->readVector('messageentity');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param chat chat
 * @return ChatInvite
 */

final class ChatInviteAlready extends Instance {
	public function request(object $chat) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5a686d7c);
		$writer->writeObject($chat);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer storyitem story
 * @return Update
 */

final class UpdateStory extends Instance {
	public function request(object $peer,object $story) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x75b3b798);
		$writer->writeObject($peer);
		$writer->writeObject($story);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['story'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text true checkbox true checked
 * @return PageListItem
 */

final class PageListItemText extends Instance {
	public function request(object $text,null | bool $checkbox = null,null | bool $checked = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2f58683c);
		$flags = 0;
		$flags |= $checkbox ? (1 << 0) : 0;
		$flags |= $checked ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['checkbox'] = boolval($flags & (1 << 0));
		$result['checked'] = boolval($flags & (1 << 1));
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true change_info true post_messages true edit_messages true delete_messages true ban_users true invite_users true pin_messages true add_admins true anonymous true manage_call true other true manage_topics true post_stories true edit_stories true delete_stories true manage_direct_messages true manage_ranks
 * @return ChatAdminRights
 */

final class ChatAdminRights extends Instance {
	public function request(null | bool $change_info = null,null | bool $post_messages = null,null | bool $edit_messages = null,null | bool $delete_messages = null,null | bool $ban_users = null,null | bool $invite_users = null,null | bool $pin_messages = null,null | bool $add_admins = null,null | bool $anonymous = null,null | bool $manage_call = null,null | bool $other = null,null | bool $manage_topics = null,null | bool $post_stories = null,null | bool $edit_stories = null,null | bool $delete_stories = null,null | bool $manage_direct_messages = null,null | bool $manage_ranks = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5fb224d5);
		$flags = 0;
		$flags |= $change_info ? (1 << 0) : 0;
		$flags |= $post_messages ? (1 << 1) : 0;
		$flags |= $edit_messages ? (1 << 2) : 0;
		$flags |= $delete_messages ? (1 << 3) : 0;
		$flags |= $ban_users ? (1 << 4) : 0;
		$flags |= $invite_users ? (1 << 5) : 0;
		$flags |= $pin_messages ? (1 << 7) : 0;
		$flags |= $add_admins ? (1 << 9) : 0;
		$flags |= $anonymous ? (1 << 10) : 0;
		$flags |= $manage_call ? (1 << 11) : 0;
		$flags |= $other ? (1 << 12) : 0;
		$flags |= $manage_topics ? (1 << 13) : 0;
		$flags |= $post_stories ? (1 << 14) : 0;
		$flags |= $edit_stories ? (1 << 15) : 0;
		$flags |= $delete_stories ? (1 << 16) : 0;
		$flags |= $manage_direct_messages ? (1 << 17) : 0;
		$flags |= $manage_ranks ? (1 << 18) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['change_info'] = boolval($flags & (1 << 0));
		$result['post_messages'] = boolval($flags & (1 << 1));
		$result['edit_messages'] = boolval($flags & (1 << 2));
		$result['delete_messages'] = boolval($flags & (1 << 3));
		$result['ban_users'] = boolval($flags & (1 << 4));
		$result['invite_users'] = boolval($flags & (1 << 5));
		$result['pin_messages'] = boolval($flags & (1 << 7));
		$result['add_admins'] = boolval($flags & (1 << 9));
		$result['anonymous'] = boolval($flags & (1 << 10));
		$result['manage_call'] = boolval($flags & (1 << 11));
		$result['other'] = boolval($flags & (1 << 12));
		$result['manage_topics'] = boolval($flags & (1 << 13));
		$result['post_stories'] = boolval($flags & (1 << 14));
		$result['edit_stories'] = boolval($flags & (1 << 15));
		$result['delete_stories'] = boolval($flags & (1 << 16));
		$result['manage_direct_messages'] = boolval($flags & (1 << 17));
		$result['manage_ranks'] = boolval($flags & (1 << 18));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id int id int forwards
 * @return Update
 */

final class UpdateChannelMessageForwards extends Instance {
	public function request(int $channel_id,int $id,int $forwards) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd29a27f4);
		$writer->writeLong($channel_id);
		$writer->writeInt($id);
		$writer->writeInt($forwards);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['id'] = $reader->readInt();
		$result['forwards'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param starsamount balance
 * @return Update
 */

final class UpdateStarsBalance extends Instance {
	public function request(object $balance) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4e80a379);
		$writer->writeObject($balance);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['balance'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id long access_hash
 * @return InputChannel
 */

final class InputChannel extends Instance {
	public function request(int $channel_id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf35aec28);
		$writer->writeLong($channel_id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<cdnpublickey> public_keys
 * @return CdnConfig
 */

final class CdnConfig extends Instance {
	public function request(array $public_keys) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5725e40a);
		$writer->writeVector($public_keys,'cdnpublickey');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['public_keys'] = $reader->readVector('cdnpublickey');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string first_name string last_name string vcard
 * @return InputMedia
 */

final class InputMediaContact extends Instance {
	public function request(string $phone_number,string $first_name,string $last_name,string $vcard) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf8ab7dfb);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($first_name);
		$writer->writeBytes($last_name);
		$writer->writeBytes($vcard);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone_number'] = $reader->readBytes();
		$result['first_name'] = $reader->readBytes();
		$result['last_name'] = $reader->readBytes();
		$result['vcard'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text string email
 * @return RichText
 */

final class TextEmail extends Instance {
	public function request(object $text,string $email) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xde5a0dd6);
		$writer->writeObject($text);
		$writer->writeBytes($email);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		$result['email'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyChatInvite extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x500e6dfa);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer recipient_id int date peer sender_id textwithentities message
 * @return StarGiftAttribute
 */

final class StarGiftAttributeOriginalDetails extends Instance {
	public function request(object $recipient_id,int $date,null | object $sender_id = null,null | object $message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe0bff26c);
		$flags = 0;
		$flags |= is_null($sender_id) ? 0 : (1 << 0);
		$flags |= is_null($message) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($sender_id) === false):
			$writer->writeObject($sender_id);
		endif;
		$writer->writeObject($recipient_id);
		$writer->writeInt($date);
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['sender_id'] = $reader->readObject();
		else:
			$result['sender_id'] = null;
		endif;
		$result['recipient_id'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['message'] = $reader->readObject();
		else:
			$result['message'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InlineQueryPeerType
 */

final class InlineQueryPeerTypeMegagroup extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5ec4be43);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockSubtitle extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ffa9a1f);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param groupcallparticipant participant
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantVolume extends Instance {
	public function request(object $participant) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e7f6847);
		$writer->writeObject($participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['participant'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string prev_value string new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeAbout extends Instance {
	public function request(string $prev_value,string $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x55188a2e);
		$writer->writeBytes($prev_value);
		$writer->writeBytes($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readBytes();
		$result['new_value'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param exportedchatinvite invite true via_chatlist
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantJoinByInvite extends Instance {
	public function request(object $invite,null | bool $via_chatlist = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfe9fc158);
		$flags = 0;
		$flags |= $via_chatlist ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($invite);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['via_chatlist'] = boolval($flags & (1 << 0));
		$result['invite'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id int parts int key_fingerprint
 * @return InputEncryptedFile
 */

final class InputEncryptedFileBigUploaded extends Instance {
	public function request(int $id,int $parts,int $key_fingerprint) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2dc173c8);
		$writer->writeLong($id);
		$writer->writeInt($parts);
		$writer->writeInt($key_fingerprint);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['parts'] = $reader->readInt();
		$result['key_fingerprint'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer starsrevenuestatus status
 * @return Update
 */

final class UpdateStarsRevenueStatus extends Instance {
	public function request(object $peer,object $status) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa584b019);
		$writer->writeObject($peer);
		$writer->writeObject($status);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['status'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphoto id
 * @return InputStickeredMedia
 */

final class InputStickeredMediaPhoto extends Instance {
	public function request(object $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4a992157);
		$writer->writeObject($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int topic_id true pinned
 * @return Update
 */

final class UpdatePinnedForumTopic extends Instance {
	public function request(object $peer,int $topic_id,null | bool $pinned = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x683b2c52);
		$flags = 0;
		$flags |= $pinned ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($topic_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pinned'] = boolval($flags & (1 << 0));
		$result['peer'] = $reader->readObject();
		$result['topic_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param folder folder peer peer int top_message int unread_muted_peers_count int unread_unmuted_peers_count int unread_muted_messages_count int unread_unmuted_messages_count true pinned
 * @return Dialog
 */

final class DialogFolder extends Instance {
	public function request(object $folder,object $peer,int $top_message,int $unread_muted_peers_count,int $unread_unmuted_peers_count,int $unread_muted_messages_count,int $unread_unmuted_messages_count,null | bool $pinned = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x71bd134c);
		$flags = 0;
		$flags |= $pinned ? (1 << 2) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($folder);
		$writer->writeObject($peer);
		$writer->writeInt($top_message);
		$writer->writeInt($unread_muted_peers_count);
		$writer->writeInt($unread_unmuted_peers_count);
		$writer->writeInt($unread_muted_messages_count);
		$writer->writeInt($unread_unmuted_messages_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pinned'] = boolval($flags & (1 << 2));
		$result['folder'] = $reader->readObject();
		$result['peer'] = $reader->readObject();
		$result['top_message'] = $reader->readInt();
		$result['unread_muted_peers_count'] = $reader->readInt();
		$result['unread_unmuted_peers_count'] = $reader->readInt();
		$result['unread_muted_messages_count'] = $reader->readInt();
		$result['unread_unmuted_messages_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextBankCard extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb956812d);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id string emoticon long effect_sticker_id true premium_required long static_icon_id long effect_animation_id
 * @return AvailableEffect
 */

final class AvailableEffect extends Instance {
	public function request(int $id,string $emoticon,int $effect_sticker_id,null | bool $premium_required = null,null | int $static_icon_id = null,null | int $effect_animation_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x93c3e27e);
		$flags = 0;
		$flags |= $premium_required ? (1 << 2) : 0;
		$flags |= is_null($static_icon_id) ? 0 : (1 << 0);
		$flags |= is_null($effect_animation_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeBytes($emoticon);
		if(is_null($static_icon_id) === false):
			$writer->writeLong($static_icon_id);
		endif;
		$writer->writeLong($effect_sticker_id);
		if(is_null($effect_animation_id) === false):
			$writer->writeLong($effect_animation_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['premium_required'] = boolval($flags & (1 << 2));
		$result['id'] = $reader->readLong();
		$result['emoticon'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['static_icon_id'] = $reader->readLong();
		else:
			$result['static_icon_id'] = null;
		endif;
		$result['effect_sticker_id'] = $reader->readLong();
		if($flags & (1 << 1)):
			$result['effect_animation_id'] = $reader->readLong();
		else:
			$result['effect_animation_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param groupcallparticipant participant
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantMute extends Instance {
	public function request(object $participant) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf92424d2);
		$writer->writeObject($participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['participant'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id long user_id long inviter_id int date int version
 * @return Update
 */

final class UpdateChatParticipantAdd extends Instance {
	public function request(int $chat_id,int $user_id,int $inviter_id,int $date,int $version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3dda5451);
		$writer->writeLong($chat_id);
		$writer->writeLong($user_id);
		$writer->writeLong($inviter_id);
		$writer->writeInt($date);
		$writer->writeInt($version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		$result['inviter_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['version'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id string prev_rank string new_rank
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantEditRank extends Instance {
	public function request(int $user_id,string $prev_rank,string $new_rank) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5806b4ec);
		$writer->writeLong($user_id);
		$writer->writeBytes($prev_rank);
		$writer->writeBytes($new_rank);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['prev_rank'] = $reader->readBytes();
		$result['new_rank'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string value
 * @return JSONValue
 */

final class JsonString extends Instance {
	public function request(string $value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb71e767a);
		$writer->writeBytes($value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['value'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyVoiceMessages extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x697f414);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title string description string currency long total_amount string start_param true shipping_address_requested true test webdocument photo int receipt_msg_id messageextendedmedia extended_media
 * @return MessageMedia
 */

final class MessageMediaInvoice extends Instance {
	public function request(string $title,string $description,string $currency,int $total_amount,string $start_param,null | bool $shipping_address_requested = null,null | bool $test = null,null | object $photo = null,null | int $receipt_msg_id = null,null | object $extended_media = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf6a548d3);
		$flags = 0;
		$flags |= $shipping_address_requested ? (1 << 1) : 0;
		$flags |= $test ? (1 << 3) : 0;
		$flags |= is_null($photo) ? 0 : (1 << 0);
		$flags |= is_null($receipt_msg_id) ? 0 : (1 << 2);
		$flags |= is_null($extended_media) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		if(is_null($receipt_msg_id) === false):
			$writer->writeInt($receipt_msg_id);
		endif;
		$writer->writeBytes($currency);
		$writer->writeLong($total_amount);
		$writer->writeBytes($start_param);
		if(is_null($extended_media) === false):
			$writer->writeObject($extended_media);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['shipping_address_requested'] = boolval($flags & (1 << 1));
		$result['test'] = boolval($flags & (1 << 3));
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['receipt_msg_id'] = $reader->readInt();
		else:
			$result['receipt_msg_id'] = null;
		endif;
		$result['currency'] = $reader->readBytes();
		$result['total_amount'] = $reader->readLong();
		$result['start_param'] = $reader->readBytes();
		if($flags & (1 << 4)):
			$result['extended_media'] = $reader->readObject();
		else:
			$result['extended_media'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputGame
 */

final class InputGameID extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x32c3e77);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string email
 * @return SecurePlainData
 */

final class SecurePlainEmail extends Instance {
	public function request(string $email) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x21ec5a5f);
		$writer->writeBytes($email);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['email'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id
 * @return Photo
 */

final class PhotoEmpty extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2331b22d);
		$writer->writeLong($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id string currency long amount
 * @return InputStorePaymentPurpose
 */

final class InputStorePaymentGiftPremium extends Instance {
	public function request(object $user_id,string $currency,int $amount) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x616f7fe8);
		$writer->writeObject($user_id);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readObject();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param botbusinessconnection connection int qts
 * @return Update
 */

final class UpdateBotBusinessConnect extends Instance {
	public function request(object $connection,int $qts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ae5c97a);
		$writer->writeObject($connection);
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['connection'] = $reader->readObject();
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string currency long total_amount true recurring_init true recurring_used string invoice_slug int subscription_until_date
 * @return MessageAction
 */

final class MessageActionPaymentSent extends Instance {
	public function request(string $currency,int $total_amount,null | bool $recurring_init = null,null | bool $recurring_used = null,null | string $invoice_slug = null,null | int $subscription_until_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc624b16e);
		$flags = 0;
		$flags |= $recurring_init ? (1 << 2) : 0;
		$flags |= $recurring_used ? (1 << 3) : 0;
		$flags |= is_null($invoice_slug) ? 0 : (1 << 0);
		$flags |= is_null($subscription_until_date) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeBytes($currency);
		$writer->writeLong($total_amount);
		if(is_null($invoice_slug) === false):
			$writer->writeBytes($invoice_slug);
		endif;
		if(is_null($subscription_until_date) === false):
			$writer->writeInt($subscription_until_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['recurring_init'] = boolval($flags & (1 << 2));
		$result['recurring_used'] = boolval($flags & (1 << 3));
		$result['currency'] = $reader->readBytes();
		$result['total_amount'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['invoice_slug'] = $reader->readBytes();
		else:
			$result['invoice_slug'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['subscription_until_date'] = $reader->readInt();
		else:
			$result['subscription_until_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypePersonalDetails extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9d2a81e3);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer double rating
 * @return TopPeer
 */

final class TopPeer extends Instance {
	public function request(object $peer,float $rating) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xedcdc05b);
		$writer->writeObject($peer);
		$writer->writeDouble($rating);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['rating'] = $reader->readDouble();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<int> order
 * @return Update
 */

final class UpdateDialogFilterOrder extends Instance {
	public function request(array $order) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa5d72105);
		$writer->writeVector($order,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['order'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson payment_token
 * @return InputPaymentCredentials
 */

final class InputPaymentCredentialsGooglePay extends Instance {
	public function request(object $payment_token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ac32801);
		$writer->writeObject($payment_token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['payment_token'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument document string emoji maskcoords mask_coords string keywords
 * @return InputStickerSetItem
 */

final class InputStickerSetItem extends Instance {
	public function request(object $document,string $emoji,null | object $mask_coords = null,null | string $keywords = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x32da9e9c);
		$flags = 0;
		$flags |= is_null($mask_coords) ? 0 : (1 << 0);
		$flags |= is_null($keywords) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($document);
		$writer->writeBytes($emoji);
		if(is_null($mask_coords) === false):
			$writer->writeObject($mask_coords);
		endif;
		if(is_null($keywords) === false):
			$writer->writeBytes($keywords);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['document'] = $reader->readObject();
		$result['emoji'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['mask_coords'] = $reader->readObject();
		else:
			$result['mask_coords'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['keywords'] = $reader->readBytes();
		else:
			$result['keywords'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stickerset set Vector<document> covers
 * @return StickerSetCovered
 */

final class StickerSetMultiCovered extends Instance {
	public function request(object $set,array $covers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3407e51b);
		$writer->writeObject($set);
		$writer->writeVector($covers,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['set'] = $reader->readObject();
		$result['covers'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextHashtag extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x519524ea);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x57e2f66c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<pageblock> blocks Vector<photo> photos Vector<document> documents true rtl true part
 * @return RichMessage
 */

final class RichMessage extends Instance {
	public function request(array $blocks,array $photos,array $documents,null | bool $rtl = null,null | bool $part = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbaf39d8b);
		$flags = 0;
		$flags |= $rtl ? (1 << 0) : 0;
		$flags |= $part ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($blocks,'pageblock');
		$writer->writeVector($photos,'photo');
		$writer->writeVector($documents,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['rtl'] = boolval($flags & (1 << 0));
		$result['part'] = boolval($flags & (1 << 1));
		$result['blocks'] = $reader->readVector('pageblock');
		$result['photos'] = $reader->readVector('photo');
		$result['documents'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_prefix_rules int dc_id Vector<ipport> ips
 * @return AccessPointRule
 */

final class AccessPointRule extends Instance {
	public function request(string $phone_prefix_rules,int $dc_id,array $ips) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4679b65f);
		$writer->writeBytes($phone_prefix_rules);
		$writer->writeInt($dc_id);
		$writer->writeVector($ips,'ipport');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone_prefix_rules'] = $reader->readBytes();
		$result['dc_id'] = $reader->readInt();
		$result['ips'] = $reader->readVector('ipport');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int center_color int edge_color int text_color
 * @return StarGiftBackground
 */

final class StarGiftBackground extends Instance {
	public function request(int $center_color,int $edge_color,int $text_color) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaff56398);
		$writer->writeInt($center_color);
		$writer->writeInt($edge_color);
		$writer->writeInt($text_color);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['center_color'] = $reader->readInt();
		$result['edge_color'] = $reader->readInt();
		$result['text_color'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int msg_id Vector<messageextendedmedia> extended_media
 * @return Update
 */

final class UpdateMessageExtendedMedia extends Instance {
	public function request(object $peer,int $msg_id,array $extended_media) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd5a41724);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeVector($extended_media,'messageextendedmedia');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		$result['extended_media'] = $reader->readVector('messageextendedmedia');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyPhoneP2P extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdb9e70d2);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int color long background_emoji_id
 * @return PeerColor
 */

final class PeerColor extends Instance {
	public function request(null | int $color = null,null | int $background_emoji_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb54b5acf);
		$flags = 0;
		$flags |= is_null($color) ? 0 : (1 << 0);
		$flags |= is_null($background_emoji_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($color) === false):
			$writer->writeInt($color);
		endif;
		if(is_null($background_emoji_id) === false):
			$writer->writeLong($background_emoji_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['color'] = $reader->readInt();
		else:
			$result['color'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['background_emoji_id'] = $reader->readLong();
		else:
			$result['background_emoji_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param textwithentities text inputmedia media
 * @return PollAnswer
 */

final class InputPollAnswer extends Instance {
	public function request(object $text,null | object $media = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x199fed96);
		$flags = 0;
		$flags |= is_null($media) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($text);
		if(is_null($media) === false):
			$writer->writeObject($media);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['text'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['media'] = $reader->readObject();
		else:
			$result['media'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureFile
 */

final class SecureFileEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x64199744);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bot_id businessbotrecipients recipients businessbotrights rights string device int date string location
 * @return ConnectedBot
 */

final class ConnectedBot extends Instance {
	public function request(int $bot_id,object $recipients,object $rights,null | string $device = null,null | int $date = null,null | string $location = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x33ed001);
		$flags = 0;
		$flags |= is_null($device) ? 0 : (1 << 0);
		$flags |= is_null($date) ? 0 : (1 << 1);
		$flags |= is_null($location) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($bot_id);
		$writer->writeObject($recipients);
		$writer->writeObject($rights);
		if(is_null($device) === false):
			$writer->writeBytes($device);
		endif;
		if(is_null($date) === false):
			$writer->writeInt($date);
		endif;
		if(is_null($location) === false):
			$writer->writeBytes($location);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['bot_id'] = $reader->readLong();
		$result['recipients'] = $reader->readObject();
		$result['rights'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['device'] = $reader->readBytes();
		else:
			$result['device'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['date'] = $reader->readInt();
		else:
			$result['date'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['location'] = $reader->readBytes();
		else:
			$result['location'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextItalic extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd912a59c);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return EmailVerifyPurpose
 */

final class EmailVerifyPurposeLoginChange extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x527d22eb);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param replymarkup reply_markup
 * @return InputBotInlineMessage
 */

final class InputBotInlineMessageGame extends Instance {
	public function request(null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4b425864);
		$flags = 0;
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash string slug string title true creator long emoji_id string prompt int installs_count long author_id aicomposetoneexample example_english
 * @return AiComposeTone
 */

final class AiComposeTone extends Instance {
	public function request(int $id,int $access_hash,string $slug,string $title,null | bool $creator = null,null | int $emoji_id = null,null | string $prompt = null,null | int $installs_count = null,null | int $author_id = null,null | object $example_english = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcff63ea9);
		$flags = 0;
		$flags |= $creator ? (1 << 0) : 0;
		$flags |= is_null($emoji_id) ? 0 : (1 << 1);
		$flags |= is_null($prompt) ? 0 : (1 << 4);
		$flags |= is_null($installs_count) ? 0 : (1 << 2);
		$flags |= is_null($author_id) ? 0 : (1 << 3);
		$flags |= is_null($example_english) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($slug);
		$writer->writeBytes($title);
		if(is_null($emoji_id) === false):
			$writer->writeLong($emoji_id);
		endif;
		if(is_null($prompt) === false):
			$writer->writeBytes($prompt);
		endif;
		if(is_null($installs_count) === false):
			$writer->writeInt($installs_count);
		endif;
		if(is_null($author_id) === false):
			$writer->writeLong($author_id);
		endif;
		if(is_null($example_english) === false):
			$writer->writeObject($example_english);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['creator'] = boolval($flags & (1 << 0));
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['slug'] = $reader->readBytes();
		$result['title'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['emoji_id'] = $reader->readLong();
		else:
			$result['emoji_id'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['prompt'] = $reader->readBytes();
		else:
			$result['prompt'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['installs_count'] = $reader->readInt();
		else:
			$result['installs_count'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['author_id'] = $reader->readLong();
		else:
			$result['author_id'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['example_english'] = $reader->readObject();
		else:
			$result['example_english'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id peer peer_id int date messageaction action true out true mentioned true media_unread true reactions_are_possible true silent true post true legacy peer from_id peer saved_peer_id messagereplyheader reply_to messagereactions reactions int ttl_period
 * @return Message
 */

final class MessageService extends Instance {
	public function request(int $id,object $peer_id,int $date,object $action,null | bool $out = null,null | bool $mentioned = null,null | bool $media_unread = null,null | bool $reactions_are_possible = null,null | bool $silent = null,null | bool $post = null,null | bool $legacy = null,null | object $from_id = null,null | object $saved_peer_id = null,null | object $reply_to = null,null | object $reactions = null,null | int $ttl_period = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7a800e0a);
		$flags = 0;
		$flags |= $out ? (1 << 1) : 0;
		$flags |= $mentioned ? (1 << 4) : 0;
		$flags |= $media_unread ? (1 << 5) : 0;
		$flags |= $reactions_are_possible ? (1 << 9) : 0;
		$flags |= $silent ? (1 << 13) : 0;
		$flags |= $post ? (1 << 14) : 0;
		$flags |= $legacy ? (1 << 19) : 0;
		$flags |= is_null($from_id) ? 0 : (1 << 8);
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 28);
		$flags |= is_null($reply_to) ? 0 : (1 << 3);
		$flags |= is_null($reactions) ? 0 : (1 << 20);
		$flags |= is_null($ttl_period) ? 0 : (1 << 25);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		if(is_null($from_id) === false):
			$writer->writeObject($from_id);
		endif;
		$writer->writeObject($peer_id);
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		$writer->writeInt($date);
		$writer->writeObject($action);
		if(is_null($reactions) === false):
			$writer->writeObject($reactions);
		endif;
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['out'] = boolval($flags & (1 << 1));
		$result['mentioned'] = boolval($flags & (1 << 4));
		$result['media_unread'] = boolval($flags & (1 << 5));
		$result['reactions_are_possible'] = boolval($flags & (1 << 9));
		$result['silent'] = boolval($flags & (1 << 13));
		$result['post'] = boolval($flags & (1 << 14));
		$result['legacy'] = boolval($flags & (1 << 19));
		$result['id'] = $reader->readInt();
		if($flags & (1 << 8)):
			$result['from_id'] = $reader->readObject();
		else:
			$result['from_id'] = null;
		endif;
		$result['peer_id'] = $reader->readObject();
		if($flags & (1 << 28)):
			$result['saved_peer_id'] = $reader->readObject();
		else:
			$result['saved_peer_id'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['reply_to'] = $reader->readObject();
		else:
			$result['reply_to'] = null;
		endif;
		$result['date'] = $reader->readInt();
		$result['action'] = $reader->readObject();
		if($flags & (1 << 20)):
			$result['reactions'] = $reader->readObject();
		else:
			$result['reactions'] = null;
		endif;
		if($flags & (1 << 25)):
			$result['ttl_period'] = $reader->readInt();
		else:
			$result['ttl_period'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer bytes option int date
 * @return MessagePeerVote
 */

final class MessagePeerVote extends Instance {
	public function request(object $peer,string $option,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb6cc2d5c);
		$writer->writeObject($peer);
		$writer->writeBytes($option);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['option'] = $reader->readBytes();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer long photo_id true big
 * @return InputFileLocation
 */

final class InputPeerPhotoFileLocation extends Instance {
	public function request(object $peer,int $photo_id,null | bool $big = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x37257e99);
		$flags = 0;
		$flags |= $big ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeLong($photo_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['big'] = boolval($flags & (1 << 0));
		$result['peer'] = $reader->readObject();
		$result['photo_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarsTransactionPeer
 */

final class StarsTransactionPeerUnsupported extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x95f2bfe4);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true header true align_center true align_right true valign_middle true valign_bottom richtext text int colspan int rowspan
 * @return PageTableCell
 */

final class PageTableCell extends Instance {
	public function request(null | bool $header = null,null | bool $align_center = null,null | bool $align_right = null,null | bool $valign_middle = null,null | bool $valign_bottom = null,null | object $text = null,null | int $colspan = null,null | int $rowspan = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x34566b6a);
		$flags = 0;
		$flags |= $header ? (1 << 0) : 0;
		$flags |= $align_center ? (1 << 3) : 0;
		$flags |= $align_right ? (1 << 4) : 0;
		$flags |= $valign_middle ? (1 << 5) : 0;
		$flags |= $valign_bottom ? (1 << 6) : 0;
		$flags |= is_null($text) ? 0 : (1 << 7);
		$flags |= is_null($colspan) ? 0 : (1 << 1);
		$flags |= is_null($rowspan) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($text) === false):
			$writer->writeObject($text);
		endif;
		if(is_null($colspan) === false):
			$writer->writeInt($colspan);
		endif;
		if(is_null($rowspan) === false):
			$writer->writeInt($rowspan);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['header'] = boolval($flags & (1 << 0));
		$result['align_center'] = boolval($flags & (1 << 3));
		$result['align_right'] = boolval($flags & (1 << 4));
		$result['valign_middle'] = boolval($flags & (1 << 5));
		$result['valign_bottom'] = boolval($flags & (1 << 6));
		if($flags & (1 << 7)):
			$result['text'] = $reader->readObject();
		else:
			$result['text'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['colspan'] = $reader->readInt();
		else:
			$result['colspan'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['rowspan'] = $reader->readInt();
		else:
			$result['rowspan'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param channellocation prev_value channellocation new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeLocation extends Instance {
	public function request(object $prev_value,object $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe6b76ae);
		$writer->writeObject($prev_value);
		$writer->writeObject($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readObject();
		$result['new_value'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id int parts string md5_checksum bytes file_hash bytes secret
 * @return InputSecureFile
 */

final class InputSecureFileUploaded extends Instance {
	public function request(int $id,int $parts,string $md5_checksum,string $file_hash,string $secret) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3334b0f0);
		$writer->writeLong($id);
		$writer->writeInt($parts);
		$writer->writeBytes($md5_checksum);
		$writer->writeBytes($file_hash);
		$writer->writeBytes($secret);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['parts'] = $reader->readInt();
		$result['md5_checksum'] = $reader->readBytes();
		$result['file_hash'] = $reader->readBytes();
		$result['secret'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PhoneCallDiscardReason
 */

final class PhoneCallDiscardReasonDisconnect extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe095c1a0);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string emoticon
 * @return InputStickerSet
 */

final class InputStickerSetDice extends Instance {
	public function request(string $emoticon) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe67f520e);
		$writer->writeBytes($emoticon);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['emoticon'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long inviter_id
 * @return MessageAction
 */

final class MessageActionChatJoinedByLink extends Instance {
	public function request(int $inviter_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31224c3);
		$writer->writeLong($inviter_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['inviter_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peercolor prev_value peercolor new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeProfilePeerColor extends Instance {
	public function request(object $prev_value,object $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5e477b25);
		$writer->writeObject($prev_value);
		$writer->writeObject($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readObject();
		$result['new_value'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars string currency long amount true extended string store_product
 * @return StarsTopupOption
 */

final class StarsTopupOption extends Instance {
	public function request(int $stars,string $currency,int $amount,null | bool $extended = null,null | string $store_product = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd915c0);
		$flags = 0;
		$flags |= $extended ? (1 << 1) : 0;
		$flags |= is_null($store_product) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($stars);
		if(is_null($store_product) === false):
			$writer->writeBytes($store_product);
		endif;
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['extended'] = boolval($flags & (1 << 1));
		$result['stars'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['store_product'] = $reader->readBytes();
		else:
			$result['store_product'] = null;
		endif;
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int ttl_period
 * @return Update
 */

final class UpdatePeerHistoryTTL extends Instance {
	public function request(object $peer,null | int $ttl_period = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbb9bb9a5);
		$flags = 0;
		$flags |= is_null($ttl_period) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['peer'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['ttl_period'] = $reader->readInt();
		else:
			$result['ttl_period'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id
 * @return PhoneCall
 */

final class PhoneCallEmpty extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5366c915);
		$writer->writeLong($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type bytes hash
 * @return SecureValueHash
 */

final class SecureValueHash extends Instance {
	public function request(object $type,string $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xed1ecdb0);
		$writer->writeObject($type);
		$writer->writeBytes($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readObject();
		$result['hash'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id string first_name string last_name Vector<username> usernames
 * @return Update
 */

final class UpdateUserName extends Instance {
	public function request(int $user_id,string $first_name,string $last_name,array $usernames) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa7848924);
		$writer->writeLong($user_id);
		$writer->writeBytes($first_name);
		$writer->writeBytes($last_name);
		$writer->writeVector($usernames,'username');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['first_name'] = $reader->readBytes();
		$result['last_name'] = $reader->readBytes();
		$result['usernames'] = $reader->readVector('username');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputStickerSet
 */

final class InputStickerSetEmojiGenericAnimations extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4c4d4ce);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string provider_charge_id
 * @return PaymentCharge
 */

final class PaymentCharge extends Instance {
	public function request(string $id,string $provider_charge_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xea02c27e);
		$writer->writeBytes($id);
		$writer->writeBytes($provider_charge_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readBytes();
		$result['provider_charge_id'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param wallpaper wallpaper true same true for_both
 * @return MessageAction
 */

final class MessageActionSetChatWallPaper extends Instance {
	public function request(object $wallpaper,null | bool $same = null,null | bool $for_both = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5060a3f4);
		$flags = 0;
		$flags |= $same ? (1 << 0) : 0;
		$flags |= $for_both ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($wallpaper);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['same'] = boolval($flags & (1 << 0));
		$result['for_both'] = boolval($flags & (1 << 1));
		$result['wallpaper'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer
 * @return StarsTransactionPeer
 */

final class StarsTransactionPeer extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd80da15d);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id int date bool stopped int qts
 * @return Update
 */

final class UpdateBotStopped extends Instance {
	public function request(int $user_id,int $date,bool $stopped,int $qts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc4870a49);
		$writer->writeLong($user_id);
		$writer->writeInt($date);
		$writer->writeBool($stopped);
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['stopped'] = $reader->readBool();
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce int128 server_nonce int128 new_nonce_hash1
 * @return Set_client_DH_params_answer
 */

final class DhGenOk extends Instance {
	public function request(int | string $nonce,int | string $server_nonce,int | string $new_nonce_hash1) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3bcbf734);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeLargeInt($new_nonce_hash1,128);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['new_nonce_hash1'] = $reader->readLargeInt(128);
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id
 * @return NotificationSound
 */

final class NotificationSoundRingtone extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xff6c8049);
		$writer->writeLong($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class BoolTrue extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x997275b5);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stargift gift starsamount price true expired
 * @return MessageAction
 */

final class MessageActionStarGiftPurchaseOfferDeclined extends Instance {
	public function request(object $gift,object $price,null | bool $expired = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x73ada76b);
		$flags = 0;
		$flags |= $expired ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($gift);
		$writer->writeObject($price);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['expired'] = boolval($flags & (1 << 0));
		$result['gift'] = $reader->readObject();
		$result['price'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int w int h
 * @return DocumentAttribute
 */

final class DocumentAttributeImageSize extends Instance {
	public function request(int $w,int $h) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c37c15c);
		$writer->writeInt($w);
		$writer->writeInt($h);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id long user_id string rank int version
 * @return Update
 */

final class UpdateChatParticipantRank extends Instance {
	public function request(int $chat_id,int $user_id,string $rank,int $version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd8367b9);
		$writer->writeLong($chat_id);
		$writer->writeLong($user_id);
		$writer->writeBytes($rank);
		$writer->writeInt($version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		$result['rank'] = $reader->readBytes();
		$result['version'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash bytes file_reference int date string mime_type long size int dc_id Vector<documentattribute> attributes Vector<photosize> thumbs Vector<videosize> video_thumbs
 * @return Document
 */

final class Document extends Instance {
	public function request(int $id,int $access_hash,string $file_reference,int $date,string $mime_type,int $size,int $dc_id,array $attributes,null | array $thumbs = null,null | array $video_thumbs = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8fd4c4d8);
		$flags = 0;
		$flags |= is_null($thumbs) ? 0 : (1 << 0);
		$flags |= is_null($video_thumbs) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($file_reference);
		$writer->writeInt($date);
		$writer->writeBytes($mime_type);
		$writer->writeLong($size);
		if(is_null($thumbs) === false):
			$writer->writeVector($thumbs,'photosize');
		endif;
		if(is_null($video_thumbs) === false):
			$writer->writeVector($video_thumbs,'videosize');
		endif;
		$writer->writeInt($dc_id);
		$writer->writeVector($attributes,'documentattribute');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['file_reference'] = $reader->readBytes();
		$result['date'] = $reader->readInt();
		$result['mime_type'] = $reader->readBytes();
		$result['size'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['thumbs'] = $reader->readVector('photosize');
		else:
			$result['thumbs'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['video_thumbs'] = $reader->readVector('videosize');
		else:
			$result['video_thumbs'] = null;
		endif;
		$result['dc_id'] = $reader->readInt();
		$result['attributes'] = $reader->readVector('documentattribute');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickerset prev_stickerset inputstickerset new_stickerset
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeStickerSet extends Instance {
	public function request(object $prev_stickerset,object $new_stickerset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb1c3caa7);
		$writer->writeObject($prev_stickerset);
		$writer->writeObject($new_stickerset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_stickerset'] = $reader->readObject();
		$result['new_stickerset'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterUrl extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7ef0dd87);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id
 * @return InputMedia
 */

final class InputMediaStory extends Instance {
	public function request(object $peer,int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x89fdd778);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param geopoint geo int zoom int w int h pagecaption caption
 * @return PageBlock
 */

final class PageBlockMap extends Instance {
	public function request(object $geo,int $zoom,int $w,int $h,object $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa44f3ef6);
		$writer->writeObject($geo);
		$writer->writeInt($zoom);
		$writer->writeInt($w);
		$writer->writeInt($h);
		$writer->writeObject($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['geo'] = $reader->readObject();
		$result['zoom'] = $reader->readInt();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		$result['caption'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true existing_chats true new_chats true contacts true non_contacts true exclude_selected Vector<long> users Vector<long> exclude_users
 * @return BusinessBotRecipients
 */

final class BusinessBotRecipients extends Instance {
	public function request(null | bool $existing_chats = null,null | bool $new_chats = null,null | bool $contacts = null,null | bool $non_contacts = null,null | bool $exclude_selected = null,null | array $users = null,null | array $exclude_users = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb88cf373);
		$flags = 0;
		$flags |= $existing_chats ? (1 << 0) : 0;
		$flags |= $new_chats ? (1 << 1) : 0;
		$flags |= $contacts ? (1 << 2) : 0;
		$flags |= $non_contacts ? (1 << 3) : 0;
		$flags |= $exclude_selected ? (1 << 5) : 0;
		$flags |= is_null($users) ? 0 : (1 << 4);
		$flags |= is_null($exclude_users) ? 0 : (1 << 6);
		$writer->writeInt($flags);
		if(is_null($users) === false):
			$writer->writeVector($users,'long');
		endif;
		if(is_null($exclude_users) === false):
			$writer->writeVector($exclude_users,'long');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['existing_chats'] = boolval($flags & (1 << 0));
		$result['new_chats'] = boolval($flags & (1 << 1));
		$result['contacts'] = boolval($flags & (1 << 2));
		$result['non_contacts'] = boolval($flags & (1 << 3));
		$result['exclude_selected'] = boolval($flags & (1 << 5));
		if($flags & (1 << 4)):
			$result['users'] = $reader->readVector('long');
		else:
			$result['users'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['exclude_users'] = $reader->readVector('long');
		else:
			$result['exclude_users'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string name string phone string email postaddress shipping_address
 * @return PaymentRequestedInfo
 */

final class PaymentRequestedInfo extends Instance {
	public function request(null | string $name = null,null | string $phone = null,null | string $email = null,null | object $shipping_address = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x909c3f94);
		$flags = 0;
		$flags |= is_null($name) ? 0 : (1 << 0);
		$flags |= is_null($phone) ? 0 : (1 << 1);
		$flags |= is_null($email) ? 0 : (1 << 2);
		$flags |= is_null($shipping_address) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($name) === false):
			$writer->writeBytes($name);
		endif;
		if(is_null($phone) === false):
			$writer->writeBytes($phone);
		endif;
		if(is_null($email) === false):
			$writer->writeBytes($email);
		endif;
		if(is_null($shipping_address) === false):
			$writer->writeObject($shipping_address);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['name'] = $reader->readBytes();
		else:
			$result['name'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['phone'] = $reader->readBytes();
		else:
			$result['phone'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['email'] = $reader->readBytes();
		else:
			$result['email'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['shipping_address'] = $reader->readObject();
		else:
			$result['shipping_address'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstorepaymentpurpose purpose
 * @return InputInvoice
 */

final class InputInvoiceStars extends Instance {
	public function request(object $purpose) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x65f00ce3);
		$writer->writeObject($purpose);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['purpose'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer_id int date reaction reaction true big true unread true my
 * @return MessagePeerReaction
 */

final class MessagePeerReaction extends Instance {
	public function request(object $peer_id,int $date,object $reaction,null | bool $big = null,null | bool $unread = null,null | bool $my = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c79b63c);
		$flags = 0;
		$flags |= $big ? (1 << 0) : 0;
		$flags |= $unread ? (1 << 1) : 0;
		$flags |= $my ? (1 << 2) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer_id);
		$writer->writeInt($date);
		$writer->writeObject($reaction);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['big'] = boolval($flags & (1 << 0));
		$result['unread'] = boolval($flags & (1 << 1));
		$result['my'] = boolval($flags & (1 << 2));
		$result['peer_id'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		$result['reaction'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityItalic extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x826f8b60);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyPhoneCall extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfabadc5f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return AttachMenuPeerType
 */

final class AttachMenuPeerTypeSameBotPM extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7d6be90e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int views int forwards messagereplies replies
 * @return MessageViews
 */

final class MessageViews extends Instance {
	public function request(null | int $views = null,null | int $forwards = null,null | object $replies = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x455b853d);
		$flags = 0;
		$flags |= is_null($views) ? 0 : (1 << 0);
		$flags |= is_null($forwards) ? 0 : (1 << 1);
		$flags |= is_null($replies) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($views) === false):
			$writer->writeInt($views);
		endif;
		if(is_null($forwards) === false):
			$writer->writeInt($forwards);
		endif;
		if(is_null($replies) === false):
			$writer->writeObject($replies);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['views'] = $reader->readInt();
		else:
			$result['views'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['forwards'] = $reader->readInt();
		else:
			$result['forwards'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['replies'] = $reader->readObject();
		else:
			$result['replies'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stargift gift stargiftauctionstate state stargiftauctionuserstate user_state
 * @return StarGiftActiveAuctionState
 */

final class StarGiftActiveAuctionState extends Instance {
	public function request(object $gift,object $state,object $user_state) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd31bc45d);
		$writer->writeObject($gift);
		$writer->writeObject($state);
		$writer->writeObject($user_state);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['gift'] = $reader->readObject();
		$result['state'] = $reader->readObject();
		$result['user_state'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true existing_chats true new_chats true contacts true non_contacts true exclude_selected Vector<inputuser> users
 * @return InputBusinessRecipients
 */

final class InputBusinessRecipients extends Instance {
	public function request(null | bool $existing_chats = null,null | bool $new_chats = null,null | bool $contacts = null,null | bool $non_contacts = null,null | bool $exclude_selected = null,null | array $users = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6f8b32aa);
		$flags = 0;
		$flags |= $existing_chats ? (1 << 0) : 0;
		$flags |= $new_chats ? (1 << 1) : 0;
		$flags |= $contacts ? (1 << 2) : 0;
		$flags |= $non_contacts ? (1 << 3) : 0;
		$flags |= $exclude_selected ? (1 << 5) : 0;
		$flags |= is_null($users) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		if(is_null($users) === false):
			$writer->writeVector($users,'inputuser');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['existing_chats'] = boolval($flags & (1 << 0));
		$result['new_chats'] = boolval($flags & (1 << 1));
		$result['contacts'] = boolval($flags & (1 << 2));
		$result['non_contacts'] = boolval($flags & (1 << 3));
		$result['exclude_selected'] = boolval($flags & (1 << 5));
		if($flags & (1 << 4)):
			$result['users'] = $reader->readVector('inputuser');
		else:
			$result['users'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer long gift_id true hide_name true include_upgrade textwithentities message
 * @return InputInvoice
 */

final class InputInvoiceStarGift extends Instance {
	public function request(object $peer,int $gift_id,null | bool $hide_name = null,null | bool $include_upgrade = null,null | object $message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe8625e92);
		$flags = 0;
		$flags |= $hide_name ? (1 << 0) : 0;
		$flags |= $include_upgrade ? (1 << 2) : 0;
		$flags |= is_null($message) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeLong($gift_id);
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['hide_name'] = boolval($flags & (1 << 0));
		$result['include_upgrade'] = boolval($flags & (1 << 2));
		$result['peer'] = $reader->readObject();
		$result['gift_id'] = $reader->readLong();
		if($flags & (1 << 1)):
			$result['message'] = $reader->readObject();
		else:
			$result['message'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecurePasswordKdfAlgo
 */

final class SecurePasswordKdfAlgoUnknown extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4a8537);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string username
 * @return InputCollectible
 */

final class InputCollectibleUsername extends Instance {
	public function request(string $username) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe39460a9);
		$writer->writeBytes($username);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['username'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long client_id int importers
 * @return PopularContact
 */

final class PopularContact extends Instance {
	public function request(int $client_id,int $importers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5ce14175);
		$writer->writeLong($client_id);
		$writer->writeInt($importers);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['client_id'] = $reader->readLong();
		$result['importers'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypePhone extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb320aadb);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return EmojiList
 */

final class EmojiListNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x481eadfa);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id int top_msg_id int read_max_id long broadcast_id int broadcast_post
 * @return Update
 */

final class UpdateReadChannelDiscussionInbox extends Instance {
	public function request(int $channel_id,int $top_msg_id,int $read_max_id,null | int $broadcast_id = null,null | int $broadcast_post = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd6b19546);
		$flags = 0;
		$flags |= is_null($broadcast_id) ? 0 : (1 << 0);
		$flags |= is_null($broadcast_post) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($channel_id);
		$writer->writeInt($top_msg_id);
		$writer->writeInt($read_max_id);
		if(is_null($broadcast_id) === false):
			$writer->writeLong($broadcast_id);
		endif;
		if(is_null($broadcast_post) === false):
			$writer->writeInt($broadcast_post);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['channel_id'] = $reader->readLong();
		$result['top_msg_id'] = $reader->readInt();
		$result['read_max_id'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['broadcast_id'] = $reader->readLong();
		else:
			$result['broadcast_id'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['broadcast_post'] = $reader->readInt();
		else:
			$result['broadcast_post'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id string ip string ipv6 int port string username string password true turn true stun
 * @return PhoneConnection
 */

final class PhoneConnectionWebrtc extends Instance {
	public function request(int $id,string $ip,string $ipv6,int $port,string $username,string $password,null | bool $turn = null,null | bool $stun = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x635fe375);
		$flags = 0;
		$flags |= $turn ? (1 << 0) : 0;
		$flags |= $stun ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeBytes($ip);
		$writer->writeBytes($ipv6);
		$writer->writeInt($port);
		$writer->writeBytes($username);
		$writer->writeBytes($password);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['turn'] = boolval($flags & (1 << 0));
		$result['stun'] = boolval($flags & (1 << 1));
		$result['id'] = $reader->readLong();
		$result['ip'] = $reader->readBytes();
		$result['ipv6'] = $reader->readBytes();
		$result['port'] = $reader->readInt();
		$result['username'] = $reader->readBytes();
		$result['password'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool prev_value bool new_value true expired
 * @return MessageAction
 */

final class MessageActionNoForwardsRequest extends Instance {
	public function request(bool $prev_value,bool $new_value,null | bool $expired = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e2793ba);
		$flags = 0;
		$flags |= $expired ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBool($prev_value);
		$writer->writeBool($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['expired'] = boolval($flags & (1 << 0));
		$result['prev_value'] = $reader->readBool();
		$result['new_value'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessageAction
 */

final class MessageActionEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb6aef7b0);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash int duration
 * @return GroupCall
 */

final class GroupCallDiscarded extends Instance {
	public function request(int $id,int $access_hash,int $duration) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7780bcb4);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeInt($duration);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['duration'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type Vector<bytes> file_hash string text
 * @return SecureValueError
 */

final class SecureValueErrorFiles extends Instance {
	public function request(object $type,array $file_hash,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x666220e9);
		$writer->writeObject($type);
		$writer->writeVector($file_hash,'bytes');
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readObject();
		$result['file_hash'] = $reader->readVector('bytes');
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date true imported true saved_out peer from_id string from_name int channel_post string post_author peer saved_from_peer int saved_from_msg_id peer saved_from_id string saved_from_name int saved_date string psa_type
 * @return MessageFwdHeader
 */

final class MessageFwdHeader extends Instance {
	public function request(int $date,null | bool $imported = null,null | bool $saved_out = null,null | object $from_id = null,null | string $from_name = null,null | int $channel_post = null,null | string $post_author = null,null | object $saved_from_peer = null,null | int $saved_from_msg_id = null,null | object $saved_from_id = null,null | string $saved_from_name = null,null | int $saved_date = null,null | string $psa_type = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4e4df4bb);
		$flags = 0;
		$flags |= $imported ? (1 << 7) : 0;
		$flags |= $saved_out ? (1 << 11) : 0;
		$flags |= is_null($from_id) ? 0 : (1 << 0);
		$flags |= is_null($from_name) ? 0 : (1 << 5);
		$flags |= is_null($channel_post) ? 0 : (1 << 2);
		$flags |= is_null($post_author) ? 0 : (1 << 3);
		$flags |= is_null($saved_from_peer) ? 0 : (1 << 4);
		$flags |= is_null($saved_from_msg_id) ? 0 : (1 << 4);
		$flags |= is_null($saved_from_id) ? 0 : (1 << 8);
		$flags |= is_null($saved_from_name) ? 0 : (1 << 9);
		$flags |= is_null($saved_date) ? 0 : (1 << 10);
		$flags |= is_null($psa_type) ? 0 : (1 << 6);
		$writer->writeInt($flags);
		if(is_null($from_id) === false):
			$writer->writeObject($from_id);
		endif;
		if(is_null($from_name) === false):
			$writer->writeBytes($from_name);
		endif;
		$writer->writeInt($date);
		if(is_null($channel_post) === false):
			$writer->writeInt($channel_post);
		endif;
		if(is_null($post_author) === false):
			$writer->writeBytes($post_author);
		endif;
		if(is_null($saved_from_peer) === false):
			$writer->writeObject($saved_from_peer);
		endif;
		if(is_null($saved_from_msg_id) === false):
			$writer->writeInt($saved_from_msg_id);
		endif;
		if(is_null($saved_from_id) === false):
			$writer->writeObject($saved_from_id);
		endif;
		if(is_null($saved_from_name) === false):
			$writer->writeBytes($saved_from_name);
		endif;
		if(is_null($saved_date) === false):
			$writer->writeInt($saved_date);
		endif;
		if(is_null($psa_type) === false):
			$writer->writeBytes($psa_type);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['imported'] = boolval($flags & (1 << 7));
		$result['saved_out'] = boolval($flags & (1 << 11));
		if($flags & (1 << 0)):
			$result['from_id'] = $reader->readObject();
		else:
			$result['from_id'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['from_name'] = $reader->readBytes();
		else:
			$result['from_name'] = null;
		endif;
		$result['date'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['channel_post'] = $reader->readInt();
		else:
			$result['channel_post'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['post_author'] = $reader->readBytes();
		else:
			$result['post_author'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['saved_from_peer'] = $reader->readObject();
		else:
			$result['saved_from_peer'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['saved_from_msg_id'] = $reader->readInt();
		else:
			$result['saved_from_msg_id'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['saved_from_id'] = $reader->readObject();
		else:
			$result['saved_from_id'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['saved_from_name'] = $reader->readBytes();
		else:
			$result['saved_from_name'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['saved_date'] = $reader->readInt();
		else:
			$result['saved_date'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['psa_type'] = $reader->readBytes();
		else:
			$result['psa_type'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date
 * @return OutboxReadDate
 */

final class OutboxReadDate extends Instance {
	public function request(int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3bb842ac);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessageMedia
 */

final class MessageMediaEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3ded6320);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot long stars
 * @return InputInvoice
 */

final class InputInvoiceBusinessBotTransferStars extends Instance {
	public function request(object $bot,int $stars) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf4997e42);
		$writer->writeObject($bot);
		$writer->writeLong($stars);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['bot'] = $reader->readObject();
		$result['stars'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash bytes file_reference int date Vector<photosize> sizes int dc_id true has_stickers Vector<videosize> video_sizes
 * @return Photo
 */

final class Photo extends Instance {
	public function request(int $id,int $access_hash,string $file_reference,int $date,array $sizes,int $dc_id,null | bool $has_stickers = null,null | array $video_sizes = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfb197a65);
		$flags = 0;
		$flags |= $has_stickers ? (1 << 0) : 0;
		$flags |= is_null($video_sizes) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($file_reference);
		$writer->writeInt($date);
		$writer->writeVector($sizes,'photosize');
		if(is_null($video_sizes) === false):
			$writer->writeVector($video_sizes,'videosize');
		endif;
		$writer->writeInt($dc_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['has_stickers'] = boolval($flags & (1 << 0));
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['file_reference'] = $reader->readBytes();
		$result['date'] = $reader->readInt();
		$result['sizes'] = $reader->readVector('photosize');
		if($flags & (1 << 1)):
			$result['video_sizes'] = $reader->readVector('videosize');
		else:
			$result['video_sizes'] = null;
		endif;
		$result['dc_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BotApp
 */

final class BotAppNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5da674b7);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string name
 * @return PageBlock
 */

final class PageBlockAnchor extends Instance {
	public function request(string $name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xce0d37b0);
		$writer->writeBytes($name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<reaction> reactions
 * @return ChatReactions
 */

final class ChatReactionsSome extends Instance {
	public function request(array $reactions) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x661d4037);
		$writer->writeVector($reactions,'reaction');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['reactions'] = $reader->readVector('reaction');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash int participants_count int unmuted_video_limit int version true join_muted true can_change_join_muted true join_date_asc true schedule_start_subscribed true can_start_video true record_video_active true rtmp_stream true listeners_hidden true conference true creator true messages_enabled true can_change_messages_enabled true min string title int stream_dc_id int record_start_date int schedule_date int unmuted_video_count string invite_link long send_paid_messages_stars peer default_send_as
 * @return GroupCall
 */

final class GroupCall extends Instance {
	public function request(int $id,int $access_hash,int $participants_count,int $unmuted_video_limit,int $version,null | bool $join_muted = null,null | bool $can_change_join_muted = null,null | bool $join_date_asc = null,null | bool $schedule_start_subscribed = null,null | bool $can_start_video = null,null | bool $record_video_active = null,null | bool $rtmp_stream = null,null | bool $listeners_hidden = null,null | bool $conference = null,null | bool $creator = null,null | bool $messages_enabled = null,null | bool $can_change_messages_enabled = null,null | bool $min = null,null | string $title = null,null | int $stream_dc_id = null,null | int $record_start_date = null,null | int $schedule_date = null,null | int $unmuted_video_count = null,null | string $invite_link = null,null | int $send_paid_messages_stars = null,null | object $default_send_as = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xefb2b617);
		$flags = 0;
		$flags |= $join_muted ? (1 << 1) : 0;
		$flags |= $can_change_join_muted ? (1 << 2) : 0;
		$flags |= $join_date_asc ? (1 << 6) : 0;
		$flags |= $schedule_start_subscribed ? (1 << 8) : 0;
		$flags |= $can_start_video ? (1 << 9) : 0;
		$flags |= $record_video_active ? (1 << 11) : 0;
		$flags |= $rtmp_stream ? (1 << 12) : 0;
		$flags |= $listeners_hidden ? (1 << 13) : 0;
		$flags |= $conference ? (1 << 14) : 0;
		$flags |= $creator ? (1 << 15) : 0;
		$flags |= $messages_enabled ? (1 << 17) : 0;
		$flags |= $can_change_messages_enabled ? (1 << 18) : 0;
		$flags |= $min ? (1 << 19) : 0;
		$flags |= is_null($title) ? 0 : (1 << 3);
		$flags |= is_null($stream_dc_id) ? 0 : (1 << 4);
		$flags |= is_null($record_start_date) ? 0 : (1 << 5);
		$flags |= is_null($schedule_date) ? 0 : (1 << 7);
		$flags |= is_null($unmuted_video_count) ? 0 : (1 << 10);
		$flags |= is_null($invite_link) ? 0 : (1 << 16);
		$flags |= is_null($send_paid_messages_stars) ? 0 : (1 << 20);
		$flags |= is_null($default_send_as) ? 0 : (1 << 21);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeInt($participants_count);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($stream_dc_id) === false):
			$writer->writeInt($stream_dc_id);
		endif;
		if(is_null($record_start_date) === false):
			$writer->writeInt($record_start_date);
		endif;
		if(is_null($schedule_date) === false):
			$writer->writeInt($schedule_date);
		endif;
		if(is_null($unmuted_video_count) === false):
			$writer->writeInt($unmuted_video_count);
		endif;
		$writer->writeInt($unmuted_video_limit);
		$writer->writeInt($version);
		if(is_null($invite_link) === false):
			$writer->writeBytes($invite_link);
		endif;
		if(is_null($send_paid_messages_stars) === false):
			$writer->writeLong($send_paid_messages_stars);
		endif;
		if(is_null($default_send_as) === false):
			$writer->writeObject($default_send_as);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['join_muted'] = boolval($flags & (1 << 1));
		$result['can_change_join_muted'] = boolval($flags & (1 << 2));
		$result['join_date_asc'] = boolval($flags & (1 << 6));
		$result['schedule_start_subscribed'] = boolval($flags & (1 << 8));
		$result['can_start_video'] = boolval($flags & (1 << 9));
		$result['record_video_active'] = boolval($flags & (1 << 11));
		$result['rtmp_stream'] = boolval($flags & (1 << 12));
		$result['listeners_hidden'] = boolval($flags & (1 << 13));
		$result['conference'] = boolval($flags & (1 << 14));
		$result['creator'] = boolval($flags & (1 << 15));
		$result['messages_enabled'] = boolval($flags & (1 << 17));
		$result['can_change_messages_enabled'] = boolval($flags & (1 << 18));
		$result['min'] = boolval($flags & (1 << 19));
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['participants_count'] = $reader->readInt();
		if($flags & (1 << 3)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['stream_dc_id'] = $reader->readInt();
		else:
			$result['stream_dc_id'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['record_start_date'] = $reader->readInt();
		else:
			$result['record_start_date'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['schedule_date'] = $reader->readInt();
		else:
			$result['schedule_date'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['unmuted_video_count'] = $reader->readInt();
		else:
			$result['unmuted_video_count'] = null;
		endif;
		$result['unmuted_video_limit'] = $reader->readInt();
		$result['version'] = $reader->readInt();
		if($flags & (1 << 16)):
			$result['invite_link'] = $reader->readBytes();
		else:
			$result['invite_link'] = null;
		endif;
		if($flags & (1 << 20)):
			$result['send_paid_messages_stars'] = $reader->readLong();
		else:
			$result['send_paid_messages_stars'] = null;
		endif;
		if($flags & (1 << 21)):
			$result['default_send_as'] = $reader->readObject();
		else:
			$result['default_send_as'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterGif extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xffc86587);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string name int date long software_emoji_id int last_usage_date
 * @return Passkey
 */

final class Passkey extends Instance {
	public function request(string $id,string $name,int $date,null | int $software_emoji_id = null,null | int $last_usage_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x98613ebf);
		$flags = 0;
		$flags |= is_null($software_emoji_id) ? 0 : (1 << 0);
		$flags |= is_null($last_usage_date) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($id);
		$writer->writeBytes($name);
		$writer->writeInt($date);
		if(is_null($software_emoji_id) === false):
			$writer->writeLong($software_emoji_id);
		endif;
		if(is_null($last_usage_date) === false):
			$writer->writeInt($last_usage_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readBytes();
		$result['name'] = $reader->readBytes();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['software_emoji_id'] = $reader->readLong();
		else:
			$result['software_emoji_id'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['last_usage_date'] = $reader->readInt();
		else:
			$result['last_usage_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InlineQueryPeerType
 */

final class InlineQueryPeerTypeBroadcast extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6334ee9a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param double long double lat long access_hash int accuracy_radius
 * @return GeoPoint
 */

final class GeoPoint extends Instance {
	public function request(float $long,float $lat,int $access_hash,null | int $accuracy_radius = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb2a2f663);
		$flags = 0;
		$flags |= is_null($accuracy_radius) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeDouble($long);
		$writer->writeDouble($lat);
		$writer->writeLong($access_hash);
		if(is_null($accuracy_radius) === false):
			$writer->writeInt($accuracy_radius);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['long'] = $reader->readDouble();
		$result['lat'] = $reader->readDouble();
		$result['access_hash'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['accuracy_radius'] = $reader->readInt();
		else:
			$result['accuracy_radius'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputStickerSet
 */

final class InputStickerSetTonGifts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1cf671a0);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ChannelParticipantsFilter
 */

final class ChannelParticipantsRecent extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xde3f3c79);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int users long per_user_stars true default
 * @return StarsGiveawayWinnersOption
 */

final class StarsGiveawayWinnersOption extends Instance {
	public function request(int $users,int $per_user_stars,null | bool $default = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x54236209);
		$flags = 0;
		$flags |= $default ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($users);
		$writer->writeLong($per_user_stars);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['default'] = boolval($flags & (1 << 0));
		$result['users'] = $reader->readInt();
		$result['per_user_stars'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id string about chatparticipants participants peernotifysettings notify_settings true can_set_username true has_scheduled true translations_disabled photo chat_photo exportedchatinvite exported_invite Vector<botinfo> bot_info int pinned_msg_id int folder_id inputgroupcall call int ttl_period peer groupcall_default_join_as string theme_emoticon int requests_pending Vector<long> recent_requesters chatreactions available_reactions int reactions_limit
 * @return ChatFull
 */

final class ChatFull extends Instance {
	public function request(int $id,string $about,object $participants,object $notify_settings,null | bool $can_set_username = null,null | bool $has_scheduled = null,null | bool $translations_disabled = null,null | object $chat_photo = null,null | object $exported_invite = null,null | array $bot_info = null,null | int $pinned_msg_id = null,null | int $folder_id = null,null | object $call = null,null | int $ttl_period = null,null | object $groupcall_default_join_as = null,null | string $theme_emoticon = null,null | int $requests_pending = null,null | array $recent_requesters = null,null | object $available_reactions = null,null | int $reactions_limit = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2633421b);
		$flags = 0;
		$flags |= $can_set_username ? (1 << 7) : 0;
		$flags |= $has_scheduled ? (1 << 8) : 0;
		$flags |= $translations_disabled ? (1 << 19) : 0;
		$flags |= is_null($chat_photo) ? 0 : (1 << 2);
		$flags |= is_null($exported_invite) ? 0 : (1 << 13);
		$flags |= is_null($bot_info) ? 0 : (1 << 3);
		$flags |= is_null($pinned_msg_id) ? 0 : (1 << 6);
		$flags |= is_null($folder_id) ? 0 : (1 << 11);
		$flags |= is_null($call) ? 0 : (1 << 12);
		$flags |= is_null($ttl_period) ? 0 : (1 << 14);
		$flags |= is_null($groupcall_default_join_as) ? 0 : (1 << 15);
		$flags |= is_null($theme_emoticon) ? 0 : (1 << 16);
		$flags |= is_null($requests_pending) ? 0 : (1 << 17);
		$flags |= is_null($recent_requesters) ? 0 : (1 << 17);
		$flags |= is_null($available_reactions) ? 0 : (1 << 18);
		$flags |= is_null($reactions_limit) ? 0 : (1 << 20);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeBytes($about);
		$writer->writeObject($participants);
		if(is_null($chat_photo) === false):
			$writer->writeObject($chat_photo);
		endif;
		$writer->writeObject($notify_settings);
		if(is_null($exported_invite) === false):
			$writer->writeObject($exported_invite);
		endif;
		if(is_null($bot_info) === false):
			$writer->writeVector($bot_info,'botinfo');
		endif;
		if(is_null($pinned_msg_id) === false):
			$writer->writeInt($pinned_msg_id);
		endif;
		if(is_null($folder_id) === false):
			$writer->writeInt($folder_id);
		endif;
		if(is_null($call) === false):
			$writer->writeObject($call);
		endif;
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		if(is_null($groupcall_default_join_as) === false):
			$writer->writeObject($groupcall_default_join_as);
		endif;
		if(is_null($theme_emoticon) === false):
			$writer->writeBytes($theme_emoticon);
		endif;
		if(is_null($requests_pending) === false):
			$writer->writeInt($requests_pending);
		endif;
		if(is_null($recent_requesters) === false):
			$writer->writeVector($recent_requesters,'long');
		endif;
		if(is_null($available_reactions) === false):
			$writer->writeObject($available_reactions);
		endif;
		if(is_null($reactions_limit) === false):
			$writer->writeInt($reactions_limit);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['can_set_username'] = boolval($flags & (1 << 7));
		$result['has_scheduled'] = boolval($flags & (1 << 8));
		$result['translations_disabled'] = boolval($flags & (1 << 19));
		$result['id'] = $reader->readLong();
		$result['about'] = $reader->readBytes();
		$result['participants'] = $reader->readObject();
		if($flags & (1 << 2)):
			$result['chat_photo'] = $reader->readObject();
		else:
			$result['chat_photo'] = null;
		endif;
		$result['notify_settings'] = $reader->readObject();
		if($flags & (1 << 13)):
			$result['exported_invite'] = $reader->readObject();
		else:
			$result['exported_invite'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['bot_info'] = $reader->readVector('botinfo');
		else:
			$result['bot_info'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['pinned_msg_id'] = $reader->readInt();
		else:
			$result['pinned_msg_id'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['folder_id'] = $reader->readInt();
		else:
			$result['folder_id'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['call'] = $reader->readObject();
		else:
			$result['call'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['ttl_period'] = $reader->readInt();
		else:
			$result['ttl_period'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['groupcall_default_join_as'] = $reader->readObject();
		else:
			$result['groupcall_default_join_as'] = null;
		endif;
		if($flags & (1 << 16)):
			$result['theme_emoticon'] = $reader->readBytes();
		else:
			$result['theme_emoticon'] = null;
		endif;
		if($flags & (1 << 17)):
			$result['requests_pending'] = $reader->readInt();
		else:
			$result['requests_pending'] = null;
		endif;
		if($flags & (1 << 17)):
			$result['recent_requesters'] = $reader->readVector('long');
		else:
			$result['recent_requesters'] = null;
		endif;
		if($flags & (1 << 18)):
			$result['available_reactions'] = $reader->readObject();
		else:
			$result['available_reactions'] = null;
		endif;
		if($flags & (1 << 20)):
			$result['reactions_limit'] = $reader->readInt();
		else:
			$result['reactions_limit'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string street_line1 string street_line2 string city string state string country_iso2 string post_code
 * @return PostAddress
 */

final class PostAddress extends Instance {
	public function request(string $street_line1,string $street_line2,string $city,string $state,string $country_iso2,string $post_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1e8caaeb);
		$writer->writeBytes($street_line1);
		$writer->writeBytes($street_line2);
		$writer->writeBytes($city);
		$writer->writeBytes($state);
		$writer->writeBytes($country_iso2);
		$writer->writeBytes($post_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['street_line1'] = $reader->readBytes();
		$result['street_line2'] = $reader->readBytes();
		$result['city'] = $reader->readBytes();
		$result['state'] = $reader->readBytes();
		$result['country_iso2'] = $reader->readBytes();
		$result['post_code'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param groupcallparticipant participant
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantUnmute extends Instance {
	public function request(object $participant) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe64429c0);
		$writer->writeObject($participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['participant'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int id storyitem story
 * @return WebPageAttribute
 */

final class WebPageAttributeStory extends Instance {
	public function request(object $peer,int $id,null | object $story = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2e94c3e7);
		$flags = 0;
		$flags |= is_null($story) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		if(is_null($story) === false):
			$writer->writeObject($story);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['peer'] = $reader->readObject();
		$result['id'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['story'] = $reader->readObject();
		else:
			$result['story'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id peer from_id sendmessageaction action
 * @return Update
 */

final class UpdateChatUserTyping extends Instance {
	public function request(int $chat_id,object $from_id,object $action) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x83487af0);
		$writer->writeLong($chat_id);
		$writer->writeObject($from_id);
		$writer->writeObject($action);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readLong();
		$result['from_id'] = $reader->readObject();
		$result['action'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long amount
 * @return StarsAmount
 */

final class StarsTonAmount extends Instance {
	public function request(int $amount) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x74aee3e0);
		$writer->writeLong($amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id peer saved_peer_id int read_max_id
 * @return Update
 */

final class UpdateReadMonoForumInbox extends Instance {
	public function request(int $channel_id,object $saved_peer_id,int $read_max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x77b0e372);
		$writer->writeLong($channel_id);
		$writer->writeObject($saved_peer_id);
		$writer->writeInt($read_max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['saved_peer_id'] = $reader->readObject();
		$result['read_max_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string code
 * @return EmailVerification
 */

final class EmailVerificationCode extends Instance {
	public function request(string $code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x922e55a9);
		$writer->writeBytes($code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['code'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce int128 server_nonce long retry_id string g_b
 * @return Client_DH_Inner_Data
 */

final class ClientDHInnerData extends Instance {
	public function request(int | string $nonce,int | string $server_nonce,int $retry_id,string $g_b) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6643b654);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeLong($retry_id);
		$writer->writeBytes($g_b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['retry_id'] = $reader->readLong();
		$result['g_b'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param mediaareacoordinates coordinates inputchannel channel int msg_id
 * @return MediaArea
 */

final class InputMediaAreaChannelPost extends Instance {
	public function request(object $coordinates,object $channel,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2271f2bf);
		$writer->writeObject($coordinates);
		$writer->writeObject($channel);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['coordinates'] = $reader->readObject();
		$result['channel'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return TopPeerCategory
 */

final class TopPeerCategoryCorrespondents extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x637b7ed);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url long chat_id
 * @return RecentMeUrl
 */

final class RecentMeUrlChat extends Instance {
	public function request(string $url,int $chat_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb2da71d2);
		$writer->writeBytes($url);
		$writer->writeLong($chat_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['chat_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url int expires
 * @return ExportedContactToken
 */

final class ExportedContactToken extends Instance {
	public function request(string $url,int $expires) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x41bf109b);
		$writer->writeBytes($url);
		$writer->writeInt($expires);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['expires'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputMessage
 */

final class InputMessagePinned extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x86872538);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length string url
 * @return MessageEntity
 */

final class MessageEntityTextUrl extends Instance {
	public function request(int $offset,int $length,string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x76a6d327);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars_amount Vector<inputmedia> extended_media string payload
 * @return InputMedia
 */

final class InputMediaPaidMedia extends Instance {
	public function request(int $stars_amount,array $extended_media,null | string $payload = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc4103386);
		$flags = 0;
		$flags |= is_null($payload) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($stars_amount);
		$writer->writeVector($extended_media,'inputmedia');
		if(is_null($payload) === false):
			$writer->writeBytes($payload);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['stars_amount'] = $reader->readLong();
		$result['extended_media'] = $reader->readVector('inputmedia');
		if($flags & (1 << 0)):
			$result['payload'] = $reader->readBytes();
		else:
			$result['payload'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessageMedia
 */

final class MessageMediaUnsupported extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9f84f49e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyNoPaidMessages extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbdc597b4);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityStrike extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbf0693d4);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text string phone
 * @return RichText
 */

final class TextPhone extends Instance {
	public function request(object $text,string $phone) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1ccb966a);
		$writer->writeObject($text);
		$writer->writeBytes($phone);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		$result['phone'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyPhoneNumber extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x352dafa);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string reaction string title document static_icon document appear_animation document select_animation document activate_animation document effect_animation true inactive true premium document around_animation document center_icon
 * @return AvailableReaction
 */

final class AvailableReaction extends Instance {
	public function request(string $reaction,string $title,object $static_icon,object $appear_animation,object $select_animation,object $activate_animation,object $effect_animation,null | bool $inactive = null,null | bool $premium = null,null | object $around_animation = null,null | object $center_icon = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc077ec01);
		$flags = 0;
		$flags |= $inactive ? (1 << 0) : 0;
		$flags |= $premium ? (1 << 2) : 0;
		$flags |= is_null($around_animation) ? 0 : (1 << 1);
		$flags |= is_null($center_icon) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($reaction);
		$writer->writeBytes($title);
		$writer->writeObject($static_icon);
		$writer->writeObject($appear_animation);
		$writer->writeObject($select_animation);
		$writer->writeObject($activate_animation);
		$writer->writeObject($effect_animation);
		if(is_null($around_animation) === false):
			$writer->writeObject($around_animation);
		endif;
		if(is_null($center_icon) === false):
			$writer->writeObject($center_icon);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['inactive'] = boolval($flags & (1 << 0));
		$result['premium'] = boolval($flags & (1 << 2));
		$result['reaction'] = $reader->readBytes();
		$result['title'] = $reader->readBytes();
		$result['static_icon'] = $reader->readObject();
		$result['appear_animation'] = $reader->readObject();
		$result['select_animation'] = $reader->readObject();
		$result['activate_animation'] = $reader->readObject();
		$result['effect_animation'] = $reader->readObject();
		if($flags & (1 << 1)):
			$result['around_animation'] = $reader->readObject();
		else:
			$result['around_animation'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['center_icon'] = $reader->readObject();
		else:
			$result['center_icon'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BaseTheme
 */

final class BaseThemeTinted extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6d5f77ee);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterRoundVideo extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb549da53);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return DocumentAttribute
 */

final class DocumentAttributeHasStickers extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9801d2f7);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type bytes file_hash string text
 * @return SecureValueError
 */

final class SecureValueErrorSelfie extends Instance {
	public function request(object $type,string $file_hash,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe537ced6);
		$writer->writeObject($type);
		$writer->writeBytes($file_hash);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readObject();
		$result['file_hash'] = $reader->readBytes();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyProfilePhoto extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x96151fed);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PhoneCallDiscardReason
 */

final class PhoneCallDiscardReasonHangup extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x57adc690);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<pageblock> blocks richtext caption
 * @return PageBlock
 */

final class PageBlockBlockquoteBlocks extends Instance {
	public function request(array $blocks,object $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe6e47c4);
		$writer->writeVector($blocks,'pageblock');
		$writer->writeObject($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['blocks'] = $reader->readVector('pageblock');
		$result['caption'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id bytes tmp_password
 * @return InputPaymentCredentials
 */

final class InputPaymentCredentialsSaved extends Instance {
	public function request(string $id,string $tmp_password) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc10eb2cf);
		$writer->writeBytes($id);
		$writer->writeBytes($tmp_password);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readBytes();
		$result['tmp_password'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ProfileTab
 */

final class ProfileTabVoice extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe477092e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string link
 * @return ExportedStoryLink
 */

final class ExportedStoryLink extends Instance {
	public function request(string $link) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3fc9053b);
		$writer->writeBytes($link);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['link'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string key string other_value string zero_value string one_value string two_value string few_value string many_value
 * @return LangPackString
 */

final class LangPackStringPluralized extends Instance {
	public function request(string $key,string $other_value,null | string $zero_value = null,null | string $one_value = null,null | string $two_value = null,null | string $few_value = null,null | string $many_value = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c47ac9f);
		$flags = 0;
		$flags |= is_null($zero_value) ? 0 : (1 << 0);
		$flags |= is_null($one_value) ? 0 : (1 << 1);
		$flags |= is_null($two_value) ? 0 : (1 << 2);
		$flags |= is_null($few_value) ? 0 : (1 << 3);
		$flags |= is_null($many_value) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeBytes($key);
		if(is_null($zero_value) === false):
			$writer->writeBytes($zero_value);
		endif;
		if(is_null($one_value) === false):
			$writer->writeBytes($one_value);
		endif;
		if(is_null($two_value) === false):
			$writer->writeBytes($two_value);
		endif;
		if(is_null($few_value) === false):
			$writer->writeBytes($few_value);
		endif;
		if(is_null($many_value) === false):
			$writer->writeBytes($many_value);
		endif;
		$writer->writeBytes($other_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['key'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['zero_value'] = $reader->readBytes();
		else:
			$result['zero_value'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['one_value'] = $reader->readBytes();
		else:
			$result['one_value'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['two_value'] = $reader->readBytes();
		else:
			$result['two_value'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['few_value'] = $reader->readBytes();
		else:
			$result['few_value'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['many_value'] = $reader->readBytes();
		else:
			$result['many_value'] = null;
		endif;
		$result['other_value'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int photo_size_max long video_size_max long file_size_max int video_upload_maxbitrate int small_queue_active_operations_max int large_queue_active_operations_max true disabled true video_preload_large true audio_preload_next true phonecalls_less_data true stories_preload
 * @return AutoDownloadSettings
 */

final class AutoDownloadSettings extends Instance {
	public function request(int $photo_size_max,int $video_size_max,int $file_size_max,int $video_upload_maxbitrate,int $small_queue_active_operations_max,int $large_queue_active_operations_max,null | bool $disabled = null,null | bool $video_preload_large = null,null | bool $audio_preload_next = null,null | bool $phonecalls_less_data = null,null | bool $stories_preload = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbaa57628);
		$flags = 0;
		$flags |= $disabled ? (1 << 0) : 0;
		$flags |= $video_preload_large ? (1 << 1) : 0;
		$flags |= $audio_preload_next ? (1 << 2) : 0;
		$flags |= $phonecalls_less_data ? (1 << 3) : 0;
		$flags |= $stories_preload ? (1 << 4) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($photo_size_max);
		$writer->writeLong($video_size_max);
		$writer->writeLong($file_size_max);
		$writer->writeInt($video_upload_maxbitrate);
		$writer->writeInt($small_queue_active_operations_max);
		$writer->writeInt($large_queue_active_operations_max);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['disabled'] = boolval($flags & (1 << 0));
		$result['video_preload_large'] = boolval($flags & (1 << 1));
		$result['audio_preload_next'] = boolval($flags & (1 << 2));
		$result['phonecalls_less_data'] = boolval($flags & (1 << 3));
		$result['stories_preload'] = boolval($flags & (1 << 4));
		$result['photo_size_max'] = $reader->readInt();
		$result['video_size_max'] = $reader->readLong();
		$result['file_size_max'] = $reader->readLong();
		$result['video_upload_maxbitrate'] = $reader->readInt();
		$result['small_queue_active_operations_max'] = $reader->readInt();
		$result['large_queue_active_operations_max'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int min_id int max_id
 * @return MessageRange
 */

final class MessageRange extends Instance {
	public function request(int $min_id,int $max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xae30253);
		$writer->writeInt($min_id);
		$writer->writeInt($max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['min_id'] = $reader->readInt();
		$result['max_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long gift_id
 * @return InputStarGiftAuction
 */

final class InputStarGiftAuction extends Instance {
	public function request(int $gift_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2e16c98);
		$writer->writeLong($gift_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['gift_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string first_name string last_name string vcard long user_id
 * @return MessageMedia
 */

final class MessageMediaContact extends Instance {
	public function request(string $phone_number,string $first_name,string $last_name,string $vcard,int $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x70322949);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($first_name);
		$writer->writeBytes($last_name);
		$writer->writeBytes($vcard);
		$writer->writeLong($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone_number'] = $reader->readBytes();
		$result['first_name'] = $reader->readBytes();
		$result['last_name'] = $reader->readBytes();
		$result['vcard'] = $reader->readBytes();
		$result['user_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true rejected true balance_too_low string reject_comment int schedule_date starsamount price
 * @return MessageAction
 */

final class MessageActionSuggestedPostApproval extends Instance {
	public function request(null | bool $rejected = null,null | bool $balance_too_low = null,null | string $reject_comment = null,null | int $schedule_date = null,null | object $price = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xee7a1596);
		$flags = 0;
		$flags |= $rejected ? (1 << 0) : 0;
		$flags |= $balance_too_low ? (1 << 1) : 0;
		$flags |= is_null($reject_comment) ? 0 : (1 << 2);
		$flags |= is_null($schedule_date) ? 0 : (1 << 3);
		$flags |= is_null($price) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		if(is_null($reject_comment) === false):
			$writer->writeBytes($reject_comment);
		endif;
		if(is_null($schedule_date) === false):
			$writer->writeInt($schedule_date);
		endif;
		if(is_null($price) === false):
			$writer->writeObject($price);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['rejected'] = boolval($flags & (1 << 0));
		$result['balance_too_low'] = boolval($flags & (1 << 1));
		if($flags & (1 << 2)):
			$result['reject_comment'] = $reader->readBytes();
		else:
			$result['reject_comment'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['schedule_date'] = $reader->readInt();
		else:
			$result['schedule_date'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['price'] = $reader->readObject();
		else:
			$result['price'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReportReason
 */

final class InputReportReasonOther extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc1e4a2b1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string name string native_name string lang_code string plural_code int strings_count int translated_count string translations_url true official true rtl true beta string base_lang_code
 * @return LangPackLanguage
 */

final class LangPackLanguage extends Instance {
	public function request(string $name,string $native_name,string $lang_code,string $plural_code,int $strings_count,int $translated_count,string $translations_url,null | bool $official = null,null | bool $rtl = null,null | bool $beta = null,null | string $base_lang_code = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeeca5ce3);
		$flags = 0;
		$flags |= $official ? (1 << 0) : 0;
		$flags |= $rtl ? (1 << 2) : 0;
		$flags |= $beta ? (1 << 3) : 0;
		$flags |= is_null($base_lang_code) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($name);
		$writer->writeBytes($native_name);
		$writer->writeBytes($lang_code);
		if(is_null($base_lang_code) === false):
			$writer->writeBytes($base_lang_code);
		endif;
		$writer->writeBytes($plural_code);
		$writer->writeInt($strings_count);
		$writer->writeInt($translated_count);
		$writer->writeBytes($translations_url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['official'] = boolval($flags & (1 << 0));
		$result['rtl'] = boolval($flags & (1 << 2));
		$result['beta'] = boolval($flags & (1 << 3));
		$result['name'] = $reader->readBytes();
		$result['native_name'] = $reader->readBytes();
		$result['lang_code'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['base_lang_code'] = $reader->readBytes();
		else:
			$result['base_lang_code'] = null;
		endif;
		$result['plural_code'] = $reader->readBytes();
		$result['strings_count'] = $reader->readInt();
		$result['translated_count'] = $reader->readInt();
		$result['translations_url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long document_id int until
 * @return EmojiStatus
 */

final class EmojiStatus extends Instance {
	public function request(int $document_id,null | int $until = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe7ff068a);
		$flags = 0;
		$flags |= is_null($until) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($document_id);
		if(is_null($until) === false):
			$writer->writeInt($until);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['document_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['until'] = $reader->readInt();
		else:
			$result['until'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputWallPaper
 */

final class InputWallPaper extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe630b979);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string emoticon
 * @return InputMedia
 */

final class InputMediaDice extends Instance {
	public function request(string $emoticon) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe66fbf7b);
		$writer->writeBytes($emoticon);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['emoticon'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string title
 * @return PaymentSavedCredentials
 */

final class PaymentSavedCredentialsCard extends Instance {
	public function request(string $id,string $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcdc27a1f);
		$writer->writeBytes($id);
		$writer->writeBytes($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readBytes();
		$result['title'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param pageblock cover
 * @return PageBlock
 */

final class PageBlockCover extends Instance {
	public function request(object $cover) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x39f23300);
		$writer->writeObject($cover);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['cover'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateFavedStickers extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe511996d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int msg_id int date Vector<reactioncount> reactions int qts
 * @return Update
 */

final class UpdateBotMessageReactions extends Instance {
	public function request(object $peer,int $msg_id,int $date,array $reactions,int $qts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9cb7759);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeInt($date);
		$writer->writeVector($reactions,'reactioncount');
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['reactions'] = $reader->readVector('reactioncount');
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarGiftAuctionState
 */

final class StarGiftAuctionStateNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfe333952);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionToggleSignatures extends Instance {
	public function request(bool $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x26ae0971);
		$writer->writeBool($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_value'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgeopoint geo int zoom int w int h pagecaption caption
 * @return PageBlock
 */

final class InputPageBlockMap extends Instance {
	public function request(object $geo,int $zoom,int $w,int $h,object $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x574b617f);
		$writer->writeObject($geo);
		$writer->writeInt($zoom);
		$writer->writeInt($w);
		$writer->writeInt($h);
		$writer->writeObject($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['geo'] = $reader->readObject();
		$result['zoom'] = $reader->readInt();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		$result['caption'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type bytes file_hash string text
 * @return SecureValueError
 */

final class SecureValueErrorFrontSide extends Instance {
	public function request(object $type,string $file_hash,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbe3dfa);
		$writer->writeObject($type);
		$writer->writeBytes($file_hash);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readObject();
		$result['file_hash'] = $reader->readBytes();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text richtext caption
 * @return PageBlock
 */

final class PageBlockPullquote extends Instance {
	public function request(object $text,object $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4f4456d3);
		$writer->writeObject($text);
		$writer->writeObject($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		$result['caption'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPeer
 */

final class InputPeerSelf extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7da07ec9);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReportReason
 */

final class InputReportReasonSpam extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x58dbcab8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long document_id
 * @return Reaction
 */

final class ReactionCustomEmoji extends Instance {
	public function request(int $document_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8935fc73);
		$writer->writeLong($document_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['document_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id businessawaymessageschedule schedule inputbusinessrecipients recipients true offline_only
 * @return InputBusinessAwayMessage
 */

final class InputBusinessAwayMessage extends Instance {
	public function request(int $shortcut_id,object $schedule,object $recipients,null | bool $offline_only = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x832175e0);
		$flags = 0;
		$flags |= $offline_only ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($shortcut_id);
		$writer->writeObject($schedule);
		$writer->writeObject($recipients);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['offline_only'] = boolval($flags & (1 << 0));
		$result['shortcut_id'] = $reader->readInt();
		$result['schedule'] = $reader->readObject();
		$result['recipients'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string country int this_dc int nearest_dc
 * @return NearestDc
 */

final class NearestDc extends Instance {
	public function request(string $country,int $this_dc,int $nearest_dc) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8e1a1775);
		$writer->writeBytes($country);
		$writer->writeInt($this_dc);
		$writer->writeInt($nearest_dc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['country'] = $reader->readBytes();
		$result['this_dc'] = $reader->readInt();
		$result['nearest_dc'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<attachmenubot> bots Vector<user> users
 * @return AttachMenuBots
 */

final class AttachMenuBots extends Instance {
	public function request(int $hash,array $bots,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3c4301c0);
		$writer->writeLong($hash);
		$writer->writeVector($bots,'attachmenubot');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['bots'] = $reader->readVector('attachmenubot');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButton extends Instance {
	public function request(string $text,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7d170cff);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title string description document sticker
 * @return BusinessIntro
 */

final class BusinessIntro extends Instance {
	public function request(string $title,string $description,null | object $sticker = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5a0a066d);
		$flags = 0;
		$flags |= is_null($sticker) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		if(is_null($sticker) === false):
			$writer->writeObject($sticker);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['sticker'] = $reader->readObject();
		else:
			$result['sticker'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypeBankStatement extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x89137c0d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call int duration
 * @return MessageAction
 */

final class MessageActionGroupCall extends Instance {
	public function request(object $call,null | int $duration = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7a0d7f42);
		$flags = 0;
		$flags |= is_null($duration) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($call);
		if(is_null($duration) === false):
			$writer->writeInt($duration);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['call'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['duration'] = $reader->readInt();
		else:
			$result['duration'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param forumtopic prev_topic forumtopic new_topic
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionPinTopic extends Instance {
	public function request(null | object $prev_topic = null,null | object $new_topic = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5d8d353b);
		$flags = 0;
		$flags |= is_null($prev_topic) ? 0 : (1 << 0);
		$flags |= is_null($new_topic) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($prev_topic) === false):
			$writer->writeObject($prev_topic);
		endif;
		if(is_null($new_topic) === false):
			$writer->writeObject($new_topic);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['prev_topic'] = $reader->readObject();
		else:
			$result['prev_topic'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['new_topic'] = $reader->readObject();
		else:
			$result['new_topic'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long photo_id int dc_id true has_video true personal bytes stripped_thumb
 * @return UserProfilePhoto
 */

final class UserProfilePhoto extends Instance {
	public function request(int $photo_id,int $dc_id,null | bool $has_video = null,null | bool $personal = null,null | string $stripped_thumb = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x82d1f706);
		$flags = 0;
		$flags |= $has_video ? (1 << 0) : 0;
		$flags |= $personal ? (1 << 2) : 0;
		$flags |= is_null($stripped_thumb) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($photo_id);
		if(is_null($stripped_thumb) === false):
			$writer->writeBytes($stripped_thumb);
		endif;
		$writer->writeInt($dc_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['has_video'] = boolval($flags & (1 << 0));
		$result['personal'] = boolval($flags & (1 << 2));
		$result['photo_id'] = $reader->readLong();
		if($flags & (1 << 1)):
			$result['stripped_thumb'] = $reader->readBytes();
		else:
			$result['stripped_thumb'] = null;
		endif;
		$result['dc_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id textwithentities title Vector<inputpeer> pinned_peers Vector<inputpeer> include_peers true has_my_invites true title_noanimate string emoticon int color
 * @return DialogFilter
 */

final class DialogFilterChatlist extends Instance {
	public function request(int $id,object $title,array $pinned_peers,array $include_peers,null | bool $has_my_invites = null,null | bool $title_noanimate = null,null | string $emoticon = null,null | int $color = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x96537bd7);
		$flags = 0;
		$flags |= $has_my_invites ? (1 << 26) : 0;
		$flags |= $title_noanimate ? (1 << 28) : 0;
		$flags |= is_null($emoticon) ? 0 : (1 << 25);
		$flags |= is_null($color) ? 0 : (1 << 27);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeObject($title);
		if(is_null($emoticon) === false):
			$writer->writeBytes($emoticon);
		endif;
		if(is_null($color) === false):
			$writer->writeInt($color);
		endif;
		$writer->writeVector($pinned_peers,'inputpeer');
		$writer->writeVector($include_peers,'inputpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['has_my_invites'] = boolval($flags & (1 << 26));
		$result['title_noanimate'] = boolval($flags & (1 << 28));
		$result['id'] = $reader->readInt();
		$result['title'] = $reader->readObject();
		if($flags & (1 << 25)):
			$result['emoticon'] = $reader->readBytes();
		else:
			$result['emoticon'] = null;
		endif;
		if($flags & (1 << 27)):
			$result['color'] = $reader->readInt();
		else:
			$result['color'] = null;
		endif;
		$result['pinned_peers'] = $reader->readVector('inputpeer');
		$result['include_peers'] = $reader->readVector('inputpeer');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return InputChatTheme
 */

final class InputChatThemeUniqueGift extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x87e5dfe4);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['slug'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true accepted true rejected starsamount price int schedule_date
 * @return SuggestedPost
 */

final class SuggestedPost extends Instance {
	public function request(null | bool $accepted = null,null | bool $rejected = null,null | object $price = null,null | int $schedule_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe8e37e5);
		$flags = 0;
		$flags |= $accepted ? (1 << 1) : 0;
		$flags |= $rejected ? (1 << 2) : 0;
		$flags |= is_null($price) ? 0 : (1 << 3);
		$flags |= is_null($schedule_date) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($price) === false):
			$writer->writeObject($price);
		endif;
		if(is_null($schedule_date) === false):
			$writer->writeInt($schedule_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['accepted'] = boolval($flags & (1 << 1));
		$result['rejected'] = boolval($flags & (1 << 2));
		if($flags & (1 << 3)):
			$result['price'] = $reader->readObject();
		else:
			$result['price'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['schedule_date'] = $reader->readInt();
		else:
			$result['schedule_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int days
 * @return AccountDaysTTL
 */

final class AccountDaysTTL extends Instance {
	public function request(int $days) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb8d0afdf);
		$writer->writeInt($days);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['days'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long msg_id long ping_id
 * @return Pong
 */

final class Pong extends Instance {
	public function request(int $msg_id,int $ping_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x347773c5);
		$writer->writeLong($msg_id);
		$writer->writeLong($ping_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_id'] = $reader->readLong();
		$result['ping_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message
 * @return Update
 */

final class UpdateQuickReplyMessage extends Instance {
	public function request(object $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e050d0f);
		$writer->writeObject($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityDiffInsert extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x71777116);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param basetheme base_theme int accent_color true message_colors_animated int outbox_accent_color Vector<int> message_colors inputwallpaper wallpaper wallpapersettings wallpaper_settings
 * @return InputThemeSettings
 */

final class InputThemeSettings extends Instance {
	public function request(object $base_theme,int $accent_color,null | bool $message_colors_animated = null,null | int $outbox_accent_color = null,null | array $message_colors = null,null | object $wallpaper = null,null | object $wallpaper_settings = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8fde504f);
		$flags = 0;
		$flags |= $message_colors_animated ? (1 << 2) : 0;
		$flags |= is_null($outbox_accent_color) ? 0 : (1 << 3);
		$flags |= is_null($message_colors) ? 0 : (1 << 0);
		$flags |= is_null($wallpaper) ? 0 : (1 << 1);
		$flags |= is_null($wallpaper_settings) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($base_theme);
		$writer->writeInt($accent_color);
		if(is_null($outbox_accent_color) === false):
			$writer->writeInt($outbox_accent_color);
		endif;
		if(is_null($message_colors) === false):
			$writer->writeVector($message_colors,'int');
		endif;
		if(is_null($wallpaper) === false):
			$writer->writeObject($wallpaper);
		endif;
		if(is_null($wallpaper_settings) === false):
			$writer->writeObject($wallpaper_settings);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['message_colors_animated'] = boolval($flags & (1 << 2));
		$result['base_theme'] = $reader->readObject();
		$result['accent_color'] = $reader->readInt();
		if($flags & (1 << 3)):
			$result['outbox_accent_color'] = $reader->readInt();
		else:
			$result['outbox_accent_color'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['message_colors'] = $reader->readVector('int');
		else:
			$result['message_colors'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['wallpaper'] = $reader->readObject();
		else:
			$result['wallpaper'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['wallpaper_settings'] = $reader->readObject();
		else:
			$result['wallpaper_settings'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int until_date true view_messages true send_messages true send_media true send_stickers true send_gifs true send_games true send_inline true embed_links true send_polls true change_info true invite_users true pin_messages true manage_topics true send_photos true send_videos true send_roundvideos true send_audios true send_voices true send_docs true send_plain true edit_rank true send_reactions
 * @return ChatBannedRights
 */

final class ChatBannedRights extends Instance {
	public function request(int $until_date,null | bool $view_messages = null,null | bool $send_messages = null,null | bool $send_media = null,null | bool $send_stickers = null,null | bool $send_gifs = null,null | bool $send_games = null,null | bool $send_inline = null,null | bool $embed_links = null,null | bool $send_polls = null,null | bool $change_info = null,null | bool $invite_users = null,null | bool $pin_messages = null,null | bool $manage_topics = null,null | bool $send_photos = null,null | bool $send_videos = null,null | bool $send_roundvideos = null,null | bool $send_audios = null,null | bool $send_voices = null,null | bool $send_docs = null,null | bool $send_plain = null,null | bool $edit_rank = null,null | bool $send_reactions = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9f120418);
		$flags = 0;
		$flags |= $view_messages ? (1 << 0) : 0;
		$flags |= $send_messages ? (1 << 1) : 0;
		$flags |= $send_media ? (1 << 2) : 0;
		$flags |= $send_stickers ? (1 << 3) : 0;
		$flags |= $send_gifs ? (1 << 4) : 0;
		$flags |= $send_games ? (1 << 5) : 0;
		$flags |= $send_inline ? (1 << 6) : 0;
		$flags |= $embed_links ? (1 << 7) : 0;
		$flags |= $send_polls ? (1 << 8) : 0;
		$flags |= $change_info ? (1 << 10) : 0;
		$flags |= $invite_users ? (1 << 15) : 0;
		$flags |= $pin_messages ? (1 << 17) : 0;
		$flags |= $manage_topics ? (1 << 18) : 0;
		$flags |= $send_photos ? (1 << 19) : 0;
		$flags |= $send_videos ? (1 << 20) : 0;
		$flags |= $send_roundvideos ? (1 << 21) : 0;
		$flags |= $send_audios ? (1 << 22) : 0;
		$flags |= $send_voices ? (1 << 23) : 0;
		$flags |= $send_docs ? (1 << 24) : 0;
		$flags |= $send_plain ? (1 << 25) : 0;
		$flags |= $edit_rank ? (1 << 26) : 0;
		$flags |= $send_reactions ? (1 << 27) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($until_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['view_messages'] = boolval($flags & (1 << 0));
		$result['send_messages'] = boolval($flags & (1 << 1));
		$result['send_media'] = boolval($flags & (1 << 2));
		$result['send_stickers'] = boolval($flags & (1 << 3));
		$result['send_gifs'] = boolval($flags & (1 << 4));
		$result['send_games'] = boolval($flags & (1 << 5));
		$result['send_inline'] = boolval($flags & (1 << 6));
		$result['embed_links'] = boolval($flags & (1 << 7));
		$result['send_polls'] = boolval($flags & (1 << 8));
		$result['change_info'] = boolval($flags & (1 << 10));
		$result['invite_users'] = boolval($flags & (1 << 15));
		$result['pin_messages'] = boolval($flags & (1 << 17));
		$result['manage_topics'] = boolval($flags & (1 << 18));
		$result['send_photos'] = boolval($flags & (1 << 19));
		$result['send_videos'] = boolval($flags & (1 << 20));
		$result['send_roundvideos'] = boolval($flags & (1 << 21));
		$result['send_audios'] = boolval($flags & (1 << 22));
		$result['send_voices'] = boolval($flags & (1 << 23));
		$result['send_docs'] = boolval($flags & (1 << 24));
		$result['send_plain'] = boolval($flags & (1 << 25));
		$result['edit_rank'] = boolval($flags & (1 << 26));
		$result['send_reactions'] = boolval($flags & (1 << 27));
		$result['until_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<pageblock> blocks true rtl true noautolink Vector<inputphoto> photos Vector<inputdocument> documents Vector<inputuser> users
 * @return InputRichMessage
 */

final class InputRichMessage extends Instance {
	public function request(array $blocks,null | bool $rtl = null,null | bool $noautolink = null,null | array $photos = null,null | array $documents = null,null | array $users = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe4c449fc);
		$flags = 0;
		$flags |= $rtl ? (1 << 0) : 0;
		$flags |= $noautolink ? (1 << 1) : 0;
		$flags |= is_null($photos) ? 0 : (1 << 2);
		$flags |= is_null($documents) ? 0 : (1 << 3);
		$flags |= is_null($users) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeVector($blocks,'pageblock');
		if(is_null($photos) === false):
			$writer->writeVector($photos,'inputphoto');
		endif;
		if(is_null($documents) === false):
			$writer->writeVector($documents,'inputdocument');
		endif;
		if(is_null($users) === false):
			$writer->writeVector($users,'inputuser');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['rtl'] = boolval($flags & (1 << 0));
		$result['noautolink'] = boolval($flags & (1 << 1));
		$result['blocks'] = $reader->readVector('pageblock');
		if($flags & (1 << 2)):
			$result['photos'] = $reader->readVector('inputphoto');
		else:
			$result['photos'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['documents'] = $reader->readVector('inputdocument');
		else:
			$result['documents'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['users'] = $reader->readVector('inputuser');
		else:
			$result['users'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes salt
 * @return SecurePasswordKdfAlgo
 */

final class SecurePasswordKdfAlgoSHA512 extends Instance {
	public function request(string $salt) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x86471d92);
		$writer->writeBytes($salt);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['salt'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextAutoEmail extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc556a45d);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext author int published_date
 * @return PageBlock
 */

final class PageBlockAuthorDate extends Instance {
	public function request(object $author,int $published_date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbaafe5e0);
		$writer->writeObject($author);
		$writer->writeInt($published_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['author'] = $reader->readObject();
		$result['published_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url long user_id
 * @return RecentMeUrl
 */

final class RecentMeUrlUser extends Instance {
	public function request(string $url,int $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb92c09e2);
		$writer->writeBytes($url);
		$writer->writeLong($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['user_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return RpcDropAnswer
 */

final class RpcAnswerUnknown extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5e2ad36e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int date long bid_amount int round int pos true name_hidden textwithentities message int gift_num
 * @return StarGiftAuctionAcquiredGift
 */

final class StarGiftAuctionAcquiredGift extends Instance {
	public function request(object $peer,int $date,int $bid_amount,int $round,int $pos,null | bool $name_hidden = null,null | object $message = null,null | int $gift_num = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x42b00348);
		$flags = 0;
		$flags |= $name_hidden ? (1 << 0) : 0;
		$flags |= is_null($message) ? 0 : (1 << 1);
		$flags |= is_null($gift_num) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($date);
		$writer->writeLong($bid_amount);
		$writer->writeInt($round);
		$writer->writeInt($pos);
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		if(is_null($gift_num) === false):
			$writer->writeInt($gift_num);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['name_hidden'] = boolval($flags & (1 << 0));
		$result['peer'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		$result['bid_amount'] = $reader->readLong();
		$result['round'] = $reader->readInt();
		$result['pos'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['message'] = $reader->readObject();
		else:
			$result['message'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['gift_num'] = $reader->readInt();
		else:
			$result['gift_num'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ChannelParticipantsFilter
 */

final class ChannelParticipantsBots extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb0d1865b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param update update int date
 * @return Updates
 */

final class UpdateShort extends Instance {
	public function request(object $update,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x78d4dec1);
		$writer->writeObject($update);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['update'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars
 * @return MessageAction
 */

final class MessageActionGiveawayLaunch extends Instance {
	public function request(null | int $stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa80f51e4);
		$flags = 0;
		$flags |= is_null($stars) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($stars) === false):
			$writer->writeLong($stars);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['stars'] = $reader->readLong();
		else:
			$result['stars'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateStarGiftCraftFail extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xac072444);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string name int backdrop_id int center_color int edge_color int pattern_color int text_color stargiftattributerarity rarity
 * @return StarGiftAttribute
 */

final class StarGiftAttributeBackdrop extends Instance {
	public function request(string $name,int $backdrop_id,int $center_color,int $edge_color,int $pattern_color,int $text_color,object $rarity) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9f2504e4);
		$writer->writeBytes($name);
		$writer->writeInt($backdrop_id);
		$writer->writeInt($center_color);
		$writer->writeInt($edge_color);
		$writer->writeInt($pattern_color);
		$writer->writeInt($text_color);
		$writer->writeObject($rarity);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['name'] = $reader->readBytes();
		$result['backdrop_id'] = $reader->readInt();
		$result['center_color'] = $reader->readInt();
		$result['edge_color'] = $reader->readInt();
		$result['pattern_color'] = $reader->readInt();
		$result['text_color'] = $reader->readInt();
		$result['rarity'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer long saved_id
 * @return InputSavedStarGift
 */

final class InputSavedStarGiftChat extends Instance {
	public function request(object $peer,int $saved_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf101aa7f);
		$writer->writeObject($peer);
		$writer->writeLong($saved_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['saved_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param textwithentities title Vector<todoitem> list true others_can_append true others_can_complete
 * @return TodoList
 */

final class TodoList extends Instance {
	public function request(object $title,array $list,null | bool $others_can_append = null,null | bool $others_can_complete = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x49b92a26);
		$flags = 0;
		$flags |= $others_can_append ? (1 << 0) : 0;
		$flags |= $others_can_complete ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($title);
		$writer->writeVector($list,'todoitem');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['others_can_append'] = boolval($flags & (1 << 0));
		$result['others_can_complete'] = boolval($flags & (1 << 1));
		$result['title'] = $reader->readObject();
		$result['list'] = $reader->readVector('todoitem');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param chatreactions prev_value chatreactions new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeAvailableReactions extends Instance {
	public function request(object $prev_value,object $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbe4e0ef8);
		$writer->writeObject($prev_value);
		$writer->writeObject($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readObject();
		$result['new_value'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true live int max_id
 * @return RecentStory
 */

final class RecentStory extends Instance {
	public function request(null | bool $live = null,null | int $max_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x711d692d);
		$flags = 0;
		$flags |= $live ? (1 << 0) : 0;
		$flags |= is_null($max_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($max_id) === false):
			$writer->writeInt($max_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['live'] = boolval($flags & (1 << 0));
		if($flags & (1 << 1)):
			$result['max_id'] = $reader->readInt();
		else:
			$result['max_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionStopPoll extends Instance {
	public function request(object $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8f079643);
		$writer->writeObject($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q
 * @return ChannelParticipantsFilter
 */

final class ChannelParticipantsBanned extends Instance {
	public function request(string $q) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1427a5e1);
		$writer->writeBytes($q);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['q'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputuser> users
 * @return InputPrivacyRule
 */

final class InputPrivacyValueDisallowUsers extends Instance {
	public function request(array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x90110467);
		$writer->writeVector($users,'inputuser');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['users'] = $reader->readVector('inputuser');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstorepaymentpurpose purpose premiumgiftcodeoption option
 * @return InputInvoice
 */

final class InputInvoicePremiumGiftCode extends Instance {
	public function request(object $purpose,object $option) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x98986c0d);
		$writer->writeObject($purpose);
		$writer->writeObject($option);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['purpose'] = $reader->readObject();
		$result['option'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id true need_rating true need_debug true video phonecalldiscardreason reason int duration
 * @return PhoneCall
 */

final class PhoneCallDiscarded extends Instance {
	public function request(int $id,null | bool $need_rating = null,null | bool $need_debug = null,null | bool $video = null,null | object $reason = null,null | int $duration = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x50ca4de1);
		$flags = 0;
		$flags |= $need_rating ? (1 << 2) : 0;
		$flags |= $need_debug ? (1 << 3) : 0;
		$flags |= $video ? (1 << 6) : 0;
		$flags |= is_null($reason) ? 0 : (1 << 0);
		$flags |= is_null($duration) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		if(is_null($reason) === false):
			$writer->writeObject($reason);
		endif;
		if(is_null($duration) === false):
			$writer->writeInt($duration);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['need_rating'] = boolval($flags & (1 << 2));
		$result['need_debug'] = boolval($flags & (1 << 3));
		$result['video'] = boolval($flags & (1 << 6));
		$result['id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['reason'] = $reader->readObject();
		else:
			$result['reason'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['duration'] = $reader->readInt();
		else:
			$result['duration'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int button_id Vector<peer> peers
 * @return MessageAction
 */

final class MessageActionRequestedPeer extends Instance {
	public function request(int $button_id,array $peers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31518e9b);
		$writer->writeInt($button_id);
		$writer->writeVector($peers,'peer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['button_id'] = $reader->readInt();
		$result['peers'] = $reader->readVector('peer');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message int pts int pts_count
 * @return Update
 */

final class UpdateNewMessage extends Instance {
	public function request(object $message,int $pts,int $pts_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1f2b0afd);
		$writer->writeObject($message);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id peer peer_id
 * @return Message
 */

final class MessageEmpty extends Instance {
	public function request(int $id,null | object $peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x90a6ca84);
		$flags = 0;
		$flags |= is_null($peer_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		if(is_null($peer_id) === false):
			$writer->writeObject($peer_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['peer_id'] = $reader->readObject();
		else:
			$result['peer_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id int flags
 * @return ReceivedNotifyMessage
 */

final class ReceivedNotifyMessage extends Instance {
	public function request(int $id,int $flags) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa384b779);
		$writer->writeInt($id);
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		$result['flags'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int w int h photosize thumb int video_duration
 * @return MessageExtendedMedia
 */

final class MessageExtendedMediaPreview extends Instance {
	public function request(null | int $w = null,null | int $h = null,null | object $thumb = null,null | int $video_duration = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xad628cc8);
		$flags = 0;
		$flags |= is_null($w) ? 0 : (1 << 0);
		$flags |= is_null($h) ? 0 : (1 << 0);
		$flags |= is_null($thumb) ? 0 : (1 << 1);
		$flags |= is_null($video_duration) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($w) === false):
			$writer->writeInt($w);
		endif;
		if(is_null($h) === false):
			$writer->writeInt($h);
		endif;
		if(is_null($thumb) === false):
			$writer->writeObject($thumb);
		endif;
		if(is_null($video_duration) === false):
			$writer->writeInt($video_duration);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['w'] = $reader->readInt();
		else:
			$result['w'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['h'] = $reader->readInt();
		else:
			$result['h'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['thumb'] = $reader->readObject();
		else:
			$result['thumb'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['video_duration'] = $reader->readInt();
		else:
			$result['video_duration'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string pnv_token
 * @return InputPasskeyCredential
 */

final class InputPasskeyCredentialFirebasePNV extends Instance {
	public function request(string $pnv_token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5b1ccb28);
		$writer->writeBytes($pnv_token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pnv_token'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockHeading5 extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdbbe6c6a);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphoto id true spoiler true live_photo int ttl_seconds inputdocument video
 * @return InputMedia
 */

final class InputMediaPhoto extends Instance {
	public function request(object $id,null | bool $spoiler = null,null | bool $live_photo = null,null | int $ttl_seconds = null,null | object $video = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe3af4434);
		$flags = 0;
		$flags |= $spoiler ? (1 << 1) : 0;
		$flags |= $live_photo ? (1 << 2) : 0;
		$flags |= is_null($ttl_seconds) ? 0 : (1 << 0);
		$flags |= is_null($video) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($id);
		if(is_null($ttl_seconds) === false):
			$writer->writeInt($ttl_seconds);
		endif;
		if(is_null($video) === false):
			$writer->writeObject($video);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['spoiler'] = boolval($flags & (1 << 1));
		$result['live_photo'] = boolval($flags & (1 << 2));
		$result['id'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['ttl_seconds'] = $reader->readInt();
		else:
			$result['ttl_seconds'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['video'] = $reader->readObject();
		else:
			$result['video'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id Vector<chatparticipant> participants int version
 * @return ChatParticipants
 */

final class ChatParticipants extends Instance {
	public function request(int $chat_id,array $participants,int $version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3cbc93f8);
		$writer->writeLong($chat_id);
		$writer->writeVector($participants,'chatparticipant');
		$writer->writeInt($version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readLong();
		$result['participants'] = $reader->readVector('chatparticipant');
		$result['version'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_code
 * @return EmojiLanguage
 */

final class EmojiLanguage extends Instance {
	public function request(string $lang_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb3fb5361);
		$writer->writeBytes($lang_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['lang_code'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long photo_id int dc_id true has_video bytes stripped_thumb
 * @return ChatPhoto
 */

final class ChatPhoto extends Instance {
	public function request(int $photo_id,int $dc_id,null | bool $has_video = null,null | string $stripped_thumb = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1c6e1c11);
		$flags = 0;
		$flags |= $has_video ? (1 << 0) : 0;
		$flags |= is_null($stripped_thumb) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($photo_id);
		if(is_null($stripped_thumb) === false):
			$writer->writeBytes($stripped_thumb);
		endif;
		$writer->writeInt($dc_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['has_video'] = boolval($flags & (1 << 0));
		$result['photo_id'] = $reader->readLong();
		if($flags & (1 << 1)):
			$result['stripped_thumb'] = $reader->readBytes();
		else:
			$result['stripped_thumb'] = null;
		endif;
		$result['dc_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param langpackdifference difference
 * @return Update
 */

final class UpdateLangPack extends Instance {
	public function request(object $difference) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x56022f4d);
		$writer->writeObject($difference);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['difference'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextStrike extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9bf8bb95);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityDiffDelete extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x652c1c5);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true modified peer from string from_name int story_id
 * @return StoryFwdHeader
 */

final class StoryFwdHeader extends Instance {
	public function request(null | bool $modified = null,null | object $from = null,null | string $from_name = null,null | int $story_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb826e150);
		$flags = 0;
		$flags |= $modified ? (1 << 3) : 0;
		$flags |= is_null($from) ? 0 : (1 << 0);
		$flags |= is_null($from_name) ? 0 : (1 << 1);
		$flags |= is_null($story_id) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($from) === false):
			$writer->writeObject($from);
		endif;
		if(is_null($from_name) === false):
			$writer->writeBytes($from_name);
		endif;
		if(is_null($story_id) === false):
			$writer->writeInt($story_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['modified'] = boolval($flags & (1 << 3));
		if($flags & (1 << 0)):
			$result['from'] = $reader->readObject();
		else:
			$result['from'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['from_name'] = $reader->readBytes();
		else:
			$result['from_name'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['story_id'] = $reader->readInt();
		else:
			$result['story_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string emoticon Vector<long> documents
 * @return StickerPack
 */

final class StickerPack extends Instance {
	public function request(string $emoticon,array $documents) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x12b299d4);
		$writer->writeBytes($emoticon);
		$writer->writeVector($documents,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['emoticon'] = $reader->readBytes();
		$result['documents'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ExportedChatInvite
 */

final class ChatInvitePublicJoinRequests extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xed107ab7);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id string query string id geopoint geo inputbotinlinemessageid msg_id
 * @return Update
 */

final class UpdateBotInlineSend extends Instance {
	public function request(int $user_id,string $query,string $id,null | object $geo = null,null | object $msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x12f12a07);
		$flags = 0;
		$flags |= is_null($geo) ? 0 : (1 << 0);
		$flags |= is_null($msg_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		$writer->writeBytes($query);
		if(is_null($geo) === false):
			$writer->writeObject($geo);
		endif;
		$writer->writeBytes($id);
		if(is_null($msg_id) === false):
			$writer->writeObject($msg_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		$result['query'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['geo'] = $reader->readObject();
		else:
			$result['geo'] = null;
		endif;
		$result['id'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['msg_id'] = $reader->readObject();
		else:
			$result['msg_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<todoitem> list
 * @return MessageAction
 */

final class MessageActionTodoAppendTasks extends Instance {
	public function request(array $list) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc7edbc83);
		$writer->writeVector($list,'todoitem');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['list'] = $reader->readVector('todoitem');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url string title
 * @return PaymentFormMethod
 */

final class PaymentFormMethod extends Instance {
	public function request(string $url,string $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x88f8f21b);
		$writer->writeBytes($url);
		$writer->writeBytes($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['title'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true creator bool has_username chatadminrights user_admin_rights chatadminrights bot_admin_rights
 * @return RequestPeerType
 */

final class RequestPeerTypeBroadcast extends Instance {
	public function request(null | bool $creator = null,null | bool $has_username = null,null | object $user_admin_rights = null,null | object $bot_admin_rights = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x339bef6c);
		$flags = 0;
		$flags |= $creator ? (1 << 0) : 0;
		$flags |= is_null($has_username) ? 0 : (1 << 3);
		$flags |= is_null($user_admin_rights) ? 0 : (1 << 1);
		$flags |= is_null($bot_admin_rights) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($has_username) === false):
			$writer->writeBool($has_username);
		endif;
		if(is_null($user_admin_rights) === false):
			$writer->writeObject($user_admin_rights);
		endif;
		if(is_null($bot_admin_rights) === false):
			$writer->writeObject($bot_admin_rights);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['creator'] = boolval($flags & (1 << 0));
		if($flags & (1 << 3)):
			$result['has_username'] = $reader->readBool();
		else:
			$result['has_username'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['user_admin_rights'] = $reader->readObject();
		else:
			$result['user_admin_rights'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['bot_admin_rights'] = $reader->readObject();
		else:
			$result['bot_admin_rights'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<peerlocated> peers
 * @return Update
 */

final class UpdatePeerLocated extends Instance {
	public function request(array $peers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb4afcfb0);
		$writer->writeVector($peers,'peerlocated');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peers'] = $reader->readVector('peerlocated');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<dcoption> dc_options
 * @return Update
 */

final class UpdateDcOptions extends Instance {
	public function request(array $dc_options) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8e5e9873);
		$writer->writeVector($dc_options,'dcoption');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['dc_options'] = $reader->readVector('dcoption');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockParagraph extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x467a0766);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateLoginToken extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x564fe691);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash string slug string title true creator true default true for_chat document document Vector<themesettings> settings string emoticon int installs_count
 * @return Theme
 */

final class Theme extends Instance {
	public function request(int $id,int $access_hash,string $slug,string $title,null | bool $creator = null,null | bool $default = null,null | bool $for_chat = null,null | object $document = null,null | array $settings = null,null | string $emoticon = null,null | int $installs_count = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa00e67d6);
		$flags = 0;
		$flags |= $creator ? (1 << 0) : 0;
		$flags |= $default ? (1 << 1) : 0;
		$flags |= $for_chat ? (1 << 5) : 0;
		$flags |= is_null($document) ? 0 : (1 << 2);
		$flags |= is_null($settings) ? 0 : (1 << 3);
		$flags |= is_null($emoticon) ? 0 : (1 << 6);
		$flags |= is_null($installs_count) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($slug);
		$writer->writeBytes($title);
		if(is_null($document) === false):
			$writer->writeObject($document);
		endif;
		if(is_null($settings) === false):
			$writer->writeVector($settings,'themesettings');
		endif;
		if(is_null($emoticon) === false):
			$writer->writeBytes($emoticon);
		endif;
		if(is_null($installs_count) === false):
			$writer->writeInt($installs_count);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['creator'] = boolval($flags & (1 << 0));
		$result['default'] = boolval($flags & (1 << 1));
		$result['for_chat'] = boolval($flags & (1 << 5));
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['slug'] = $reader->readBytes();
		$result['title'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['document'] = $reader->readObject();
		else:
			$result['document'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['settings'] = $reader->readVector('themesettings');
		else:
			$result['settings'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['emoticon'] = $reader->readBytes();
		else:
			$result['emoticon'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['installs_count'] = $reader->readInt();
		else:
			$result['installs_count'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url Vector<pageblock> blocks Vector<photo> photos Vector<document> documents true part true rtl true v2 int views
 * @return Page
 */

final class Page extends Instance {
	public function request(string $url,array $blocks,array $photos,array $documents,null | bool $part = null,null | bool $rtl = null,null | bool $v2 = null,null | int $views = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x98657f0d);
		$flags = 0;
		$flags |= $part ? (1 << 0) : 0;
		$flags |= $rtl ? (1 << 1) : 0;
		$flags |= $v2 ? (1 << 2) : 0;
		$flags |= is_null($views) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeBytes($url);
		$writer->writeVector($blocks,'pageblock');
		$writer->writeVector($photos,'photo');
		$writer->writeVector($documents,'document');
		if(is_null($views) === false):
			$writer->writeInt($views);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['part'] = boolval($flags & (1 << 0));
		$result['rtl'] = boolval($flags & (1 << 1));
		$result['v2'] = boolval($flags & (1 << 2));
		$result['url'] = $reader->readBytes();
		$result['blocks'] = $reader->readVector('pageblock');
		$result['photos'] = $reader->readVector('photo');
		$result['documents'] = $reader->readVector('document');
		if($flags & (1 << 3)):
			$result['views'] = $reader->readInt();
		else:
			$result['views'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputUser
 */

final class InputUserEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb98886cf);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int progress
 * @return SendMessageAction
 */

final class SendMessageUploadRoundAction extends Instance {
	public function request(int $progress) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x243e1c66);
		$writer->writeInt($progress);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['progress'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message
 * @return PublicForward
 */

final class PublicForwardMessage extends Instance {
	public function request(object $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1f2bf4a);
		$writer->writeObject($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone string first_name string last_name int date
 * @return SavedContact
 */

final class SavedPhoneContact extends Instance {
	public function request(string $phone,string $first_name,string $last_name,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1142bd56);
		$writer->writeBytes($phone);
		$writer->writeBytes($first_name);
		$writer->writeBytes($last_name);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone'] = $reader->readBytes();
		$result['first_name'] = $reader->readBytes();
		$result['last_name'] = $reader->readBytes();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyForwards extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa4dd4c08);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionToggleNoForwards extends Instance {
	public function request(bool $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcb2ac766);
		$writer->writeBool($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_value'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param pagecaption caption true full_width true allow_scrolling string url string html long poster_photo_id int w int h
 * @return PageBlock
 */

final class PageBlockEmbed extends Instance {
	public function request(object $caption,null | bool $full_width = null,null | bool $allow_scrolling = null,null | string $url = null,null | string $html = null,null | int $poster_photo_id = null,null | int $w = null,null | int $h = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa8718dc5);
		$flags = 0;
		$flags |= $full_width ? (1 << 0) : 0;
		$flags |= $allow_scrolling ? (1 << 3) : 0;
		$flags |= is_null($url) ? 0 : (1 << 1);
		$flags |= is_null($html) ? 0 : (1 << 2);
		$flags |= is_null($poster_photo_id) ? 0 : (1 << 4);
		$flags |= is_null($w) ? 0 : (1 << 5);
		$flags |= is_null($h) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		if(is_null($html) === false):
			$writer->writeBytes($html);
		endif;
		if(is_null($poster_photo_id) === false):
			$writer->writeLong($poster_photo_id);
		endif;
		if(is_null($w) === false):
			$writer->writeInt($w);
		endif;
		if(is_null($h) === false):
			$writer->writeInt($h);
		endif;
		$writer->writeObject($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['full_width'] = boolval($flags & (1 << 0));
		$result['allow_scrolling'] = boolval($flags & (1 << 3));
		if($flags & (1 << 1)):
			$result['url'] = $reader->readBytes();
		else:
			$result['url'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['html'] = $reader->readBytes();
		else:
			$result['html'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['poster_photo_id'] = $reader->readLong();
		else:
			$result['poster_photo_id'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['w'] = $reader->readInt();
		else:
			$result['w'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['h'] = $reader->readInt();
		else:
			$result['h'] = null;
		endif;
		$result['caption'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SendMessageAction
 */

final class SendMessageChooseStickerAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb05ac6b1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextUnderline extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc12622c4);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int ipv4 int port
 * @return IpPort
 */

final class IpPort extends Instance {
	public function request(int $ipv4,int $port) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd433ad73);
		$writer->writeInt($ipv4);
		$writer->writeInt($port);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['ipv4'] = $reader->readInt();
		$result['port'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockHeading3 extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x67e731ad);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputGroupCall
 */

final class InputGroupCall extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd8aa840f);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<pageblock> blocks true checkbox true checked string num int value string type
 * @return PageListOrderedItem
 */

final class PageListOrderedItemBlocks extends Instance {
	public function request(array $blocks,null | bool $checkbox = null,null | bool $checked = null,null | string $num = null,null | int $value = null,null | string $type = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ff2d5f0);
		$flags = 0;
		$flags |= $checkbox ? (1 << 0) : 0;
		$flags |= $checked ? (1 << 1) : 0;
		$flags |= is_null($num) ? 0 : (1 << 2);
		$flags |= is_null($value) ? 0 : (1 << 3);
		$flags |= is_null($type) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		if(is_null($num) === false):
			$writer->writeBytes($num);
		endif;
		$writer->writeVector($blocks,'pageblock');
		if(is_null($value) === false):
			$writer->writeInt($value);
		endif;
		if(is_null($type) === false):
			$writer->writeBytes($type);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['checkbox'] = boolval($flags & (1 << 0));
		$result['checked'] = boolval($flags & (1 << 1));
		if($flags & (1 << 2)):
			$result['num'] = $reader->readBytes();
		else:
			$result['num'] = null;
		endif;
		$result['blocks'] = $reader->readVector('pageblock');
		if($flags & (1 << 3)):
			$result['value'] = $reader->readInt();
		else:
			$result['value'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['type'] = $reader->readBytes();
		else:
			$result['type'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypeRentalAgreement extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8b883488);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long msg_id long answer_msg_id int bytes int status
 * @return MsgDetailedInfo
 */

final class MsgDetailedInfo extends Instance {
	public function request(int $msg_id,int $answer_msg_id,int $bytes,int $status) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x276d3ec6);
		$writer->writeLong($msg_id);
		$writer->writeLong($answer_msg_id);
		$writer->writeInt($bytes);
		$writer->writeInt($status);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_id'] = $reader->readLong();
		$result['answer_msg_id'] = $reader->readLong();
		$result['bytes'] = $reader->readInt();
		$result['status'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool value
 * @return JSONValue
 */

final class JsonBool extends Instance {
	public function request(bool $value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc7345e6a);
		$writer->writeBool($value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['value'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer chatbannedrights default_banned_rights int version
 * @return Update
 */

final class UpdateChatDefaultBannedRights extends Instance {
	public function request(object $peer,object $default_banned_rights,int $version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x54c01850);
		$writer->writeObject($peer);
		$writer->writeObject($default_banned_rights);
		$writer->writeInt($version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['default_banned_rights'] = $reader->readObject();
		$result['version'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long emoji_id
 * @return WebPageAttribute
 */

final class WebPageAttributeAiComposeTone extends Instance {
	public function request(int $emoji_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7781fe18);
		$writer->writeLong($emoji_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['emoji_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long random_id textwithentities text
 * @return SendMessageAction
 */

final class SendMessageTextDraftAction extends Instance {
	public function request(int $random_id,object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x376d975c);
		$writer->writeLong($random_id);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['random_id'] = $reader->readLong();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param pollanswer answer
 * @return MessageAction
 */

final class MessageActionPollDeleteAnswer extends Instance {
	public function request(object $answer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x399674dc);
		$writer->writeObject($answer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['answer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InlineQueryPeerType
 */

final class InlineQueryPeerTypeChat extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd766c50a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int top_msg_id
 * @return InputNotifyPeer
 */

final class InputNotifyForumTopic extends Instance {
	public function request(object $peer,int $top_msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5c467992);
		$writer->writeObject($peer);
		$writer->writeInt($top_msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['top_msg_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int replies int replies_pts true comments Vector<peer> recent_repliers long channel_id int max_id int read_max_id
 * @return MessageReplies
 */

final class MessageReplies extends Instance {
	public function request(int $replies,int $replies_pts,null | bool $comments = null,null | array $recent_repliers = null,null | int $channel_id = null,null | int $max_id = null,null | int $read_max_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x83d60fc2);
		$flags = 0;
		$flags |= $comments ? (1 << 0) : 0;
		$flags |= is_null($recent_repliers) ? 0 : (1 << 1);
		$flags |= is_null($channel_id) ? 0 : (1 << 0);
		$flags |= is_null($max_id) ? 0 : (1 << 2);
		$flags |= is_null($read_max_id) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeInt($replies);
		$writer->writeInt($replies_pts);
		if(is_null($recent_repliers) === false):
			$writer->writeVector($recent_repliers,'peer');
		endif;
		if(is_null($channel_id) === false):
			$writer->writeLong($channel_id);
		endif;
		if(is_null($max_id) === false):
			$writer->writeInt($max_id);
		endif;
		if(is_null($read_max_id) === false):
			$writer->writeInt($read_max_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['comments'] = boolval($flags & (1 << 0));
		$result['replies'] = $reader->readInt();
		$result['replies_pts'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['recent_repliers'] = $reader->readVector('peer');
		else:
			$result['recent_repliers'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['channel_id'] = $reader->readLong();
		else:
			$result['channel_id'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['max_id'] = $reader->readInt();
		else:
			$result['max_id'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['read_max_id'] = $reader->readInt();
		else:
			$result['read_max_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true by_me
 * @return UserStatus
 */

final class UserStatusLastWeek extends Instance {
	public function request(null | bool $by_me = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x541a1d1a);
		$flags = 0;
		$flags |= $by_me ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['by_me'] = boolval($flags & (1 << 0));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Reaction
 */

final class ReactionEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x79f5d419);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextBold extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6724abc4);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string connection_id peer peer Vector<int> messages int qts
 * @return Update
 */

final class UpdateBotDeleteBusinessMessage extends Instance {
	public function request(string $connection_id,object $peer,array $messages,int $qts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa02a982e);
		$writer->writeBytes($connection_id);
		$writer->writeObject($peer);
		$writer->writeVector($messages,'int');
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['connection_id'] = $reader->readBytes();
		$result['peer'] = $reader->readObject();
		$result['messages'] = $reader->readVector('int');
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string source
 * @return RichText
 */

final class TextMath extends Instance {
	public function request(string $source) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9d2eac97);
		$writer->writeBytes($source);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['source'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text string name
 * @return RichText
 */

final class TextAnchor extends Instance {
	public function request(object $text,string $name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x35553762);
		$writer->writeObject($text);
		$writer->writeBytes($name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		$result['name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int permille
 * @return StarGiftAttributeRarity
 */

final class StarGiftAttributeRarity extends Instance {
	public function request(int $permille) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x36437737);
		$writer->writeInt($permille);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['permille'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string type botinlinemessage send_message string title string description string url webdocument thumb webdocument content
 * @return BotInlineResult
 */

final class BotInlineResult extends Instance {
	public function request(string $id,string $type,object $send_message,null | string $title = null,null | string $description = null,null | string $url = null,null | object $thumb = null,null | object $content = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x11965f3a);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 1);
		$flags |= is_null($description) ? 0 : (1 << 2);
		$flags |= is_null($url) ? 0 : (1 << 3);
		$flags |= is_null($thumb) ? 0 : (1 << 4);
		$flags |= is_null($content) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeBytes($id);
		$writer->writeBytes($type);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($description) === false):
			$writer->writeBytes($description);
		endif;
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		if(is_null($thumb) === false):
			$writer->writeObject($thumb);
		endif;
		if(is_null($content) === false):
			$writer->writeObject($content);
		endif;
		$writer->writeObject($send_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readBytes();
		$result['type'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['description'] = $reader->readBytes();
		else:
			$result['description'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['url'] = $reader->readBytes();
		else:
			$result['url'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['thumb'] = $reader->readObject();
		else:
			$result['thumb'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['content'] = $reader->readObject();
		else:
			$result['content'] = null;
		endif;
		$result['send_message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<reactioncount> results true min true can_see_list true reactions_as_tags Vector<messagepeerreaction> recent_reactions Vector<messagereactor> top_reactors
 * @return MessageReactions
 */

final class MessageReactions extends Instance {
	public function request(array $results,null | bool $min = null,null | bool $can_see_list = null,null | bool $reactions_as_tags = null,null | array $recent_reactions = null,null | array $top_reactors = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa339f0b);
		$flags = 0;
		$flags |= $min ? (1 << 0) : 0;
		$flags |= $can_see_list ? (1 << 2) : 0;
		$flags |= $reactions_as_tags ? (1 << 3) : 0;
		$flags |= is_null($recent_reactions) ? 0 : (1 << 1);
		$flags |= is_null($top_reactors) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeVector($results,'reactioncount');
		if(is_null($recent_reactions) === false):
			$writer->writeVector($recent_reactions,'messagepeerreaction');
		endif;
		if(is_null($top_reactors) === false):
			$writer->writeVector($top_reactors,'messagereactor');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['min'] = boolval($flags & (1 << 0));
		$result['can_see_list'] = boolval($flags & (1 << 2));
		$result['reactions_as_tags'] = boolval($flags & (1 << 3));
		$result['results'] = $reader->readVector('reactioncount');
		if($flags & (1 << 1)):
			$result['recent_reactions'] = $reader->readVector('messagepeerreaction');
		else:
			$result['recent_reactions'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['top_reactors'] = $reader->readVector('messagereactor');
		else:
			$result['top_reactors'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputChannel
 */

final class InputChannelEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xee8c1e86);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param starsamount current_balance starsamount available_balance starsamount overall_revenue true withdrawal_enabled int next_withdrawal_at
 * @return StarsRevenueStatus
 */

final class StarsRevenueStatus extends Instance {
	public function request(object $current_balance,object $available_balance,object $overall_revenue,null | bool $withdrawal_enabled = null,null | int $next_withdrawal_at = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfebe5491);
		$flags = 0;
		$flags |= $withdrawal_enabled ? (1 << 0) : 0;
		$flags |= is_null($next_withdrawal_at) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($current_balance);
		$writer->writeObject($available_balance);
		$writer->writeObject($overall_revenue);
		if(is_null($next_withdrawal_at) === false):
			$writer->writeInt($next_withdrawal_at);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['withdrawal_enabled'] = boolval($flags & (1 << 0));
		$result['current_balance'] = $reader->readObject();
		$result['available_balance'] = $reader->readObject();
		$result['overall_revenue'] = $reader->readObject();
		if($flags & (1 << 1)):
			$result['next_withdrawal_at'] = $reader->readInt();
		else:
			$result['next_withdrawal_at'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param dialogpeer peer true pinned int folder_id
 * @return Update
 */

final class UpdateDialogPinned extends Instance {
	public function request(object $peer,null | bool $pinned = null,null | int $folder_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6e6fe51c);
		$flags = 0;
		$flags |= $pinned ? (1 << 0) : 0;
		$flags |= is_null($folder_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($folder_id) === false):
			$writer->writeInt($folder_id);
		endif;
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pinned'] = boolval($flags & (1 << 0));
		if($flags & (1 << 1)):
			$result['folder_id'] = $reader->readInt();
		else:
			$result['folder_id'] = null;
		endif;
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<keyboardbuttonrow> rows true resize true single_use true selective true persistent string placeholder
 * @return ReplyMarkup
 */

final class ReplyKeyboardMarkup extends Instance {
	public function request(array $rows,null | bool $resize = null,null | bool $single_use = null,null | bool $selective = null,null | bool $persistent = null,null | string $placeholder = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x85dd99d1);
		$flags = 0;
		$flags |= $resize ? (1 << 0) : 0;
		$flags |= $single_use ? (1 << 1) : 0;
		$flags |= $selective ? (1 << 2) : 0;
		$flags |= $persistent ? (1 << 4) : 0;
		$flags |= is_null($placeholder) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeVector($rows,'keyboardbuttonrow');
		if(is_null($placeholder) === false):
			$writer->writeBytes($placeholder);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['resize'] = boolval($flags & (1 << 0));
		$result['single_use'] = boolval($flags & (1 << 1));
		$result['selective'] = boolval($flags & (1 << 2));
		$result['persistent'] = boolval($flags & (1 << 4));
		$result['rows'] = $reader->readVector('keyboardbuttonrow');
		if($flags & (1 << 3)):
			$result['placeholder'] = $reader->readBytes();
		else:
			$result['placeholder'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_code int from_version int version Vector<langpackstring> strings
 * @return LangPackDifference
 */

final class LangPackDifference extends Instance {
	public function request(string $lang_code,int $from_version,int $version,array $strings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf385c1f6);
		$writer->writeBytes($lang_code);
		$writer->writeInt($from_version);
		$writer->writeInt($version);
		$writer->writeVector($strings,'langpackstring');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['lang_code'] = $reader->readBytes();
		$result['from_version'] = $reader->readInt();
		$result['version'] = $reader->readInt();
		$result['strings'] = $reader->readVector('langpackstring');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url true fullsize true fullscreen true same_origin long query_id
 * @return WebViewResult
 */

final class WebViewResultUrl extends Instance {
	public function request(string $url,null | bool $fullsize = null,null | bool $fullscreen = null,null | bool $same_origin = null,null | int $query_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4d22ff98);
		$flags = 0;
		$flags |= $fullsize ? (1 << 1) : 0;
		$flags |= $fullscreen ? (1 << 2) : 0;
		$flags |= $same_origin ? (1 << 3) : 0;
		$flags |= is_null($query_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($query_id) === false):
			$writer->writeLong($query_id);
		endif;
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['fullsize'] = boolval($flags & (1 << 1));
		$result['fullscreen'] = boolval($flags & (1 << 2));
		$result['same_origin'] = boolval($flags & (1 << 3));
		if($flags & (1 << 0)):
			$result['query_id'] = $reader->readLong();
		else:
			$result['query_id'] = null;
		endif;
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPhoto
 */

final class InputPhotoEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1cd7bf0d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool join_muted
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionToggleGroupCallSetting extends Instance {
	public function request(bool $join_muted) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x56d6a247);
		$writer->writeBool($join_muted);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['join_muted'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash long size int dc_id int key_fingerprint
 * @return EncryptedFile
 */

final class EncryptedFile extends Instance {
	public function request(int $id,int $access_hash,int $size,int $dc_id,int $key_fingerprint) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa8008cd8);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeLong($size);
		$writer->writeInt($dc_id);
		$writer->writeInt($key_fingerprint);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['size'] = $reader->readLong();
		$result['dc_id'] = $reader->readInt();
		$result['key_fingerprint'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<update> updates Vector<user> users Vector<chat> chats int date int seq_start int seq
 * @return Updates
 */

final class UpdatesCombined extends Instance {
	public function request(array $updates,array $users,array $chats,int $date,int $seq_start,int $seq) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x725b04c3);
		$writer->writeVector($updates,'update');
		$writer->writeVector($users,'user');
		$writer->writeVector($chats,'chat');
		$writer->writeInt($date);
		$writer->writeInt($seq_start);
		$writer->writeInt($seq);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['updates'] = $reader->readVector('update');
		$result['users'] = $reader->readVector('user');
		$result['chats'] = $reader->readVector('chat');
		$result['date'] = $reader->readInt();
		$result['seq_start'] = $reader->readInt();
		$result['seq'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyRule
 */

final class PrivacyValueAllowPremium extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xece9814b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id long promoted_by int date chatadminrights admin_rights true can_edit true self long inviter_id string rank
 * @return ChannelParticipant
 */

final class ChannelParticipantAdmin extends Instance {
	public function request(int $user_id,int $promoted_by,int $date,object $admin_rights,null | bool $can_edit = null,null | bool $self = null,null | int $inviter_id = null,null | string $rank = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x34c3bb53);
		$flags = 0;
		$flags |= $can_edit ? (1 << 0) : 0;
		$flags |= $self ? (1 << 1) : 0;
		$flags |= is_null($inviter_id) ? 0 : (1 << 1);
		$flags |= is_null($rank) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		if(is_null($inviter_id) === false):
			$writer->writeLong($inviter_id);
		endif;
		$writer->writeLong($promoted_by);
		$writer->writeInt($date);
		$writer->writeObject($admin_rights);
		if(is_null($rank) === false):
			$writer->writeBytes($rank);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['can_edit'] = boolval($flags & (1 << 0));
		$result['self'] = boolval($flags & (1 << 1));
		$result['user_id'] = $reader->readLong();
		if($flags & (1 << 1)):
			$result['inviter_id'] = $reader->readLong();
		else:
			$result['inviter_id'] = null;
		endif;
		$result['promoted_by'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['admin_rights'] = $reader->readObject();
		if($flags & (1 << 2)):
			$result['rank'] = $reader->readBytes();
		else:
			$result['rank'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param reaction reaction int count int chosen_order
 * @return ReactionCount
 */

final class ReactionCount extends Instance {
	public function request(object $reaction,int $count,null | int $chosen_order = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa3d1cb80);
		$flags = 0;
		$flags |= is_null($chosen_order) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($chosen_order) === false):
			$writer->writeInt($chosen_order);
		endif;
		$writer->writeObject($reaction);
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['chosen_order'] = $reader->readInt();
		else:
			$result['chosen_order'] = null;
		endif;
		$result['reaction'] = $reader->readObject();
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyAddedByPhone extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x42ffd42b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id long user_id string message int pts int pts_count int date true out true mentioned true media_unread true silent messagefwdheader fwd_from long via_bot_id messagereplyheader reply_to Vector<messageentity> entities int ttl_period
 * @return Updates
 */

final class UpdateShortMessage extends Instance {
	public function request(int $id,int $user_id,string $message,int $pts,int $pts_count,int $date,null | bool $out = null,null | bool $mentioned = null,null | bool $media_unread = null,null | bool $silent = null,null | object $fwd_from = null,null | int $via_bot_id = null,null | object $reply_to = null,null | array $entities = null,null | int $ttl_period = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x313bc7f8);
		$flags = 0;
		$flags |= $out ? (1 << 1) : 0;
		$flags |= $mentioned ? (1 << 4) : 0;
		$flags |= $media_unread ? (1 << 5) : 0;
		$flags |= $silent ? (1 << 13) : 0;
		$flags |= is_null($fwd_from) ? 0 : (1 << 2);
		$flags |= is_null($via_bot_id) ? 0 : (1 << 11);
		$flags |= is_null($reply_to) ? 0 : (1 << 3);
		$flags |= is_null($entities) ? 0 : (1 << 7);
		$flags |= is_null($ttl_period) ? 0 : (1 << 25);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeLong($user_id);
		$writer->writeBytes($message);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		$writer->writeInt($date);
		if(is_null($fwd_from) === false):
			$writer->writeObject($fwd_from);
		endif;
		if(is_null($via_bot_id) === false):
			$writer->writeLong($via_bot_id);
		endif;
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['out'] = boolval($flags & (1 << 1));
		$result['mentioned'] = boolval($flags & (1 << 4));
		$result['media_unread'] = boolval($flags & (1 << 5));
		$result['silent'] = boolval($flags & (1 << 13));
		$result['id'] = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		$result['message'] = $reader->readBytes();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['fwd_from'] = $reader->readObject();
		else:
			$result['fwd_from'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['via_bot_id'] = $reader->readLong();
		else:
			$result['via_bot_id'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['reply_to'] = $reader->readObject();
		else:
			$result['reply_to'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 25)):
			$result['ttl_period'] = $reader->readInt();
		else:
			$result['ttl_period'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockHeading2 extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x96b2aec);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<pageblock> blocks true checkbox true checked
 * @return PageListItem
 */

final class PageListItemBlocks extends Instance {
	public function request(array $blocks,null | bool $checkbox = null,null | bool $checked = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x63ca67aa);
		$flags = 0;
		$flags |= $checkbox ? (1 << 0) : 0;
		$flags |= $checked ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($blocks,'pageblock');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['checkbox'] = boolval($flags & (1 << 0));
		$result['checked'] = boolval($flags & (1 << 1));
		$result['blocks'] = $reader->readVector('pageblock');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id long access_hash
 * @return InputPeer
 */

final class InputPeerChannel extends Instance {
	public function request(int $channel_id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x27bcbbfc);
		$writer->writeLong($channel_id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int folder_id
 * @return FolderPeer
 */

final class FolderPeer extends Instance {
	public function request(object $peer,int $folder_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe9baa668);
		$writer->writeObject($peer);
		$writer->writeInt($folder_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['folder_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text long user_id keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButtonUserProfile extends Instance {
	public function request(string $text,int $user_id,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc0fd5d09);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		$writer->writeLong($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		$result['user_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string pq string p string q int128 nonce int128 server_nonce int256 new_nonce int expires_in
 * @return P_Q_inner_data
 */

final class PQInnerDataTemp extends Instance {
	public function request(string $pq,string $p,string $q,int | string $nonce,int | string $server_nonce,int | string $new_nonce,int $expires_in) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3c6a84d4);
		$writer->writeBytes($pq);
		$writer->writeBytes($p);
		$writer->writeBytes($q);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeLargeInt($new_nonce,256);
		$writer->writeInt($expires_in);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pq'] = $reader->readBytes();
		$result['p'] = $reader->readBytes();
		$result['q'] = $reader->readBytes();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['new_nonce'] = $reader->readLargeInt(256);
		$result['expires_in'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id string url string display_url int hash true has_large_media true video_cover_photo string type string site_name string title string description photo photo string embed_url string embed_type int embed_width int embed_height int duration string author document document page cached_page Vector<webpageattribute> attributes
 * @return WebPage
 */

final class WebPage extends Instance {
	public function request(int $id,string $url,string $display_url,int $hash,null | bool $has_large_media = null,null | bool $video_cover_photo = null,null | string $type = null,null | string $site_name = null,null | string $title = null,null | string $description = null,null | object $photo = null,null | string $embed_url = null,null | string $embed_type = null,null | int $embed_width = null,null | int $embed_height = null,null | int $duration = null,null | string $author = null,null | object $document = null,null | object $cached_page = null,null | array $attributes = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe89c45b2);
		$flags = 0;
		$flags |= $has_large_media ? (1 << 13) : 0;
		$flags |= $video_cover_photo ? (1 << 14) : 0;
		$flags |= is_null($type) ? 0 : (1 << 0);
		$flags |= is_null($site_name) ? 0 : (1 << 1);
		$flags |= is_null($title) ? 0 : (1 << 2);
		$flags |= is_null($description) ? 0 : (1 << 3);
		$flags |= is_null($photo) ? 0 : (1 << 4);
		$flags |= is_null($embed_url) ? 0 : (1 << 5);
		$flags |= is_null($embed_type) ? 0 : (1 << 5);
		$flags |= is_null($embed_width) ? 0 : (1 << 6);
		$flags |= is_null($embed_height) ? 0 : (1 << 6);
		$flags |= is_null($duration) ? 0 : (1 << 7);
		$flags |= is_null($author) ? 0 : (1 << 8);
		$flags |= is_null($document) ? 0 : (1 << 9);
		$flags |= is_null($cached_page) ? 0 : (1 << 10);
		$flags |= is_null($attributes) ? 0 : (1 << 12);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeBytes($url);
		$writer->writeBytes($display_url);
		$writer->writeInt($hash);
		if(is_null($type) === false):
			$writer->writeBytes($type);
		endif;
		if(is_null($site_name) === false):
			$writer->writeBytes($site_name);
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($description) === false):
			$writer->writeBytes($description);
		endif;
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		if(is_null($embed_url) === false):
			$writer->writeBytes($embed_url);
		endif;
		if(is_null($embed_type) === false):
			$writer->writeBytes($embed_type);
		endif;
		if(is_null($embed_width) === false):
			$writer->writeInt($embed_width);
		endif;
		if(is_null($embed_height) === false):
			$writer->writeInt($embed_height);
		endif;
		if(is_null($duration) === false):
			$writer->writeInt($duration);
		endif;
		if(is_null($author) === false):
			$writer->writeBytes($author);
		endif;
		if(is_null($document) === false):
			$writer->writeObject($document);
		endif;
		if(is_null($cached_page) === false):
			$writer->writeObject($cached_page);
		endif;
		if(is_null($attributes) === false):
			$writer->writeVector($attributes,'webpageattribute');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['has_large_media'] = boolval($flags & (1 << 13));
		$result['video_cover_photo'] = boolval($flags & (1 << 14));
		$result['id'] = $reader->readLong();
		$result['url'] = $reader->readBytes();
		$result['display_url'] = $reader->readBytes();
		$result['hash'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['type'] = $reader->readBytes();
		else:
			$result['type'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['site_name'] = $reader->readBytes();
		else:
			$result['site_name'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['description'] = $reader->readBytes();
		else:
			$result['description'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['embed_url'] = $reader->readBytes();
		else:
			$result['embed_url'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['embed_type'] = $reader->readBytes();
		else:
			$result['embed_type'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['embed_width'] = $reader->readInt();
		else:
			$result['embed_width'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['embed_height'] = $reader->readInt();
		else:
			$result['embed_height'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['duration'] = $reader->readInt();
		else:
			$result['duration'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['author'] = $reader->readBytes();
		else:
			$result['author'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['document'] = $reader->readObject();
		else:
			$result['document'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['cached_page'] = $reader->readObject();
		else:
			$result['cached_page'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['attributes'] = $reader->readVector('webpageattribute');
		else:
			$result['attributes'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id long bot_id int qts
 * @return Update
 */

final class UpdateManagedBot extends Instance {
	public function request(int $user_id,int $bot_id,int $qts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4880ed9a);
		$writer->writeLong($user_id);
		$writer->writeLong($bot_id);
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['bot_id'] = $reader->readLong();
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockHeading4 extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb532772b);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars int yearly_boosts string currency long amount Vector<starsgiveawaywinnersoption> winners true extended true default string store_product
 * @return StarsGiveawayOption
 */

final class StarsGiveawayOption extends Instance {
	public function request(int $stars,int $yearly_boosts,string $currency,int $amount,array $winners,null | bool $extended = null,null | bool $default = null,null | string $store_product = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x94ce852a);
		$flags = 0;
		$flags |= $extended ? (1 << 0) : 0;
		$flags |= $default ? (1 << 1) : 0;
		$flags |= is_null($store_product) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($stars);
		$writer->writeInt($yearly_boosts);
		if(is_null($store_product) === false):
			$writer->writeBytes($store_product);
		endif;
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		$writer->writeVector($winners,'starsgiveawaywinnersoption');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['extended'] = boolval($flags & (1 << 0));
		$result['default'] = boolval($flags & (1 << 1));
		$result['stars'] = $reader->readLong();
		$result['yearly_boosts'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['store_product'] = $reader->readBytes();
		else:
			$result['store_product'] = null;
		endif;
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		$result['winners'] = $reader->readVector('starsgiveawaywinnersoption');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bot_id int commission_permille int duration_months int end_date starsamount daily_revenue_per_user
 * @return StarRefProgram
 */

final class StarRefProgram extends Instance {
	public function request(int $bot_id,int $commission_permille,null | int $duration_months = null,null | int $end_date = null,null | object $daily_revenue_per_user = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdd0c66f2);
		$flags = 0;
		$flags |= is_null($duration_months) ? 0 : (1 << 0);
		$flags |= is_null($end_date) ? 0 : (1 << 1);
		$flags |= is_null($daily_revenue_per_user) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($bot_id);
		$writer->writeInt($commission_permille);
		if(is_null($duration_months) === false):
			$writer->writeInt($duration_months);
		endif;
		if(is_null($end_date) === false):
			$writer->writeInt($end_date);
		endif;
		if(is_null($daily_revenue_per_user) === false):
			$writer->writeObject($daily_revenue_per_user);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['bot_id'] = $reader->readLong();
		$result['commission_permille'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['duration_months'] = $reader->readInt();
		else:
			$result['duration_months'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['end_date'] = $reader->readInt();
		else:
			$result['end_date'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['daily_revenue_per_user'] = $reader->readObject();
		else:
			$result['daily_revenue_per_user'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateConfig extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa229dd06);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string first_name string last_name string vcard replymarkup reply_markup
 * @return InputBotInlineMessage
 */

final class InputBotInlineMessageMediaContact extends Instance {
	public function request(string $phone_number,string $first_name,string $last_name,string $vcard,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa6edbffd);
		$flags = 0;
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($first_name);
		$writer->writeBytes($last_name);
		$writer->writeBytes($vcard);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['phone_number'] = $reader->readBytes();
		$result['first_name'] = $reader->readBytes();
		$result['last_name'] = $reader->readBytes();
		$result['vcard'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputStickerSet
 */

final class InputStickerSetEmojiDefaultTopicIcons extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x44c1f8e9);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyAbout extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa486b761);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return TopPeerCategory
 */

final class TopPeerCategoryForwardUsers extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa8406ca9);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param channelparticipant prev_participant channelparticipant new_participant
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantToggleAdmin extends Instance {
	public function request(object $prev_participant,object $new_participant) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd5676710);
		$writer->writeObject($prev_participant);
		$writer->writeObject($new_participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_participant'] = $reader->readObject();
		$result['new_participant'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string connection_id message message int qts message reply_to_message
 * @return Update
 */

final class UpdateBotNewBusinessMessage extends Instance {
	public function request(string $connection_id,object $message,int $qts,null | object $reply_to_message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9ddb347c);
		$flags = 0;
		$flags |= is_null($reply_to_message) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($connection_id);
		$writer->writeObject($message);
		if(is_null($reply_to_message) === false):
			$writer->writeObject($reply_to_message);
		endif;
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['connection_id'] = $reader->readBytes();
		$result['message'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['reply_to_message'] = $reader->readObject();
		else:
			$result['reply_to_message'] = null;
		endif;
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockThinking extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3c29a3e2);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PaidReactionPrivacy
 */

final class PaidReactionPrivacyAnonymous extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1f0c1ad9);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id Vector<int> messages int pts int pts_count true pinned
 * @return Update
 */

final class UpdatePinnedChannelMessages extends Instance {
	public function request(int $channel_id,array $messages,int $pts,int $pts_count,null | bool $pinned = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5bb98608);
		$flags = 0;
		$flags |= $pinned ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($channel_id);
		$writer->writeVector($messages,'int');
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pinned'] = boolval($flags & (1 << 0));
		$result['channel_id'] = $reader->readLong();
		$result['messages'] = $reader->readVector('int');
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id chatparticipant self_participant
 * @return ChatParticipants
 */

final class ChatParticipantsForbidden extends Instance {
	public function request(int $chat_id,null | object $self_participant = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8763d3e1);
		$flags = 0;
		$flags |= is_null($self_participant) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($chat_id);
		if(is_null($self_participant) === false):
			$writer->writeObject($self_participant);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['chat_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['self_participant'] = $reader->readObject();
		else:
			$result['self_participant'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title photo photo int participants_count int color true channel true broadcast true public true megagroup true request_needed true verified true scam true fake true can_refulfill_subscription string about Vector<user> participants starssubscriptionpricing subscription_pricing long subscription_form_id botverification bot_verification
 * @return ChatInvite
 */

final class ChatInvite extends Instance {
	public function request(string $title,object $photo,int $participants_count,int $color,null | bool $channel = null,null | bool $broadcast = null,null | bool $public = null,null | bool $megagroup = null,null | bool $request_needed = null,null | bool $verified = null,null | bool $scam = null,null | bool $fake = null,null | bool $can_refulfill_subscription = null,null | string $about = null,null | array $participants = null,null | object $subscription_pricing = null,null | int $subscription_form_id = null,null | object $bot_verification = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5c9d3702);
		$flags = 0;
		$flags |= $channel ? (1 << 0) : 0;
		$flags |= $broadcast ? (1 << 1) : 0;
		$flags |= $public ? (1 << 2) : 0;
		$flags |= $megagroup ? (1 << 3) : 0;
		$flags |= $request_needed ? (1 << 6) : 0;
		$flags |= $verified ? (1 << 7) : 0;
		$flags |= $scam ? (1 << 8) : 0;
		$flags |= $fake ? (1 << 9) : 0;
		$flags |= $can_refulfill_subscription ? (1 << 11) : 0;
		$flags |= is_null($about) ? 0 : (1 << 5);
		$flags |= is_null($participants) ? 0 : (1 << 4);
		$flags |= is_null($subscription_pricing) ? 0 : (1 << 10);
		$flags |= is_null($subscription_form_id) ? 0 : (1 << 12);
		$flags |= is_null($bot_verification) ? 0 : (1 << 13);
		$writer->writeInt($flags);
		$writer->writeBytes($title);
		if(is_null($about) === false):
			$writer->writeBytes($about);
		endif;
		$writer->writeObject($photo);
		$writer->writeInt($participants_count);
		if(is_null($participants) === false):
			$writer->writeVector($participants,'user');
		endif;
		$writer->writeInt($color);
		if(is_null($subscription_pricing) === false):
			$writer->writeObject($subscription_pricing);
		endif;
		if(is_null($subscription_form_id) === false):
			$writer->writeLong($subscription_form_id);
		endif;
		if(is_null($bot_verification) === false):
			$writer->writeObject($bot_verification);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['channel'] = boolval($flags & (1 << 0));
		$result['broadcast'] = boolval($flags & (1 << 1));
		$result['public'] = boolval($flags & (1 << 2));
		$result['megagroup'] = boolval($flags & (1 << 3));
		$result['request_needed'] = boolval($flags & (1 << 6));
		$result['verified'] = boolval($flags & (1 << 7));
		$result['scam'] = boolval($flags & (1 << 8));
		$result['fake'] = boolval($flags & (1 << 9));
		$result['can_refulfill_subscription'] = boolval($flags & (1 << 11));
		$result['title'] = $reader->readBytes();
		if($flags & (1 << 5)):
			$result['about'] = $reader->readBytes();
		else:
			$result['about'] = null;
		endif;
		$result['photo'] = $reader->readObject();
		$result['participants_count'] = $reader->readInt();
		if($flags & (1 << 4)):
			$result['participants'] = $reader->readVector('user');
		else:
			$result['participants'] = null;
		endif;
		$result['color'] = $reader->readInt();
		if($flags & (1 << 10)):
			$result['subscription_pricing'] = $reader->readObject();
		else:
			$result['subscription_pricing'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['subscription_form_id'] = $reader->readLong();
		else:
			$result['subscription_form_id'] = null;
		endif;
		if($flags & (1 << 13)):
			$result['bot_verification'] = $reader->readObject();
		else:
			$result['bot_verification'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return NotifyPeer
 */

final class NotifyUsers extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb4c83b4c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stargift gift true name_hidden true saved true converted true upgraded true refunded true can_upgrade true prepaid_upgrade true upgrade_separate true auction_acquired textwithentities message long convert_stars int upgrade_msg_id long upgrade_stars peer from_id peer peer long saved_id string prepaid_upgrade_hash int gift_msg_id peer to_id int gift_num
 * @return MessageAction
 */

final class MessageActionStarGift extends Instance {
	public function request(object $gift,null | bool $name_hidden = null,null | bool $saved = null,null | bool $converted = null,null | bool $upgraded = null,null | bool $refunded = null,null | bool $can_upgrade = null,null | bool $prepaid_upgrade = null,null | bool $upgrade_separate = null,null | bool $auction_acquired = null,null | object $message = null,null | int $convert_stars = null,null | int $upgrade_msg_id = null,null | int $upgrade_stars = null,null | object $from_id = null,null | object $peer = null,null | int $saved_id = null,null | string $prepaid_upgrade_hash = null,null | int $gift_msg_id = null,null | object $to_id = null,null | int $gift_num = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xea2c31d3);
		$flags = 0;
		$flags |= $name_hidden ? (1 << 0) : 0;
		$flags |= $saved ? (1 << 2) : 0;
		$flags |= $converted ? (1 << 3) : 0;
		$flags |= $upgraded ? (1 << 5) : 0;
		$flags |= $refunded ? (1 << 9) : 0;
		$flags |= $can_upgrade ? (1 << 10) : 0;
		$flags |= $prepaid_upgrade ? (1 << 13) : 0;
		$flags |= $upgrade_separate ? (1 << 16) : 0;
		$flags |= $auction_acquired ? (1 << 17) : 0;
		$flags |= is_null($message) ? 0 : (1 << 1);
		$flags |= is_null($convert_stars) ? 0 : (1 << 4);
		$flags |= is_null($upgrade_msg_id) ? 0 : (1 << 5);
		$flags |= is_null($upgrade_stars) ? 0 : (1 << 8);
		$flags |= is_null($from_id) ? 0 : (1 << 11);
		$flags |= is_null($peer) ? 0 : (1 << 12);
		$flags |= is_null($saved_id) ? 0 : (1 << 12);
		$flags |= is_null($prepaid_upgrade_hash) ? 0 : (1 << 14);
		$flags |= is_null($gift_msg_id) ? 0 : (1 << 15);
		$flags |= is_null($to_id) ? 0 : (1 << 18);
		$flags |= is_null($gift_num) ? 0 : (1 << 19);
		$writer->writeInt($flags);
		$writer->writeObject($gift);
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		if(is_null($convert_stars) === false):
			$writer->writeLong($convert_stars);
		endif;
		if(is_null($upgrade_msg_id) === false):
			$writer->writeInt($upgrade_msg_id);
		endif;
		if(is_null($upgrade_stars) === false):
			$writer->writeLong($upgrade_stars);
		endif;
		if(is_null($from_id) === false):
			$writer->writeObject($from_id);
		endif;
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		if(is_null($saved_id) === false):
			$writer->writeLong($saved_id);
		endif;
		if(is_null($prepaid_upgrade_hash) === false):
			$writer->writeBytes($prepaid_upgrade_hash);
		endif;
		if(is_null($gift_msg_id) === false):
			$writer->writeInt($gift_msg_id);
		endif;
		if(is_null($to_id) === false):
			$writer->writeObject($to_id);
		endif;
		if(is_null($gift_num) === false):
			$writer->writeInt($gift_num);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['name_hidden'] = boolval($flags & (1 << 0));
		$result['saved'] = boolval($flags & (1 << 2));
		$result['converted'] = boolval($flags & (1 << 3));
		$result['upgraded'] = boolval($flags & (1 << 5));
		$result['refunded'] = boolval($flags & (1 << 9));
		$result['can_upgrade'] = boolval($flags & (1 << 10));
		$result['prepaid_upgrade'] = boolval($flags & (1 << 13));
		$result['upgrade_separate'] = boolval($flags & (1 << 16));
		$result['auction_acquired'] = boolval($flags & (1 << 17));
		$result['gift'] = $reader->readObject();
		if($flags & (1 << 1)):
			$result['message'] = $reader->readObject();
		else:
			$result['message'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['convert_stars'] = $reader->readLong();
		else:
			$result['convert_stars'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['upgrade_msg_id'] = $reader->readInt();
		else:
			$result['upgrade_msg_id'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['upgrade_stars'] = $reader->readLong();
		else:
			$result['upgrade_stars'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['from_id'] = $reader->readObject();
		else:
			$result['from_id'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['peer'] = $reader->readObject();
		else:
			$result['peer'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['saved_id'] = $reader->readLong();
		else:
			$result['saved_id'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['prepaid_upgrade_hash'] = $reader->readBytes();
		else:
			$result['prepaid_upgrade_hash'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['gift_msg_id'] = $reader->readInt();
		else:
			$result['gift_msg_id'] = null;
		endif;
		if($flags & (1 << 18)):
			$result['to_id'] = $reader->readObject();
		else:
			$result['to_id'] = null;
		endif;
		if($flags & (1 << 19)):
			$result['gift_num'] = $reader->readInt();
		else:
			$result['gift_num'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextMarked extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x34b8621);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int expires int distance
 * @return PeerLocated
 */

final class PeerLocated extends Instance {
	public function request(object $peer,int $expires,int $distance) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xca461b5d);
		$writer->writeObject($peer);
		$writer->writeInt($expires);
		$writer->writeInt($distance);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['expires'] = $reader->readInt();
		$result['distance'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param photo photo
 * @return MessageAction
 */

final class MessageActionChatEditPhoto extends Instance {
	public function request(object $photo) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7fcb13a8);
		$writer->writeObject($photo);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['photo'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReportReason
 */

final class InputReportReasonViolence extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1e22c78d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id int pts int pts_count int date true out messagemedia media Vector<messageentity> entities int ttl_period
 * @return Updates
 */

final class UpdateShortSentMessage extends Instance {
	public function request(int $id,int $pts,int $pts_count,int $date,null | bool $out = null,null | object $media = null,null | array $entities = null,null | int $ttl_period = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9015e101);
		$flags = 0;
		$flags |= $out ? (1 << 1) : 0;
		$flags |= is_null($media) ? 0 : (1 << 9);
		$flags |= is_null($entities) ? 0 : (1 << 7);
		$flags |= is_null($ttl_period) ? 0 : (1 << 25);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		$writer->writeInt($date);
		if(is_null($media) === false):
			$writer->writeObject($media);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['out'] = boolval($flags & (1 << 1));
		$result['id'] = $reader->readInt();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 9)):
			$result['media'] = $reader->readObject();
		else:
			$result['media'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 25)):
			$result['ttl_period'] = $reader->readInt();
		else:
			$result['ttl_period'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return EmojiURL
 */

final class EmojiURL extends Instance {
	public function request(string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa575739d);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<keyboardbuttonrow> rows
 * @return ReplyMarkup
 */

final class ReplyInlineMarkup extends Instance {
	public function request(array $rows) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x48a30254);
		$writer->writeVector($rows,'keyboardbuttonrow');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['rows'] = $reader->readVector('keyboardbuttonrow');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param toppeercategory category int count Vector<toppeer> peers
 * @return TopPeerCategoryPeers
 */

final class TopPeerCategoryPeers extends Instance {
	public function request(object $category,int $count,array $peers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfb834291);
		$writer->writeObject($category);
		$writer->writeInt($count);
		$writer->writeVector($peers,'toppeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['category'] = $reader->readObject();
		$result['count'] = $reader->readInt();
		$result['peers'] = $reader->readVector('toppeer');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int top_message int read_inbox_max_id int read_outbox_max_id int unread_count int unread_reactions_count true unread_mark true nopaid_messages_exception draftmessage draft
 * @return SavedDialog
 */

final class MonoForumDialog extends Instance {
	public function request(object $peer,int $top_message,int $read_inbox_max_id,int $read_outbox_max_id,int $unread_count,int $unread_reactions_count,null | bool $unread_mark = null,null | bool $nopaid_messages_exception = null,null | object $draft = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x64407ea7);
		$flags = 0;
		$flags |= $unread_mark ? (1 << 3) : 0;
		$flags |= $nopaid_messages_exception ? (1 << 4) : 0;
		$flags |= is_null($draft) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($top_message);
		$writer->writeInt($read_inbox_max_id);
		$writer->writeInt($read_outbox_max_id);
		$writer->writeInt($unread_count);
		$writer->writeInt($unread_reactions_count);
		if(is_null($draft) === false):
			$writer->writeObject($draft);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['unread_mark'] = boolval($flags & (1 << 3));
		$result['nopaid_messages_exception'] = boolval($flags & (1 << 4));
		$result['peer'] = $reader->readObject();
		$result['top_message'] = $reader->readInt();
		$result['read_inbox_max_id'] = $reader->readInt();
		$result['read_outbox_max_id'] = $reader->readInt();
		$result['unread_count'] = $reader->readInt();
		$result['unread_reactions_count'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['draft'] = $reader->readObject();
		else:
			$result['draft'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call int schedule_date
 * @return MessageAction
 */

final class MessageActionGroupCallScheduled extends Instance {
	public function request(object $call,int $schedule_date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb3a07661);
		$writer->writeObject($call);
		$writer->writeInt($schedule_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['call'] = $reader->readObject();
		$result['schedule_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date long upgrade_stars
 * @return StarGiftUpgradePrice
 */

final class StarGiftUpgradePrice extends Instance {
	public function request(int $date,int $upgrade_stars) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x99ea331d);
		$writer->writeInt($date);
		$writer->writeLong($upgrade_stars);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['date'] = $reader->readInt();
		$result['upgrade_stars'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bot_id true confirmed int date string device string location
 * @return Update
 */

final class UpdateNewBotConnection extends Instance {
	public function request(int $bot_id,null | bool $confirmed = null,null | int $date = null,null | string $device = null,null | string $location = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb22083a6);
		$flags = 0;
		$flags |= $confirmed ? (1 << 0) : 0;
		$flags |= is_null($date) ? 0 : (1 << 1);
		$flags |= is_null($device) ? 0 : (1 << 1);
		$flags |= is_null($location) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($bot_id);
		if(is_null($date) === false):
			$writer->writeInt($date);
		endif;
		if(is_null($device) === false):
			$writer->writeBytes($device);
		endif;
		if(is_null($location) === false):
			$writer->writeBytes($location);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['confirmed'] = boolval($flags & (1 << 0));
		$result['bot_id'] = $reader->readLong();
		if($flags & (1 << 1)):
			$result['date'] = $reader->readInt();
		else:
			$result['date'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['device'] = $reader->readBytes();
		else:
			$result['device'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['location'] = $reader->readBytes();
		else:
			$result['location'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id int date int expire_date messagemedia media true pinned true public true close_friends true min true noforwards true edited true contacts true selected_contacts true out peer from_id storyfwdheader fwd_from string caption Vector<messageentity> entities Vector<mediaarea> media_areas Vector<privacyrule> privacy storyviews views reaction sent_reaction Vector<int> albums document music
 * @return StoryItem
 */

final class StoryItem extends Instance {
	public function request(int $id,int $date,int $expire_date,object $media,null | bool $pinned = null,null | bool $public = null,null | bool $close_friends = null,null | bool $min = null,null | bool $noforwards = null,null | bool $edited = null,null | bool $contacts = null,null | bool $selected_contacts = null,null | bool $out = null,null | object $from_id = null,null | object $fwd_from = null,null | string $caption = null,null | array $entities = null,null | array $media_areas = null,null | array $privacy = null,null | object $views = null,null | object $sent_reaction = null,null | array $albums = null,null | object $music = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x16a4b93c);
		$flags = 0;
		$flags |= $pinned ? (1 << 5) : 0;
		$flags |= $public ? (1 << 7) : 0;
		$flags |= $close_friends ? (1 << 8) : 0;
		$flags |= $min ? (1 << 9) : 0;
		$flags |= $noforwards ? (1 << 10) : 0;
		$flags |= $edited ? (1 << 11) : 0;
		$flags |= $contacts ? (1 << 12) : 0;
		$flags |= $selected_contacts ? (1 << 13) : 0;
		$flags |= $out ? (1 << 16) : 0;
		$flags |= is_null($from_id) ? 0 : (1 << 18);
		$flags |= is_null($fwd_from) ? 0 : (1 << 17);
		$flags |= is_null($caption) ? 0 : (1 << 0);
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$flags |= is_null($media_areas) ? 0 : (1 << 14);
		$flags |= is_null($privacy) ? 0 : (1 << 2);
		$flags |= is_null($views) ? 0 : (1 << 3);
		$flags |= is_null($sent_reaction) ? 0 : (1 << 15);
		$flags |= is_null($albums) ? 0 : (1 << 19);
		$flags |= is_null($music) ? 0 : (1 << 20);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeInt($date);
		if(is_null($from_id) === false):
			$writer->writeObject($from_id);
		endif;
		if(is_null($fwd_from) === false):
			$writer->writeObject($fwd_from);
		endif;
		$writer->writeInt($expire_date);
		if(is_null($caption) === false):
			$writer->writeBytes($caption);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		$writer->writeObject($media);
		if(is_null($media_areas) === false):
			$writer->writeVector($media_areas,'mediaarea');
		endif;
		if(is_null($privacy) === false):
			$writer->writeVector($privacy,'privacyrule');
		endif;
		if(is_null($views) === false):
			$writer->writeObject($views);
		endif;
		if(is_null($sent_reaction) === false):
			$writer->writeObject($sent_reaction);
		endif;
		if(is_null($albums) === false):
			$writer->writeVector($albums,'int');
		endif;
		if(is_null($music) === false):
			$writer->writeObject($music);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pinned'] = boolval($flags & (1 << 5));
		$result['public'] = boolval($flags & (1 << 7));
		$result['close_friends'] = boolval($flags & (1 << 8));
		$result['min'] = boolval($flags & (1 << 9));
		$result['noforwards'] = boolval($flags & (1 << 10));
		$result['edited'] = boolval($flags & (1 << 11));
		$result['contacts'] = boolval($flags & (1 << 12));
		$result['selected_contacts'] = boolval($flags & (1 << 13));
		$result['out'] = boolval($flags & (1 << 16));
		$result['id'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 18)):
			$result['from_id'] = $reader->readObject();
		else:
			$result['from_id'] = null;
		endif;
		if($flags & (1 << 17)):
			$result['fwd_from'] = $reader->readObject();
		else:
			$result['fwd_from'] = null;
		endif;
		$result['expire_date'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['caption'] = $reader->readBytes();
		else:
			$result['caption'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		$result['media'] = $reader->readObject();
		if($flags & (1 << 14)):
			$result['media_areas'] = $reader->readVector('mediaarea');
		else:
			$result['media_areas'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['privacy'] = $reader->readVector('privacyrule');
		else:
			$result['privacy'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['views'] = $reader->readObject();
		else:
			$result['views'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['sent_reaction'] = $reader->readObject();
		else:
			$result['sent_reaction'] = null;
		endif;
		if($flags & (1 << 19)):
			$result['albums'] = $reader->readVector('int');
		else:
			$result['albums'] = null;
		endif;
		if($flags & (1 << 20)):
			$result['music'] = $reader->readObject();
		else:
			$result['music'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title string description invoice invoice bytes payload string provider datajson provider_data inputwebdocument photo replymarkup reply_markup
 * @return InputBotInlineMessage
 */

final class InputBotInlineMessageMediaInvoice extends Instance {
	public function request(string $title,string $description,object $invoice,string $payload,string $provider,object $provider_data,null | object $photo = null,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd7e78225);
		$flags = 0;
		$flags |= is_null($photo) ? 0 : (1 << 0);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		$writer->writeObject($invoice);
		$writer->writeBytes($payload);
		$writer->writeBytes($provider);
		$writer->writeObject($provider_data);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		$result['invoice'] = $reader->readObject();
		$result['payload'] = $reader->readBytes();
		$result['provider'] = $reader->readBytes();
		$result['provider_data'] = $reader->readObject();
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title
 * @return MessageAction
 */

final class MessageActionChannelCreate extends Instance {
	public function request(string $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x95d2ac92);
		$writer->writeBytes($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id inputdocument document
 * @return InputRichFile
 */

final class InputRichFileDocument extends Instance {
	public function request(string $id,object $document) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x83281dbd);
		$writer->writeBytes($id);
		$writer->writeObject($document);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readBytes();
		$result['document'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title string url Vector<peer> peers
 * @return ExportedChatlistInvite
 */

final class ExportedChatlistInvite extends Instance {
	public function request(string $title,string $url,array $peers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc5181ac);
		$flags = 0;
		$writer->writeInt($flags);
		$writer->writeBytes($title);
		$writer->writeBytes($url);
		$writer->writeVector($peers,'peer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['title'] = $reader->readBytes();
		$result['url'] = $reader->readBytes();
		$result['peers'] = $reader->readVector('peer');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityHashtag extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6f635b0d);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string job_id
 * @return Update
 */

final class UpdateSmsJob extends Instance {
	public function request(string $job_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf16269d4);
		$writer->writeBytes($job_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['job_id'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param dialogpeer peer true unread peer saved_peer_id
 * @return Update
 */

final class UpdateDialogUnreadMark extends Instance {
	public function request(object $peer,null | bool $unread = null,null | object $saved_peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb658f23e);
		$flags = 0;
		$flags |= $unread ? (1 << 0) : 0;
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['unread'] = boolval($flags & (1 << 0));
		$result['peer'] = $reader->readObject();
		if($flags & (1 << 1)):
			$result['saved_peer_id'] = $reader->readObject();
		else:
			$result['saved_peer_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long random_id richmessage rich_message
 * @return SendMessageAction
 */

final class SendMessageRichMessageDraftAction extends Instance {
	public function request(int $random_id,object $rich_message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa2cb24f9);
		$writer->writeLong($random_id);
		$writer->writeObject($rich_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['random_id'] = $reader->readLong();
		$result['rich_message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title long icon_emoji_id Vector<string> emoticons
 * @return EmojiGroup
 */

final class EmojiGroup extends Instance {
	public function request(string $title,int $icon_emoji_id,array $emoticons) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7a9abda9);
		$writer->writeBytes($title);
		$writer->writeLong($icon_emoji_id);
		$writer->writeVector($emoticons,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readBytes();
		$result['icon_emoji_id'] = $reader->readLong();
		$result['emoticons'] = $reader->readVector('string');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true restore true upgrade
 * @return InputStorePaymentPurpose
 */

final class InputStorePaymentPremiumSubscription extends Instance {
	public function request(null | bool $restore = null,null | bool $upgrade = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa6751e66);
		$flags = 0;
		$flags |= $restore ? (1 << 0) : 0;
		$flags |= $upgrade ? (1 << 1) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['restore'] = boolval($flags & (1 << 0));
		$result['upgrade'] = boolval($flags & (1 << 1));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash true unconfirmed int date string device string location
 * @return Update
 */

final class UpdateNewAuthorization extends Instance {
	public function request(int $hash,null | bool $unconfirmed = null,null | int $date = null,null | string $device = null,null | string $location = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8951abef);
		$flags = 0;
		$flags |= $unconfirmed ? (1 << 0) : 0;
		$flags |= is_null($date) ? 0 : (1 << 0);
		$flags |= is_null($device) ? 0 : (1 << 0);
		$flags |= is_null($location) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($hash);
		if(is_null($date) === false):
			$writer->writeInt($date);
		endif;
		if(is_null($device) === false):
			$writer->writeBytes($device);
		endif;
		if(is_null($location) === false):
			$writer->writeBytes($location);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['unconfirmed'] = boolval($flags & (1 << 0));
		$result['hash'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['date'] = $reader->readInt();
		else:
			$result['date'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['device'] = $reader->readBytes();
		else:
			$result['device'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['location'] = $reader->readBytes();
		else:
			$result['location'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer Vector<int> messages int pts int pts_count true pinned
 * @return Update
 */

final class UpdatePinnedMessages extends Instance {
	public function request(object $peer,array $messages,int $pts,int $pts_count,null | bool $pinned = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xed85eab5);
		$flags = 0;
		$flags |= $pinned ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeVector($messages,'int');
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pinned'] = boolval($flags & (1 << 0));
		$result['peer'] = $reader->readObject();
		$result['messages'] = $reader->readVector('int');
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int n double x double y double zoom
 * @return MaskCoords
 */

final class MaskCoords extends Instance {
	public function request(int $n,float $x,float $y,float $zoom) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaed6dbb2);
		$writer->writeInt($n);
		$writer->writeDouble($x);
		$writer->writeDouble($y);
		$writer->writeDouble($zoom);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['n'] = $reader->readInt();
		$result['x'] = $reader->readDouble();
		$result['y'] = $reader->readDouble();
		$result['zoom'] = $reader->readDouble();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id peer from_id sendmessageaction action int top_msg_id
 * @return Update
 */

final class UpdateChannelUserTyping extends Instance {
	public function request(int $channel_id,object $from_id,object $action,null | int $top_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c88c923);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($channel_id);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		$writer->writeObject($from_id);
		$writer->writeObject($action);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['channel_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['top_msg_id'] = $reader->readInt();
		else:
			$result['top_msg_id'] = null;
		endif;
		$result['from_id'] = $reader->readObject();
		$result['action'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param geopoint geo
 * @return MessageMedia
 */

final class MessageMediaGeo extends Instance {
	public function request(object $geo) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x56e0d474);
		$writer->writeObject($geo);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['geo'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes salt1 bytes salt2 int g bytes p
 * @return PasswordKdfAlgo
 */

final class PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow extends Instance {
	public function request(string $salt1,string $salt2,int $g,string $p) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3a912d4a);
		$writer->writeBytes($salt1);
		$writer->writeBytes($salt2);
		$writer->writeInt($g);
		$writer->writeBytes($p);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['salt1'] = $reader->readBytes();
		$result['salt2'] = $reader->readBytes();
		$result['g'] = $reader->readInt();
		$result['p'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url true spoiler int ttl_seconds
 * @return InputMedia
 */

final class InputMediaPhotoExternal extends Instance {
	public function request(string $url,null | bool $spoiler = null,null | int $ttl_seconds = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe5bbfe1a);
		$flags = 0;
		$flags |= $spoiler ? (1 << 1) : 0;
		$flags |= is_null($ttl_seconds) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($url);
		if(is_null($ttl_seconds) === false):
			$writer->writeInt($ttl_seconds);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['spoiler'] = boolval($flags & (1 << 1));
		$result['url'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['ttl_seconds'] = $reader->readInt();
		else:
			$result['ttl_seconds'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string currency long amount long stars string crypto_currency long crypto_amount string transaction_id
 * @return MessageAction
 */

final class MessageActionGiftStars extends Instance {
	public function request(string $currency,int $amount,int $stars,null | string $crypto_currency = null,null | int $crypto_amount = null,null | string $transaction_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x45d5b021);
		$flags = 0;
		$flags |= is_null($crypto_currency) ? 0 : (1 << 0);
		$flags |= is_null($crypto_amount) ? 0 : (1 << 0);
		$flags |= is_null($transaction_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		$writer->writeLong($stars);
		if(is_null($crypto_currency) === false):
			$writer->writeBytes($crypto_currency);
		endif;
		if(is_null($crypto_amount) === false):
			$writer->writeLong($crypto_amount);
		endif;
		if(is_null($transaction_id) === false):
			$writer->writeBytes($transaction_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		$result['stars'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['crypto_currency'] = $reader->readBytes();
		else:
			$result['crypto_currency'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['crypto_amount'] = $reader->readLong();
		else:
			$result['crypto_amount'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['transaction_id'] = $reader->readBytes();
		else:
			$result['transaction_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id long user_id bool is_admin int version
 * @return Update
 */

final class UpdateChatParticipantAdmin extends Instance {
	public function request(int $chat_id,int $user_id,bool $is_admin,int $version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd7ca61a2);
		$writer->writeLong($chat_id);
		$writer->writeLong($user_id);
		$writer->writeBool($is_admin);
		$writer->writeInt($version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		$result['is_admin'] = $reader->readBool();
		$result['version'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextAutoUrl extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xac6a83aa);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id document sticker long stars long convert_stars true limited true sold_out true birthday true require_premium true limited_per_user true peer_color_available true auction int availability_remains int availability_total long availability_resale int first_sale_date int last_sale_date long upgrade_stars long resell_min_stars string title peer released_by int per_user_total int per_user_remains int locked_until_date string auction_slug int gifts_per_round int auction_start_date int upgrade_variants stargiftbackground background
 * @return StarGift
 */

final class StarGift extends Instance {
	public function request(int $id,object $sticker,int $stars,int $convert_stars,null | bool $limited = null,null | bool $sold_out = null,null | bool $birthday = null,null | bool $require_premium = null,null | bool $limited_per_user = null,null | bool $peer_color_available = null,null | bool $auction = null,null | int $availability_remains = null,null | int $availability_total = null,null | int $availability_resale = null,null | int $first_sale_date = null,null | int $last_sale_date = null,null | int $upgrade_stars = null,null | int $resell_min_stars = null,null | string $title = null,null | object $released_by = null,null | int $per_user_total = null,null | int $per_user_remains = null,null | int $locked_until_date = null,null | string $auction_slug = null,null | int $gifts_per_round = null,null | int $auction_start_date = null,null | int $upgrade_variants = null,null | object $background = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x313a9547);
		$flags = 0;
		$flags |= $limited ? (1 << 0) : 0;
		$flags |= $sold_out ? (1 << 1) : 0;
		$flags |= $birthday ? (1 << 2) : 0;
		$flags |= $require_premium ? (1 << 7) : 0;
		$flags |= $limited_per_user ? (1 << 8) : 0;
		$flags |= $peer_color_available ? (1 << 10) : 0;
		$flags |= $auction ? (1 << 11) : 0;
		$flags |= is_null($availability_remains) ? 0 : (1 << 0);
		$flags |= is_null($availability_total) ? 0 : (1 << 0);
		$flags |= is_null($availability_resale) ? 0 : (1 << 4);
		$flags |= is_null($first_sale_date) ? 0 : (1 << 1);
		$flags |= is_null($last_sale_date) ? 0 : (1 << 1);
		$flags |= is_null($upgrade_stars) ? 0 : (1 << 3);
		$flags |= is_null($resell_min_stars) ? 0 : (1 << 4);
		$flags |= is_null($title) ? 0 : (1 << 5);
		$flags |= is_null($released_by) ? 0 : (1 << 6);
		$flags |= is_null($per_user_total) ? 0 : (1 << 8);
		$flags |= is_null($per_user_remains) ? 0 : (1 << 8);
		$flags |= is_null($locked_until_date) ? 0 : (1 << 9);
		$flags |= is_null($auction_slug) ? 0 : (1 << 11);
		$flags |= is_null($gifts_per_round) ? 0 : (1 << 11);
		$flags |= is_null($auction_start_date) ? 0 : (1 << 11);
		$flags |= is_null($upgrade_variants) ? 0 : (1 << 12);
		$flags |= is_null($background) ? 0 : (1 << 13);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeObject($sticker);
		$writer->writeLong($stars);
		if(is_null($availability_remains) === false):
			$writer->writeInt($availability_remains);
		endif;
		if(is_null($availability_total) === false):
			$writer->writeInt($availability_total);
		endif;
		if(is_null($availability_resale) === false):
			$writer->writeLong($availability_resale);
		endif;
		$writer->writeLong($convert_stars);
		if(is_null($first_sale_date) === false):
			$writer->writeInt($first_sale_date);
		endif;
		if(is_null($last_sale_date) === false):
			$writer->writeInt($last_sale_date);
		endif;
		if(is_null($upgrade_stars) === false):
			$writer->writeLong($upgrade_stars);
		endif;
		if(is_null($resell_min_stars) === false):
			$writer->writeLong($resell_min_stars);
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($released_by) === false):
			$writer->writeObject($released_by);
		endif;
		if(is_null($per_user_total) === false):
			$writer->writeInt($per_user_total);
		endif;
		if(is_null($per_user_remains) === false):
			$writer->writeInt($per_user_remains);
		endif;
		if(is_null($locked_until_date) === false):
			$writer->writeInt($locked_until_date);
		endif;
		if(is_null($auction_slug) === false):
			$writer->writeBytes($auction_slug);
		endif;
		if(is_null($gifts_per_round) === false):
			$writer->writeInt($gifts_per_round);
		endif;
		if(is_null($auction_start_date) === false):
			$writer->writeInt($auction_start_date);
		endif;
		if(is_null($upgrade_variants) === false):
			$writer->writeInt($upgrade_variants);
		endif;
		if(is_null($background) === false):
			$writer->writeObject($background);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['limited'] = boolval($flags & (1 << 0));
		$result['sold_out'] = boolval($flags & (1 << 1));
		$result['birthday'] = boolval($flags & (1 << 2));
		$result['require_premium'] = boolval($flags & (1 << 7));
		$result['limited_per_user'] = boolval($flags & (1 << 8));
		$result['peer_color_available'] = boolval($flags & (1 << 10));
		$result['auction'] = boolval($flags & (1 << 11));
		$result['id'] = $reader->readLong();
		$result['sticker'] = $reader->readObject();
		$result['stars'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['availability_remains'] = $reader->readInt();
		else:
			$result['availability_remains'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['availability_total'] = $reader->readInt();
		else:
			$result['availability_total'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['availability_resale'] = $reader->readLong();
		else:
			$result['availability_resale'] = null;
		endif;
		$result['convert_stars'] = $reader->readLong();
		if($flags & (1 << 1)):
			$result['first_sale_date'] = $reader->readInt();
		else:
			$result['first_sale_date'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['last_sale_date'] = $reader->readInt();
		else:
			$result['last_sale_date'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['upgrade_stars'] = $reader->readLong();
		else:
			$result['upgrade_stars'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['resell_min_stars'] = $reader->readLong();
		else:
			$result['resell_min_stars'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['released_by'] = $reader->readObject();
		else:
			$result['released_by'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['per_user_total'] = $reader->readInt();
		else:
			$result['per_user_total'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['per_user_remains'] = $reader->readInt();
		else:
			$result['per_user_remains'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['locked_until_date'] = $reader->readInt();
		else:
			$result['locked_until_date'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['auction_slug'] = $reader->readBytes();
		else:
			$result['auction_slug'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['gifts_per_round'] = $reader->readInt();
		else:
			$result['gifts_per_round'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['auction_start_date'] = $reader->readInt();
		else:
			$result['auction_start_date'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['upgrade_variants'] = $reader->readInt();
		else:
			$result['upgrade_variants'] = null;
		endif;
		if($flags & (1 << 13)):
			$result['background'] = $reader->readObject();
		else:
			$result['background'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stargift gift starsamount price int expires_at true accepted true declined
 * @return MessageAction
 */

final class MessageActionStarGiftPurchaseOffer extends Instance {
	public function request(object $gift,object $price,int $expires_at,null | bool $accepted = null,null | bool $declined = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x774278d4);
		$flags = 0;
		$flags |= $accepted ? (1 << 0) : 0;
		$flags |= $declined ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($gift);
		$writer->writeObject($price);
		$writer->writeInt($expires_at);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['accepted'] = boolval($flags & (1 << 0));
		$result['declined'] = boolval($flags & (1 << 1));
		$result['gift'] = $reader->readObject();
		$result['price'] = $reader->readObject();
		$result['expires_at'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int expires
 * @return PeerLocated
 */

final class PeerSelfLocated extends Instance {
	public function request(int $expires) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf8ec284b);
		$writer->writeInt($expires);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['expires'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int period long auto_setting_from
 * @return MessageAction
 */

final class MessageActionSetMessagesTTL extends Instance {
	public function request(int $period,null | int $auto_setting_from = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3c134d7b);
		$flags = 0;
		$flags |= is_null($auto_setting_from) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($period);
		if(is_null($auto_setting_from) === false):
			$writer->writeLong($auto_setting_from);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['period'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['auto_setting_from'] = $reader->readLong();
		else:
			$result['auto_setting_from'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgame id
 * @return InputMedia
 */

final class InputMediaGame extends Instance {
	public function request(object $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd33f43f3);
		$writer->writeObject($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title string data
 * @return NotificationSound
 */

final class NotificationSoundLocal extends Instance {
	public function request(string $title,string $data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x830b9ae4);
		$writer->writeBytes($title);
		$writer->writeBytes($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readBytes();
		$result['data'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash int date long admin_id long participant_id bytes g_a_or_b long key_fingerprint phonecallprotocol protocol Vector<phoneconnection> connections int start_date true p2p_allowed true video true conference_supported datajson custom_parameters
 * @return PhoneCall
 */

final class PhoneCall extends Instance {
	public function request(int $id,int $access_hash,int $date,int $admin_id,int $participant_id,string $g_a_or_b,int $key_fingerprint,object $protocol,array $connections,int $start_date,null | bool $p2p_allowed = null,null | bool $video = null,null | bool $conference_supported = null,null | object $custom_parameters = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x30535af5);
		$flags = 0;
		$flags |= $p2p_allowed ? (1 << 5) : 0;
		$flags |= $video ? (1 << 6) : 0;
		$flags |= $conference_supported ? (1 << 8) : 0;
		$flags |= is_null($custom_parameters) ? 0 : (1 << 7);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeInt($date);
		$writer->writeLong($admin_id);
		$writer->writeLong($participant_id);
		$writer->writeBytes($g_a_or_b);
		$writer->writeLong($key_fingerprint);
		$writer->writeObject($protocol);
		$writer->writeVector($connections,'phoneconnection');
		$writer->writeInt($start_date);
		if(is_null($custom_parameters) === false):
			$writer->writeObject($custom_parameters);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['p2p_allowed'] = boolval($flags & (1 << 5));
		$result['video'] = boolval($flags & (1 << 6));
		$result['conference_supported'] = boolval($flags & (1 << 8));
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['admin_id'] = $reader->readLong();
		$result['participant_id'] = $reader->readLong();
		$result['g_a_or_b'] = $reader->readBytes();
		$result['key_fingerprint'] = $reader->readLong();
		$result['protocol'] = $reader->readObject();
		$result['connections'] = $reader->readVector('phoneconnection');
		$result['start_date'] = $reader->readInt();
		if($flags & (1 << 7)):
			$result['custom_parameters'] = $reader->readObject();
		else:
			$result['custom_parameters'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type bytes file_hash string text
 * @return SecureValueError
 */

final class SecureValueErrorFile extends Instance {
	public function request(object $type,string $file_hash,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7a700873);
		$writer->writeObject($type);
		$writer->writeBytes($file_hash);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readObject();
		$result['file_hash'] = $reader->readBytes();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputfile file inputfile video double video_start_ts videosize video_emoji_markup
 * @return InputChatPhoto
 */

final class InputChatUploadedPhoto extends Instance {
	public function request(null | object $file = null,null | object $video = null,null | float $video_start_ts = null,null | object $video_emoji_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbdcdaec0);
		$flags = 0;
		$flags |= is_null($file) ? 0 : (1 << 0);
		$flags |= is_null($video) ? 0 : (1 << 1);
		$flags |= is_null($video_start_ts) ? 0 : (1 << 2);
		$flags |= is_null($video_emoji_markup) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($file) === false):
			$writer->writeObject($file);
		endif;
		if(is_null($video) === false):
			$writer->writeObject($video);
		endif;
		if(is_null($video_start_ts) === false):
			$writer->writeDouble($video_start_ts);
		endif;
		if(is_null($video_emoji_markup) === false):
			$writer->writeObject($video_emoji_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['file'] = $reader->readObject();
		else:
			$result['file'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['video'] = $reader->readObject();
		else:
			$result['video'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['video_start_ts'] = $reader->readDouble();
		else:
			$result['video_start_ts'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['video_emoji_markup'] = $reader->readObject();
		else:
			$result['video_emoji_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int collection_id string title int gifts_count long hash document icon
 * @return StarGiftCollection
 */

final class StarGiftCollection extends Instance {
	public function request(int $collection_id,string $title,int $gifts_count,int $hash,null | object $icon = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9d6b13b0);
		$flags = 0;
		$flags |= is_null($icon) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($collection_id);
		$writer->writeBytes($title);
		if(is_null($icon) === false):
			$writer->writeObject($icon);
		endif;
		$writer->writeInt($gifts_count);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['collection_id'] = $reader->readInt();
		$result['title'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['icon'] = $reader->readObject();
		else:
			$result['icon'] = null;
		endif;
		$result['gifts_count'] = $reader->readInt();
		$result['hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param forumtopic prev_topic forumtopic new_topic
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionEditTopic extends Instance {
	public function request(object $prev_topic,object $new_topic) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf06fe208);
		$writer->writeObject($prev_topic);
		$writer->writeObject($new_topic);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_topic'] = $reader->readObject();
		$result['new_topic'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stargift gift Vector<themesettings> theme_settings
 * @return ChatTheme
 */

final class ChatThemeUniqueGift extends Instance {
	public function request(object $gift,array $theme_settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3458f9c8);
		$writer->writeObject($gift);
		$writer->writeVector($theme_settings,'themesettings');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['gift'] = $reader->readObject();
		$result['theme_settings'] = $reader->readVector('themesettings');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return BotCommandScope
 */

final class BotCommandScopePeerAdmins extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3fd863d1);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id int date true blocked true blocked_my_stories_from reaction reaction
 * @return StoryView
 */

final class StoryView extends Instance {
	public function request(int $user_id,int $date,null | bool $blocked = null,null | bool $blocked_my_stories_from = null,null | object $reaction = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb0bdeac5);
		$flags = 0;
		$flags |= $blocked ? (1 << 0) : 0;
		$flags |= $blocked_my_stories_from ? (1 << 1) : 0;
		$flags |= is_null($reaction) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		$writer->writeInt($date);
		if(is_null($reaction) === false):
			$writer->writeObject($reaction);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['blocked'] = boolval($flags & (1 << 0));
		$result['blocked_my_stories_from'] = boolval($flags & (1 << 1));
		$result['user_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['reaction'] = $reader->readObject();
		else:
			$result['reaction'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string html true rtl true noautolink Vector<inputrichfile> files
 * @return InputRichMessage
 */

final class InputRichMessageHTML extends Instance {
	public function request(string $html,null | bool $rtl = null,null | bool $noautolink = null,null | array $files = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdacb836a);
		$flags = 0;
		$flags |= $rtl ? (1 << 0) : 0;
		$flags |= $noautolink ? (1 << 1) : 0;
		$flags |= is_null($files) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($html);
		if(is_null($files) === false):
			$writer->writeVector($files,'inputrichfile');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['rtl'] = boolval($flags & (1 << 0));
		$result['noautolink'] = boolval($flags & (1 << 1));
		$result['html'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['files'] = $reader->readVector('inputrichfile');
		else:
			$result['files'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionSendMessage extends Instance {
	public function request(object $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x278f2868);
		$writer->writeObject($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message true blocked true blocked_my_stories_from
 * @return StoryView
 */

final class StoryViewPublicForward extends Instance {
	public function request(object $message,null | bool $blocked = null,null | bool $blocked_my_stories_from = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9083670b);
		$flags = 0;
		$flags |= $blocked ? (1 << 0) : 0;
		$flags |= $blocked_my_stories_from ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['blocked'] = boolval($flags & (1 << 0));
		$result['blocked_my_stories_from'] = boolval($flags & (1 << 1));
		$result['message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson data
 * @return Update
 */

final class UpdateBotWebhookJSON extends Instance {
	public function request(object $data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8317c0c3);
		$writer->writeObject($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['data'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param messagemedia media
 * @return MessageExtendedMedia
 */

final class MessageExtendedMedia extends Instance {
	public function request(object $media) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xee479c64);
		$writer->writeObject($media);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['media'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param mediaareacoordinates coordinates string url
 * @return MediaArea
 */

final class MediaAreaUrl extends Instance {
	public function request(object $coordinates,string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x37381085);
		$writer->writeObject($coordinates);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['coordinates'] = $reader->readObject();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return TopPeerCategory
 */

final class TopPeerCategoryForwardChats extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfbeec0f0);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButtonRequestPhone extends Instance {
	public function request(string $text,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x417efd8f);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer Vector<int> order
 * @return Update
 */

final class UpdatePinnedForumTopics extends Instance {
	public function request(object $peer,null | array $order = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdef143d0);
		$flags = 0;
		$flags |= is_null($order) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($order) === false):
			$writer->writeVector($order,'int');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['peer'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['order'] = $reader->readVector('int');
		else:
			$result['order'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param geopoint geo string title string address string provider string venue_id string venue_type replymarkup reply_markup
 * @return BotInlineMessage
 */

final class BotInlineMessageMediaVenue extends Instance {
	public function request(object $geo,string $title,string $address,string $provider,string $venue_id,string $venue_type,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8a86659c);
		$flags = 0;
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($geo);
		$writer->writeBytes($title);
		$writer->writeBytes($address);
		$writer->writeBytes($provider);
		$writer->writeBytes($venue_id);
		$writer->writeBytes($venue_type);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['geo'] = $reader->readObject();
		$result['title'] = $reader->readBytes();
		$result['address'] = $reader->readBytes();
		$result['provider'] = $reader->readBytes();
		$result['venue_id'] = $reader->readBytes();
		$result['venue_type'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id
 * @return User
 */

final class UserEmpty extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd3bc4b7a);
		$writer->writeLong($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BotCommandScope
 */

final class BotCommandScopeUsers extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3c4f04d8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateRecentReactions extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6f7863f4);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars true top true my peer peer_id
 * @return GroupCallDonor
 */

final class GroupCallDonor extends Instance {
	public function request(int $stars,null | bool $top = null,null | bool $my = null,null | object $peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xee430c85);
		$flags = 0;
		$flags |= $top ? (1 << 0) : 0;
		$flags |= $my ? (1 << 1) : 0;
		$flags |= is_null($peer_id) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($peer_id) === false):
			$writer->writeObject($peer_id);
		endif;
		$writer->writeLong($stars);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['top'] = boolval($flags & (1 << 0));
		$result['my'] = boolval($flags & (1 << 1));
		if($flags & (1 << 3)):
			$result['peer_id'] = $reader->readObject();
		else:
			$result['peer_id'] = null;
		endif;
		$result['stars'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int progress
 * @return SendMessageAction
 */

final class SendMessageUploadDocumentAction extends Instance {
	public function request(int $progress) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaa0cd9e4);
		$writer->writeInt($progress);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['progress'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReportReason
 */

final class InputReportReasonChildAbuse extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xadf44ee3);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string keyword Vector<string> emoticons
 * @return EmojiKeyword
 */

final class EmojiKeywordDeleted extends Instance {
	public function request(string $keyword,array $emoticons) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x236df622);
		$writer->writeBytes($keyword);
		$writer->writeVector($emoticons,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['keyword'] = $reader->readBytes();
		$result['emoticons'] = $reader->readVector('string');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int story_id
 * @return MessageReplyHeader
 */

final class MessageReplyStoryHeader extends Instance {
	public function request(object $peer,int $story_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe5af939);
		$writer->writeObject($peer);
		$writer->writeInt($story_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['story_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterPinned extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1bb00451);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<keyboardbutton> buttons
 * @return KeyboardButtonRow
 */

final class KeyboardButtonRow extends Instance {
	public function request(array $buttons) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x77608b83);
		$writer->writeVector($buttons,'keyboardbutton');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['buttons'] = $reader->readVector('keyboardbutton');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long amount int nanos
 * @return StarsAmount
 */

final class StarsAmount extends Instance {
	public function request(int $amount,int $nanos) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbbb6b4a3);
		$writer->writeLong($amount);
		$writer->writeInt($nanos);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['amount'] = $reader->readLong();
		$result['nanos'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer true premium_required
 * @return SendAsPeer
 */

final class SendAsPeer extends Instance {
	public function request(object $peer,null | bool $premium_required = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb81c7034);
		$flags = 0;
		$flags |= $premium_required ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['premium_required'] = boolval($flags & (1 << 0));
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int expires
 * @return UserStatus
 */

final class UserStatusOnline extends Instance {
	public function request(int $expires) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xedb93949);
		$writer->writeInt($expires);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['expires'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarGiftAttributeRarity
 */

final class StarGiftAttributeRarityRare extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf08d516b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true masks true emojis
 * @return Update
 */

final class UpdateStickerSets extends Instance {
	public function request(null | bool $masks = null,null | bool $emojis = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31c24808);
		$flags = 0;
		$flags |= $masks ? (1 << 0) : 0;
		$flags |= $emojis ? (1 << 1) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['masks'] = boolval($flags & (1 << 0));
		$result['emojis'] = boolval($flags & (1 << 1));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id int parts string md5_checksum int key_fingerprint
 * @return InputEncryptedFile
 */

final class InputEncryptedFileUploaded extends Instance {
	public function request(int $id,int $parts,string $md5_checksum,int $key_fingerprint) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x64bd0306);
		$writer->writeLong($id);
		$writer->writeInt($parts);
		$writer->writeBytes($md5_checksum);
		$writer->writeInt($key_fingerprint);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['parts'] = $reader->readInt();
		$result['md5_checksum'] = $reader->readBytes();
		$result['key_fingerprint'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length string old_text
 * @return MessageEntity
 */

final class MessageEntityDiffReplace extends Instance {
	public function request(int $offset,int $length,string $old_text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc6c1e5a7);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		$writer->writeBytes($old_text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		$result['old_text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return PaidReactionPrivacy
 */

final class PaidReactionPrivacyPeer extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdc6cfcf0);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stargift gift int end_date
 * @return WebPageAttribute
 */

final class WebPageAttributeStarGiftAuction extends Instance {
	public function request(object $gift,int $end_date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1c641c2);
		$writer->writeObject($gift);
		$writer->writeInt($end_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['gift'] = $reader->readObject();
		$result['end_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash int date long admin_id long participant_id phonecallprotocol protocol true video int receive_date
 * @return PhoneCall
 */

final class PhoneCallWaiting extends Instance {
	public function request(int $id,int $access_hash,int $date,int $admin_id,int $participant_id,object $protocol,null | bool $video = null,null | int $receive_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc5226f17);
		$flags = 0;
		$flags |= $video ? (1 << 6) : 0;
		$flags |= is_null($receive_date) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeInt($date);
		$writer->writeLong($admin_id);
		$writer->writeLong($participant_id);
		$writer->writeObject($protocol);
		if(is_null($receive_date) === false):
			$writer->writeInt($receive_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['video'] = boolval($flags & (1 << 6));
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['admin_id'] = $reader->readLong();
		$result['participant_id'] = $reader->readLong();
		$result['protocol'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['receive_date'] = $reader->readInt();
		else:
			$result['receive_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param todolist todo Vector<todocompletion> completions
 * @return MessageMedia
 */

final class MessageMediaToDo extends Instance {
	public function request(object $todo,null | array $completions = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8a53b014);
		$flags = 0;
		$flags |= is_null($completions) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($todo);
		if(is_null($completions) === false):
			$writer->writeVector($completions,'todocompletion');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['todo'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['completions'] = $reader->readVector('todocompletion');
		else:
			$result['completions'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputPhoneCall
 */

final class InputPhoneCall extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1e36fded);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InlineQueryPeerType
 */

final class InlineQueryPeerTypeSameBotPM extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3081ed9d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextFixed extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c3f19b9);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputChatTheme
 */

final class InputChatThemeEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x83268483);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id peer saved_peer_id int read_max_id
 * @return Update
 */

final class UpdateReadMonoForumOutbox extends Instance {
	public function request(int $channel_id,object $saved_peer_id,int $read_max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa4a79376);
		$writer->writeLong($channel_id);
		$writer->writeObject($saved_peer_id);
		$writer->writeInt($read_max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['saved_peer_id'] = $reader->readObject();
		$result['read_max_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id peer completed_by int date
 * @return TodoCompletion
 */

final class TodoCompletion extends Instance {
	public function request(int $id,object $completed_by,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x221bb5e4);
		$writer->writeInt($id);
		$writer->writeObject($completed_by);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		$result['completed_by'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgeopoint geo_point string title string address string provider string venue_id string venue_type
 * @return InputMedia
 */

final class InputMediaVenue extends Instance {
	public function request(object $geo_point,string $title,string $address,string $provider,string $venue_id,string $venue_type) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc13d1c11);
		$writer->writeObject($geo_point);
		$writer->writeBytes($title);
		$writer->writeBytes($address);
		$writer->writeBytes($provider);
		$writer->writeBytes($venue_id);
		$writer->writeBytes($venue_type);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['geo_point'] = $reader->readObject();
		$result['title'] = $reader->readBytes();
		$result['address'] = $reader->readBytes();
		$result['provider'] = $reader->readBytes();
		$result['venue_id'] = $reader->readBytes();
		$result['venue_type'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id true refund
 * @return InputStarsTransaction
 */

final class InputStarsTransaction extends Instance {
	public function request(string $id,null | bool $refund = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x206ae6d1);
		$flags = 0;
		$flags |= $refund ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['refund'] = boolval($flags & (1 << 0));
		$result['id'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeySavedMusic extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xff7a571b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string link string html
 * @return ExportedMessageLink
 */

final class ExportedMessageLink extends Instance {
	public function request(string $link,string $html) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5dab1af4);
		$writer->writeBytes($link);
		$writer->writeBytes($html);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['link'] = $reader->readBytes();
		$result['html'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id int top_msg_id int read_max_id
 * @return Update
 */

final class UpdateReadChannelDiscussionOutbox extends Instance {
	public function request(int $channel_id,int $top_msg_id,int $read_max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x695c9e7c);
		$writer->writeLong($channel_id);
		$writer->writeInt($top_msg_id);
		$writer->writeInt($read_max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['top_msg_id'] = $reader->readInt();
		$result['read_max_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param photo photo
 * @return MessageAction
 */

final class MessageActionSuggestProfilePhoto extends Instance {
	public function request(object $photo) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x57de635e);
		$writer->writeObject($photo);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['photo'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> chats
 * @return PrivacyRule
 */

final class PrivacyValueDisallowChatParticipants extends Instance {
	public function request(array $chats) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x41c87565);
		$writer->writeVector($chats,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chats'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id
 * @return EncryptedChat
 */

final class EncryptedChatEmpty extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xab7ec0a0);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer string currency long total_amount paymentcharge charge bytes payload
 * @return MessageAction
 */

final class MessageActionPaymentRefunded extends Instance {
	public function request(object $peer,string $currency,int $total_amount,object $charge,null | string $payload = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x41b3e202);
		$flags = 0;
		$flags |= is_null($payload) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBytes($currency);
		$writer->writeLong($total_amount);
		if(is_null($payload) === false):
			$writer->writeBytes($payload);
		endif;
		$writer->writeObject($charge);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['peer'] = $reader->readObject();
		$result['currency'] = $reader->readBytes();
		$result['total_amount'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['payload'] = $reader->readBytes();
		else:
			$result['payload'] = null;
		endif;
		$result['charge'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string first_name string last_name string vcard replymarkup reply_markup
 * @return BotInlineMessage
 */

final class BotInlineMessageMediaContact extends Instance {
	public function request(string $phone_number,string $first_name,string $last_name,string $vcard,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x18d1cdc2);
		$flags = 0;
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($first_name);
		$writer->writeBytes($last_name);
		$writer->writeBytes($vcard);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['phone_number'] = $reader->readBytes();
		$result['first_name'] = $reader->readBytes();
		$result['last_name'] = $reader->readBytes();
		$result['vcard'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id long access_hash int date long admin_id long participant_id bytes g_a_or_b long key_fingerprint
 * @return EncryptedChat
 */

final class EncryptedChat extends Instance {
	public function request(int $id,int $access_hash,int $date,int $admin_id,int $participant_id,string $g_a_or_b,int $key_fingerprint) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x61f0d4c7);
		$writer->writeInt($id);
		$writer->writeLong($access_hash);
		$writer->writeInt($date);
		$writer->writeLong($admin_id);
		$writer->writeLong($participant_id);
		$writer->writeBytes($g_a_or_b);
		$writer->writeLong($key_fingerprint);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		$result['access_hash'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['admin_id'] = $reader->readLong();
		$result['participant_id'] = $reader->readLong();
		$result['g_a_or_b'] = $reader->readBytes();
		$result['key_fingerprint'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string alt inputstickerset stickerset true free true text_color
 * @return DocumentAttribute
 */

final class DocumentAttributeCustomEmoji extends Instance {
	public function request(string $alt,object $stickerset,null | bool $free = null,null | bool $text_color = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfd149899);
		$flags = 0;
		$flags |= $free ? (1 << 0) : 0;
		$flags |= $text_color ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($alt);
		$writer->writeObject($stickerset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['free'] = boolval($flags & (1 << 0));
		$result['text_color'] = boolval($flags & (1 << 1));
		$result['alt'] = $reader->readBytes();
		$result['stickerset'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return JoinChatBotResult
 */

final class JoinChatBotResultApproved extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xae152a69);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stargift gift true upgrade true transferred true saved true refunded true prepaid_upgrade true assigned true from_offer true craft int can_export_at long transfer_stars peer from_id peer peer long saved_id starsamount resale_amount int can_transfer_at int can_resell_at long drop_original_details_stars int can_craft_at
 * @return MessageAction
 */

final class MessageActionStarGiftUnique extends Instance {
	public function request(object $gift,null | bool $upgrade = null,null | bool $transferred = null,null | bool $saved = null,null | bool $refunded = null,null | bool $prepaid_upgrade = null,null | bool $assigned = null,null | bool $from_offer = null,null | bool $craft = null,null | int $can_export_at = null,null | int $transfer_stars = null,null | object $from_id = null,null | object $peer = null,null | int $saved_id = null,null | object $resale_amount = null,null | int $can_transfer_at = null,null | int $can_resell_at = null,null | int $drop_original_details_stars = null,null | int $can_craft_at = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe6c31522);
		$flags = 0;
		$flags |= $upgrade ? (1 << 0) : 0;
		$flags |= $transferred ? (1 << 1) : 0;
		$flags |= $saved ? (1 << 2) : 0;
		$flags |= $refunded ? (1 << 5) : 0;
		$flags |= $prepaid_upgrade ? (1 << 11) : 0;
		$flags |= $assigned ? (1 << 13) : 0;
		$flags |= $from_offer ? (1 << 14) : 0;
		$flags |= $craft ? (1 << 16) : 0;
		$flags |= is_null($can_export_at) ? 0 : (1 << 3);
		$flags |= is_null($transfer_stars) ? 0 : (1 << 4);
		$flags |= is_null($from_id) ? 0 : (1 << 6);
		$flags |= is_null($peer) ? 0 : (1 << 7);
		$flags |= is_null($saved_id) ? 0 : (1 << 7);
		$flags |= is_null($resale_amount) ? 0 : (1 << 8);
		$flags |= is_null($can_transfer_at) ? 0 : (1 << 9);
		$flags |= is_null($can_resell_at) ? 0 : (1 << 10);
		$flags |= is_null($drop_original_details_stars) ? 0 : (1 << 12);
		$flags |= is_null($can_craft_at) ? 0 : (1 << 15);
		$writer->writeInt($flags);
		$writer->writeObject($gift);
		if(is_null($can_export_at) === false):
			$writer->writeInt($can_export_at);
		endif;
		if(is_null($transfer_stars) === false):
			$writer->writeLong($transfer_stars);
		endif;
		if(is_null($from_id) === false):
			$writer->writeObject($from_id);
		endif;
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		if(is_null($saved_id) === false):
			$writer->writeLong($saved_id);
		endif;
		if(is_null($resale_amount) === false):
			$writer->writeObject($resale_amount);
		endif;
		if(is_null($can_transfer_at) === false):
			$writer->writeInt($can_transfer_at);
		endif;
		if(is_null($can_resell_at) === false):
			$writer->writeInt($can_resell_at);
		endif;
		if(is_null($drop_original_details_stars) === false):
			$writer->writeLong($drop_original_details_stars);
		endif;
		if(is_null($can_craft_at) === false):
			$writer->writeInt($can_craft_at);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['upgrade'] = boolval($flags & (1 << 0));
		$result['transferred'] = boolval($flags & (1 << 1));
		$result['saved'] = boolval($flags & (1 << 2));
		$result['refunded'] = boolval($flags & (1 << 5));
		$result['prepaid_upgrade'] = boolval($flags & (1 << 11));
		$result['assigned'] = boolval($flags & (1 << 13));
		$result['from_offer'] = boolval($flags & (1 << 14));
		$result['craft'] = boolval($flags & (1 << 16));
		$result['gift'] = $reader->readObject();
		if($flags & (1 << 3)):
			$result['can_export_at'] = $reader->readInt();
		else:
			$result['can_export_at'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['transfer_stars'] = $reader->readLong();
		else:
			$result['transfer_stars'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['from_id'] = $reader->readObject();
		else:
			$result['from_id'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['peer'] = $reader->readObject();
		else:
			$result['peer'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['saved_id'] = $reader->readLong();
		else:
			$result['saved_id'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['resale_amount'] = $reader->readObject();
		else:
			$result['resale_amount'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['can_transfer_at'] = $reader->readInt();
		else:
			$result['can_transfer_at'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['can_resell_at'] = $reader->readInt();
		else:
			$result['can_resell_at'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['drop_original_details_stars'] = $reader->readLong();
		else:
			$result['drop_original_details_stars'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['can_craft_at'] = $reader->readInt();
		else:
			$result['can_craft_at'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SendMessageAction
 */

final class SendMessageRecordVideoAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa187d66f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int reply_to_msg_id int top_msg_id inputpeer reply_to_peer_id string quote_text Vector<messageentity> quote_entities int quote_offset inputpeer monoforum_peer_id int todo_item_id bytes poll_option
 * @return InputReplyTo
 */

final class InputReplyToMessage extends Instance {
	public function request(int $reply_to_msg_id,null | int $top_msg_id = null,null | object $reply_to_peer_id = null,null | string $quote_text = null,null | array $quote_entities = null,null | int $quote_offset = null,null | object $monoforum_peer_id = null,null | int $todo_item_id = null,null | string $poll_option = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3bd4b7c2);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$flags |= is_null($reply_to_peer_id) ? 0 : (1 << 1);
		$flags |= is_null($quote_text) ? 0 : (1 << 2);
		$flags |= is_null($quote_entities) ? 0 : (1 << 3);
		$flags |= is_null($quote_offset) ? 0 : (1 << 4);
		$flags |= is_null($monoforum_peer_id) ? 0 : (1 << 5);
		$flags |= is_null($todo_item_id) ? 0 : (1 << 6);
		$flags |= is_null($poll_option) ? 0 : (1 << 7);
		$writer->writeInt($flags);
		$writer->writeInt($reply_to_msg_id);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		if(is_null($reply_to_peer_id) === false):
			$writer->writeObject($reply_to_peer_id);
		endif;
		if(is_null($quote_text) === false):
			$writer->writeBytes($quote_text);
		endif;
		if(is_null($quote_entities) === false):
			$writer->writeVector($quote_entities,'messageentity');
		endif;
		if(is_null($quote_offset) === false):
			$writer->writeInt($quote_offset);
		endif;
		if(is_null($monoforum_peer_id) === false):
			$writer->writeObject($monoforum_peer_id);
		endif;
		if(is_null($todo_item_id) === false):
			$writer->writeInt($todo_item_id);
		endif;
		if(is_null($poll_option) === false):
			$writer->writeBytes($poll_option);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['reply_to_msg_id'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['top_msg_id'] = $reader->readInt();
		else:
			$result['top_msg_id'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['reply_to_peer_id'] = $reader->readObject();
		else:
			$result['reply_to_peer_id'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['quote_text'] = $reader->readBytes();
		else:
			$result['quote_text'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['quote_entities'] = $reader->readVector('messageentity');
		else:
			$result['quote_entities'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['quote_offset'] = $reader->readInt();
		else:
			$result['quote_offset'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['monoforum_peer_id'] = $reader->readObject();
		else:
			$result['monoforum_peer_id'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['todo_item_id'] = $reader->readInt();
		else:
			$result['todo_item_id'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['poll_option'] = $reader->readBytes();
		else:
			$result['poll_option'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text string url keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButtonUrl extends Instance {
	public function request(string $text,string $url,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd80c25ec);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param reaction reaction int count string title
 * @return SavedReactionTag
 */

final class SavedReactionTag extends Instance {
	public function request(object $reaction,int $count,null | string $title = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcb6ff828);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($reaction);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['reaction'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<int> messages int pts int pts_count
 * @return Update
 */

final class UpdateDeleteMessages extends Instance {
	public function request(array $messages,int $pts,int $pts_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa20db0e5);
		$writer->writeVector($messages,'int');
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['messages'] = $reader->readVector('int');
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyRule
 */

final class InputPrivacyValueDisallowBots extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc4e57915);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickerset stickerset long sticker_id Vector<int> background_colors
 * @return VideoSize
 */

final class VideoSizeStickerMarkup extends Instance {
	public function request(object $stickerset,int $sticker_id,array $background_colors) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xda082fe);
		$writer->writeObject($stickerset);
		$writer->writeLong($sticker_id);
		$writer->writeVector($background_colors,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['stickerset'] = $reader->readObject();
		$result['sticker_id'] = $reader->readLong();
		$result['background_colors'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string pq string p string q int128 nonce int128 server_nonce int256 new_nonce
 * @return P_Q_inner_data
 */

final class PQInnerData extends Instance {
	public function request(string $pq,string $p,string $q,int | string $nonce,int | string $server_nonce,int | string $new_nonce) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x83c95aec);
		$writer->writeBytes($pq);
		$writer->writeBytes($p);
		$writer->writeBytes($q);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeLargeInt($new_nonce,256);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pq'] = $reader->readBytes();
		$result['p'] = $reader->readBytes();
		$result['q'] = $reader->readBytes();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['new_nonce'] = $reader->readLargeInt(256);
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int months string currency long amount string bot_url true current true can_purchase_upgrade string transaction string store_product
 * @return PremiumSubscriptionOption
 */

final class PremiumSubscriptionOption extends Instance {
	public function request(int $months,string $currency,int $amount,string $bot_url,null | bool $current = null,null | bool $can_purchase_upgrade = null,null | string $transaction = null,null | string $store_product = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5f2d1df2);
		$flags = 0;
		$flags |= $current ? (1 << 1) : 0;
		$flags |= $can_purchase_upgrade ? (1 << 2) : 0;
		$flags |= is_null($transaction) ? 0 : (1 << 3);
		$flags |= is_null($store_product) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($transaction) === false):
			$writer->writeBytes($transaction);
		endif;
		$writer->writeInt($months);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		$writer->writeBytes($bot_url);
		if(is_null($store_product) === false):
			$writer->writeBytes($store_product);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['current'] = boolval($flags & (1 << 1));
		$result['can_purchase_upgrade'] = boolval($flags & (1 << 2));
		if($flags & (1 << 3)):
			$result['transaction'] = $reader->readBytes();
		else:
			$result['transaction'] = null;
		endif;
		$result['months'] = $reader->readInt();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		$result['bot_url'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['store_product'] = $reader->readBytes();
		else:
			$result['store_product'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return InputTheme
 */

final class InputThemeSlug extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf5890df1);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['slug'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bot_id botmenubutton button
 * @return Update
 */

final class UpdateBotMenuButton extends Instance {
	public function request(int $bot_id,object $button) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x14b85813);
		$writer->writeLong($bot_id);
		$writer->writeObject($button);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['bot_id'] = $reader->readLong();
		$result['button'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id textwithentities question Vector<pollanswer> answers long hash true closed true public_voters true multiple_choice true quiz true open_answers true revoting_disabled true shuffle_answers true hide_results_until_close true creator true subscribers_only int close_period int close_date Vector<string> countries_iso2
 * @return Poll
 */

final class Poll extends Instance {
	public function request(int $id,object $question,array $answers,int $hash,null | bool $closed = null,null | bool $public_voters = null,null | bool $multiple_choice = null,null | bool $quiz = null,null | bool $open_answers = null,null | bool $revoting_disabled = null,null | bool $shuffle_answers = null,null | bool $hide_results_until_close = null,null | bool $creator = null,null | bool $subscribers_only = null,null | int $close_period = null,null | int $close_date = null,null | array $countries_iso2 = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x966e2dbf);
		$writer->writeLong($id);
		$flags = 0;
		$flags |= $closed ? (1 << 0) : 0;
		$flags |= $public_voters ? (1 << 1) : 0;
		$flags |= $multiple_choice ? (1 << 2) : 0;
		$flags |= $quiz ? (1 << 3) : 0;
		$flags |= $open_answers ? (1 << 6) : 0;
		$flags |= $revoting_disabled ? (1 << 7) : 0;
		$flags |= $shuffle_answers ? (1 << 8) : 0;
		$flags |= $hide_results_until_close ? (1 << 9) : 0;
		$flags |= $creator ? (1 << 10) : 0;
		$flags |= $subscribers_only ? (1 << 11) : 0;
		$flags |= is_null($close_period) ? 0 : (1 << 4);
		$flags |= is_null($close_date) ? 0 : (1 << 5);
		$flags |= is_null($countries_iso2) ? 0 : (1 << 12);
		$writer->writeInt($flags);
		$writer->writeObject($question);
		$writer->writeVector($answers,'pollanswer');
		if(is_null($close_period) === false):
			$writer->writeInt($close_period);
		endif;
		if(is_null($close_date) === false):
			$writer->writeInt($close_date);
		endif;
		if(is_null($countries_iso2) === false):
			$writer->writeVector($countries_iso2,'string');
		endif;
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$flags = $reader->readInt();
		$result['closed'] = boolval($flags & (1 << 0));
		$result['public_voters'] = boolval($flags & (1 << 1));
		$result['multiple_choice'] = boolval($flags & (1 << 2));
		$result['quiz'] = boolval($flags & (1 << 3));
		$result['open_answers'] = boolval($flags & (1 << 6));
		$result['revoting_disabled'] = boolval($flags & (1 << 7));
		$result['shuffle_answers'] = boolval($flags & (1 << 8));
		$result['hide_results_until_close'] = boolval($flags & (1 << 9));
		$result['creator'] = boolval($flags & (1 << 10));
		$result['subscribers_only'] = boolval($flags & (1 << 11));
		$result['question'] = $reader->readObject();
		$result['answers'] = $reader->readVector('pollanswer');
		if($flags & (1 << 4)):
			$result['close_period'] = $reader->readInt();
		else:
			$result['close_period'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['close_date'] = $reader->readInt();
		else:
			$result['close_date'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['countries_iso2'] = $reader->readVector('string');
		else:
			$result['countries_iso2'] = null;
		endif;
		$result['hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputGeoPoint
 */

final class InputGeoPointEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe4c123d6);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputTheme
 */

final class InputTheme extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3c5693e9);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string hash
 * @return InputInvoice
 */

final class InputInvoiceChatInviteSubscription extends Instance {
	public function request(string $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x34e793f1);
		$writer->writeBytes($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stickerset set document cover
 * @return StickerSetCovered
 */

final class StickerSetCovered extends Instance {
	public function request(object $set,object $cover) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6410a5d2);
		$writer->writeObject($set);
		$writer->writeObject($cover);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['set'] = $reader->readObject();
		$result['cover'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes random_id peer peer string sponsor_info string additional_info
 * @return SponsoredPeer
 */

final class SponsoredPeer extends Instance {
	public function request(string $random_id,object $peer,null | string $sponsor_info = null,null | string $additional_info = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc69708d3);
		$flags = 0;
		$flags |= is_null($sponsor_info) ? 0 : (1 << 0);
		$flags |= is_null($additional_info) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($random_id);
		$writer->writeObject($peer);
		if(is_null($sponsor_info) === false):
			$writer->writeBytes($sponsor_info);
		endif;
		if(is_null($additional_info) === false):
			$writer->writeBytes($additional_info);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['random_id'] = $reader->readBytes();
		$result['peer'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['sponsor_info'] = $reader->readBytes();
		else:
			$result['sponsor_info'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['additional_info'] = $reader->readBytes();
		else:
			$result['additional_info'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return EmailVerifyPurpose
 */

final class EmailVerifyPurposePassport extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbbf51685);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id int date long actor_id long user_id int qts true via_chatlist channelparticipant prev_participant channelparticipant new_participant exportedchatinvite invite
 * @return Update
 */

final class UpdateChannelParticipant extends Instance {
	public function request(int $channel_id,int $date,int $actor_id,int $user_id,int $qts,null | bool $via_chatlist = null,null | object $prev_participant = null,null | object $new_participant = null,null | object $invite = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x985d3abb);
		$flags = 0;
		$flags |= $via_chatlist ? (1 << 3) : 0;
		$flags |= is_null($prev_participant) ? 0 : (1 << 0);
		$flags |= is_null($new_participant) ? 0 : (1 << 1);
		$flags |= is_null($invite) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($channel_id);
		$writer->writeInt($date);
		$writer->writeLong($actor_id);
		$writer->writeLong($user_id);
		if(is_null($prev_participant) === false):
			$writer->writeObject($prev_participant);
		endif;
		if(is_null($new_participant) === false):
			$writer->writeObject($new_participant);
		endif;
		if(is_null($invite) === false):
			$writer->writeObject($invite);
		endif;
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['via_chatlist'] = boolval($flags & (1 << 3));
		$result['channel_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['actor_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['prev_participant'] = $reader->readObject();
		else:
			$result['prev_participant'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['new_participant'] = $reader->readObject();
		else:
			$result['new_participant'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['invite'] = $reader->readObject();
		else:
			$result['invite'] = null;
		endif;
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title Vector<messagereportoption> options
 * @return ReportResult
 */

final class ReportResultChooseOption extends Instance {
	public function request(string $title,array $options) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf0e4e0b6);
		$writer->writeBytes($title);
		$writer->writeVector($options,'messagereportoption');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readBytes();
		$result['options'] = $reader->readVector('messagereportoption');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date int min_msg_id int max_msg_id int count
 * @return SearchResultsCalendarPeriod
 */

final class SearchResultsCalendarPeriod extends Instance {
	public function request(int $date,int $min_msg_id,int $max_msg_id,int $count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc9b0539f);
		$writer->writeInt($date);
		$writer->writeInt($min_msg_id);
		$writer->writeInt($max_msg_id);
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['date'] = $reader->readInt();
		$result['min_msg_id'] = $reader->readInt();
		$result['max_msg_id'] = $reader->readInt();
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bad_msg_id int bad_msg_seqno int error_code long new_server_salt
 * @return BadMsgNotification
 */

final class BadServerSalt extends Instance {
	public function request(int $bad_msg_id,int $bad_msg_seqno,int $error_code,int $new_server_salt) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xedab447b);
		$writer->writeLong($bad_msg_id);
		$writer->writeInt($bad_msg_seqno);
		$writer->writeInt($error_code);
		$writer->writeLong($new_server_salt);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['bad_msg_id'] = $reader->readLong();
		$result['bad_msg_seqno'] = $reader->readInt();
		$result['error_code'] = $reader->readInt();
		$result['new_server_salt'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id int parts string name string md5_checksum
 * @return InputFile
 */

final class InputFile extends Instance {
	public function request(int $id,int $parts,string $name,string $md5_checksum) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf52ff27f);
		$writer->writeLong($id);
		$writer->writeInt($parts);
		$writer->writeBytes($name);
		$writer->writeBytes($md5_checksum);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['parts'] = $reader->readInt();
		$result['name'] = $reader->readBytes();
		$result['md5_checksum'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id Vector<int> messages
 * @return Update
 */

final class UpdateDeleteQuickReplyMessages extends Instance {
	public function request(int $shortcut_id,array $messages) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x566fe7cd);
		$writer->writeInt($shortcut_id);
		$writer->writeVector($messages,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['shortcut_id'] = $reader->readInt();
		$result['messages'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id true premium_would_allow_invite true premium_required_for_pm
 * @return MissingInvitee
 */

final class MissingInvitee extends Instance {
	public function request(int $user_id,null | bool $premium_would_allow_invite = null,null | bool $premium_required_for_pm = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x628c9224);
		$flags = 0;
		$flags |= $premium_would_allow_invite ? (1 << 0) : 0;
		$flags |= $premium_required_for_pm ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['premium_would_allow_invite'] = boolval($flags & (1 << 0));
		$result['premium_required_for_pm'] = boolval($flags & (1 << 1));
		$result['user_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id long access_hash int date long admin_id long participant_id
 * @return EncryptedChat
 */

final class EncryptedChatWaiting extends Instance {
	public function request(int $id,int $access_hash,int $date,int $admin_id,int $participant_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x66b25953);
		$writer->writeInt($id);
		$writer->writeLong($access_hash);
		$writer->writeInt($date);
		$writer->writeLong($admin_id);
		$writer->writeLong($participant_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		$result['access_hash'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['admin_id'] = $reader->readLong();
		$result['participant_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id
 * @return Update
 */

final class UpdateChannel extends Instance {
	public function request(int $channel_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x635b4c09);
		$writer->writeLong($channel_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id string title true autofill_new_broadcasts true autofill_public_groups true autofill_new_correspondents chatphoto photo
 * @return Folder
 */

final class Folder extends Instance {
	public function request(int $id,string $title,null | bool $autofill_new_broadcasts = null,null | bool $autofill_public_groups = null,null | bool $autofill_new_correspondents = null,null | object $photo = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xff544e65);
		$flags = 0;
		$flags |= $autofill_new_broadcasts ? (1 << 0) : 0;
		$flags |= $autofill_public_groups ? (1 << 1) : 0;
		$flags |= $autofill_new_correspondents ? (1 << 2) : 0;
		$flags |= is_null($photo) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeBytes($title);
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['autofill_new_broadcasts'] = boolval($flags & (1 << 0));
		$result['autofill_public_groups'] = boolval($flags & (1 << 1));
		$result['autofill_new_correspondents'] = boolval($flags & (1 << 2));
		$result['id'] = $reader->readInt();
		$result['title'] = $reader->readBytes();
		if($flags & (1 << 3)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call Vector<int> messages
 * @return Update
 */

final class UpdateDeleteGroupCallMessages extends Instance {
	public function request(object $call,array $messages) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e85e92c);
		$writer->writeObject($call);
		$writer->writeVector($messages,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['call'] = $reader->readObject();
		$result['messages'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone
 * @return InputCollectible
 */

final class InputCollectiblePhone extends Instance {
	public function request(string $phone) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa2e214a4);
		$writer->writeBytes($phone);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgeopoint geo_point long access_hash int w int h int zoom int scale
 * @return InputWebFileLocation
 */

final class InputWebFileGeoPointLocation extends Instance {
	public function request(object $geo_point,int $access_hash,int $w,int $h,int $zoom,int $scale) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9f2221c9);
		$writer->writeObject($geo_point);
		$writer->writeLong($access_hash);
		$writer->writeInt($w);
		$writer->writeInt($h);
		$writer->writeInt($zoom);
		$writer->writeInt($scale);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['geo_point'] = $reader->readObject();
		$result['access_hash'] = $reader->readLong();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		$result['zoom'] = $reader->readInt();
		$result['scale'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int onlines
 * @return ChatOnlines
 */

final class ChatOnlines extends Instance {
	public function request(int $onlines) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf041e250);
		$writer->writeInt($onlines);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['onlines'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long random_id inputrichmessage rich_message
 * @return SendMessageAction
 */

final class InputSendMessageRichMessageDraftAction extends Instance {
	public function request(int $random_id,object $rich_message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe2b23b51);
		$writer->writeLong($random_id);
		$writer->writeObject($rich_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['random_id'] = $reader->readLong();
		$result['rich_message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateSavedReactionTags extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x39c67432);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int msg_id int views int forwards int reactions
 * @return PostInteractionCounters
 */

final class PostInteractionCountersMessage extends Instance {
	public function request(int $msg_id,int $views,int $forwards,int $reactions) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe7058e7f);
		$writer->writeInt($msg_id);
		$writer->writeInt($views);
		$writer->writeInt($forwards);
		$writer->writeInt($reactions);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_id'] = $reader->readInt();
		$result['views'] = $reader->readInt();
		$result['forwards'] = $reader->readInt();
		$result['reactions'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars true broadcast_messages_allowed
 * @return MessageAction
 */

final class MessageActionPaidMessagesPrice extends Instance {
	public function request(int $stars,null | bool $broadcast_messages_allowed = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x84b88578);
		$flags = 0;
		$flags |= $broadcast_messages_allowed ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($stars);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['broadcast_messages_allowed'] = boolval($flags & (1 << 0));
		$result['stars'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<folderpeer> folder_peers int pts int pts_count
 * @return Update
 */

final class UpdateFolderPeers extends Instance {
	public function request(array $folder_peers,int $pts,int $pts_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x19360dc0);
		$writer->writeVector($folder_peers,'folderpeer');
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['folder_peers'] = $reader->readVector('folderpeer');
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param wallpaper prev_value wallpaper new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeWallpaper extends Instance {
	public function request(object $prev_value,object $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31bb5d52);
		$writer->writeObject($prev_value);
		$writer->writeObject($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readObject();
		$result['new_value'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string type int w int h bytes bytes
 * @return PhotoSize
 */

final class PhotoCachedSize extends Instance {
	public function request(string $type,int $w,int $h,string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x21e1ad6);
		$writer->writeBytes($type);
		$writer->writeInt($w);
		$writer->writeInt($h);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readBytes();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		$result['bytes'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long document_id
 * @return StarGiftAttributeId
 */

final class StarGiftAttributeIdModel extends Instance {
	public function request(int $document_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x48aaae3c);
		$writer->writeLong($document_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['document_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length true collapsed
 * @return MessageEntity
 */

final class MessageEntityBlockquote extends Instance {
	public function request(int $offset,int $length,null | bool $collapsed = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf1ccaaac);
		$flags = 0;
		$flags |= $collapsed ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['collapsed'] = boolval($flags & (1 << 0));
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text string url
 * @return InlineBotWebView
 */

final class InlineBotWebView extends Instance {
	public function request(string $text,string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb57295d5);
		$writer->writeBytes($text);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readBytes();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url true spoiler int ttl_seconds inputphoto video_cover int video_timestamp
 * @return InputMedia
 */

final class InputMediaDocumentExternal extends Instance {
	public function request(string $url,null | bool $spoiler = null,null | int $ttl_seconds = null,null | object $video_cover = null,null | int $video_timestamp = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x779600f9);
		$flags = 0;
		$flags |= $spoiler ? (1 << 1) : 0;
		$flags |= is_null($ttl_seconds) ? 0 : (1 << 0);
		$flags |= is_null($video_cover) ? 0 : (1 << 2);
		$flags |= is_null($video_timestamp) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeBytes($url);
		if(is_null($ttl_seconds) === false):
			$writer->writeInt($ttl_seconds);
		endif;
		if(is_null($video_cover) === false):
			$writer->writeObject($video_cover);
		endif;
		if(is_null($video_timestamp) === false):
			$writer->writeInt($video_timestamp);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['spoiler'] = boolval($flags & (1 << 1));
		$result['url'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['ttl_seconds'] = $reader->readInt();
		else:
			$result['ttl_seconds'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['video_cover'] = $reader->readObject();
		else:
			$result['video_cover'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['video_timestamp'] = $reader->readInt();
		else:
			$result['video_timestamp'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text bytes option
 * @return MessageReportOption
 */

final class MessageReportOption extends Instance {
	public function request(string $text,string $option) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7903e3d9);
		$writer->writeBytes($text);
		$writer->writeBytes($option);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readBytes();
		$result['option'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param channelparticipant prev_participant channelparticipant new_participant
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantSubExtend extends Instance {
	public function request(object $prev_participant,object $new_participant) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x64642db3);
		$writer->writeObject($prev_participant);
		$writer->writeObject($new_participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_participant'] = $reader->readObject();
		$result['new_participant'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count long stars
 * @return MessageAction
 */

final class MessageActionPaidMessagesRefunded extends Instance {
	public function request(int $count,int $stars) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xac1f1fcd);
		$writer->writeInt($count);
		$writer->writeLong($stars);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count'] = $reader->readInt();
		$result['stars'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int slot int date int expires peer peer int cooldown_until_date
 * @return MyBoost
 */

final class MyBoost extends Instance {
	public function request(int $slot,int $date,int $expires,null | object $peer = null,null | int $cooldown_until_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc448415c);
		$flags = 0;
		$flags |= is_null($peer) ? 0 : (1 << 0);
		$flags |= is_null($cooldown_until_date) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeInt($slot);
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		$writer->writeInt($date);
		$writer->writeInt($expires);
		if(is_null($cooldown_until_date) === false):
			$writer->writeInt($cooldown_until_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['slot'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['peer'] = $reader->readObject();
		else:
			$result['peer'] = null;
		endif;
		$result['date'] = $reader->readInt();
		$result['expires'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['cooldown_until_date'] = $reader->readInt();
		else:
			$result['cooldown_until_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ProfileTab
 */

final class ProfileTabGifts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4d4bd46a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int album_id string title photo icon_photo document icon_video
 * @return StoryAlbum
 */

final class StoryAlbum extends Instance {
	public function request(int $album_id,string $title,null | object $icon_photo = null,null | object $icon_video = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9325705a);
		$flags = 0;
		$flags |= is_null($icon_photo) ? 0 : (1 << 0);
		$flags |= is_null($icon_video) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeInt($album_id);
		$writer->writeBytes($title);
		if(is_null($icon_photo) === false):
			$writer->writeObject($icon_photo);
		endif;
		if(is_null($icon_video) === false):
			$writer->writeObject($icon_video);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['album_id'] = $reader->readInt();
		$result['title'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['icon_photo'] = $reader->readObject();
		else:
			$result['icon_photo'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['icon_video'] = $reader->readObject();
		else:
			$result['icon_video'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int msg_id
 * @return InputGroupCall
 */

final class InputGroupCallInviteMessage extends Instance {
	public function request(int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c10603f);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputFileLocation
 */

final class InputTakeoutFileLocation extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x29be5899);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputDocument
 */

final class InputDocumentEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x72f0eaae);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title
 * @return MessageAction
 */

final class MessageActionChatEditTitle extends Instance {
	public function request(string $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb5a1ce5a);
		$writer->writeBytes($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text true checkbox true checked string num int value string type
 * @return PageListOrderedItem
 */

final class PageListOrderedItemText extends Instance {
	public function request(object $text,null | bool $checkbox = null,null | bool $checked = null,null | string $num = null,null | int $value = null,null | string $type = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x15031189);
		$flags = 0;
		$flags |= $checkbox ? (1 << 0) : 0;
		$flags |= $checked ? (1 << 1) : 0;
		$flags |= is_null($num) ? 0 : (1 << 2);
		$flags |= is_null($value) ? 0 : (1 << 3);
		$flags |= is_null($type) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		if(is_null($num) === false):
			$writer->writeBytes($num);
		endif;
		$writer->writeObject($text);
		if(is_null($value) === false):
			$writer->writeInt($value);
		endif;
		if(is_null($type) === false):
			$writer->writeBytes($type);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['checkbox'] = boolval($flags & (1 << 0));
		$result['checked'] = boolval($flags & (1 << 1));
		if($flags & (1 << 2)):
			$result['num'] = $reader->readBytes();
		else:
			$result['num'] = null;
		endif;
		$result['text'] = $reader->readObject();
		if($flags & (1 << 3)):
			$result['value'] = $reader->readInt();
		else:
			$result['value'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['type'] = $reader->readBytes();
		else:
			$result['type'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyRule
 */

final class InputPrivacyValueDisallowContacts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xba52007);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long gift_id string title string slug int num Vector<stargiftattribute> attributes int availability_issued int availability_total true require_premium true resale_ton_only true theme_available true burned true crafted peer owner_id string owner_name string owner_address string gift_address Vector<starsamount> resell_amount peer released_by long value_amount string value_currency long value_usd_amount peer theme_peer peercolor peer_color peer host_id int offer_min_stars int craft_chance_permille
 * @return StarGift
 */

final class StarGiftUnique extends Instance {
	public function request(int $id,int $gift_id,string $title,string $slug,int $num,array $attributes,int $availability_issued,int $availability_total,null | bool $require_premium = null,null | bool $resale_ton_only = null,null | bool $theme_available = null,null | bool $burned = null,null | bool $crafted = null,null | object $owner_id = null,null | string $owner_name = null,null | string $owner_address = null,null | string $gift_address = null,null | array $resell_amount = null,null | object $released_by = null,null | int $value_amount = null,null | string $value_currency = null,null | int $value_usd_amount = null,null | object $theme_peer = null,null | object $peer_color = null,null | object $host_id = null,null | int $offer_min_stars = null,null | int $craft_chance_permille = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x85f0a9cd);
		$flags = 0;
		$flags |= $require_premium ? (1 << 6) : 0;
		$flags |= $resale_ton_only ? (1 << 7) : 0;
		$flags |= $theme_available ? (1 << 9) : 0;
		$flags |= $burned ? (1 << 14) : 0;
		$flags |= $crafted ? (1 << 15) : 0;
		$flags |= is_null($owner_id) ? 0 : (1 << 0);
		$flags |= is_null($owner_name) ? 0 : (1 << 1);
		$flags |= is_null($owner_address) ? 0 : (1 << 2);
		$flags |= is_null($gift_address) ? 0 : (1 << 3);
		$flags |= is_null($resell_amount) ? 0 : (1 << 4);
		$flags |= is_null($released_by) ? 0 : (1 << 5);
		$flags |= is_null($value_amount) ? 0 : (1 << 8);
		$flags |= is_null($value_currency) ? 0 : (1 << 8);
		$flags |= is_null($value_usd_amount) ? 0 : (1 << 8);
		$flags |= is_null($theme_peer) ? 0 : (1 << 10);
		$flags |= is_null($peer_color) ? 0 : (1 << 11);
		$flags |= is_null($host_id) ? 0 : (1 << 12);
		$flags |= is_null($offer_min_stars) ? 0 : (1 << 13);
		$flags |= is_null($craft_chance_permille) ? 0 : (1 << 16);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($gift_id);
		$writer->writeBytes($title);
		$writer->writeBytes($slug);
		$writer->writeInt($num);
		if(is_null($owner_id) === false):
			$writer->writeObject($owner_id);
		endif;
		if(is_null($owner_name) === false):
			$writer->writeBytes($owner_name);
		endif;
		if(is_null($owner_address) === false):
			$writer->writeBytes($owner_address);
		endif;
		$writer->writeVector($attributes,'stargiftattribute');
		$writer->writeInt($availability_issued);
		$writer->writeInt($availability_total);
		if(is_null($gift_address) === false):
			$writer->writeBytes($gift_address);
		endif;
		if(is_null($resell_amount) === false):
			$writer->writeVector($resell_amount,'starsamount');
		endif;
		if(is_null($released_by) === false):
			$writer->writeObject($released_by);
		endif;
		if(is_null($value_amount) === false):
			$writer->writeLong($value_amount);
		endif;
		if(is_null($value_currency) === false):
			$writer->writeBytes($value_currency);
		endif;
		if(is_null($value_usd_amount) === false):
			$writer->writeLong($value_usd_amount);
		endif;
		if(is_null($theme_peer) === false):
			$writer->writeObject($theme_peer);
		endif;
		if(is_null($peer_color) === false):
			$writer->writeObject($peer_color);
		endif;
		if(is_null($host_id) === false):
			$writer->writeObject($host_id);
		endif;
		if(is_null($offer_min_stars) === false):
			$writer->writeInt($offer_min_stars);
		endif;
		if(is_null($craft_chance_permille) === false):
			$writer->writeInt($craft_chance_permille);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['require_premium'] = boolval($flags & (1 << 6));
		$result['resale_ton_only'] = boolval($flags & (1 << 7));
		$result['theme_available'] = boolval($flags & (1 << 9));
		$result['burned'] = boolval($flags & (1 << 14));
		$result['crafted'] = boolval($flags & (1 << 15));
		$result['id'] = $reader->readLong();
		$result['gift_id'] = $reader->readLong();
		$result['title'] = $reader->readBytes();
		$result['slug'] = $reader->readBytes();
		$result['num'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['owner_id'] = $reader->readObject();
		else:
			$result['owner_id'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['owner_name'] = $reader->readBytes();
		else:
			$result['owner_name'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['owner_address'] = $reader->readBytes();
		else:
			$result['owner_address'] = null;
		endif;
		$result['attributes'] = $reader->readVector('stargiftattribute');
		$result['availability_issued'] = $reader->readInt();
		$result['availability_total'] = $reader->readInt();
		if($flags & (1 << 3)):
			$result['gift_address'] = $reader->readBytes();
		else:
			$result['gift_address'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['resell_amount'] = $reader->readVector('starsamount');
		else:
			$result['resell_amount'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['released_by'] = $reader->readObject();
		else:
			$result['released_by'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['value_amount'] = $reader->readLong();
		else:
			$result['value_amount'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['value_currency'] = $reader->readBytes();
		else:
			$result['value_currency'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['value_usd_amount'] = $reader->readLong();
		else:
			$result['value_usd_amount'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['theme_peer'] = $reader->readObject();
		else:
			$result['theme_peer'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['peer_color'] = $reader->readObject();
		else:
			$result['peer_color'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['host_id'] = $reader->readObject();
		else:
			$result['host_id'] = null;
		endif;
		if($flags & (1 << 13)):
			$result['offer_min_stars'] = $reader->readInt();
		else:
			$result['offer_min_stars'] = null;
		endif;
		if($flags & (1 << 16)):
			$result['craft_chance_permille'] = $reader->readInt();
		else:
			$result['craft_chance_permille'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionDiscardGroupCall extends Instance {
	public function request(object $call) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdb9f9140);
		$writer->writeObject($call);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['call'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count true top true my true anonymous peer peer_id
 * @return MessageReactor
 */

final class MessageReactor extends Instance {
	public function request(int $count,null | bool $top = null,null | bool $my = null,null | bool $anonymous = null,null | object $peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4ba3a95a);
		$flags = 0;
		$flags |= $top ? (1 << 0) : 0;
		$flags |= $my ? (1 << 1) : 0;
		$flags |= $anonymous ? (1 << 2) : 0;
		$flags |= is_null($peer_id) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($peer_id) === false):
			$writer->writeObject($peer_id);
		endif;
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['top'] = boolval($flags & (1 << 0));
		$result['my'] = boolval($flags & (1 << 1));
		$result['anonymous'] = boolval($flags & (1 << 2));
		if($flags & (1 << 3)):
			$result['peer_id'] = $reader->readObject();
		else:
			$result['peer_id'] = null;
		endif;
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyNoPaidMessages extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x17d348d2);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InlineQueryPeerType
 */

final class InlineQueryPeerTypeBotPM extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe3b2d0c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message
 * @return Update
 */

final class UpdateNewScheduledMessage extends Instance {
	public function request(object $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x39a51dfb);
		$writer->writeObject($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityUrl extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6ed02538);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id
 * @return Peer
 */

final class PeerChannel extends Instance {
	public function request(int $channel_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa2a5371e);
		$writer->writeLong($channel_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true spoiler true live_photo photo photo int ttl_seconds document video
 * @return MessageMedia
 */

final class MessageMediaPhoto extends Instance {
	public function request(null | bool $spoiler = null,null | bool $live_photo = null,null | object $photo = null,null | int $ttl_seconds = null,null | object $video = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe216eb63);
		$flags = 0;
		$flags |= $spoiler ? (1 << 3) : 0;
		$flags |= $live_photo ? (1 << 4) : 0;
		$flags |= is_null($photo) ? 0 : (1 << 0);
		$flags |= is_null($ttl_seconds) ? 0 : (1 << 2);
		$flags |= is_null($video) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		if(is_null($ttl_seconds) === false):
			$writer->writeInt($ttl_seconds);
		endif;
		if(is_null($video) === false):
			$writer->writeObject($video);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['spoiler'] = boolval($flags & (1 << 3));
		$result['live_photo'] = boolval($flags & (1 << 4));
		if($flags & (1 << 0)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['ttl_seconds'] = $reader->readInt();
		else:
			$result['ttl_seconds'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['video'] = $reader->readObject();
		else:
			$result['video'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButtonRequestGeoLocation extends Instance {
	public function request(string $text,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaa40f94d);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title string description string currency long total_amount true shipping_address_requested true test webdocument photo replymarkup reply_markup
 * @return BotInlineMessage
 */

final class BotInlineMessageMediaInvoice extends Instance {
	public function request(string $title,string $description,string $currency,int $total_amount,null | bool $shipping_address_requested = null,null | bool $test = null,null | object $photo = null,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x354a9b09);
		$flags = 0;
		$flags |= $shipping_address_requested ? (1 << 1) : 0;
		$flags |= $test ? (1 << 3) : 0;
		$flags |= is_null($photo) ? 0 : (1 << 0);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		$writer->writeBytes($currency);
		$writer->writeLong($total_amount);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['shipping_address_requested'] = boolval($flags & (1 << 1));
		$result['test'] = boolval($flags & (1 << 3));
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		$result['currency'] = $reader->readBytes();
		$result['total_amount'] = $reader->readLong();
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param todolist todo
 * @return InputMedia
 */

final class InputMediaTodo extends Instance {
	public function request(object $todo) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9fc55fde);
		$writer->writeObject($todo);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['todo'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int start_date int end_date
 * @return BusinessAwayMessageSchedule
 */

final class BusinessAwayMessageScheduleCustom extends Instance {
	public function request(int $start_date,int $end_date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcc4d9ecc);
		$writer->writeInt($start_date);
		$writer->writeInt($end_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['start_date'] = $reader->readInt();
		$result['end_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextSubscript extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xed6a8504);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash string title string short_name int count int hash true archived true official true masks true emojis true text_color true channel_emoji_status true creator int installed_date Vector<photosize> thumbs int thumb_dc_id int thumb_version long thumb_document_id
 * @return StickerSet
 */

final class StickerSet extends Instance {
	public function request(int $id,int $access_hash,string $title,string $short_name,int $count,int $hash,null | bool $archived = null,null | bool $official = null,null | bool $masks = null,null | bool $emojis = null,null | bool $text_color = null,null | bool $channel_emoji_status = null,null | bool $creator = null,null | int $installed_date = null,null | array $thumbs = null,null | int $thumb_dc_id = null,null | int $thumb_version = null,null | int $thumb_document_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2dd14edc);
		$flags = 0;
		$flags |= $archived ? (1 << 1) : 0;
		$flags |= $official ? (1 << 2) : 0;
		$flags |= $masks ? (1 << 3) : 0;
		$flags |= $emojis ? (1 << 7) : 0;
		$flags |= $text_color ? (1 << 9) : 0;
		$flags |= $channel_emoji_status ? (1 << 10) : 0;
		$flags |= $creator ? (1 << 11) : 0;
		$flags |= is_null($installed_date) ? 0 : (1 << 0);
		$flags |= is_null($thumbs) ? 0 : (1 << 4);
		$flags |= is_null($thumb_dc_id) ? 0 : (1 << 4);
		$flags |= is_null($thumb_version) ? 0 : (1 << 4);
		$flags |= is_null($thumb_document_id) ? 0 : (1 << 8);
		$writer->writeInt($flags);
		if(is_null($installed_date) === false):
			$writer->writeInt($installed_date);
		endif;
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($title);
		$writer->writeBytes($short_name);
		if(is_null($thumbs) === false):
			$writer->writeVector($thumbs,'photosize');
		endif;
		if(is_null($thumb_dc_id) === false):
			$writer->writeInt($thumb_dc_id);
		endif;
		if(is_null($thumb_version) === false):
			$writer->writeInt($thumb_version);
		endif;
		if(is_null($thumb_document_id) === false):
			$writer->writeLong($thumb_document_id);
		endif;
		$writer->writeInt($count);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['archived'] = boolval($flags & (1 << 1));
		$result['official'] = boolval($flags & (1 << 2));
		$result['masks'] = boolval($flags & (1 << 3));
		$result['emojis'] = boolval($flags & (1 << 7));
		$result['text_color'] = boolval($flags & (1 << 9));
		$result['channel_emoji_status'] = boolval($flags & (1 << 10));
		$result['creator'] = boolval($flags & (1 << 11));
		if($flags & (1 << 0)):
			$result['installed_date'] = $reader->readInt();
		else:
			$result['installed_date'] = null;
		endif;
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['title'] = $reader->readBytes();
		$result['short_name'] = $reader->readBytes();
		if($flags & (1 << 4)):
			$result['thumbs'] = $reader->readVector('photosize');
		else:
			$result['thumbs'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['thumb_dc_id'] = $reader->readInt();
		else:
			$result['thumb_dc_id'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['thumb_version'] = $reader->readInt();
		else:
			$result['thumb_version'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['thumb_document_id'] = $reader->readLong();
		else:
			$result['thumb_document_id'] = null;
		endif;
		$result['count'] = $reader->readInt();
		$result['hash'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyVoiceMessages extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaee69d68);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash string short_name string title string description photo photo long hash document document
 * @return BotApp
 */

final class BotApp extends Instance {
	public function request(int $id,int $access_hash,string $short_name,string $title,string $description,object $photo,int $hash,null | object $document = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x95fcd1d6);
		$flags = 0;
		$flags |= is_null($document) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($short_name);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		$writer->writeObject($photo);
		if(is_null($document) === false):
			$writer->writeObject($document);
		endif;
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['short_name'] = $reader->readBytes();
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		$result['photo'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['document'] = $reader->readObject();
		else:
			$result['document'] = null;
		endif;
		$result['hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int story_id
 * @return InputReplyTo
 */

final class InputReplyToStory extends Instance {
	public function request(object $peer,int $story_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5881323a);
		$writer->writeObject($peer);
		$writer->writeInt($story_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['story_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true report_spam true add_contact true block_contact true share_contact true need_contacts_exception true report_geo true autoarchived true invite_members true request_chat_broadcast true business_bot_paused true business_bot_can_reply int geo_distance string request_chat_title int request_chat_date long business_bot_id string business_bot_manage_url long charge_paid_message_stars string registration_month string phone_country int name_change_date int photo_change_date
 * @return PeerSettings
 */

final class PeerSettings extends Instance {
	public function request(null | bool $report_spam = null,null | bool $add_contact = null,null | bool $block_contact = null,null | bool $share_contact = null,null | bool $need_contacts_exception = null,null | bool $report_geo = null,null | bool $autoarchived = null,null | bool $invite_members = null,null | bool $request_chat_broadcast = null,null | bool $business_bot_paused = null,null | bool $business_bot_can_reply = null,null | int $geo_distance = null,null | string $request_chat_title = null,null | int $request_chat_date = null,null | int $business_bot_id = null,null | string $business_bot_manage_url = null,null | int $charge_paid_message_stars = null,null | string $registration_month = null,null | string $phone_country = null,null | int $name_change_date = null,null | int $photo_change_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf47741f7);
		$flags = 0;
		$flags |= $report_spam ? (1 << 0) : 0;
		$flags |= $add_contact ? (1 << 1) : 0;
		$flags |= $block_contact ? (1 << 2) : 0;
		$flags |= $share_contact ? (1 << 3) : 0;
		$flags |= $need_contacts_exception ? (1 << 4) : 0;
		$flags |= $report_geo ? (1 << 5) : 0;
		$flags |= $autoarchived ? (1 << 7) : 0;
		$flags |= $invite_members ? (1 << 8) : 0;
		$flags |= $request_chat_broadcast ? (1 << 10) : 0;
		$flags |= $business_bot_paused ? (1 << 11) : 0;
		$flags |= $business_bot_can_reply ? (1 << 12) : 0;
		$flags |= is_null($geo_distance) ? 0 : (1 << 6);
		$flags |= is_null($request_chat_title) ? 0 : (1 << 9);
		$flags |= is_null($request_chat_date) ? 0 : (1 << 9);
		$flags |= is_null($business_bot_id) ? 0 : (1 << 13);
		$flags |= is_null($business_bot_manage_url) ? 0 : (1 << 13);
		$flags |= is_null($charge_paid_message_stars) ? 0 : (1 << 14);
		$flags |= is_null($registration_month) ? 0 : (1 << 15);
		$flags |= is_null($phone_country) ? 0 : (1 << 16);
		$flags |= is_null($name_change_date) ? 0 : (1 << 17);
		$flags |= is_null($photo_change_date) ? 0 : (1 << 18);
		$writer->writeInt($flags);
		if(is_null($geo_distance) === false):
			$writer->writeInt($geo_distance);
		endif;
		if(is_null($request_chat_title) === false):
			$writer->writeBytes($request_chat_title);
		endif;
		if(is_null($request_chat_date) === false):
			$writer->writeInt($request_chat_date);
		endif;
		if(is_null($business_bot_id) === false):
			$writer->writeLong($business_bot_id);
		endif;
		if(is_null($business_bot_manage_url) === false):
			$writer->writeBytes($business_bot_manage_url);
		endif;
		if(is_null($charge_paid_message_stars) === false):
			$writer->writeLong($charge_paid_message_stars);
		endif;
		if(is_null($registration_month) === false):
			$writer->writeBytes($registration_month);
		endif;
		if(is_null($phone_country) === false):
			$writer->writeBytes($phone_country);
		endif;
		if(is_null($name_change_date) === false):
			$writer->writeInt($name_change_date);
		endif;
		if(is_null($photo_change_date) === false):
			$writer->writeInt($photo_change_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['report_spam'] = boolval($flags & (1 << 0));
		$result['add_contact'] = boolval($flags & (1 << 1));
		$result['block_contact'] = boolval($flags & (1 << 2));
		$result['share_contact'] = boolval($flags & (1 << 3));
		$result['need_contacts_exception'] = boolval($flags & (1 << 4));
		$result['report_geo'] = boolval($flags & (1 << 5));
		$result['autoarchived'] = boolval($flags & (1 << 7));
		$result['invite_members'] = boolval($flags & (1 << 8));
		$result['request_chat_broadcast'] = boolval($flags & (1 << 10));
		$result['business_bot_paused'] = boolval($flags & (1 << 11));
		$result['business_bot_can_reply'] = boolval($flags & (1 << 12));
		if($flags & (1 << 6)):
			$result['geo_distance'] = $reader->readInt();
		else:
			$result['geo_distance'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['request_chat_title'] = $reader->readBytes();
		else:
			$result['request_chat_title'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['request_chat_date'] = $reader->readInt();
		else:
			$result['request_chat_date'] = null;
		endif;
		if($flags & (1 << 13)):
			$result['business_bot_id'] = $reader->readLong();
		else:
			$result['business_bot_id'] = null;
		endif;
		if($flags & (1 << 13)):
			$result['business_bot_manage_url'] = $reader->readBytes();
		else:
			$result['business_bot_manage_url'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['charge_paid_message_stars'] = $reader->readLong();
		else:
			$result['charge_paid_message_stars'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['registration_month'] = $reader->readBytes();
		else:
			$result['registration_month'] = null;
		endif;
		if($flags & (1 << 16)):
			$result['phone_country'] = $reader->readBytes();
		else:
			$result['phone_country'] = null;
		endif;
		if($flags & (1 << 17)):
			$result['name_change_date'] = $reader->readInt();
		else:
			$result['name_change_date'] = null;
		endif;
		if($flags & (1 << 18)):
			$result['photo_change_date'] = $reader->readInt();
		else:
			$result['photo_change_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int valid_since int valid_until long salt
 * @return FutureSalt
 */

final class FutureSalt extends Instance {
	public function request(int $valid_since,int $valid_until,int $salt) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x949d9dc);
		$writer->writeInt($valid_since);
		$writer->writeInt($valid_until);
		$writer->writeLong($salt);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['valid_since'] = $reader->readInt();
		$result['valid_until'] = $reader->readInt();
		$result['salt'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson params true presentation
 * @return Update
 */

final class UpdateGroupCallConnection extends Instance {
	public function request(object $params,null | bool $presentation = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb783982);
		$flags = 0;
		$flags |= $presentation ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($params);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['presentation'] = boolval($flags & (1 << 0));
		$result['params'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument id
 * @return InputFile
 */

final class InputFileStoryDocument extends Instance {
	public function request(object $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x62dc8b48);
		$writer->writeObject($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id long stars string currency long amount
 * @return InputStorePaymentPurpose
 */

final class InputStorePaymentStarsGift extends Instance {
	public function request(object $user_id,int $stars,string $currency,int $amount) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1d741ef7);
		$writer->writeObject($user_id);
		$writer->writeLong($stars);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readObject();
		$result['stars'] = $reader->readLong();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PasswordKdfAlgo
 */

final class PasswordKdfAlgoUnknown extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd45ab096);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateContactsReset extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7084a7be);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash string short_name string title string description photo photo document document
 * @return Game
 */

final class Game extends Instance {
	public function request(int $id,int $access_hash,string $short_name,string $title,string $description,object $photo,null | object $document = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbdf9653b);
		$flags = 0;
		$flags |= is_null($document) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($short_name);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		$writer->writeObject($photo);
		if(is_null($document) === false):
			$writer->writeObject($document);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['short_name'] = $reader->readBytes();
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		$result['photo'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['document'] = $reader->readObject();
		else:
			$result['document'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id long user_id int version
 * @return Update
 */

final class UpdateChatParticipantDelete extends Instance {
	public function request(int $chat_id,int $user_id,int $version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe32f3d77);
		$writer->writeLong($chat_id);
		$writer->writeLong($user_id);
		$writer->writeInt($version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		$result['version'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string short_name inputbotinlinemessage send_message
 * @return InputBotInlineResult
 */

final class InputBotInlineResultGame extends Instance {
	public function request(string $id,string $short_name,object $send_message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4fa417f2);
		$writer->writeBytes($id);
		$writer->writeBytes($short_name);
		$writer->writeObject($send_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readBytes();
		$result['short_name'] = $reader->readBytes();
		$result['send_message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param double lat double long int accuracy_radius
 * @return InputGeoPoint
 */

final class InputGeoPoint extends Instance {
	public function request(float $lat,float $long,null | int $accuracy_radius = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x48222faf);
		$flags = 0;
		$flags |= is_null($accuracy_radius) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeDouble($lat);
		$writer->writeDouble($long);
		if(is_null($accuracy_radius) === false):
			$writer->writeInt($accuracy_radius);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['lat'] = $reader->readDouble();
		$result['long'] = $reader->readDouble();
		if($flags & (1 << 0)):
			$result['accuracy_radius'] = $reader->readInt();
		else:
			$result['accuracy_radius'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_code int from_version int version Vector<emojikeyword> keywords
 * @return EmojiKeywordsDifference
 */

final class EmojiKeywordsDifference extends Instance {
	public function request(string $lang_code,int $from_version,int $version,array $keywords) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5cc761bd);
		$writer->writeBytes($lang_code);
		$writer->writeInt($from_version);
		$writer->writeInt($version);
		$writer->writeVector($keywords,'emojikeyword');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['lang_code'] = $reader->readBytes();
		$result['from_version'] = $reader->readInt();
		$result['version'] = $reader->readInt();
		$result['keywords'] = $reader->readVector('emojikeyword');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<document> documents themesettings settings
 * @return WebPageAttribute
 */

final class WebPageAttributeTheme extends Instance {
	public function request(null | array $documents = null,null | object $settings = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x54b56617);
		$flags = 0;
		$flags |= is_null($documents) ? 0 : (1 << 0);
		$flags |= is_null($settings) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($documents) === false):
			$writer->writeVector($documents,'document');
		endif;
		if(is_null($settings) === false):
			$writer->writeObject($settings);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['documents'] = $reader->readVector('document');
		else:
			$result['documents'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['settings'] = $reader->readObject();
		else:
			$result['settings'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long gift_id stargiftauctionuserstate user_state
 * @return Update
 */

final class UpdateStarGiftAuctionUserState extends Instance {
	public function request(int $gift_id,object $user_state) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdc58f31e);
		$writer->writeLong($gift_id);
		$writer->writeObject($user_state);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['gift_id'] = $reader->readLong();
		$result['user_state'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<jsonobjectvalue> value
 * @return JSONValue
 */

final class JsonObject extends Instance {
	public function request(array $value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x99c1d49d);
		$writer->writeVector($value,'jsonobjectvalue');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['value'] = $reader->readVector('jsonobjectvalue');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id int date long actor_id long user_id int qts chatparticipant prev_participant chatparticipant new_participant exportedchatinvite invite
 * @return Update
 */

final class UpdateChatParticipant extends Instance {
	public function request(int $chat_id,int $date,int $actor_id,int $user_id,int $qts,null | object $prev_participant = null,null | object $new_participant = null,null | object $invite = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd087663a);
		$flags = 0;
		$flags |= is_null($prev_participant) ? 0 : (1 << 0);
		$flags |= is_null($new_participant) ? 0 : (1 << 1);
		$flags |= is_null($invite) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($chat_id);
		$writer->writeInt($date);
		$writer->writeLong($actor_id);
		$writer->writeLong($user_id);
		if(is_null($prev_participant) === false):
			$writer->writeObject($prev_participant);
		endif;
		if(is_null($new_participant) === false):
			$writer->writeObject($new_participant);
		endif;
		if(is_null($invite) === false):
			$writer->writeObject($invite);
		endif;
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['chat_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['actor_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['prev_participant'] = $reader->readObject();
		else:
			$result['prev_participant'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['new_participant'] = $reader->readObject();
		else:
			$result['new_participant'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['invite'] = $reader->readObject();
		else:
			$result['invite'] = null;
		endif;
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param mediaareacoordinates coordinates string emoji double temperature_c int color
 * @return MediaArea
 */

final class MediaAreaWeather extends Instance {
	public function request(object $coordinates,string $emoji,float $temperature_c,int $color) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x49a6549c);
		$writer->writeObject($coordinates);
		$writer->writeBytes($emoji);
		$writer->writeDouble($temperature_c);
		$writer->writeInt($color);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['coordinates'] = $reader->readObject();
		$result['emoji'] = $reader->readBytes();
		$result['temperature_c'] = $reader->readDouble();
		$result['color'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<pageblock> items pagecaption caption
 * @return PageBlock
 */

final class PageBlockCollage extends Instance {
	public function request(array $items,object $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x65a0fa4d);
		$writer->writeVector($items,'pageblock');
		$writer->writeObject($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['items'] = $reader->readVector('pageblock');
		$result['caption'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true photos true videos long video_max_size
 * @return AutoSaveSettings
 */

final class AutoSaveSettings extends Instance {
	public function request(null | bool $photos = null,null | bool $videos = null,null | int $video_max_size = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc84834ce);
		$flags = 0;
		$flags |= $photos ? (1 << 0) : 0;
		$flags |= $videos ? (1 << 1) : 0;
		$flags |= is_null($video_max_size) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($video_max_size) === false):
			$writer->writeLong($video_max_size);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['photos'] = boolval($flags & (1 << 0));
		$result['videos'] = boolval($flags & (1 << 1));
		if($flags & (1 << 2)):
			$result['video_max_size'] = $reader->readLong();
		else:
			$result['video_max_size'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id businessrecipients recipients int no_activity_days
 * @return BusinessGreetingMessage
 */

final class BusinessGreetingMessage extends Instance {
	public function request(int $shortcut_id,object $recipients,int $no_activity_days) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe519abab);
		$writer->writeInt($shortcut_id);
		$writer->writeObject($recipients);
		$writer->writeInt($no_activity_days);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['shortcut_id'] = $reader->readInt();
		$result['recipients'] = $reader->readObject();
		$result['no_activity_days'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument id true spoiler inputphoto video_cover int video_timestamp int ttl_seconds string query
 * @return InputMedia
 */

final class InputMediaDocument extends Instance {
	public function request(object $id,null | bool $spoiler = null,null | object $video_cover = null,null | int $video_timestamp = null,null | int $ttl_seconds = null,null | string $query = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa8763ab5);
		$flags = 0;
		$flags |= $spoiler ? (1 << 2) : 0;
		$flags |= is_null($video_cover) ? 0 : (1 << 3);
		$flags |= is_null($video_timestamp) ? 0 : (1 << 4);
		$flags |= is_null($ttl_seconds) ? 0 : (1 << 0);
		$flags |= is_null($query) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($id);
		if(is_null($video_cover) === false):
			$writer->writeObject($video_cover);
		endif;
		if(is_null($video_timestamp) === false):
			$writer->writeInt($video_timestamp);
		endif;
		if(is_null($ttl_seconds) === false):
			$writer->writeInt($ttl_seconds);
		endif;
		if(is_null($query) === false):
			$writer->writeBytes($query);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['spoiler'] = boolval($flags & (1 << 2));
		$result['id'] = $reader->readObject();
		if($flags & (1 << 3)):
			$result['video_cover'] = $reader->readObject();
		else:
			$result['video_cover'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['video_timestamp'] = $reader->readInt();
		else:
			$result['video_timestamp'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['ttl_seconds'] = $reader->readInt();
		else:
			$result['ttl_seconds'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['query'] = $reader->readBytes();
		else:
			$result['query'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return DestroyAuthKeyRes
 */

final class DestroyAuthKeyFail extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xea109b13);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return StatsURL
 */

final class StatsURL extends Instance {
	public function request(string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x47a971e0);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text string url
 * @return BotMenuButton
 */

final class BotMenuButton extends Instance {
	public function request(string $text,string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc7b57ce6);
		$writer->writeBytes($text);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readBytes();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url chatinvite chat_invite
 * @return RecentMeUrl
 */

final class RecentMeUrlChatInvite extends Instance {
	public function request(string $url,object $chat_invite) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeb49081d);
		$writer->writeBytes($url);
		$writer->writeObject($chat_invite);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['chat_invite'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyRule
 */

final class InputPrivacyValueDisallowAll extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd66b66c9);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id string title
 * @return Chat
 */

final class ChatForbidden extends Instance {
	public function request(int $id,string $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6592a1a7);
		$writer->writeLong($id);
		$writer->writeBytes($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['title'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string name int utc_offset
 * @return Timezone
 */

final class Timezone extends Instance {
	public function request(string $id,string $name,int $utc_offset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xff9289f5);
		$writer->writeBytes($id);
		$writer->writeBytes($name);
		$writer->writeInt($utc_offset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readBytes();
		$result['name'] = $reader->readBytes();
		$result['utc_offset'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long photo_id pagecaption caption true spoiler string url long webpage_id
 * @return PageBlock
 */

final class PageBlockPhoto extends Instance {
	public function request(int $photo_id,object $caption,null | bool $spoiler = null,null | string $url = null,null | int $webpage_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1759c560);
		$flags = 0;
		$flags |= $spoiler ? (1 << 1) : 0;
		$flags |= is_null($url) ? 0 : (1 << 0);
		$flags |= is_null($webpage_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($photo_id);
		$writer->writeObject($caption);
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		if(is_null($webpage_id) === false):
			$writer->writeLong($webpage_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['spoiler'] = boolval($flags & (1 << 1));
		$result['photo_id'] = $reader->readLong();
		$result['caption'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['url'] = $reader->readBytes();
		else:
			$result['url'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['webpage_id'] = $reader->readLong();
		else:
			$result['webpage_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id long inviter_id int date string rank
 * @return ChatParticipant
 */

final class ChatParticipant extends Instance {
	public function request(int $user_id,int $inviter_id,int $date,null | string $rank = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x38e79fde);
		$flags = 0;
		$flags |= is_null($rank) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		$writer->writeLong($inviter_id);
		$writer->writeInt($date);
		if(is_null($rank) === false):
			$writer->writeBytes($rank);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		$result['inviter_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['rank'] = $reader->readBytes();
		else:
			$result['rank'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<quickreply> quick_replies
 * @return Update
 */

final class UpdateQuickReplies extends Instance {
	public function request(array $quick_replies) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf9470ab2);
		$writer->writeVector($quick_replies,'quickreply');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['quick_replies'] = $reader->readVector('quickreply');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionUpdatePinned extends Instance {
	public function request(object $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe9e82c18);
		$writer->writeObject($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param poll poll pollresults results messagemedia attached_media
 * @return MessageMedia
 */

final class MessageMediaPoll extends Instance {
	public function request(object $poll,object $results,null | object $attached_media = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x773f4e66);
		$flags = 0;
		$flags |= is_null($attached_media) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($poll);
		$writer->writeObject($results);
		if(is_null($attached_media) === false):
			$writer->writeObject($attached_media);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['poll'] = $reader->readObject();
		$result['results'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['attached_media'] = $reader->readObject();
		else:
			$result['attached_media'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int max_delay int wait_after int max_wait
 * @return HttpWait
 */

final class HttpWait extends Instance {
	public function request(int $max_delay,int $wait_after,int $max_wait) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9299359f);
		$writer->writeInt($max_delay);
		$writer->writeInt($wait_after);
		$writer->writeInt($max_wait);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['max_delay'] = $reader->readInt();
		$result['wait_after'] = $reader->readInt();
		$result['max_wait'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id peer peer_id int date string message true out true mentioned true media_unread true silent true post true from_scheduled true legacy true edit_hide true pinned true noforwards true invert_media true offline true video_processing_pending true paid_suggested_post_stars true paid_suggested_post_ton peer from_id int from_boosts_applied string from_rank peer saved_peer_id messagefwdheader fwd_from long via_bot_id long via_business_bot_id peer guestchat_via_from messagereplyheader reply_to messagemedia media replymarkup reply_markup Vector<messageentity> entities int views int forwards messagereplies replies int edit_date string post_author long grouped_id messagereactions reactions Vector<restrictionreason> restriction_reason int ttl_period int quick_reply_shortcut_id long effect factcheck factcheck int report_delivery_until_date long paid_message_stars suggestedpost suggested_post int schedule_repeat_period string summary_from_language richmessage rich_message
 * @return Message
 */

final class Message extends Instance {
	public function request(int $id,object $peer_id,int $date,string $message,null | bool $out = null,null | bool $mentioned = null,null | bool $media_unread = null,null | bool $silent = null,null | bool $post = null,null | bool $from_scheduled = null,null | bool $legacy = null,null | bool $edit_hide = null,null | bool $pinned = null,null | bool $noforwards = null,null | bool $invert_media = null,null | bool $offline = null,null | bool $video_processing_pending = null,null | bool $paid_suggested_post_stars = null,null | bool $paid_suggested_post_ton = null,null | object $from_id = null,null | int $from_boosts_applied = null,null | string $from_rank = null,null | object $saved_peer_id = null,null | object $fwd_from = null,null | int $via_bot_id = null,null | int $via_business_bot_id = null,null | object $guestchat_via_from = null,null | object $reply_to = null,null | object $media = null,null | object $reply_markup = null,null | array $entities = null,null | int $views = null,null | int $forwards = null,null | object $replies = null,null | int $edit_date = null,null | string $post_author = null,null | int $grouped_id = null,null | object $reactions = null,null | array $restriction_reason = null,null | int $ttl_period = null,null | int $quick_reply_shortcut_id = null,null | int $effect = null,null | object $factcheck = null,null | int $report_delivery_until_date = null,null | int $paid_message_stars = null,null | object $suggested_post = null,null | int $schedule_repeat_period = null,null | string $summary_from_language = null,null | object $rich_message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7600b9d3);
		$flags = 0;
		$flags |= $out ? (1 << 1) : 0;
		$flags |= $mentioned ? (1 << 4) : 0;
		$flags |= $media_unread ? (1 << 5) : 0;
		$flags |= $silent ? (1 << 13) : 0;
		$flags |= $post ? (1 << 14) : 0;
		$flags |= $from_scheduled ? (1 << 18) : 0;
		$flags |= $legacy ? (1 << 19) : 0;
		$flags |= $edit_hide ? (1 << 21) : 0;
		$flags |= $pinned ? (1 << 24) : 0;
		$flags |= $noforwards ? (1 << 26) : 0;
		$flags |= $invert_media ? (1 << 27) : 0;
		$flags |= is_null($from_id) ? 0 : (1 << 8);
		$flags |= is_null($from_boosts_applied) ? 0 : (1 << 29);
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 28);
		$flags |= is_null($fwd_from) ? 0 : (1 << 2);
		$flags |= is_null($via_bot_id) ? 0 : (1 << 11);
		$flags |= is_null($reply_to) ? 0 : (1 << 3);
		$flags |= is_null($media) ? 0 : (1 << 9);
		$flags |= is_null($reply_markup) ? 0 : (1 << 6);
		$flags |= is_null($entities) ? 0 : (1 << 7);
		$flags |= is_null($views) ? 0 : (1 << 10);
		$flags |= is_null($forwards) ? 0 : (1 << 10);
		$flags |= is_null($replies) ? 0 : (1 << 23);
		$flags |= is_null($edit_date) ? 0 : (1 << 15);
		$flags |= is_null($post_author) ? 0 : (1 << 16);
		$flags |= is_null($grouped_id) ? 0 : (1 << 17);
		$flags |= is_null($reactions) ? 0 : (1 << 20);
		$flags |= is_null($restriction_reason) ? 0 : (1 << 22);
		$flags |= is_null($ttl_period) ? 0 : (1 << 25);
		$flags |= is_null($quick_reply_shortcut_id) ? 0 : (1 << 30);
		$writer->writeInt($flags);
		$flags2 = 0;
		$flags2 |= $offline ? (1 << 1) : 0;
		$flags2 |= $video_processing_pending ? (1 << 4) : 0;
		$flags2 |= $paid_suggested_post_stars ? (1 << 8) : 0;
		$flags2 |= $paid_suggested_post_ton ? (1 << 9) : 0;
		$flags2 |= is_null($from_rank) ? 0 : (1 << 12);
		$flags2 |= is_null($via_business_bot_id) ? 0 : (1 << 0);
		$flags2 |= is_null($guestchat_via_from) ? 0 : (1 << 19);
		$flags2 |= is_null($effect) ? 0 : (1 << 2);
		$flags2 |= is_null($factcheck) ? 0 : (1 << 3);
		$flags2 |= is_null($report_delivery_until_date) ? 0 : (1 << 5);
		$flags2 |= is_null($paid_message_stars) ? 0 : (1 << 6);
		$flags2 |= is_null($suggested_post) ? 0 : (1 << 7);
		$flags2 |= is_null($schedule_repeat_period) ? 0 : (1 << 10);
		$flags2 |= is_null($summary_from_language) ? 0 : (1 << 11);
		$flags2 |= is_null($rich_message) ? 0 : (1 << 13);
		$writer->writeInt($flags2);
		$writer->writeInt($id);
		if(is_null($from_id) === false):
			$writer->writeObject($from_id);
		endif;
		if(is_null($from_boosts_applied) === false):
			$writer->writeInt($from_boosts_applied);
		endif;
		if(is_null($from_rank) === false):
			$writer->writeBytes($from_rank);
		endif;
		$writer->writeObject($peer_id);
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		if(is_null($fwd_from) === false):
			$writer->writeObject($fwd_from);
		endif;
		if(is_null($via_bot_id) === false):
			$writer->writeLong($via_bot_id);
		endif;
		if(is_null($via_business_bot_id) === false):
			$writer->writeLong($via_business_bot_id);
		endif;
		if(is_null($guestchat_via_from) === false):
			$writer->writeObject($guestchat_via_from);
		endif;
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		$writer->writeInt($date);
		$writer->writeBytes($message);
		if(is_null($media) === false):
			$writer->writeObject($media);
		endif;
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($views) === false):
			$writer->writeInt($views);
		endif;
		if(is_null($forwards) === false):
			$writer->writeInt($forwards);
		endif;
		if(is_null($replies) === false):
			$writer->writeObject($replies);
		endif;
		if(is_null($edit_date) === false):
			$writer->writeInt($edit_date);
		endif;
		if(is_null($post_author) === false):
			$writer->writeBytes($post_author);
		endif;
		if(is_null($grouped_id) === false):
			$writer->writeLong($grouped_id);
		endif;
		if(is_null($reactions) === false):
			$writer->writeObject($reactions);
		endif;
		if(is_null($restriction_reason) === false):
			$writer->writeVector($restriction_reason,'restrictionreason');
		endif;
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		if(is_null($quick_reply_shortcut_id) === false):
			$writer->writeInt($quick_reply_shortcut_id);
		endif;
		if(is_null($effect) === false):
			$writer->writeLong($effect);
		endif;
		if(is_null($factcheck) === false):
			$writer->writeObject($factcheck);
		endif;
		if(is_null($report_delivery_until_date) === false):
			$writer->writeInt($report_delivery_until_date);
		endif;
		if(is_null($paid_message_stars) === false):
			$writer->writeLong($paid_message_stars);
		endif;
		if(is_null($suggested_post) === false):
			$writer->writeObject($suggested_post);
		endif;
		if(is_null($schedule_repeat_period) === false):
			$writer->writeInt($schedule_repeat_period);
		endif;
		if(is_null($summary_from_language) === false):
			$writer->writeBytes($summary_from_language);
		endif;
		if(is_null($rich_message) === false):
			$writer->writeObject($rich_message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['out'] = boolval($flags & (1 << 1));
		$result['mentioned'] = boolval($flags & (1 << 4));
		$result['media_unread'] = boolval($flags & (1 << 5));
		$result['silent'] = boolval($flags & (1 << 13));
		$result['post'] = boolval($flags & (1 << 14));
		$result['from_scheduled'] = boolval($flags & (1 << 18));
		$result['legacy'] = boolval($flags & (1 << 19));
		$result['edit_hide'] = boolval($flags & (1 << 21));
		$result['pinned'] = boolval($flags & (1 << 24));
		$result['noforwards'] = boolval($flags & (1 << 26));
		$result['invert_media'] = boolval($flags & (1 << 27));
		$flags2 = $reader->readInt();
		$result['offline'] = boolval($flags2 & (1 << 1));
		$result['video_processing_pending'] = boolval($flags2 & (1 << 4));
		$result['paid_suggested_post_stars'] = boolval($flags2 & (1 << 8));
		$result['paid_suggested_post_ton'] = boolval($flags2 & (1 << 9));
		$result['id'] = $reader->readInt();
		if($flags & (1 << 8)):
			$result['from_id'] = $reader->readObject();
		else:
			$result['from_id'] = null;
		endif;
		if($flags & (1 << 29)):
			$result['from_boosts_applied'] = $reader->readInt();
		else:
			$result['from_boosts_applied'] = null;
		endif;
		if($flags2 & (1 << 12)):
			$result['from_rank'] = $reader->readBytes();
		else:
			$result['from_rank'] = null;
		endif;
		$result['peer_id'] = $reader->readObject();
		if($flags & (1 << 28)):
			$result['saved_peer_id'] = $reader->readObject();
		else:
			$result['saved_peer_id'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['fwd_from'] = $reader->readObject();
		else:
			$result['fwd_from'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['via_bot_id'] = $reader->readLong();
		else:
			$result['via_bot_id'] = null;
		endif;
		if($flags2 & (1 << 0)):
			$result['via_business_bot_id'] = $reader->readLong();
		else:
			$result['via_business_bot_id'] = null;
		endif;
		if($flags2 & (1 << 19)):
			$result['guestchat_via_from'] = $reader->readObject();
		else:
			$result['guestchat_via_from'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['reply_to'] = $reader->readObject();
		else:
			$result['reply_to'] = null;
		endif;
		$result['date'] = $reader->readInt();
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 9)):
			$result['media'] = $reader->readObject();
		else:
			$result['media'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['views'] = $reader->readInt();
		else:
			$result['views'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['forwards'] = $reader->readInt();
		else:
			$result['forwards'] = null;
		endif;
		if($flags & (1 << 23)):
			$result['replies'] = $reader->readObject();
		else:
			$result['replies'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['edit_date'] = $reader->readInt();
		else:
			$result['edit_date'] = null;
		endif;
		if($flags & (1 << 16)):
			$result['post_author'] = $reader->readBytes();
		else:
			$result['post_author'] = null;
		endif;
		if($flags & (1 << 17)):
			$result['grouped_id'] = $reader->readLong();
		else:
			$result['grouped_id'] = null;
		endif;
		if($flags & (1 << 20)):
			$result['reactions'] = $reader->readObject();
		else:
			$result['reactions'] = null;
		endif;
		if($flags & (1 << 22)):
			$result['restriction_reason'] = $reader->readVector('restrictionreason');
		else:
			$result['restriction_reason'] = null;
		endif;
		if($flags & (1 << 25)):
			$result['ttl_period'] = $reader->readInt();
		else:
			$result['ttl_period'] = null;
		endif;
		if($flags & (1 << 30)):
			$result['quick_reply_shortcut_id'] = $reader->readInt();
		else:
			$result['quick_reply_shortcut_id'] = null;
		endif;
		if($flags2 & (1 << 2)):
			$result['effect'] = $reader->readLong();
		else:
			$result['effect'] = null;
		endif;
		if($flags2 & (1 << 3)):
			$result['factcheck'] = $reader->readObject();
		else:
			$result['factcheck'] = null;
		endif;
		if($flags2 & (1 << 5)):
			$result['report_delivery_until_date'] = $reader->readInt();
		else:
			$result['report_delivery_until_date'] = null;
		endif;
		if($flags2 & (1 << 6)):
			$result['paid_message_stars'] = $reader->readLong();
		else:
			$result['paid_message_stars'] = null;
		endif;
		if($flags2 & (1 << 7)):
			$result['suggested_post'] = $reader->readObject();
		else:
			$result['suggested_post'] = null;
		endif;
		if($flags2 & (1 << 10)):
			$result['schedule_repeat_period'] = $reader->readInt();
		else:
			$result['schedule_repeat_period'] = null;
		endif;
		if($flags2 & (1 << 11)):
			$result['summary_from_language'] = $reader->readBytes();
		else:
			$result['summary_from_language'] = null;
		endif;
		if($flags2 & (1 << 13)):
			$result['rich_message'] = $reader->readObject();
		else:
			$result['rich_message'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int story_id peer peer reaction reaction
 * @return Update
 */

final class UpdateNewStoryReaction extends Instance {
	public function request(int $story_id,object $peer,object $reaction) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1824e40b);
		$writer->writeInt($story_id);
		$writer->writeObject($peer);
		$writer->writeObject($reaction);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['story_id'] = $reader->readInt();
		$result['peer'] = $reader->readObject();
		$result['reaction'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockTitle extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x70abc3fd);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarsTransactionPeer
 */

final class StarsTransactionPeerAppStore extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb457b375);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true disallow_unlimited_stargifts true disallow_limited_stargifts true disallow_unique_stargifts true disallow_premium_gifts true disallow_stargifts_from_channels
 * @return DisallowedGiftsSettings
 */

final class DisallowedGiftsSettings extends Instance {
	public function request(null | bool $disallow_unlimited_stargifts = null,null | bool $disallow_limited_stargifts = null,null | bool $disallow_unique_stargifts = null,null | bool $disallow_premium_gifts = null,null | bool $disallow_stargifts_from_channels = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x71f276c4);
		$flags = 0;
		$flags |= $disallow_unlimited_stargifts ? (1 << 0) : 0;
		$flags |= $disallow_limited_stargifts ? (1 << 1) : 0;
		$flags |= $disallow_unique_stargifts ? (1 << 2) : 0;
		$flags |= $disallow_premium_gifts ? (1 << 3) : 0;
		$flags |= $disallow_stargifts_from_channels ? (1 << 4) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['disallow_unlimited_stargifts'] = boolval($flags & (1 << 0));
		$result['disallow_limited_stargifts'] = boolval($flags & (1 << 1));
		$result['disallow_unique_stargifts'] = boolval($flags & (1 << 2));
		$result['disallow_premium_gifts'] = boolval($flags & (1 << 3));
		$result['disallow_stargifts_from_channels'] = boolval($flags & (1 << 4));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer
 * @return DialogPeer
 */

final class DialogPeer extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe56dbf05);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id
 * @return InputPeer
 */

final class InputPeerChat extends Instance {
	public function request(int $chat_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x35a95cb9);
		$writer->writeLong($chat_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long random_id int chat_id int date bytes bytes
 * @return EncryptedMessage
 */

final class EncryptedMessageService extends Instance {
	public function request(int $random_id,int $chat_id,int $date,string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x23734b06);
		$writer->writeLong($random_id);
		$writer->writeInt($chat_id);
		$writer->writeInt($date);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['random_id'] = $reader->readLong();
		$result['chat_id'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['bytes'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message true invert_media Vector<messageentity> entities replymarkup reply_markup
 * @return InputBotInlineMessage
 */

final class InputBotInlineMessageMediaAuto extends Instance {
	public function request(string $message,null | bool $invert_media = null,null | array $entities = null,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3380c786);
		$flags = 0;
		$flags |= $invert_media ? (1 << 3) : 0;
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['invert_media'] = boolval($flags & (1 << 3));
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgeopoint geo_point string title string address string provider string venue_id string venue_type replymarkup reply_markup
 * @return InputBotInlineMessage
 */

final class InputBotInlineMessageMediaVenue extends Instance {
	public function request(object $geo_point,string $title,string $address,string $provider,string $venue_id,string $venue_type,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x417bbf11);
		$flags = 0;
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($geo_point);
		$writer->writeBytes($title);
		$writer->writeBytes($address);
		$writer->writeBytes($provider);
		$writer->writeBytes($venue_id);
		$writer->writeBytes($venue_type);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['geo_point'] = $reader->readObject();
		$result['title'] = $reader->readBytes();
		$result['address'] = $reader->readBytes();
		$result['provider'] = $reader->readBytes();
		$result['venue_id'] = $reader->readBytes();
		$result['venue_type'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param double current double previous
 * @return StatsAbsValueAndPrev
 */

final class StatsAbsValueAndPrev extends Instance {
	public function request(float $current,float $previous) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcb43acde);
		$writer->writeDouble($current);
		$writer->writeDouble($previous);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['current'] = $reader->readDouble();
		$result['previous'] = $reader->readDouble();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyRule
 */

final class InputPrivacyValueAllowPremium extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x77cdc9f1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long document_id int w int h
 * @return RichText
 */

final class TextImage extends Instance {
	public function request(int $document_id,int $w,int $h) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x81ccf4f);
		$writer->writeLong($document_id);
		$writer->writeInt($w);
		$writer->writeInt($h);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['document_id'] = $reader->readLong();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BusinessAwayMessageSchedule
 */

final class BusinessAwayMessageScheduleOutsideWorkHours extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc3f2f501);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionToggleAntiSpam extends Instance {
	public function request(bool $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x64f36dfc);
		$writer->writeBool($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_value'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id
 * @return Peer
 */

final class PeerChat extends Instance {
	public function request(int $chat_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x36c6019a);
		$writer->writeLong($chat_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReactionNotificationsFrom
 */

final class ReactionNotificationsFromContacts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbac3a61a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length long user_id
 * @return MessageEntity
 */

final class MessageEntityMentionName extends Instance {
	public function request(int $offset,int $length,int $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdc7b1140);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		$writer->writeLong($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ChannelLocation
 */

final class ChannelLocationEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbfb5ad8b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id long inviter_id int date true via_request int subscription_until_date string rank
 * @return ChannelParticipant
 */

final class ChannelParticipantSelf extends Instance {
	public function request(int $user_id,int $inviter_id,int $date,null | bool $via_request = null,null | int $subscription_until_date = null,null | string $rank = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa9478a1a);
		$flags = 0;
		$flags |= $via_request ? (1 << 0) : 0;
		$flags |= is_null($subscription_until_date) ? 0 : (1 << 1);
		$flags |= is_null($rank) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		$writer->writeLong($inviter_id);
		$writer->writeInt($date);
		if(is_null($subscription_until_date) === false):
			$writer->writeInt($subscription_until_date);
		endif;
		if(is_null($rank) === false):
			$writer->writeBytes($rank);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['via_request'] = boolval($flags & (1 << 0));
		$result['user_id'] = $reader->readLong();
		$result['inviter_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['subscription_until_date'] = $reader->readInt();
		else:
			$result['subscription_until_date'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['rank'] = $reader->readBytes();
		else:
			$result['rank'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id businessawaymessageschedule schedule businessrecipients recipients true offline_only
 * @return BusinessAwayMessage
 */

final class BusinessAwayMessage extends Instance {
	public function request(int $shortcut_id,object $schedule,object $recipients,null | bool $offline_only = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xef156a5c);
		$flags = 0;
		$flags |= $offline_only ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($shortcut_id);
		$writer->writeObject($schedule);
		$writer->writeObject($recipients);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['offline_only'] = boolval($flags & (1 << 0));
		$result['shortcut_id'] = $reader->readInt();
		$result['schedule'] = $reader->readObject();
		$result['recipients'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string keyword Vector<string> emoticons
 * @return EmojiKeyword
 */

final class EmojiKeyword extends Instance {
	public function request(string $keyword,array $emoticons) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd5b3b9f9);
		$writer->writeBytes($keyword);
		$writer->writeVector($emoticons,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['keyword'] = $reader->readBytes();
		$result['emoticons'] = $reader->readVector('string');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return InputStarGiftAuction
 */

final class InputStarGiftAuctionSlug extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7ab58308);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['slug'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param webpage webpage true force_large_media true force_small_media true manual true safe
 * @return MessageMedia
 */

final class MessageMediaWebPage extends Instance {
	public function request(object $webpage,null | bool $force_large_media = null,null | bool $force_small_media = null,null | bool $manual = null,null | bool $safe = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xddf10c3b);
		$flags = 0;
		$flags |= $force_large_media ? (1 << 0) : 0;
		$flags |= $force_small_media ? (1 << 1) : 0;
		$flags |= $manual ? (1 << 3) : 0;
		$flags |= $safe ? (1 << 4) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($webpage);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['force_large_media'] = boolval($flags & (1 << 0));
		$result['force_small_media'] = boolval($flags & (1 << 1));
		$result['manual'] = boolval($flags & (1 << 3));
		$result['safe'] = boolval($flags & (1 << 4));
		$result['webpage'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypeUtilityBill extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfc36954e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long gift_id stargiftauctionstate state
 * @return Update
 */

final class UpdateStarGiftAuctionState extends Instance {
	public function request(int $gift_id,object $state) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x48e246c2);
		$writer->writeLong($gift_id);
		$writer->writeObject($state);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['gift_id'] = $reader->readLong();
		$result['state'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer_id true blocked true blocked_my_stories_from
 * @return Update
 */

final class UpdatePeerBlocked extends Instance {
	public function request(object $peer_id,null | bool $blocked = null,null | bool $blocked_my_stories_from = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xebe07752);
		$flags = 0;
		$flags |= $blocked ? (1 << 0) : 0;
		$flags |= $blocked_my_stories_from ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['blocked'] = boolval($flags & (1 << 0));
		$result['blocked_my_stories_from'] = boolval($flags & (1 << 1));
		$result['peer_id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer long bot_id Vector<botcommand> commands
 * @return Update
 */

final class UpdateBotCommands extends Instance {
	public function request(object $peer,int $bot_id,array $commands) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4d712f2e);
		$writer->writeObject($peer);
		$writer->writeLong($bot_id);
		$writer->writeVector($commands,'botcommand');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['bot_id'] = $reader->readLong();
		$result['commands'] = $reader->readVector('botcommand');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long collectible_id long document_id string title string slug long pattern_document_id int center_color int edge_color int pattern_color int text_color int until
 * @return EmojiStatus
 */

final class EmojiStatusCollectible extends Instance {
	public function request(int $collectible_id,int $document_id,string $title,string $slug,int $pattern_document_id,int $center_color,int $edge_color,int $pattern_color,int $text_color,null | int $until = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7184603b);
		$flags = 0;
		$flags |= is_null($until) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($collectible_id);
		$writer->writeLong($document_id);
		$writer->writeBytes($title);
		$writer->writeBytes($slug);
		$writer->writeLong($pattern_document_id);
		$writer->writeInt($center_color);
		$writer->writeInt($edge_color);
		$writer->writeInt($pattern_color);
		$writer->writeInt($text_color);
		if(is_null($until) === false):
			$writer->writeInt($until);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['collectible_id'] = $reader->readLong();
		$result['document_id'] = $reader->readLong();
		$result['title'] = $reader->readBytes();
		$result['slug'] = $reader->readBytes();
		$result['pattern_document_id'] = $reader->readLong();
		$result['center_color'] = $reader->readInt();
		$result['edge_color'] = $reader->readInt();
		$result['pattern_color'] = $reader->readInt();
		$result['text_color'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['until'] = $reader->readInt();
		else:
			$result['until'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputmedia media long random_id string message Vector<messageentity> entities
 * @return InputSingleMedia
 */

final class InputSingleMedia extends Instance {
	public function request(object $media,int $random_id,string $message,null | array $entities = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1cc6e91f);
		$flags = 0;
		$flags |= is_null($entities) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($media);
		$writer->writeLong($random_id);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['media'] = $reader->readObject();
		$result['random_id'] = $reader->readLong();
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long document_id
 * @return StarGiftAttributeId
 */

final class StarGiftAttributeIdPattern extends Instance {
	public function request(int $document_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4a162433);
		$writer->writeLong($document_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['document_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param chat channel
 * @return PageBlock
 */

final class PageBlockChannel extends Instance {
	public function request(object $channel) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xef1751b5);
		$writer->writeObject($channel);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash string device_model string platform string system_version int api_id string app_name string app_version int date_created int date_active string ip string country string region true current true official_app true password_pending true encrypted_requests_disabled true call_requests_disabled true unconfirmed
 * @return Authorization
 */

final class Authorization extends Instance {
	public function request(int $hash,string $device_model,string $platform,string $system_version,int $api_id,string $app_name,string $app_version,int $date_created,int $date_active,string $ip,string $country,string $region,null | bool $current = null,null | bool $official_app = null,null | bool $password_pending = null,null | bool $encrypted_requests_disabled = null,null | bool $call_requests_disabled = null,null | bool $unconfirmed = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xad01d61d);
		$flags = 0;
		$flags |= $current ? (1 << 0) : 0;
		$flags |= $official_app ? (1 << 1) : 0;
		$flags |= $password_pending ? (1 << 2) : 0;
		$flags |= $encrypted_requests_disabled ? (1 << 3) : 0;
		$flags |= $call_requests_disabled ? (1 << 4) : 0;
		$flags |= $unconfirmed ? (1 << 5) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($hash);
		$writer->writeBytes($device_model);
		$writer->writeBytes($platform);
		$writer->writeBytes($system_version);
		$writer->writeInt($api_id);
		$writer->writeBytes($app_name);
		$writer->writeBytes($app_version);
		$writer->writeInt($date_created);
		$writer->writeInt($date_active);
		$writer->writeBytes($ip);
		$writer->writeBytes($country);
		$writer->writeBytes($region);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['current'] = boolval($flags & (1 << 0));
		$result['official_app'] = boolval($flags & (1 << 1));
		$result['password_pending'] = boolval($flags & (1 << 2));
		$result['encrypted_requests_disabled'] = boolval($flags & (1 << 3));
		$result['call_requests_disabled'] = boolval($flags & (1 << 4));
		$result['unconfirmed'] = boolval($flags & (1 << 5));
		$result['hash'] = $reader->readLong();
		$result['device_model'] = $reader->readBytes();
		$result['platform'] = $reader->readBytes();
		$result['system_version'] = $reader->readBytes();
		$result['api_id'] = $reader->readInt();
		$result['app_name'] = $reader->readBytes();
		$result['app_version'] = $reader->readBytes();
		$result['date_created'] = $reader->readInt();
		$result['date_active'] = $reader->readInt();
		$result['ip'] = $reader->readBytes();
		$result['country'] = $reader->readBytes();
		$result['region'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param chatbannedrights prev_banned_rights chatbannedrights new_banned_rights
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionDefaultBannedRights extends Instance {
	public function request(object $prev_banned_rights,object $new_banned_rights) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2df5fc0a);
		$writer->writeObject($prev_banned_rights);
		$writer->writeObject($new_banned_rights);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_banned_rights'] = $reader->readObject();
		$result['new_banned_rights'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityCashtag extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4c4e743f);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int msg_id
 * @return Update
 */

final class UpdateGeoLiveViewed extends Instance {
	public function request(object $peer,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x871fb939);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param paidreactionprivacy private
 * @return Update
 */

final class UpdatePaidReactionPrivacy extends Instance {
	public function request(object $private) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8b725fce);
		$writer->writeObject($private);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['private'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long emoji_id Vector<int> background_colors
 * @return VideoSize
 */

final class VideoSizeEmojiMarkup extends Instance {
	public function request(int $emoji_id,array $background_colors) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf85c413c);
		$writer->writeLong($emoji_id);
		$writer->writeVector($background_colors,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['emoji_id'] = $reader->readLong();
		$result['background_colors'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson client_data bytes authenticator_data bytes signature string user_handle
 * @return InputPasskeyResponse
 */

final class InputPasskeyResponseLogin extends Instance {
	public function request(object $client_data,string $authenticator_data,string $signature,string $user_handle) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc31fc14a);
		$writer->writeObject($client_data);
		$writer->writeBytes($authenticator_data);
		$writer->writeBytes($signature);
		$writer->writeBytes($user_handle);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['client_data'] = $reader->readObject();
		$result['authenticator_data'] = $reader->readBytes();
		$result['signature'] = $reader->readBytes();
		$result['user_handle'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputEncryptedFile
 */

final class InputEncryptedFile extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5a17b5e5);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputFileLocation
 */

final class InputSecureFileLocation extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcbc7ee28);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputuser> users string currency long amount inputpeer boost_peer textwithentities message
 * @return InputStorePaymentPurpose
 */

final class InputStorePaymentPremiumGiftCode extends Instance {
	public function request(array $users,string $currency,int $amount,null | object $boost_peer = null,null | object $message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfb790393);
		$flags = 0;
		$flags |= is_null($boost_peer) ? 0 : (1 << 0);
		$flags |= is_null($message) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeVector($users,'inputuser');
		if(is_null($boost_peer) === false):
			$writer->writeObject($boost_peer);
		endif;
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['users'] = $reader->readVector('inputuser');
		if($flags & (1 << 0)):
			$result['boost_peer'] = $reader->readObject();
		else:
			$result['boost_peer'] = null;
		endif;
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		if($flags & (1 << 1)):
			$result['message'] = $reader->readObject();
		else:
			$result['message'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param geopoint geo int heading int period int proximity_notification_radius replymarkup reply_markup
 * @return BotInlineMessage
 */

final class BotInlineMessageMediaGeo extends Instance {
	public function request(object $geo,null | int $heading = null,null | int $period = null,null | int $proximity_notification_radius = null,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x51846fd);
		$flags = 0;
		$flags |= is_null($heading) ? 0 : (1 << 0);
		$flags |= is_null($period) ? 0 : (1 << 1);
		$flags |= is_null($proximity_notification_radius) ? 0 : (1 << 3);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($geo);
		if(is_null($heading) === false):
			$writer->writeInt($heading);
		endif;
		if(is_null($period) === false):
			$writer->writeInt($period);
		endif;
		if(is_null($proximity_notification_radius) === false):
			$writer->writeInt($proximity_notification_radius);
		endif;
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['geo'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['heading'] = $reader->readInt();
		else:
			$result['heading'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['period'] = $reader->readInt();
		else:
			$result['period'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['proximity_notification_radius'] = $reader->readInt();
		else:
			$result['proximity_notification_radius'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer long kicked_by int date chatbannedrights banned_rights true left string rank
 * @return ChannelParticipant
 */

final class ChannelParticipantBanned extends Instance {
	public function request(object $peer,int $kicked_by,int $date,object $banned_rights,null | bool $left = null,null | string $rank = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd5f0ad91);
		$flags = 0;
		$flags |= $left ? (1 << 0) : 0;
		$flags |= is_null($rank) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeLong($kicked_by);
		$writer->writeInt($date);
		$writer->writeObject($banned_rights);
		if(is_null($rank) === false):
			$writer->writeBytes($rank);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['left'] = boolval($flags & (1 << 0));
		$result['peer'] = $reader->readObject();
		$result['kicked_by'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['banned_rights'] = $reader->readObject();
		if($flags & (1 << 2)):
			$result['rank'] = $reader->readBytes();
		else:
			$result['rank'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id
 * @return Document
 */

final class DocumentEmpty extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x36f8c871);
		$writer->writeLong($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id true history_deleted
 * @return EncryptedChat
 */

final class EncryptedChatDiscarded extends Instance {
	public function request(int $id,null | bool $history_deleted = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1e1c7c45);
		$flags = 0;
		$flags |= $history_deleted ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['history_deleted'] = boolval($flags & (1 << 0));
		$result['id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return UserStatus
 */

final class UserStatusEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9d05049);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateReadFeaturedStickers extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x571d2742);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash string slug document document true creator true default true pattern true dark wallpapersettings settings
 * @return WallPaper
 */

final class WallPaper extends Instance {
	public function request(int $id,int $access_hash,string $slug,object $document,null | bool $creator = null,null | bool $default = null,null | bool $pattern = null,null | bool $dark = null,null | object $settings = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa437c3ed);
		$writer->writeLong($id);
		$flags = 0;
		$flags |= $creator ? (1 << 0) : 0;
		$flags |= $default ? (1 << 1) : 0;
		$flags |= $pattern ? (1 << 3) : 0;
		$flags |= $dark ? (1 << 4) : 0;
		$flags |= is_null($settings) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($access_hash);
		$writer->writeBytes($slug);
		$writer->writeObject($document);
		if(is_null($settings) === false):
			$writer->writeObject($settings);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$flags = $reader->readInt();
		$result['creator'] = boolval($flags & (1 << 0));
		$result['default'] = boolval($flags & (1 << 1));
		$result['pattern'] = boolval($flags & (1 << 3));
		$result['dark'] = boolval($flags & (1 << 4));
		$result['access_hash'] = $reader->readLong();
		$result['slug'] = $reader->readBytes();
		$result['document'] = $reader->readObject();
		if($flags & (1 << 2)):
			$result['settings'] = $reader->readObject();
		else:
			$result['settings'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<int> messages int pts int pts_count int date
 * @return Update
 */

final class UpdateReadMessagesContents extends Instance {
	public function request(array $messages,int $pts,int $pts_count,null | int $date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf8227181);
		$flags = 0;
		$flags |= is_null($date) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeVector($messages,'int');
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		if(is_null($date) === false):
			$writer->writeInt($date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['messages'] = $reader->readVector('int');
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['date'] = $reader->readInt();
		else:
			$result['date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date int expires bool test_mode int this_dc Vector<dcoption> dc_options string dc_txt_domain_name int chat_size_max int megagroup_size_max int forwarded_count_max int online_update_period_ms int offline_blur_timeout_ms int offline_idle_timeout_ms int online_cloud_timeout_ms int notify_cloud_delay_ms int notify_default_delay_ms int push_chat_period_ms int push_chat_limit int edit_time_limit int revoke_time_limit int revoke_pm_time_limit int rating_e_decay int stickers_recent_limit int channels_read_media_period int call_receive_timeout_ms int call_ring_timeout_ms int call_connect_timeout_ms int call_packet_timeout_ms string me_url_prefix int caption_length_max int message_length_max int webfile_dc_id true default_p2p_contacts true preload_featured_stickers true revoke_pm_inbox true blocked_mode true force_try_ipv6 int tmp_sessions string autoupdate_url_prefix string gif_search_username string venue_search_username string img_search_username string static_maps_provider string suggested_lang_code int lang_pack_version int base_lang_pack_version reaction reactions_default string autologin_token
 * @return Config
 */

final class Config extends Instance {
	public function request(int $date,int $expires,bool $test_mode,int $this_dc,array $dc_options,string $dc_txt_domain_name,int $chat_size_max,int $megagroup_size_max,int $forwarded_count_max,int $online_update_period_ms,int $offline_blur_timeout_ms,int $offline_idle_timeout_ms,int $online_cloud_timeout_ms,int $notify_cloud_delay_ms,int $notify_default_delay_ms,int $push_chat_period_ms,int $push_chat_limit,int $edit_time_limit,int $revoke_time_limit,int $revoke_pm_time_limit,int $rating_e_decay,int $stickers_recent_limit,int $channels_read_media_period,int $call_receive_timeout_ms,int $call_ring_timeout_ms,int $call_connect_timeout_ms,int $call_packet_timeout_ms,string $me_url_prefix,int $caption_length_max,int $message_length_max,int $webfile_dc_id,null | bool $default_p2p_contacts = null,null | bool $preload_featured_stickers = null,null | bool $revoke_pm_inbox = null,null | bool $blocked_mode = null,null | bool $force_try_ipv6 = null,null | int $tmp_sessions = null,null | string $autoupdate_url_prefix = null,null | string $gif_search_username = null,null | string $venue_search_username = null,null | string $img_search_username = null,null | string $static_maps_provider = null,null | string $suggested_lang_code = null,null | int $lang_pack_version = null,null | int $base_lang_pack_version = null,null | object $reactions_default = null,null | string $autologin_token = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcc1a241e);
		$flags = 0;
		$flags |= $default_p2p_contacts ? (1 << 3) : 0;
		$flags |= $preload_featured_stickers ? (1 << 4) : 0;
		$flags |= $revoke_pm_inbox ? (1 << 6) : 0;
		$flags |= $blocked_mode ? (1 << 8) : 0;
		$flags |= $force_try_ipv6 ? (1 << 14) : 0;
		$flags |= is_null($tmp_sessions) ? 0 : (1 << 0);
		$flags |= is_null($autoupdate_url_prefix) ? 0 : (1 << 7);
		$flags |= is_null($gif_search_username) ? 0 : (1 << 9);
		$flags |= is_null($venue_search_username) ? 0 : (1 << 10);
		$flags |= is_null($img_search_username) ? 0 : (1 << 11);
		$flags |= is_null($static_maps_provider) ? 0 : (1 << 12);
		$flags |= is_null($suggested_lang_code) ? 0 : (1 << 2);
		$flags |= is_null($lang_pack_version) ? 0 : (1 << 2);
		$flags |= is_null($base_lang_pack_version) ? 0 : (1 << 2);
		$flags |= is_null($reactions_default) ? 0 : (1 << 15);
		$flags |= is_null($autologin_token) ? 0 : (1 << 16);
		$writer->writeInt($flags);
		$writer->writeInt($date);
		$writer->writeInt($expires);
		$writer->writeBool($test_mode);
		$writer->writeInt($this_dc);
		$writer->writeVector($dc_options,'dcoption');
		$writer->writeBytes($dc_txt_domain_name);
		$writer->writeInt($chat_size_max);
		$writer->writeInt($megagroup_size_max);
		$writer->writeInt($forwarded_count_max);
		$writer->writeInt($online_update_period_ms);
		$writer->writeInt($offline_blur_timeout_ms);
		$writer->writeInt($offline_idle_timeout_ms);
		$writer->writeInt($online_cloud_timeout_ms);
		$writer->writeInt($notify_cloud_delay_ms);
		$writer->writeInt($notify_default_delay_ms);
		$writer->writeInt($push_chat_period_ms);
		$writer->writeInt($push_chat_limit);
		$writer->writeInt($edit_time_limit);
		$writer->writeInt($revoke_time_limit);
		$writer->writeInt($revoke_pm_time_limit);
		$writer->writeInt($rating_e_decay);
		$writer->writeInt($stickers_recent_limit);
		$writer->writeInt($channels_read_media_period);
		if(is_null($tmp_sessions) === false):
			$writer->writeInt($tmp_sessions);
		endif;
		$writer->writeInt($call_receive_timeout_ms);
		$writer->writeInt($call_ring_timeout_ms);
		$writer->writeInt($call_connect_timeout_ms);
		$writer->writeInt($call_packet_timeout_ms);
		$writer->writeBytes($me_url_prefix);
		if(is_null($autoupdate_url_prefix) === false):
			$writer->writeBytes($autoupdate_url_prefix);
		endif;
		if(is_null($gif_search_username) === false):
			$writer->writeBytes($gif_search_username);
		endif;
		if(is_null($venue_search_username) === false):
			$writer->writeBytes($venue_search_username);
		endif;
		if(is_null($img_search_username) === false):
			$writer->writeBytes($img_search_username);
		endif;
		if(is_null($static_maps_provider) === false):
			$writer->writeBytes($static_maps_provider);
		endif;
		$writer->writeInt($caption_length_max);
		$writer->writeInt($message_length_max);
		$writer->writeInt($webfile_dc_id);
		if(is_null($suggested_lang_code) === false):
			$writer->writeBytes($suggested_lang_code);
		endif;
		if(is_null($lang_pack_version) === false):
			$writer->writeInt($lang_pack_version);
		endif;
		if(is_null($base_lang_pack_version) === false):
			$writer->writeInt($base_lang_pack_version);
		endif;
		if(is_null($reactions_default) === false):
			$writer->writeObject($reactions_default);
		endif;
		if(is_null($autologin_token) === false):
			$writer->writeBytes($autologin_token);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['default_p2p_contacts'] = boolval($flags & (1 << 3));
		$result['preload_featured_stickers'] = boolval($flags & (1 << 4));
		$result['revoke_pm_inbox'] = boolval($flags & (1 << 6));
		$result['blocked_mode'] = boolval($flags & (1 << 8));
		$result['force_try_ipv6'] = boolval($flags & (1 << 14));
		$result['date'] = $reader->readInt();
		$result['expires'] = $reader->readInt();
		$result['test_mode'] = $reader->readBool();
		$result['this_dc'] = $reader->readInt();
		$result['dc_options'] = $reader->readVector('dcoption');
		$result['dc_txt_domain_name'] = $reader->readBytes();
		$result['chat_size_max'] = $reader->readInt();
		$result['megagroup_size_max'] = $reader->readInt();
		$result['forwarded_count_max'] = $reader->readInt();
		$result['online_update_period_ms'] = $reader->readInt();
		$result['offline_blur_timeout_ms'] = $reader->readInt();
		$result['offline_idle_timeout_ms'] = $reader->readInt();
		$result['online_cloud_timeout_ms'] = $reader->readInt();
		$result['notify_cloud_delay_ms'] = $reader->readInt();
		$result['notify_default_delay_ms'] = $reader->readInt();
		$result['push_chat_period_ms'] = $reader->readInt();
		$result['push_chat_limit'] = $reader->readInt();
		$result['edit_time_limit'] = $reader->readInt();
		$result['revoke_time_limit'] = $reader->readInt();
		$result['revoke_pm_time_limit'] = $reader->readInt();
		$result['rating_e_decay'] = $reader->readInt();
		$result['stickers_recent_limit'] = $reader->readInt();
		$result['channels_read_media_period'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['tmp_sessions'] = $reader->readInt();
		else:
			$result['tmp_sessions'] = null;
		endif;
		$result['call_receive_timeout_ms'] = $reader->readInt();
		$result['call_ring_timeout_ms'] = $reader->readInt();
		$result['call_connect_timeout_ms'] = $reader->readInt();
		$result['call_packet_timeout_ms'] = $reader->readInt();
		$result['me_url_prefix'] = $reader->readBytes();
		if($flags & (1 << 7)):
			$result['autoupdate_url_prefix'] = $reader->readBytes();
		else:
			$result['autoupdate_url_prefix'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['gif_search_username'] = $reader->readBytes();
		else:
			$result['gif_search_username'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['venue_search_username'] = $reader->readBytes();
		else:
			$result['venue_search_username'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['img_search_username'] = $reader->readBytes();
		else:
			$result['img_search_username'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['static_maps_provider'] = $reader->readBytes();
		else:
			$result['static_maps_provider'] = null;
		endif;
		$result['caption_length_max'] = $reader->readInt();
		$result['message_length_max'] = $reader->readInt();
		$result['webfile_dc_id'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['suggested_lang_code'] = $reader->readBytes();
		else:
			$result['suggested_lang_code'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['lang_pack_version'] = $reader->readInt();
		else:
			$result['lang_pack_version'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['base_lang_pack_version'] = $reader->readInt();
		else:
			$result['base_lang_pack_version'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['reactions_default'] = $reader->readObject();
		else:
			$result['reactions_default'] = null;
		endif;
		if($flags & (1 << 16)):
			$result['autologin_token'] = $reader->readBytes();
		else:
			$result['autologin_token'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text richtext credit
 * @return PageCaption
 */

final class PageCaption extends Instance {
	public function request(object $text,object $credit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6f747657);
		$writer->writeObject($text);
		$writer->writeObject($credit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		$result['credit'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypeIdentityCard extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa0d0744b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param mediaareacoordinates coordinates reaction reaction true dark true flipped
 * @return MediaArea
 */

final class MediaAreaSuggestedReaction extends Instance {
	public function request(object $coordinates,object $reaction,null | bool $dark = null,null | bool $flipped = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x14455871);
		$flags = 0;
		$flags |= $dark ? (1 << 0) : 0;
		$flags |= $flipped ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($coordinates);
		$writer->writeObject($reaction);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['dark'] = boolval($flags & (1 << 0));
		$result['flipped'] = boolval($flags & (1 << 1));
		$result['coordinates'] = $reader->readObject();
		$result['reaction'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterContacts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe062db83);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return TopPeerCategory
 */

final class TopPeerCategoryBotsApp extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfd9e7bec);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long collectible_id
 * @return PeerColor
 */

final class InputPeerColorCollectible extends Instance {
	public function request(int $collectible_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb8ea86a9);
		$writer->writeLong($collectible_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['collectible_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string name document document stargiftattributerarity rarity true crafted
 * @return StarGiftAttribute
 */

final class StarGiftAttributeModel extends Instance {
	public function request(string $name,object $document,object $rarity,null | bool $crafted = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x565251e2);
		$flags = 0;
		$flags |= $crafted ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($name);
		$writer->writeObject($document);
		$writer->writeObject($rarity);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['crafted'] = boolval($flags & (1 << 0));
		$result['name'] = $reader->readBytes();
		$result['document'] = $reader->readObject();
		$result['rarity'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id
 * @return Update
 */

final class UpdateChat extends Instance {
	public function request(int $chat_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf89a6a4e);
		$writer->writeLong($chat_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextAutoPhone extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x24c26789);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer boost boost int qts
 * @return Update
 */

final class UpdateBotChatBoost extends Instance {
	public function request(object $peer,object $boost,int $qts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x904dd49c);
		$writer->writeObject($peer);
		$writer->writeObject($boost);
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['boost'] = $reader->readObject();
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer_id storyitem story
 * @return StoryReaction
 */

final class StoryReactionPublicRepost extends Instance {
	public function request(object $peer_id,object $story) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcfcd0f13);
		$writer->writeObject($peer_id);
		$writer->writeObject($story);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer_id'] = $reader->readObject();
		$result['story'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return RequirementToContact
 */

final class RequirementToContactPremium extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe581e4e9);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string type inputphoto photo inputbotinlinemessage send_message
 * @return InputBotInlineResult
 */

final class InputBotInlineResultPhoto extends Instance {
	public function request(string $id,string $type,object $photo,object $send_message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa8d864a7);
		$writer->writeBytes($id);
		$writer->writeBytes($type);
		$writer->writeObject($photo);
		$writer->writeObject($send_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readBytes();
		$result['type'] = $reader->readBytes();
		$result['photo'] = $reader->readObject();
		$result['send_message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id inputphoto photo
 * @return InputRichFile
 */

final class InputRichFilePhoto extends Instance {
	public function request(string $id,object $photo) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9b00622b);
		$writer->writeBytes($id);
		$writer->writeObject($photo);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readBytes();
		$result['photo'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash bytes file_reference long volume_id int local_id long secret
 * @return InputFileLocation
 */

final class InputPhotoLegacyFileLocation extends Instance {
	public function request(int $id,int $access_hash,string $file_reference,int $volume_id,int $local_id,int $secret) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd83466f3);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($file_reference);
		$writer->writeLong($volume_id);
		$writer->writeInt($local_id);
		$writer->writeLong($secret);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['file_reference'] = $reader->readBytes();
		$result['volume_id'] = $reader->readLong();
		$result['local_id'] = $reader->readInt();
		$result['secret'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int min_layer int max_layer Vector<string> library_versions true udp_p2p true udp_reflector
 * @return PhoneCallProtocol
 */

final class PhoneCallProtocol extends Instance {
	public function request(int $min_layer,int $max_layer,array $library_versions,null | bool $udp_p2p = null,null | bool $udp_reflector = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfc878fc8);
		$flags = 0;
		$flags |= $udp_p2p ? (1 << 0) : 0;
		$flags |= $udp_reflector ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($min_layer);
		$writer->writeInt($max_layer);
		$writer->writeVector($library_versions,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['udp_p2p'] = boolval($flags & (1 << 0));
		$result['udp_reflector'] = boolval($flags & (1 << 1));
		$result['min_layer'] = $reader->readInt();
		$result['max_layer'] = $reader->readInt();
		$result['library_versions'] = $reader->readVector('string');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param notifypeer peer peernotifysettings notify_settings
 * @return Update
 */

final class UpdateNotifySettings extends Instance {
	public function request(object $peer,object $notify_settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbec268ef);
		$writer->writeObject($peer);
		$writer->writeObject($notify_settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['notify_settings'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id inputbusinessrecipients recipients int no_activity_days
 * @return InputBusinessGreetingMessage
 */

final class InputBusinessGreetingMessage extends Instance {
	public function request(int $shortcut_id,object $recipients,int $no_activity_days) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x194cb3b);
		$writer->writeInt($shortcut_id);
		$writer->writeObject($recipients);
		$writer->writeInt($no_activity_days);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['shortcut_id'] = $reader->readInt();
		$result['recipients'] = $reader->readObject();
		$result['no_activity_days'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text int button_id requestpeertype peer_type int max_quantity keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButtonRequestPeer extends Instance {
	public function request(string $text,int $button_id,object $peer_type,int $max_quantity,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5b0f15f5);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		$writer->writeInt($button_id);
		$writer->writeObject($peer_type);
		$writer->writeInt($max_quantity);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		$result['button_id'] = $reader->readInt();
		$result['peer_type'] = $reader->readObject();
		$result['max_quantity'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce int128 server_nonce int128 new_nonce_hash
 * @return Server_DH_Params
 */

final class ServerDHParamsFail extends Instance {
	public function request(int | string $nonce,int | string $server_nonce,int | string $new_nonce_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x79cb045d);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeLargeInt($new_nonce_hash,128);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['new_nonce_hash'] = $reader->readLargeInt(128);
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param emojistatus prev_value emojistatus new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeEmojiStatus extends Instance {
	public function request(object $prev_value,object $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3ea9feb1);
		$writer->writeObject($prev_value);
		$writer->writeObject($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readObject();
		$result['new_value'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id int date int subscription_until_date string rank
 * @return ChannelParticipant
 */

final class ChannelParticipant extends Instance {
	public function request(int $user_id,int $date,null | int $subscription_until_date = null,null | string $rank = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1bd54456);
		$flags = 0;
		$flags |= is_null($subscription_until_date) ? 0 : (1 << 0);
		$flags |= is_null($rank) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		$writer->writeInt($date);
		if(is_null($subscription_until_date) === false):
			$writer->writeInt($subscription_until_date);
		endif;
		if(is_null($rank) === false):
			$writer->writeBytes($rank);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['subscription_until_date'] = $reader->readInt();
		else:
			$result['subscription_until_date'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['rank'] = $reader->readBytes();
		else:
			$result['rank'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<document> stickers true emojis true text_color
 * @return WebPageAttribute
 */

final class WebPageAttributeStickerSet extends Instance {
	public function request(array $stickers,null | bool $emojis = null,null | bool $text_color = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x50cc03d3);
		$flags = 0;
		$flags |= $emojis ? (1 << 0) : 0;
		$flags |= $text_color ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($stickers,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['emojis'] = boolval($flags & (1 << 0));
		$result['text_color'] = boolval($flags & (1 << 1));
		$result['stickers'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int msg_id int date peer actor Vector<reaction> old_reactions Vector<reaction> new_reactions int qts
 * @return Update
 */

final class UpdateBotMessageReaction extends Instance {
	public function request(object $peer,int $msg_id,int $date,object $actor,array $old_reactions,array $new_reactions,int $qts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xac21d3ce);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeInt($date);
		$writer->writeObject($actor);
		$writer->writeVector($old_reactions,'reaction');
		$writer->writeVector($new_reactions,'reaction');
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['actor'] = $reader->readObject();
		$result['old_reactions'] = $reader->readVector('reaction');
		$result['new_reactions'] = $reader->readVector('reaction');
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReportReason
 */

final class InputReportReasonCopyright extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9b89f93a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id int available_min_id
 * @return Update
 */

final class UpdateChannelAvailableMessages extends Instance {
	public function request(int $channel_id,int $available_min_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb23fc698);
		$writer->writeLong($channel_id);
		$writer->writeInt($available_min_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['available_min_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> msg_ids bytes info
 * @return MsgsAllInfo
 */

final class MsgsAllInfo extends Instance {
	public function request(array $msg_ids,string $info) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8cc0d131);
		$writer->writeVector($msg_ids,'long');
		$writer->writeBytes($info);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_ids'] = $reader->readVector('long');
		$result['info'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string tone
 * @return InputAiComposeTone
 */

final class InputAiComposeToneDefault extends Instance {
	public function request(string $tone) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1fe9a9bf);
		$writer->writeBytes($tone);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['tone'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphoto id
 * @return InputChatPhoto
 */

final class InputChatPhoto extends Instance {
	public function request(object $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8953ad37);
		$writer->writeObject($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<messagerange> ranges true exclude_new_messages
 * @return ChannelMessagesFilter
 */

final class ChannelMessagesFilter extends Instance {
	public function request(array $ranges,null | bool $exclude_new_messages = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcd77d957);
		$flags = 0;
		$flags |= $exclude_new_messages ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($ranges,'messagerange');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['exclude_new_messages'] = boolval($flags & (1 << 1));
		$result['ranges'] = $reader->readVector('messagerange');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce int128 server_nonce int128 new_nonce_hash3
 * @return Set_client_DH_params_answer
 */

final class DhGenFail extends Instance {
	public function request(int | string $nonce,int | string $server_nonce,int | string $new_nonce_hash3) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa69dae02);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeLargeInt($new_nonce_hash3,128);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['new_nonce_hash3'] = $reader->readLargeInt(128);
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int date
 * @return MessagePeerVote
 */

final class MessagePeerVoteInputOption extends Instance {
	public function request(object $peer,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x74cda504);
		$writer->writeObject($peer);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param quickreply quick_reply
 * @return Update
 */

final class UpdateNewQuickReply extends Instance {
	public function request(object $quick_reply) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf53da717);
		$writer->writeObject($quick_reply);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['quick_reply'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterMusic extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3751b49e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> chats
 * @return InputPrivacyRule
 */

final class InputPrivacyValueAllowChatParticipants extends Instance {
	public function request(array $chats) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x840649cf);
		$writer->writeVector($chats,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chats'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes placeholder_path int background_color int background_dark_color int header_color int header_dark_color
 * @return BotAppSettings
 */

final class BotAppSettings extends Instance {
	public function request(null | string $placeholder_path = null,null | int $background_color = null,null | int $background_dark_color = null,null | int $header_color = null,null | int $header_dark_color = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc99b1950);
		$flags = 0;
		$flags |= is_null($placeholder_path) ? 0 : (1 << 0);
		$flags |= is_null($background_color) ? 0 : (1 << 1);
		$flags |= is_null($background_dark_color) ? 0 : (1 << 2);
		$flags |= is_null($header_color) ? 0 : (1 << 3);
		$flags |= is_null($header_dark_color) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		if(is_null($placeholder_path) === false):
			$writer->writeBytes($placeholder_path);
		endif;
		if(is_null($background_color) === false):
			$writer->writeInt($background_color);
		endif;
		if(is_null($background_dark_color) === false):
			$writer->writeInt($background_dark_color);
		endif;
		if(is_null($header_color) === false):
			$writer->writeInt($header_color);
		endif;
		if(is_null($header_dark_color) === false):
			$writer->writeInt($header_dark_color);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['placeholder_path'] = $reader->readBytes();
		else:
			$result['placeholder_path'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['background_color'] = $reader->readInt();
		else:
			$result['background_color'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['background_dark_color'] = $reader->readInt();
		else:
			$result['background_dark_color'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['header_color'] = $reader->readInt();
		else:
			$result['header_color'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['header_dark_color'] = $reader->readInt();
		else:
			$result['header_dark_color'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title int icon_color true title_missing long icon_emoji_id
 * @return MessageAction
 */

final class MessageActionTopicCreate extends Instance {
	public function request(string $title,int $icon_color,null | bool $title_missing = null,null | int $icon_emoji_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd999256);
		$flags = 0;
		$flags |= $title_missing ? (1 << 1) : 0;
		$flags |= is_null($icon_emoji_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($title);
		$writer->writeInt($icon_color);
		if(is_null($icon_emoji_id) === false):
			$writer->writeLong($icon_emoji_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['title_missing'] = boolval($flags & (1 << 1));
		$result['title'] = $reader->readBytes();
		$result['icon_color'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['icon_emoji_id'] = $reader->readLong();
		else:
			$result['icon_emoji_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string address int port
 * @return InputClientProxy
 */

final class InputClientProxy extends Instance {
	public function request(string $address,int $port) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x75588b3f);
		$writer->writeBytes($address);
		$writer->writeInt($port);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['address'] = $reader->readBytes();
		$result['port'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> chats
 * @return PrivacyRule
 */

final class PrivacyValueAllowChatParticipants extends Instance {
	public function request(array $chats) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6b134e8e);
		$writer->writeVector($chats,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chats'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int max_id int still_unread_count int pts int pts_count int folder_id int top_msg_id
 * @return Update
 */

final class UpdateReadHistoryInbox extends Instance {
	public function request(object $peer,int $max_id,int $still_unread_count,int $pts,int $pts_count,null | int $folder_id = null,null | int $top_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9e84bc99);
		$flags = 0;
		$flags |= is_null($folder_id) ? 0 : (1 << 0);
		$flags |= is_null($top_msg_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($folder_id) === false):
			$writer->writeInt($folder_id);
		endif;
		$writer->writeObject($peer);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		$writer->writeInt($max_id);
		$writer->writeInt($still_unread_count);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['folder_id'] = $reader->readInt();
		else:
			$result['folder_id'] = null;
		endif;
		$result['peer'] = $reader->readObject();
		if($flags & (1 << 1)):
			$result['top_msg_id'] = $reader->readInt();
		else:
			$result['top_msg_id'] = null;
		endif;
		$result['max_id'] = $reader->readInt();
		$result['still_unread_count'] = $reader->readInt();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterRoundVoice extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7a7c17a4);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyRule
 */

final class InputPrivacyValueAllowBots extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5a4fcce5);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message int pts int pts_count
 * @return Update
 */

final class UpdateEditChannelMessage extends Instance {
	public function request(object $message,int $pts,int $pts_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1b3f4df7);
		$writer->writeObject($message);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int top_message true pinned
 * @return SavedDialog
 */

final class SavedDialog extends Instance {
	public function request(object $peer,int $top_message,null | bool $pinned = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd87cb6c);
		$flags = 0;
		$flags |= $pinned ? (1 << 2) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($top_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pinned'] = boolval($flags & (1 << 2));
		$result['peer'] = $reader->readObject();
		$result['top_message'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string type
 * @return PhotoSize
 */

final class PhotoSizeEmpty extends Instance {
	public function request(string $type) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe17e23c);
		$writer->writeBytes($type);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string tone long emoji_id string title
 * @return AiComposeTone
 */

final class AiComposeToneDefault extends Instance {
	public function request(string $tone,int $emoji_id,string $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9bad6414);
		$writer->writeBytes($tone);
		$writer->writeLong($emoji_id);
		$writer->writeBytes($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['tone'] = $reader->readBytes();
		$result['emoji_id'] = $reader->readLong();
		$result['title'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int period long amount
 * @return StarsSubscriptionPricing
 */

final class StarsSubscriptionPricing extends Instance {
	public function request(int $period,int $amount) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5416d58);
		$writer->writeInt($period);
		$writer->writeLong($amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['period'] = $reader->readInt();
		$result['amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputfile file string mime_type Vector<documentattribute> attributes true nosound_video true force_file true spoiler inputfile thumb Vector<inputdocument> stickers inputphoto video_cover int video_timestamp int ttl_seconds
 * @return InputMedia
 */

final class InputMediaUploadedDocument extends Instance {
	public function request(object $file,string $mime_type,array $attributes,null | bool $nosound_video = null,null | bool $force_file = null,null | bool $spoiler = null,null | object $thumb = null,null | array $stickers = null,null | object $video_cover = null,null | int $video_timestamp = null,null | int $ttl_seconds = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x37c9330);
		$flags = 0;
		$flags |= $nosound_video ? (1 << 3) : 0;
		$flags |= $force_file ? (1 << 4) : 0;
		$flags |= $spoiler ? (1 << 5) : 0;
		$flags |= is_null($thumb) ? 0 : (1 << 2);
		$flags |= is_null($stickers) ? 0 : (1 << 0);
		$flags |= is_null($video_cover) ? 0 : (1 << 6);
		$flags |= is_null($video_timestamp) ? 0 : (1 << 7);
		$flags |= is_null($ttl_seconds) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($file);
		if(is_null($thumb) === false):
			$writer->writeObject($thumb);
		endif;
		$writer->writeBytes($mime_type);
		$writer->writeVector($attributes,'documentattribute');
		if(is_null($stickers) === false):
			$writer->writeVector($stickers,'inputdocument');
		endif;
		if(is_null($video_cover) === false):
			$writer->writeObject($video_cover);
		endif;
		if(is_null($video_timestamp) === false):
			$writer->writeInt($video_timestamp);
		endif;
		if(is_null($ttl_seconds) === false):
			$writer->writeInt($ttl_seconds);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['nosound_video'] = boolval($flags & (1 << 3));
		$result['force_file'] = boolval($flags & (1 << 4));
		$result['spoiler'] = boolval($flags & (1 << 5));
		$result['file'] = $reader->readObject();
		if($flags & (1 << 2)):
			$result['thumb'] = $reader->readObject();
		else:
			$result['thumb'] = null;
		endif;
		$result['mime_type'] = $reader->readBytes();
		$result['attributes'] = $reader->readVector('documentattribute');
		if($flags & (1 << 0)):
			$result['stickers'] = $reader->readVector('inputdocument');
		else:
			$result['stickers'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['video_cover'] = $reader->readObject();
		else:
			$result['video_cover'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['video_timestamp'] = $reader->readInt();
		else:
			$result['video_timestamp'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['ttl_seconds'] = $reader->readInt();
		else:
			$result['ttl_seconds'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type true native_names true selfie_required true translation_required
 * @return SecureRequiredType
 */

final class SecureRequiredType extends Instance {
	public function request(object $type,null | bool $native_names = null,null | bool $selfie_required = null,null | bool $translation_required = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x829d99da);
		$flags = 0;
		$flags |= $native_names ? (1 << 0) : 0;
		$flags |= $selfie_required ? (1 << 1) : 0;
		$flags |= $translation_required ? (1 << 2) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($type);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['native_names'] = boolval($flags & (1 << 0));
		$result['selfie_required'] = boolval($flags & (1 << 1));
		$result['translation_required'] = boolval($flags & (1 << 2));
		$result['type'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id string title string username photo photo
 * @return RequestedPeer
 */

final class RequestedPeerChannel extends Instance {
	public function request(int $channel_id,null | string $title = null,null | string $username = null,null | object $photo = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ba403e4);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$flags |= is_null($username) ? 0 : (1 << 1);
		$flags |= is_null($photo) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($channel_id);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($username) === false):
			$writer->writeBytes($username);
		endif;
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['channel_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['username'] = $reader->readBytes();
		else:
			$result['username'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypeInternalPassport extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x99a48f23);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateRecentStickers extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9a422c20);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionTogglePreHistoryHidden extends Instance {
	public function request(bool $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5f5c95f1);
		$writer->writeBool($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_value'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyAbout extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3823cc40);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PhoneCallDiscardReason
 */

final class PhoneCallDiscardReasonBusy extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfaf7e8c9);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return BotCommandScope
 */

final class BotCommandScopePeer extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdb9d897d);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer long query_id joinchatbotresult result
 * @return Update
 */

final class UpdateJoinChatWebViewDecision extends Instance {
	public function request(object $peer,int $query_id,object $result) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbdac7e70);
		$writer->writeObject($peer);
		$writer->writeLong($query_id);
		$writer->writeObject($result);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['query_id'] = $reader->readLong();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityCode extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x28a20571);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes salt
 * @return SecurePasswordKdfAlgo
 */

final class SecurePasswordKdfAlgoPBKDF2HMACSHA512iter100000 extends Instance {
	public function request(string $salt) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbbf2dda0);
		$writer->writeBytes($salt);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['salt'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true creator true bot_participant bool has_username bool forum chatadminrights user_admin_rights chatadminrights bot_admin_rights
 * @return RequestPeerType
 */

final class RequestPeerTypeChat extends Instance {
	public function request(null | bool $creator = null,null | bool $bot_participant = null,null | bool $has_username = null,null | bool $forum = null,null | object $user_admin_rights = null,null | object $bot_admin_rights = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc9f06e1b);
		$flags = 0;
		$flags |= $creator ? (1 << 0) : 0;
		$flags |= $bot_participant ? (1 << 5) : 0;
		$flags |= is_null($has_username) ? 0 : (1 << 3);
		$flags |= is_null($forum) ? 0 : (1 << 4);
		$flags |= is_null($user_admin_rights) ? 0 : (1 << 1);
		$flags |= is_null($bot_admin_rights) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($has_username) === false):
			$writer->writeBool($has_username);
		endif;
		if(is_null($forum) === false):
			$writer->writeBool($forum);
		endif;
		if(is_null($user_admin_rights) === false):
			$writer->writeObject($user_admin_rights);
		endif;
		if(is_null($bot_admin_rights) === false):
			$writer->writeObject($bot_admin_rights);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['creator'] = boolval($flags & (1 << 0));
		$result['bot_participant'] = boolval($flags & (1 << 5));
		if($flags & (1 << 3)):
			$result['has_username'] = $reader->readBool();
		else:
			$result['has_username'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['forum'] = $reader->readBool();
		else:
			$result['forum'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['user_admin_rights'] = $reader->readObject();
		else:
			$result['user_admin_rights'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['bot_admin_rights'] = $reader->readObject();
		else:
			$result['bot_admin_rights'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int version int start_date int end_date long min_bid_amount Vector<auctionbidlevel> bid_levels Vector<long> top_bidders int next_round_at int last_gift_num int gifts_left int current_round int total_rounds Vector<stargiftauctionround> rounds
 * @return StarGiftAuctionState
 */

final class StarGiftAuctionState extends Instance {
	public function request(int $version,int $start_date,int $end_date,int $min_bid_amount,array $bid_levels,array $top_bidders,int $next_round_at,int $last_gift_num,int $gifts_left,int $current_round,int $total_rounds,array $rounds) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x771a4e66);
		$writer->writeInt($version);
		$writer->writeInt($start_date);
		$writer->writeInt($end_date);
		$writer->writeLong($min_bid_amount);
		$writer->writeVector($bid_levels,'auctionbidlevel');
		$writer->writeVector($top_bidders,'long');
		$writer->writeInt($next_round_at);
		$writer->writeInt($last_gift_num);
		$writer->writeInt($gifts_left);
		$writer->writeInt($current_round);
		$writer->writeInt($total_rounds);
		$writer->writeVector($rounds,'stargiftauctionround');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['version'] = $reader->readInt();
		$result['start_date'] = $reader->readInt();
		$result['end_date'] = $reader->readInt();
		$result['min_bid_amount'] = $reader->readLong();
		$result['bid_levels'] = $reader->readVector('auctionbidlevel');
		$result['top_bidders'] = $reader->readVector('long');
		$result['next_round_at'] = $reader->readInt();
		$result['last_gift_num'] = $reader->readInt();
		$result['gifts_left'] = $reader->readInt();
		$result['current_round'] = $reader->readInt();
		$result['total_rounds'] = $reader->readInt();
		$result['rounds'] = $reader->readVector('stargiftauctionround');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int level long current_level_stars long stars long next_level_stars
 * @return StarsRating
 */

final class StarsRating extends Instance {
	public function request(int $level,int $current_level_stars,int $stars,null | int $next_level_stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1b0e4f07);
		$flags = 0;
		$flags |= is_null($next_level_stars) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($level);
		$writer->writeLong($current_level_stars);
		$writer->writeLong($stars);
		if(is_null($next_level_stars) === false):
			$writer->writeLong($next_level_stars);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['level'] = $reader->readInt();
		$result['current_level_stars'] = $reader->readLong();
		$result['stars'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['next_level_stars'] = $reader->readLong();
		else:
			$result['next_level_stars'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id Vector<int> messages int top_msg_id peer saved_peer_id
 * @return Update
 */

final class UpdateChannelReadMessagesContents extends Instance {
	public function request(int $channel_id,array $messages,null | int $top_msg_id = null,null | object $saved_peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x25f324f7);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($channel_id);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		$writer->writeVector($messages,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['channel_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['top_msg_id'] = $reader->readInt();
		else:
			$result['top_msg_id'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['saved_peer_id'] = $reader->readObject();
		else:
			$result['saved_peer_id'] = null;
		endif;
		$result['messages'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<update> updates Vector<user> users Vector<chat> chats int date int seq
 * @return Updates
 */

final class Updates extends Instance {
	public function request(array $updates,array $users,array $chats,int $date,int $seq) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x74ae4240);
		$writer->writeVector($updates,'update');
		$writer->writeVector($users,'user');
		$writer->writeVector($chats,'chat');
		$writer->writeInt($date);
		$writer->writeInt($seq);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['updates'] = $reader->readVector('update');
		$result['users'] = $reader->readVector('user');
		$result['chats'] = $reader->readVector('chat');
		$result['date'] = $reader->readInt();
		$result['seq'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string emoticon
 * @return Reaction
 */

final class ReactionEmoji extends Instance {
	public function request(string $emoticon) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1b2286b8);
		$writer->writeBytes($emoticon);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['emoticon'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string type int w int h Vector<int> sizes
 * @return PhotoSize
 */

final class PhotoSizeProgressive extends Instance {
	public function request(string $type,int $w,int $h,array $sizes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfa3efb95);
		$writer->writeBytes($type);
		$writer->writeInt($w);
		$writer->writeInt($h);
		$writer->writeVector($sizes,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readBytes();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		$result['sizes'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string type inputdocument document inputbotinlinemessage send_message string title string description
 * @return InputBotInlineResult
 */

final class InputBotInlineResultDocument extends Instance {
	public function request(string $id,string $type,object $document,object $send_message,null | string $title = null,null | string $description = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfff8fdc4);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 1);
		$flags |= is_null($description) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($id);
		$writer->writeBytes($type);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($description) === false):
			$writer->writeBytes($description);
		endif;
		$writer->writeObject($document);
		$writer->writeObject($send_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readBytes();
		$result['type'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['description'] = $reader->readBytes();
		else:
			$result['description'] = null;
		endif;
		$result['document'] = $reader->readObject();
		$result['send_message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param theme theme
 * @return Update
 */

final class UpdateTheme extends Instance {
	public function request(object $theme) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8216fba3);
		$writer->writeObject($theme);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['theme'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param poll poll Vector<int> correct_answers inputmedia attached_media string solution Vector<messageentity> solution_entities inputmedia solution_media
 * @return InputMedia
 */

final class InputMediaPoll extends Instance {
	public function request(object $poll,null | array $correct_answers = null,null | object $attached_media = null,null | string $solution = null,null | array $solution_entities = null,null | object $solution_media = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x883a4108);
		$flags = 0;
		$flags |= is_null($correct_answers) ? 0 : (1 << 0);
		$flags |= is_null($attached_media) ? 0 : (1 << 3);
		$flags |= is_null($solution) ? 0 : (1 << 1);
		$flags |= is_null($solution_entities) ? 0 : (1 << 1);
		$flags |= is_null($solution_media) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($poll);
		if(is_null($correct_answers) === false):
			$writer->writeVector($correct_answers,'int');
		endif;
		if(is_null($attached_media) === false):
			$writer->writeObject($attached_media);
		endif;
		if(is_null($solution) === false):
			$writer->writeBytes($solution);
		endif;
		if(is_null($solution_entities) === false):
			$writer->writeVector($solution_entities,'messageentity');
		endif;
		if(is_null($solution_media) === false):
			$writer->writeObject($solution_media);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['poll'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['correct_answers'] = $reader->readVector('int');
		else:
			$result['correct_answers'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['attached_media'] = $reader->readObject();
		else:
			$result['attached_media'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['solution'] = $reader->readBytes();
		else:
			$result['solution'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['solution_entities'] = $reader->readVector('messageentity');
		else:
			$result['solution_entities'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['solution_media'] = $reader->readObject();
		else:
			$result['solution_media'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stickerset set
 * @return StickerSetCovered
 */

final class StickerSetNoCovered extends Instance {
	public function request(object $set) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x77b15d1c);
		$writer->writeObject($set);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['set'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<securerequiredtype> types
 * @return SecureRequiredType
 */

final class SecureRequiredTypeOneOf extends Instance {
	public function request(array $types) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x27477b4);
		$writer->writeVector($types,'securerequiredtype');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['types'] = $reader->readVector('securerequiredtype');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<pagetablecell> cells
 * @return PageTableRow
 */

final class PageTableRow extends Instance {
	public function request(array $cells) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe0c0c5e5);
		$writer->writeVector($cells,'pagetablecell');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['cells'] = $reader->readVector('pagetablecell');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string name document icon Vector<attachmenuboticoncolor> colors
 * @return AttachMenuBotIcon
 */

final class AttachMenuBotIcon extends Instance {
	public function request(string $name,object $icon,null | array $colors = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb2a7386b);
		$flags = 0;
		$flags |= is_null($colors) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($name);
		$writer->writeObject($icon);
		if(is_null($colors) === false):
			$writer->writeVector($colors,'attachmenuboticoncolor');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['name'] = $reader->readBytes();
		$result['icon'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['colors'] = $reader->readVector('attachmenuboticoncolor');
		else:
			$result['colors'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param dialogpeer peer true pinned
 * @return Update
 */

final class UpdateSavedDialogPinned extends Instance {
	public function request(object $peer,null | bool $pinned = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaeaf9e74);
		$flags = 0;
		$flags |= $pinned ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pinned'] = boolval($flags & (1 << 0));
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param photo prev_photo photo new_photo
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangePhoto extends Instance {
	public function request(object $prev_photo,object $new_photo) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x434bd2af);
		$writer->writeObject($prev_photo);
		$writer->writeObject($new_photo);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_photo'] = $reader->readObject();
		$result['new_photo'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id sendmessageaction action int top_msg_id
 * @return Update
 */

final class UpdateUserTyping extends Instance {
	public function request(int $user_id,object $action,null | int $top_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2a17bf5c);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		$writer->writeObject($action);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['top_msg_id'] = $reader->readInt();
		else:
			$result['top_msg_id'] = null;
		endif;
		$result['action'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return AttachMenuPeerType
 */

final class AttachMenuPeerTypeChat extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x509113f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return GeoPoint
 */

final class GeoPointEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1117dd5f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bot_id long icon string description
 * @return BotVerification
 */

final class BotVerification extends Instance {
	public function request(int $bot_id,int $icon,string $description) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf93cd45c);
		$writer->writeLong($bot_id);
		$writer->writeLong($icon);
		$writer->writeBytes($description);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['bot_id'] = $reader->readLong();
		$result['icon'] = $reader->readLong();
		$result['description'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash bytes file_reference string thumb_size
 * @return InputFileLocation
 */

final class InputPhotoFileLocation extends Instance {
	public function request(int $id,int $access_hash,string $file_reference,string $thumb_size) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x40181ffe);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($file_reference);
		$writer->writeBytes($thumb_size);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['file_reference'] = $reader->readBytes();
		$result['thumb_size'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return NotificationSound
 */

final class NotificationSoundDefault extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x97e8bebe);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param mediaareacoordinates coordinates geopoint geo geopointaddress address
 * @return MediaArea
 */

final class MediaAreaGeoPoint extends Instance {
	public function request(object $coordinates,object $geo,null | object $address = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcad5452d);
		$flags = 0;
		$flags |= is_null($address) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($coordinates);
		$writer->writeObject($geo);
		if(is_null($address) === false):
			$writer->writeObject($address);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['coordinates'] = $reader->readObject();
		$result['geo'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['address'] = $reader->readObject();
		else:
			$result['address'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securepasswordkdfalgo secure_algo bytes secure_secret long secure_secret_id
 * @return SecureSecretSettings
 */

final class SecureSecretSettings extends Instance {
	public function request(object $secure_algo,string $secure_secret,int $secure_secret_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1527bcac);
		$writer->writeObject($secure_algo);
		$writer->writeBytes($secure_secret);
		$writer->writeLong($secure_secret_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['secure_algo'] = $reader->readObject();
		$result['secure_secret'] = $reader->readBytes();
		$result['secure_secret_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id long user_id inputbotinlinemessageid msg_id long chat_instance bytes data string game_short_name
 * @return Update
 */

final class UpdateInlineBotCallbackQuery extends Instance {
	public function request(int $query_id,int $user_id,object $msg_id,int $chat_instance,null | string $data = null,null | string $game_short_name = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x691e9052);
		$flags = 0;
		$flags |= is_null($data) ? 0 : (1 << 0);
		$flags |= is_null($game_short_name) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($query_id);
		$writer->writeLong($user_id);
		$writer->writeObject($msg_id);
		$writer->writeLong($chat_instance);
		if(is_null($data) === false):
			$writer->writeBytes($data);
		endif;
		if(is_null($game_short_name) === false):
			$writer->writeBytes($game_short_name);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['query_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		$result['msg_id'] = $reader->readObject();
		$result['chat_instance'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['data'] = $reader->readBytes();
		else:
			$result['data'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['game_short_name'] = $reader->readBytes();
		else:
			$result['game_short_name'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReportReason
 */

final class InputReportReasonPornography extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2e59d922);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id bool enabled
 * @return Update
 */

final class UpdateChannelViewForumAsMessages extends Instance {
	public function request(int $channel_id,bool $enabled) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7b68920);
		$writer->writeLong($channel_id);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['enabled'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<document> icons
 * @return WebPageAttribute
 */

final class WebPageAttributeStarGiftCollection extends Instance {
	public function request(array $icons) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31cad303);
		$writer->writeVector($icons,'document');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['icons'] = $reader->readVector('document');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<jsonvalue> value
 * @return JSONValue
 */

final class JsonArray extends Instance {
	public function request(array $value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf7444763);
		$writer->writeVector($value,'jsonvalue');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['value'] = $reader->readVector('jsonvalue');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q int top_msg_id
 * @return ChannelParticipantsFilter
 */

final class ChannelParticipantsMentions extends Instance {
	public function request(null | string $q = null,null | int $top_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe04b5ceb);
		$flags = 0;
		$flags |= is_null($q) ? 0 : (1 << 0);
		$flags |= is_null($top_msg_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($q) === false):
			$writer->writeBytes($q);
		endif;
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['q'] = $reader->readBytes();
		else:
			$result['q'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['top_msg_id'] = $reader->readInt();
		else:
			$result['top_msg_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string game_hash long ton_amount bytes client_seed
 * @return InputMedia
 */

final class InputMediaStakeDice extends Instance {
	public function request(string $game_hash,int $ton_amount,string $client_seed) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf3a9244a);
		$writer->writeBytes($game_hash);
		$writer->writeLong($ton_amount);
		$writer->writeBytes($client_seed);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['game_hash'] = $reader->readBytes();
		$result['ton_amount'] = $reader->readLong();
		$result['client_seed'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long msg_id int seq_no int bytes
 * @return RpcDropAnswer
 */

final class RpcAnswerDropped extends Instance {
	public function request(int $msg_id,int $seq_no,int $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa43ad8b7);
		$writer->writeLong($msg_id);
		$writer->writeInt($seq_no);
		$writer->writeInt($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_id'] = $reader->readLong();
		$result['seq_no'] = $reader->readInt();
		$result['bytes'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return DestroyAuthKeyRes
 */

final class DestroyAuthKeyNone extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa9f2259);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message true no_webpage true invert_media Vector<messageentity> entities replymarkup reply_markup
 * @return BotInlineMessage
 */

final class BotInlineMessageText extends Instance {
	public function request(string $message,null | bool $no_webpage = null,null | bool $invert_media = null,null | array $entities = null,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c7f65e2);
		$flags = 0;
		$flags |= $no_webpage ? (1 << 0) : 0;
		$flags |= $invert_media ? (1 << 3) : 0;
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['no_webpage'] = boolval($flags & (1 << 0));
		$result['invert_media'] = boolval($flags & (1 << 3));
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash
 * @return EmailVerifyPurpose
 */

final class EmailVerifyPurposeLoginSetup extends Instance {
	public function request(string $phone_number,string $phone_code_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4345be73);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone_number'] = $reader->readBytes();
		$result['phone_code_hash'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int progress
 * @return SendMessageAction
 */

final class SendMessageUploadPhotoAction extends Instance {
	public function request(int $progress) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd1d34a26);
		$writer->writeInt($progress);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['progress'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string connection_id long user_id int dc_id int date true disabled businessbotrights rights
 * @return BotBusinessConnection
 */

final class BotBusinessConnection extends Instance {
	public function request(string $connection_id,int $user_id,int $dc_id,int $date,null | bool $disabled = null,null | object $rights = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8f34b2f5);
		$flags = 0;
		$flags |= $disabled ? (1 << 1) : 0;
		$flags |= is_null($rights) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($connection_id);
		$writer->writeLong($user_id);
		$writer->writeInt($dc_id);
		$writer->writeInt($date);
		if(is_null($rights) === false):
			$writer->writeObject($rights);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['disabled'] = boolval($flags & (1 << 1));
		$result['connection_id'] = $reader->readBytes();
		$result['user_id'] = $reader->readLong();
		$result['dc_id'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['rights'] = $reader->readObject();
		else:
			$result['rights'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer boost_peer long random_id int until_date string currency long amount true only_new_subscribers true winners_are_visible Vector<inputpeer> additional_peers Vector<string> countries_iso2 string prize_description
 * @return InputStorePaymentPurpose
 */

final class InputStorePaymentPremiumGiveaway extends Instance {
	public function request(object $boost_peer,int $random_id,int $until_date,string $currency,int $amount,null | bool $only_new_subscribers = null,null | bool $winners_are_visible = null,null | array $additional_peers = null,null | array $countries_iso2 = null,null | string $prize_description = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x160544ca);
		$flags = 0;
		$flags |= $only_new_subscribers ? (1 << 0) : 0;
		$flags |= $winners_are_visible ? (1 << 3) : 0;
		$flags |= is_null($additional_peers) ? 0 : (1 << 1);
		$flags |= is_null($countries_iso2) ? 0 : (1 << 2);
		$flags |= is_null($prize_description) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeObject($boost_peer);
		if(is_null($additional_peers) === false):
			$writer->writeVector($additional_peers,'inputpeer');
		endif;
		if(is_null($countries_iso2) === false):
			$writer->writeVector($countries_iso2,'string');
		endif;
		if(is_null($prize_description) === false):
			$writer->writeBytes($prize_description);
		endif;
		$writer->writeLong($random_id);
		$writer->writeInt($until_date);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['only_new_subscribers'] = boolval($flags & (1 << 0));
		$result['winners_are_visible'] = boolval($flags & (1 << 3));
		$result['boost_peer'] = $reader->readObject();
		if($flags & (1 << 1)):
			$result['additional_peers'] = $reader->readVector('inputpeer');
		else:
			$result['additional_peers'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['countries_iso2'] = $reader->readVector('string');
		else:
			$result['countries_iso2'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['prize_description'] = $reader->readBytes();
		else:
			$result['prize_description'] = null;
		endif;
		$result['random_id'] = $reader->readLong();
		$result['until_date'] = $reader->readInt();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long call_id true missed true active true video int duration Vector<peer> other_participants
 * @return MessageAction
 */

final class MessageActionConferenceCall extends Instance {
	public function request(int $call_id,null | bool $missed = null,null | bool $active = null,null | bool $video = null,null | int $duration = null,null | array $other_participants = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2ffe2f7a);
		$flags = 0;
		$flags |= $missed ? (1 << 0) : 0;
		$flags |= $active ? (1 << 1) : 0;
		$flags |= $video ? (1 << 4) : 0;
		$flags |= is_null($duration) ? 0 : (1 << 2);
		$flags |= is_null($other_participants) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeLong($call_id);
		if(is_null($duration) === false):
			$writer->writeInt($duration);
		endif;
		if(is_null($other_participants) === false):
			$writer->writeVector($other_participants,'peer');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['missed'] = boolval($flags & (1 << 0));
		$result['active'] = boolval($flags & (1 << 1));
		$result['video'] = boolval($flags & (1 << 4));
		$result['call_id'] = $reader->readLong();
		if($flags & (1 << 2)):
			$result['duration'] = $reader->readInt();
		else:
			$result['duration'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['other_participants'] = $reader->readVector('peer');
		else:
			$result['other_participants'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long phone_call_id bytes data
 * @return Update
 */

final class UpdatePhoneCallSignalingData extends Instance {
	public function request(int $phone_call_id,string $data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2661bf09);
		$writer->writeLong($phone_call_id);
		$writer->writeBytes($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone_call_id'] = $reader->readLong();
		$result['data'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string pq string p string q int128 nonce int128 server_nonce int256 new_nonce int dc
 * @return P_Q_inner_data
 */

final class PQInnerDataDc extends Instance {
	public function request(string $pq,string $p,string $q,int | string $nonce,int | string $server_nonce,int | string $new_nonce,int $dc) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa9f55f95);
		$writer->writeBytes($pq);
		$writer->writeBytes($p);
		$writer->writeBytes($q);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeLargeInt($new_nonce,256);
		$writer->writeInt($dc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pq'] = $reader->readBytes();
		$result['p'] = $reader->readBytes();
		$result['q'] = $reader->readBytes();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['new_nonce'] = $reader->readLargeInt(256);
		$result['dc'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id bool mutual
 * @return Contact
 */

final class Contact extends Instance {
	public function request(int $user_id,bool $mutual) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x145ade0b);
		$writer->writeLong($user_id);
		$writer->writeBool($mutual);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['mutual'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int ipv4 int port bytes secret
 * @return IpPort
 */

final class IpPortSecret extends Instance {
	public function request(int $ipv4,int $port,string $secret) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x37982646);
		$writer->writeInt($ipv4);
		$writer->writeInt($port);
		$writer->writeBytes($secret);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['ipv4'] = $reader->readInt();
		$result['port'] = $reader->readInt();
		$result['secret'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id int id int views
 * @return Update
 */

final class UpdateChannelMessageViews extends Instance {
	public function request(int $channel_id,int $id,int $views) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf226ac08);
		$writer->writeLong($channel_id);
		$writer->writeInt($id);
		$writer->writeInt($views);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['id'] = $reader->readInt();
		$result['views'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string suggestion textwithentities title textwithentities description string url
 * @return PendingSuggestion
 */

final class PendingSuggestion extends Instance {
	public function request(string $suggestion,object $title,object $description,string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe7e82e12);
		$writer->writeBytes($suggestion);
		$writer->writeObject($title);
		$writer->writeObject($description);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['suggestion'] = $reader->readBytes();
		$result['title'] = $reader->readObject();
		$result['description'] = $reader->readObject();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id string title chatphoto photo int date true creator true left true broadcast true verified true megagroup true restricted true signatures true min true scam true has_link true has_geo true slowmode_enabled true call_active true call_not_empty true fake true gigagroup true noforwards true join_to_send true join_request true forum true stories_hidden true stories_hidden_min true stories_unavailable true signature_profiles true autotranslation true broadcast_messages_allowed true monoforum true forum_tabs long access_hash string username Vector<restrictionreason> restriction_reason chatadminrights admin_rights chatbannedrights banned_rights chatbannedrights default_banned_rights int participants_count Vector<username> usernames recentstory stories_max_id peercolor color peercolor profile_color emojistatus emoji_status int level int subscription_until_date long bot_verification_icon long send_paid_messages_stars long linked_monoforum_id
 * @return Chat
 */

final class Channel extends Instance {
	public function request(int $id,string $title,object $photo,int $date,null | bool $creator = null,null | bool $left = null,null | bool $broadcast = null,null | bool $verified = null,null | bool $megagroup = null,null | bool $restricted = null,null | bool $signatures = null,null | bool $min = null,null | bool $scam = null,null | bool $has_link = null,null | bool $has_geo = null,null | bool $slowmode_enabled = null,null | bool $call_active = null,null | bool $call_not_empty = null,null | bool $fake = null,null | bool $gigagroup = null,null | bool $noforwards = null,null | bool $join_to_send = null,null | bool $join_request = null,null | bool $forum = null,null | bool $stories_hidden = null,null | bool $stories_hidden_min = null,null | bool $stories_unavailable = null,null | bool $signature_profiles = null,null | bool $autotranslation = null,null | bool $broadcast_messages_allowed = null,null | bool $monoforum = null,null | bool $forum_tabs = null,null | int $access_hash = null,null | string $username = null,null | array $restriction_reason = null,null | object $admin_rights = null,null | object $banned_rights = null,null | object $default_banned_rights = null,null | int $participants_count = null,null | array $usernames = null,null | object $stories_max_id = null,null | object $color = null,null | object $profile_color = null,null | object $emoji_status = null,null | int $level = null,null | int $subscription_until_date = null,null | int $bot_verification_icon = null,null | int $send_paid_messages_stars = null,null | int $linked_monoforum_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1c32b11c);
		$flags = 0;
		$flags |= $creator ? (1 << 0) : 0;
		$flags |= $left ? (1 << 2) : 0;
		$flags |= $broadcast ? (1 << 5) : 0;
		$flags |= $verified ? (1 << 7) : 0;
		$flags |= $megagroup ? (1 << 8) : 0;
		$flags |= $restricted ? (1 << 9) : 0;
		$flags |= $signatures ? (1 << 11) : 0;
		$flags |= $min ? (1 << 12) : 0;
		$flags |= $scam ? (1 << 19) : 0;
		$flags |= $has_link ? (1 << 20) : 0;
		$flags |= $has_geo ? (1 << 21) : 0;
		$flags |= $slowmode_enabled ? (1 << 22) : 0;
		$flags |= $call_active ? (1 << 23) : 0;
		$flags |= $call_not_empty ? (1 << 24) : 0;
		$flags |= $fake ? (1 << 25) : 0;
		$flags |= $gigagroup ? (1 << 26) : 0;
		$flags |= $noforwards ? (1 << 27) : 0;
		$flags |= $join_to_send ? (1 << 28) : 0;
		$flags |= $join_request ? (1 << 29) : 0;
		$flags |= $forum ? (1 << 30) : 0;
		$flags |= is_null($access_hash) ? 0 : (1 << 13);
		$flags |= is_null($username) ? 0 : (1 << 6);
		$flags |= is_null($restriction_reason) ? 0 : (1 << 9);
		$flags |= is_null($admin_rights) ? 0 : (1 << 14);
		$flags |= is_null($banned_rights) ? 0 : (1 << 15);
		$flags |= is_null($default_banned_rights) ? 0 : (1 << 18);
		$flags |= is_null($participants_count) ? 0 : (1 << 17);
		$writer->writeInt($flags);
		$flags2 = 0;
		$flags2 |= $stories_hidden ? (1 << 1) : 0;
		$flags2 |= $stories_hidden_min ? (1 << 2) : 0;
		$flags2 |= $stories_unavailable ? (1 << 3) : 0;
		$flags2 |= $signature_profiles ? (1 << 12) : 0;
		$flags2 |= $autotranslation ? (1 << 15) : 0;
		$flags2 |= $broadcast_messages_allowed ? (1 << 16) : 0;
		$flags2 |= $monoforum ? (1 << 17) : 0;
		$flags2 |= $forum_tabs ? (1 << 19) : 0;
		$flags2 |= is_null($usernames) ? 0 : (1 << 0);
		$flags2 |= is_null($stories_max_id) ? 0 : (1 << 4);
		$flags2 |= is_null($color) ? 0 : (1 << 7);
		$flags2 |= is_null($profile_color) ? 0 : (1 << 8);
		$flags2 |= is_null($emoji_status) ? 0 : (1 << 9);
		$flags2 |= is_null($level) ? 0 : (1 << 10);
		$flags2 |= is_null($subscription_until_date) ? 0 : (1 << 11);
		$flags2 |= is_null($bot_verification_icon) ? 0 : (1 << 13);
		$flags2 |= is_null($send_paid_messages_stars) ? 0 : (1 << 14);
		$flags2 |= is_null($linked_monoforum_id) ? 0 : (1 << 18);
		$writer->writeInt($flags2);
		$writer->writeLong($id);
		if(is_null($access_hash) === false):
			$writer->writeLong($access_hash);
		endif;
		$writer->writeBytes($title);
		if(is_null($username) === false):
			$writer->writeBytes($username);
		endif;
		$writer->writeObject($photo);
		$writer->writeInt($date);
		if(is_null($restriction_reason) === false):
			$writer->writeVector($restriction_reason,'restrictionreason');
		endif;
		if(is_null($admin_rights) === false):
			$writer->writeObject($admin_rights);
		endif;
		if(is_null($banned_rights) === false):
			$writer->writeObject($banned_rights);
		endif;
		if(is_null($default_banned_rights) === false):
			$writer->writeObject($default_banned_rights);
		endif;
		if(is_null($participants_count) === false):
			$writer->writeInt($participants_count);
		endif;
		if(is_null($usernames) === false):
			$writer->writeVector($usernames,'username');
		endif;
		if(is_null($stories_max_id) === false):
			$writer->writeObject($stories_max_id);
		endif;
		if(is_null($color) === false):
			$writer->writeObject($color);
		endif;
		if(is_null($profile_color) === false):
			$writer->writeObject($profile_color);
		endif;
		if(is_null($emoji_status) === false):
			$writer->writeObject($emoji_status);
		endif;
		if(is_null($level) === false):
			$writer->writeInt($level);
		endif;
		if(is_null($subscription_until_date) === false):
			$writer->writeInt($subscription_until_date);
		endif;
		if(is_null($bot_verification_icon) === false):
			$writer->writeLong($bot_verification_icon);
		endif;
		if(is_null($send_paid_messages_stars) === false):
			$writer->writeLong($send_paid_messages_stars);
		endif;
		if(is_null($linked_monoforum_id) === false):
			$writer->writeLong($linked_monoforum_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['creator'] = boolval($flags & (1 << 0));
		$result['left'] = boolval($flags & (1 << 2));
		$result['broadcast'] = boolval($flags & (1 << 5));
		$result['verified'] = boolval($flags & (1 << 7));
		$result['megagroup'] = boolval($flags & (1 << 8));
		$result['restricted'] = boolval($flags & (1 << 9));
		$result['signatures'] = boolval($flags & (1 << 11));
		$result['min'] = boolval($flags & (1 << 12));
		$result['scam'] = boolval($flags & (1 << 19));
		$result['has_link'] = boolval($flags & (1 << 20));
		$result['has_geo'] = boolval($flags & (1 << 21));
		$result['slowmode_enabled'] = boolval($flags & (1 << 22));
		$result['call_active'] = boolval($flags & (1 << 23));
		$result['call_not_empty'] = boolval($flags & (1 << 24));
		$result['fake'] = boolval($flags & (1 << 25));
		$result['gigagroup'] = boolval($flags & (1 << 26));
		$result['noforwards'] = boolval($flags & (1 << 27));
		$result['join_to_send'] = boolval($flags & (1 << 28));
		$result['join_request'] = boolval($flags & (1 << 29));
		$result['forum'] = boolval($flags & (1 << 30));
		$flags2 = $reader->readInt();
		$result['stories_hidden'] = boolval($flags2 & (1 << 1));
		$result['stories_hidden_min'] = boolval($flags2 & (1 << 2));
		$result['stories_unavailable'] = boolval($flags2 & (1 << 3));
		$result['signature_profiles'] = boolval($flags2 & (1 << 12));
		$result['autotranslation'] = boolval($flags2 & (1 << 15));
		$result['broadcast_messages_allowed'] = boolval($flags2 & (1 << 16));
		$result['monoforum'] = boolval($flags2 & (1 << 17));
		$result['forum_tabs'] = boolval($flags2 & (1 << 19));
		$result['id'] = $reader->readLong();
		if($flags & (1 << 13)):
			$result['access_hash'] = $reader->readLong();
		else:
			$result['access_hash'] = null;
		endif;
		$result['title'] = $reader->readBytes();
		if($flags & (1 << 6)):
			$result['username'] = $reader->readBytes();
		else:
			$result['username'] = null;
		endif;
		$result['photo'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 9)):
			$result['restriction_reason'] = $reader->readVector('restrictionreason');
		else:
			$result['restriction_reason'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['admin_rights'] = $reader->readObject();
		else:
			$result['admin_rights'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['banned_rights'] = $reader->readObject();
		else:
			$result['banned_rights'] = null;
		endif;
		if($flags & (1 << 18)):
			$result['default_banned_rights'] = $reader->readObject();
		else:
			$result['default_banned_rights'] = null;
		endif;
		if($flags & (1 << 17)):
			$result['participants_count'] = $reader->readInt();
		else:
			$result['participants_count'] = null;
		endif;
		if($flags2 & (1 << 0)):
			$result['usernames'] = $reader->readVector('username');
		else:
			$result['usernames'] = null;
		endif;
		if($flags2 & (1 << 4)):
			$result['stories_max_id'] = $reader->readObject();
		else:
			$result['stories_max_id'] = null;
		endif;
		if($flags2 & (1 << 7)):
			$result['color'] = $reader->readObject();
		else:
			$result['color'] = null;
		endif;
		if($flags2 & (1 << 8)):
			$result['profile_color'] = $reader->readObject();
		else:
			$result['profile_color'] = null;
		endif;
		if($flags2 & (1 << 9)):
			$result['emoji_status'] = $reader->readObject();
		else:
			$result['emoji_status'] = null;
		endif;
		if($flags2 & (1 << 10)):
			$result['level'] = $reader->readInt();
		else:
			$result['level'] = null;
		endif;
		if($flags2 & (1 << 11)):
			$result['subscription_until_date'] = $reader->readInt();
		else:
			$result['subscription_until_date'] = null;
		endif;
		if($flags2 & (1 << 13)):
			$result['bot_verification_icon'] = $reader->readLong();
		else:
			$result['bot_verification_icon'] = null;
		endif;
		if($flags2 & (1 << 14)):
			$result['send_paid_messages_stars'] = $reader->readLong();
		else:
			$result['send_paid_messages_stars'] = null;
		endif;
		if($flags2 & (1 << 18)):
			$result['linked_monoforum_id'] = $reader->readLong();
		else:
			$result['linked_monoforum_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type Vector<bytes> file_hash string text
 * @return SecureValueError
 */

final class SecureValueErrorTranslationFiles extends Instance {
	public function request(object $type,array $file_hash,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x34636dd8);
		$writer->writeObject($type);
		$writer->writeVector($file_hash,'bytes');
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readObject();
		$result['file_hash'] = $reader->readVector('bytes');
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InlineQueryPeerType
 */

final class InlineQueryPeerTypePM extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x833c0fac);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer monoforum_peer_id
 * @return InputReplyTo
 */

final class InputReplyToMonoForum extends Instance {
	public function request(object $monoforum_peer_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x69d66c45);
		$writer->writeObject($monoforum_peer_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['monoforum_peer_id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return NotificationSound
 */

final class NotificationSoundNone extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6f0c34df);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyRule
 */

final class PrivacyValueDisallowAll extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8b73e763);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message Vector<messageentity> entities string title
 * @return InputBusinessChatLink
 */

final class InputBusinessChatLink extends Instance {
	public function request(string $message,null | array $entities = null,null | string $title = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x11679fa7);
		$flags = 0;
		$flags |= is_null($entities) ? 0 : (1 << 0);
		$flags |= is_null($title) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyRule
 */

final class InputPrivacyValueAllowAll extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x184b35ce);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pos long user_id int score
 * @return HighScore
 */

final class HighScore extends Instance {
	public function request(int $pos,int $user_id,int $score) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x73a379eb);
		$writer->writeInt($pos);
		$writer->writeLong($user_id);
		$writer->writeInt($score);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pos'] = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		$result['score'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id string title photo photo
 * @return RequestedPeer
 */

final class RequestedPeerChat extends Instance {
	public function request(int $chat_id,null | string $title = null,null | object $photo = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7307544f);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$flags |= is_null($photo) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($chat_id);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['chat_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityPhone extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9b69e34b);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long srp_id bytes A bytes M1
 * @return InputCheckPasswordSRP
 */

final class InputCheckPasswordSRP extends Instance {
	public function request(int $srp_id,string $A,string $M1) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd27ff082);
		$writer->writeLong($srp_id);
		$writer->writeBytes($A);
		$writer->writeBytes($M1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['srp_id'] = $reader->readLong();
		$result['A'] = $reader->readBytes();
		$result['M1'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id dialogfilter filter
 * @return Update
 */

final class UpdateDialogFilter extends Instance {
	public function request(int $id,null | object $filter = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x26ffde7d);
		$flags = 0;
		$flags |= is_null($filter) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		if(is_null($filter) === false):
			$writer->writeObject($filter);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['filter'] = $reader->readObject();
		else:
			$result['filter'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int value string emoticon messages.emojigameoutcome game_outcome
 * @return MessageMedia
 */

final class MessageMediaDice extends Instance {
	public function request(int $value,string $emoticon,null | object $game_outcome = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8cbec07);
		$flags = 0;
		$flags |= is_null($game_outcome) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($value);
		$writer->writeBytes($emoticon);
		if(is_null($game_outcome) === false):
			$writer->writeObject($game_outcome);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['value'] = $reader->readInt();
		$result['emoticon'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['game_outcome'] = $reader->readObject();
		else:
			$result['game_outcome'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id
 * @return Chat
 */

final class ChatEmpty extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x29562865);
		$writer->writeLong($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputuser user_id
 * @return BotCommandScope
 */

final class BotCommandScopePeerUser extends Instance {
	public function request(object $peer,object $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa1321f3);
		$writer->writeObject($peer);
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['user_id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string timezone_id Vector<businessweeklyopen> weekly_open true open_now
 * @return BusinessWorkHours
 */

final class BusinessWorkHours extends Instance {
	public function request(string $timezone_id,array $weekly_open,null | bool $open_now = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c92b098);
		$flags = 0;
		$flags |= $open_now ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($timezone_id);
		$writer->writeVector($weekly_open,'businessweeklyopen');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['open_now'] = boolval($flags & (1 << 0));
		$result['timezone_id'] = $reader->readBytes();
		$result['weekly_open'] = $reader->readVector('businessweeklyopen');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string emoticon
 * @return ChatTheme
 */

final class ChatTheme extends Instance {
	public function request(string $emoticon) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc3dffc04);
		$writer->writeBytes($emoticon);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['emoticon'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextCashtag extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7b9e1801);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessageAction
 */

final class MessageActionChatJoinedByRequest extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xebbca3cb);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id int date int expires true gift true giveaway true unclaimed long user_id int giveaway_msg_id string used_gift_slug int multiplier long stars
 * @return Boost
 */

final class Boost extends Instance {
	public function request(string $id,int $date,int $expires,null | bool $gift = null,null | bool $giveaway = null,null | bool $unclaimed = null,null | int $user_id = null,null | int $giveaway_msg_id = null,null | string $used_gift_slug = null,null | int $multiplier = null,null | int $stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4b3e14d6);
		$flags = 0;
		$flags |= $gift ? (1 << 1) : 0;
		$flags |= $giveaway ? (1 << 2) : 0;
		$flags |= $unclaimed ? (1 << 3) : 0;
		$flags |= is_null($user_id) ? 0 : (1 << 0);
		$flags |= is_null($giveaway_msg_id) ? 0 : (1 << 2);
		$flags |= is_null($used_gift_slug) ? 0 : (1 << 4);
		$flags |= is_null($multiplier) ? 0 : (1 << 5);
		$flags |= is_null($stars) ? 0 : (1 << 6);
		$writer->writeInt($flags);
		$writer->writeBytes($id);
		if(is_null($user_id) === false):
			$writer->writeLong($user_id);
		endif;
		if(is_null($giveaway_msg_id) === false):
			$writer->writeInt($giveaway_msg_id);
		endif;
		$writer->writeInt($date);
		$writer->writeInt($expires);
		if(is_null($used_gift_slug) === false):
			$writer->writeBytes($used_gift_slug);
		endif;
		if(is_null($multiplier) === false):
			$writer->writeInt($multiplier);
		endif;
		if(is_null($stars) === false):
			$writer->writeLong($stars);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['gift'] = boolval($flags & (1 << 1));
		$result['giveaway'] = boolval($flags & (1 << 2));
		$result['unclaimed'] = boolval($flags & (1 << 3));
		$result['id'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['user_id'] = $reader->readLong();
		else:
			$result['user_id'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['giveaway_msg_id'] = $reader->readInt();
		else:
			$result['giveaway_msg_id'] = null;
		endif;
		$result['date'] = $reader->readInt();
		$result['expires'] = $reader->readInt();
		if($flags & (1 << 4)):
			$result['used_gift_slug'] = $reader->readBytes();
		else:
			$result['used_gift_slug'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['multiplier'] = $reader->readInt();
		else:
			$result['multiplier'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['stars'] = $reader->readLong();
		else:
			$result['stars'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ChatPhoto
 */

final class ChatPhotoEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x37c1011c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id string phone
 * @return Update
 */

final class UpdateUserPhone extends Instance {
	public function request(int $user_id,string $phone) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5492a13);
		$writer->writeLong($user_id);
		$writer->writeBytes($phone);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['phone'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<pageblock> items pagecaption caption
 * @return PageBlock
 */

final class PageBlockSlideshow extends Instance {
	public function request(array $items,object $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31f9590);
		$writer->writeVector($items,'pageblock');
		$writer->writeObject($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['items'] = $reader->readVector('pageblock');
		$result['caption'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer Vector<storyitem> stories int max_read_id
 * @return PeerStories
 */

final class PeerStories extends Instance {
	public function request(object $peer,array $stories,null | int $max_read_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9a35e999);
		$flags = 0;
		$flags |= is_null($max_read_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($max_read_id) === false):
			$writer->writeInt($max_read_id);
		endif;
		$writer->writeVector($stories,'storyitem');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['peer'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['max_read_id'] = $reader->readInt();
		else:
			$result['max_read_id'] = null;
		endif;
		$result['stories'] = $reader->readVector('storyitem');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url long webpage_id long author_photo_id string author int date Vector<pageblock> blocks pagecaption caption
 * @return PageBlock
 */

final class PageBlockEmbedPost extends Instance {
	public function request(string $url,int $webpage_id,int $author_photo_id,string $author,int $date,array $blocks,object $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf259a80b);
		$writer->writeBytes($url);
		$writer->writeLong($webpage_id);
		$writer->writeLong($author_photo_id);
		$writer->writeBytes($author);
		$writer->writeInt($date);
		$writer->writeVector($blocks,'pageblock');
		$writer->writeObject($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['webpage_id'] = $reader->readLong();
		$result['author_photo_id'] = $reader->readLong();
		$result['author'] = $reader->readBytes();
		$result['date'] = $reader->readInt();
		$result['blocks'] = $reader->readVector('pageblock');
		$result['caption'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ChannelMessagesFilter
 */

final class ChannelMessagesFilterEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x94d42ee7);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text string url long webpage_id
 * @return RichText
 */

final class TextUrl extends Instance {
	public function request(object $text,string $url,int $webpage_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3c2884c1);
		$writer->writeObject($text);
		$writer->writeBytes($url);
		$writer->writeLong($webpage_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		$result['url'] = $reader->readBytes();
		$result['webpage_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true selective
 * @return ReplyMarkup
 */

final class ReplyKeyboardHide extends Instance {
	public function request(null | bool $selective = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa03e5b85);
		$flags = 0;
		$flags |= $selective ? (1 << 2) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['selective'] = boolval($flags & (1 << 2));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<int> completed Vector<int> incompleted
 * @return MessageAction
 */

final class MessageActionTodoCompletions extends Instance {
	public function request(array $completed,array $incompleted) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcc7c5c89);
		$writer->writeVector($completed,'int');
		$writer->writeVector($incompleted,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['completed'] = $reader->readVector('int');
		$result['incompleted'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call Vector<long> users
 * @return MessageAction
 */

final class MessageActionInviteToGroupCall extends Instance {
	public function request(object $call,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x502f92f7);
		$writer->writeObject($call);
		$writer->writeVector($users,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['call'] = $reader->readObject();
		$result['users'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int folder_id
 * @return InputDialogPeer
 */

final class InputDialogPeerFolder extends Instance {
	public function request(int $folder_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x64600527);
		$writer->writeInt($folder_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['folder_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return AttachMenuPeerType
 */

final class AttachMenuPeerTypeBotPM extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc32bfa1a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call peer from_id bytes encrypted_message
 * @return Update
 */

final class UpdateGroupCallEncryptedMessage extends Instance {
	public function request(object $call,object $from_id,string $encrypted_message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc957a766);
		$writer->writeObject($call);
		$writer->writeObject($from_id);
		$writer->writeBytes($encrypted_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['call'] = $reader->readObject();
		$result['from_id'] = $reader->readObject();
		$result['encrypted_message'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int msg_id int date int offset
 * @return SearchResultsPosition
 */

final class SearchResultPosition extends Instance {
	public function request(int $msg_id,int $date,int $offset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7f648b67);
		$writer->writeInt($msg_id);
		$writer->writeInt($date);
		$writer->writeInt($offset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_id'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['offset'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyRule
 */

final class PrivacyValueDisallowContacts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf888fa1a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url long webpage_id string title string description long photo_id string author int published_date
 * @return PageRelatedArticle
 */

final class PageRelatedArticle extends Instance {
	public function request(string $url,int $webpage_id,null | string $title = null,null | string $description = null,null | int $photo_id = null,null | string $author = null,null | int $published_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb390dc08);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$flags |= is_null($description) ? 0 : (1 << 1);
		$flags |= is_null($photo_id) ? 0 : (1 << 2);
		$flags |= is_null($author) ? 0 : (1 << 3);
		$flags |= is_null($published_date) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeBytes($url);
		$writer->writeLong($webpage_id);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($description) === false):
			$writer->writeBytes($description);
		endif;
		if(is_null($photo_id) === false):
			$writer->writeLong($photo_id);
		endif;
		if(is_null($author) === false):
			$writer->writeBytes($author);
		endif;
		if(is_null($published_date) === false):
			$writer->writeInt($published_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['url'] = $reader->readBytes();
		$result['webpage_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['description'] = $reader->readBytes();
		else:
			$result['description'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['photo_id'] = $reader->readLong();
		else:
			$result['photo_id'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['author'] = $reader->readBytes();
		else:
			$result['author'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['published_date'] = $reader->readInt();
		else:
			$result['published_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id int max_id
 * @return Update
 */

final class UpdateReadChannelOutbox extends Instance {
	public function request(int $channel_id,int $max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb75f99a9);
		$writer->writeLong($channel_id);
		$writer->writeInt($max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['max_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool bot bool premium
 * @return RequestPeerType
 */

final class RequestPeerTypeUser extends Instance {
	public function request(null | bool $bot = null,null | bool $premium = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5f3b8a00);
		$flags = 0;
		$flags |= is_null($bot) ? 0 : (1 << 0);
		$flags |= is_null($premium) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($bot) === false):
			$writer->writeBool($bot);
		endif;
		if(is_null($premium) === false):
			$writer->writeBool($premium);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['bot'] = $reader->readBool();
		else:
			$result['bot'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['premium'] = $reader->readBool();
		else:
			$result['premium'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id
 * @return StoryItem
 */

final class StoryItemDeleted extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x51e6ee4f);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long poll_id peer peer Vector<bytes> options Vector<int> positions int qts
 * @return Update
 */

final class UpdateMessagePollVote extends Instance {
	public function request(int $poll_id,object $peer,array $options,array $positions,int $qts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7699f014);
		$writer->writeLong($poll_id);
		$writer->writeObject($peer);
		$writer->writeVector($options,'bytes');
		$writer->writeVector($positions,'int');
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['poll_id'] = $reader->readLong();
		$result['peer'] = $reader->readObject();
		$result['options'] = $reader->readVector('bytes');
		$result['positions'] = $reader->readVector('int');
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<long> document_id
 * @return EmojiList
 */

final class EmojiList extends Instance {
	public function request(int $hash,array $document_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7a1e11d1);
		$writer->writeLong($hash);
		$writer->writeVector($document_id,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['document_id'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyAddedByPhone extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd1219bdd);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars string transaction_id peer boost_peer int giveaway_msg_id true unclaimed
 * @return MessageAction
 */

final class MessageActionPrizeStars extends Instance {
	public function request(int $stars,string $transaction_id,object $boost_peer,int $giveaway_msg_id,null | bool $unclaimed = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb00c47a2);
		$flags = 0;
		$flags |= $unclaimed ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($stars);
		$writer->writeBytes($transaction_id);
		$writer->writeObject($boost_peer);
		$writer->writeInt($giveaway_msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['unclaimed'] = boolval($flags & (1 << 0));
		$result['stars'] = $reader->readLong();
		$result['transaction_id'] = $reader->readBytes();
		$result['boost_peer'] = $reader->readObject();
		$result['giveaway_msg_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce int128 server_nonce string encrypted_answer
 * @return Server_DH_Params
 */

final class ServerDHParamsOk extends Instance {
	public function request(int | string $nonce,int | string $server_nonce,string $encrypted_answer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd0e8075c);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeBytes($encrypted_answer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['encrypted_answer'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long poll_id pollresults results peer peer int msg_id int top_msg_id poll poll
 * @return Update
 */

final class UpdateMessagePoll extends Instance {
	public function request(int $poll_id,object $results,null | object $peer = null,null | int $msg_id = null,null | int $top_msg_id = null,null | object $poll = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd64c522b);
		$flags = 0;
		$flags |= is_null($peer) ? 0 : (1 << 1);
		$flags |= is_null($msg_id) ? 0 : (1 << 1);
		$flags |= is_null($top_msg_id) ? 0 : (1 << 2);
		$flags |= is_null($poll) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		if(is_null($msg_id) === false):
			$writer->writeInt($msg_id);
		endif;
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		$writer->writeLong($poll_id);
		if(is_null($poll) === false):
			$writer->writeObject($poll);
		endif;
		$writer->writeObject($results);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 1)):
			$result['peer'] = $reader->readObject();
		else:
			$result['peer'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['msg_id'] = $reader->readInt();
		else:
			$result['msg_id'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['top_msg_id'] = $reader->readInt();
		else:
			$result['top_msg_id'] = null;
		endif;
		$result['poll_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['poll'] = $reader->readObject();
		else:
			$result['poll'] = null;
		endif;
		$result['results'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text string start_param
 * @return InlineBotSwitchPM
 */

final class InlineBotSwitchPM extends Instance {
	public function request(string $text,string $start_param) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3c20629f);
		$writer->writeBytes($text);
		$writer->writeBytes($start_param);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readBytes();
		$result['start_param'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int chat_id long access_hash
 * @return InputEncryptedChat
 */

final class InputEncryptedChat extends Instance {
	public function request(int $chat_id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf141b5e1);
		$writer->writeInt($chat_id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readInt();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string job_id string phone_number string text
 * @return SmsJob
 */

final class SmsJob extends Instance {
	public function request(string $job_id,string $phone_number,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe6a1eeb8);
		$writer->writeBytes($job_id);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['job_id'] = $reader->readBytes();
		$result['phone_number'] = $reader->readBytes();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string username true editable true active
 * @return Username
 */

final class Username extends Instance {
	public function request(string $username,null | bool $editable = null,null | bool $active = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb4073647);
		$flags = 0;
		$flags |= $editable ? (1 << 0) : 0;
		$flags |= $active ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($username);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['editable'] = boolval($flags & (1 << 0));
		$result['active'] = boolval($flags & (1 << 1));
		$result['username'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int acquired_count true returned long bid_amount int bid_date long min_bid_amount peer bid_peer
 * @return StarGiftAuctionUserState
 */

final class StarGiftAuctionUserState extends Instance {
	public function request(int $acquired_count,null | bool $returned = null,null | int $bid_amount = null,null | int $bid_date = null,null | int $min_bid_amount = null,null | object $bid_peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2eeed1c4);
		$flags = 0;
		$flags |= $returned ? (1 << 1) : 0;
		$flags |= is_null($bid_amount) ? 0 : (1 << 0);
		$flags |= is_null($bid_date) ? 0 : (1 << 0);
		$flags |= is_null($min_bid_amount) ? 0 : (1 << 0);
		$flags |= is_null($bid_peer) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($bid_amount) === false):
			$writer->writeLong($bid_amount);
		endif;
		if(is_null($bid_date) === false):
			$writer->writeInt($bid_date);
		endif;
		if(is_null($min_bid_amount) === false):
			$writer->writeLong($min_bid_amount);
		endif;
		if(is_null($bid_peer) === false):
			$writer->writeObject($bid_peer);
		endif;
		$writer->writeInt($acquired_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['returned'] = boolval($flags & (1 << 1));
		if($flags & (1 << 0)):
			$result['bid_amount'] = $reader->readLong();
		else:
			$result['bid_amount'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['bid_date'] = $reader->readInt();
		else:
			$result['bid_date'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['min_bid_amount'] = $reader->readLong();
		else:
			$result['min_bid_amount'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['bid_peer'] = $reader->readObject();
		else:
			$result['bid_peer'] = null;
		endif;
		$result['acquired_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypePassportRegistration extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x99e3806a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PageBlock
 */

final class PageBlockDivider extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdb20b188);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text
 * @return MessageAction
 */

final class MessageActionWebViewDataSent extends Instance {
	public function request(string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb4c38cb5);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text int button_id requestpeertype peer_type int max_quantity true name_requested true username_requested true photo_requested keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class InputKeyboardButtonRequestPeer extends Instance {
	public function request(string $text,int $button_id,object $peer_type,int $max_quantity,null | bool $name_requested = null,null | bool $username_requested = null,null | bool $photo_requested = null,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2b78156);
		$flags = 0;
		$flags |= $name_requested ? (1 << 0) : 0;
		$flags |= $username_requested ? (1 << 1) : 0;
		$flags |= $photo_requested ? (1 << 2) : 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		$writer->writeInt($button_id);
		$writer->writeObject($peer_type);
		$writer->writeInt($max_quantity);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['name_requested'] = boolval($flags & (1 << 0));
		$result['username_requested'] = boolval($flags & (1 << 1));
		$result['photo_requested'] = boolval($flags & (1 << 2));
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		$result['button_id'] = $reader->readInt();
		$result['peer_type'] = $reader->readObject();
		$result['max_quantity'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id int messages int avg_chars
 * @return StatsGroupTopPoster
 */

final class StatsGroupTopPoster extends Instance {
	public function request(int $user_id,int $messages,int $avg_chars) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9d04af9b);
		$writer->writeLong($user_id);
		$writer->writeInt($messages);
		$writer->writeInt($avg_chars);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['messages'] = $reader->readInt();
		$result['avg_chars'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string name document document stargiftattributerarity rarity
 * @return StarGiftAttribute
 */

final class StarGiftAttributePattern extends Instance {
	public function request(string $name,object $document,object $rarity) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4e7085ea);
		$writer->writeBytes($name);
		$writer->writeObject($document);
		$writer->writeObject($rarity);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['name'] = $reader->readBytes();
		$result['document'] = $reader->readObject();
		$result['rarity'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length inputuser user_id
 * @return MessageEntity
 */

final class InputMessageEntityMentionName extends Instance {
	public function request(int $offset,int $length,object $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x208e68c9);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		$result['user_id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ProfileTab
 */

final class ProfileTabPosts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb98cd696);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text int date true relative true short_time true long_time true short_date true long_date true day_of_week
 * @return RichText
 */

final class TextDate extends Instance {
	public function request(object $text,int $date,null | bool $relative = null,null | bool $short_time = null,null | bool $long_time = null,null | bool $short_date = null,null | bool $long_date = null,null | bool $day_of_week = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa5b45e2b);
		$flags = 0;
		$flags |= $relative ? (1 << 0) : 0;
		$flags |= $short_time ? (1 << 1) : 0;
		$flags |= $long_time ? (1 << 2) : 0;
		$flags |= $short_date ? (1 << 3) : 0;
		$flags |= $long_date ? (1 << 4) : 0;
		$flags |= $day_of_week ? (1 << 5) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($text);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['relative'] = boolval($flags & (1 << 0));
		$result['short_time'] = boolval($flags & (1 << 1));
		$result['long_time'] = boolval($flags & (1 << 2));
		$result['short_date'] = boolval($flags & (1 << 3));
		$result['long_date'] = boolval($flags & (1 << 4));
		$result['day_of_week'] = boolval($flags & (1 << 5));
		$result['text'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string file_name
 * @return DocumentAttribute
 */

final class DocumentAttributeFilename extends Instance {
	public function request(string $file_name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x15590068);
		$writer->writeBytes($file_name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['file_name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ProfileTab
 */

final class ProfileTabGifs extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa2c0f695);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id string shortcut int top_message int count
 * @return QuickReply
 */

final class QuickReply extends Instance {
	public function request(int $shortcut_id,string $shortcut,int $top_message,int $count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x697102b);
		$writer->writeInt($shortcut_id);
		$writer->writeBytes($shortcut);
		$writer->writeInt($top_message);
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['shortcut_id'] = $reader->readInt();
		$result['shortcut'] = $reader->readBytes();
		$result['top_message'] = $reader->readInt();
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityBotCommand extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6cef8ac7);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return InputNotifyPeer
 */

final class InputNotifyPeer extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb8bc5b0c);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param pollanswer answer
 * @return MessageAction
 */

final class MessageActionPollAppendAnswer extends Instance {
	public function request(object $answer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9da1cd6c);
		$writer->writeObject($answer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['answer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int filter_id
 * @return InputChatlist
 */

final class InputChatlistDialogFilter extends Instance {
	public function request(int $filter_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf3e0da33);
		$writer->writeInt($filter_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['filter_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true by_me
 * @return UserStatus
 */

final class UserStatusLastMonth extends Instance {
	public function request(null | bool $by_me = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x65899777);
		$flags = 0;
		$flags |= $by_me ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['by_me'] = boolval($flags & (1 << 0));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id string payload int qts
 * @return Update
 */

final class UpdateBotPurchasedPaidMedia extends Instance {
	public function request(int $user_id,string $payload,int $qts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x283bd312);
		$writer->writeLong($user_id);
		$writer->writeBytes($payload);
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['payload'] = $reader->readBytes();
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputChatPhoto
 */

final class InputChatPhotoEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1ca48f57);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true allow_flashcall true current_number true allow_app_hash true allow_missed_call true allow_firebase true unknown_number Vector<bytes> logout_tokens string token bool app_sandbox
 * @return CodeSettings
 */

final class CodeSettings extends Instance {
	public function request(null | bool $allow_flashcall = null,null | bool $current_number = null,null | bool $allow_app_hash = null,null | bool $allow_missed_call = null,null | bool $allow_firebase = null,null | bool $unknown_number = null,null | array $logout_tokens = null,null | string $token = null,null | bool $app_sandbox = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xad253d78);
		$flags = 0;
		$flags |= $allow_flashcall ? (1 << 0) : 0;
		$flags |= $current_number ? (1 << 1) : 0;
		$flags |= $allow_app_hash ? (1 << 4) : 0;
		$flags |= $allow_missed_call ? (1 << 5) : 0;
		$flags |= $allow_firebase ? (1 << 7) : 0;
		$flags |= $unknown_number ? (1 << 9) : 0;
		$flags |= is_null($logout_tokens) ? 0 : (1 << 6);
		$flags |= is_null($token) ? 0 : (1 << 8);
		$flags |= is_null($app_sandbox) ? 0 : (1 << 8);
		$writer->writeInt($flags);
		if(is_null($logout_tokens) === false):
			$writer->writeVector($logout_tokens,'bytes');
		endif;
		if(is_null($token) === false):
			$writer->writeBytes($token);
		endif;
		if(is_null($app_sandbox) === false):
			$writer->writeBool($app_sandbox);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['allow_flashcall'] = boolval($flags & (1 << 0));
		$result['current_number'] = boolval($flags & (1 << 1));
		$result['allow_app_hash'] = boolval($flags & (1 << 4));
		$result['allow_missed_call'] = boolval($flags & (1 << 5));
		$result['allow_firebase'] = boolval($flags & (1 << 7));
		$result['unknown_number'] = boolval($flags & (1 << 9));
		if($flags & (1 << 6)):
			$result['logout_tokens'] = $reader->readVector('bytes');
		else:
			$result['logout_tokens'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['token'] = $reader->readBytes();
		else:
			$result['token'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['app_sandbox'] = $reader->readBool();
		else:
			$result['app_sandbox'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long answer_msg_id int bytes int status
 * @return MsgDetailedInfo
 */

final class MsgNewDetailedInfo extends Instance {
	public function request(int $answer_msg_id,int $bytes,int $status) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x809db6df);
		$writer->writeLong($answer_msg_id);
		$writer->writeInt($bytes);
		$writer->writeInt($status);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['answer_msg_id'] = $reader->readLong();
		$result['bytes'] = $reader->readInt();
		$result['status'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return NotifyPeer
 */

final class NotifyChats extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc007cec3);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title string description inputdocument sticker
 * @return InputBusinessIntro
 */

final class InputBusinessIntro extends Instance {
	public function request(string $title,string $description,null | object $sticker = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9c469cd);
		$flags = 0;
		$flags |= is_null($sticker) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		if(is_null($sticker) === false):
			$writer->writeObject($sticker);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['sticker'] = $reader->readObject();
		else:
			$result['sticker'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string token
 * @return EmailVerification
 */

final class EmailVerificationApple extends Instance {
	public function request(string $token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x96d074fd);
		$writer->writeBytes($token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['token'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string short_name
 * @return InputStickerSet
 */

final class InputStickerSetShortName extends Instance {
	public function request(string $short_name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x861cc8a0);
		$writer->writeBytes($short_name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['short_name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type bytes hash securedata data securefile front_side securefile reverse_side securefile selfie Vector<securefile> translation Vector<securefile> files secureplaindata plain_data
 * @return SecureValue
 */

final class SecureValue extends Instance {
	public function request(object $type,string $hash,null | object $data = null,null | object $front_side = null,null | object $reverse_side = null,null | object $selfie = null,null | array $translation = null,null | array $files = null,null | object $plain_data = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x187fa0ca);
		$flags = 0;
		$flags |= is_null($data) ? 0 : (1 << 0);
		$flags |= is_null($front_side) ? 0 : (1 << 1);
		$flags |= is_null($reverse_side) ? 0 : (1 << 2);
		$flags |= is_null($selfie) ? 0 : (1 << 3);
		$flags |= is_null($translation) ? 0 : (1 << 6);
		$flags |= is_null($files) ? 0 : (1 << 4);
		$flags |= is_null($plain_data) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeObject($type);
		if(is_null($data) === false):
			$writer->writeObject($data);
		endif;
		if(is_null($front_side) === false):
			$writer->writeObject($front_side);
		endif;
		if(is_null($reverse_side) === false):
			$writer->writeObject($reverse_side);
		endif;
		if(is_null($selfie) === false):
			$writer->writeObject($selfie);
		endif;
		if(is_null($translation) === false):
			$writer->writeVector($translation,'securefile');
		endif;
		if(is_null($files) === false):
			$writer->writeVector($files,'securefile');
		endif;
		if(is_null($plain_data) === false):
			$writer->writeObject($plain_data);
		endif;
		$writer->writeBytes($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['type'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['data'] = $reader->readObject();
		else:
			$result['data'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['front_side'] = $reader->readObject();
		else:
			$result['front_side'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['reverse_side'] = $reader->readObject();
		else:
			$result['reverse_side'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['selfie'] = $reader->readObject();
		else:
			$result['selfie'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['translation'] = $reader->readVector('securefile');
		else:
			$result['translation'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['files'] = $reader->readVector('securefile');
		else:
			$result['files'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['plain_data'] = $reader->readObject();
		else:
			$result['plain_data'] = null;
		endif;
		$result['hash'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessageAction
 */

final class MessageActionContactSignUp extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf3f25f76);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> chats
 * @return InputPrivacyRule
 */

final class InputPrivacyValueDisallowChatParticipants extends Instance {
	public function request(array $chats) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe94f0f86);
		$writer->writeVector($chats,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chats'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool show_previews bool silent int mute_until notificationsound sound bool stories_muted bool stories_hide_sender notificationsound stories_sound
 * @return InputPeerNotifySettings
 */

final class InputPeerNotifySettings extends Instance {
	public function request(null | bool $show_previews = null,null | bool $silent = null,null | int $mute_until = null,null | object $sound = null,null | bool $stories_muted = null,null | bool $stories_hide_sender = null,null | object $stories_sound = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcacb6ae2);
		$flags = 0;
		$flags |= is_null($show_previews) ? 0 : (1 << 0);
		$flags |= is_null($silent) ? 0 : (1 << 1);
		$flags |= is_null($mute_until) ? 0 : (1 << 2);
		$flags |= is_null($sound) ? 0 : (1 << 3);
		$flags |= is_null($stories_muted) ? 0 : (1 << 6);
		$flags |= is_null($stories_hide_sender) ? 0 : (1 << 7);
		$flags |= is_null($stories_sound) ? 0 : (1 << 8);
		$writer->writeInt($flags);
		if(is_null($show_previews) === false):
			$writer->writeBool($show_previews);
		endif;
		if(is_null($silent) === false):
			$writer->writeBool($silent);
		endif;
		if(is_null($mute_until) === false):
			$writer->writeInt($mute_until);
		endif;
		if(is_null($sound) === false):
			$writer->writeObject($sound);
		endif;
		if(is_null($stories_muted) === false):
			$writer->writeBool($stories_muted);
		endif;
		if(is_null($stories_hide_sender) === false):
			$writer->writeBool($stories_hide_sender);
		endif;
		if(is_null($stories_sound) === false):
			$writer->writeObject($stories_sound);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['show_previews'] = $reader->readBool();
		else:
			$result['show_previews'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['silent'] = $reader->readBool();
		else:
			$result['silent'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['mute_until'] = $reader->readInt();
		else:
			$result['mute_until'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['sound'] = $reader->readObject();
		else:
			$result['sound'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['stories_muted'] = $reader->readBool();
		else:
			$result['stories_muted'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['stories_hide_sender'] = $reader->readBool();
		else:
			$result['stories_hide_sender'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['stories_sound'] = $reader->readObject();
		else:
			$result['stories_sound'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id int pts
 * @return Update
 */

final class UpdateChannelTooLong extends Instance {
	public function request(int $channel_id,null | int $pts = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x108d941f);
		$flags = 0;
		$flags |= is_null($pts) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($channel_id);
		if(is_null($pts) === false):
			$writer->writeInt($pts);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['channel_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['pts'] = $reader->readInt();
		else:
			$result['pts'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param exportedchatinvite invite
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionExportedInviteDelete extends Instance {
	public function request(object $invite) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5a50fca4);
		$writer->writeObject($invite);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['invite'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateAttachMenuBots extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x17b7a20b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id string title chatphoto photo int participants_count int date int version true creator true left true deactivated true call_active true call_not_empty true noforwards inputchannel migrated_to chatadminrights admin_rights chatbannedrights default_banned_rights
 * @return Chat
 */

final class Chat extends Instance {
	public function request(int $id,string $title,object $photo,int $participants_count,int $date,int $version,null | bool $creator = null,null | bool $left = null,null | bool $deactivated = null,null | bool $call_active = null,null | bool $call_not_empty = null,null | bool $noforwards = null,null | object $migrated_to = null,null | object $admin_rights = null,null | object $default_banned_rights = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x41cbf256);
		$flags = 0;
		$flags |= $creator ? (1 << 0) : 0;
		$flags |= $left ? (1 << 2) : 0;
		$flags |= $deactivated ? (1 << 5) : 0;
		$flags |= $call_active ? (1 << 23) : 0;
		$flags |= $call_not_empty ? (1 << 24) : 0;
		$flags |= $noforwards ? (1 << 25) : 0;
		$flags |= is_null($migrated_to) ? 0 : (1 << 6);
		$flags |= is_null($admin_rights) ? 0 : (1 << 14);
		$flags |= is_null($default_banned_rights) ? 0 : (1 << 18);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeBytes($title);
		$writer->writeObject($photo);
		$writer->writeInt($participants_count);
		$writer->writeInt($date);
		$writer->writeInt($version);
		if(is_null($migrated_to) === false):
			$writer->writeObject($migrated_to);
		endif;
		if(is_null($admin_rights) === false):
			$writer->writeObject($admin_rights);
		endif;
		if(is_null($default_banned_rights) === false):
			$writer->writeObject($default_banned_rights);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['creator'] = boolval($flags & (1 << 0));
		$result['left'] = boolval($flags & (1 << 2));
		$result['deactivated'] = boolval($flags & (1 << 5));
		$result['call_active'] = boolval($flags & (1 << 23));
		$result['call_not_empty'] = boolval($flags & (1 << 24));
		$result['noforwards'] = boolval($flags & (1 << 25));
		$result['id'] = $reader->readLong();
		$result['title'] = $reader->readBytes();
		$result['photo'] = $reader->readObject();
		$result['participants_count'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['version'] = $reader->readInt();
		if($flags & (1 << 6)):
			$result['migrated_to'] = $reader->readObject();
		else:
			$result['migrated_to'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['admin_rights'] = $reader->readObject();
		else:
			$result['admin_rights'] = null;
		endif;
		if($flags & (1 << 18)):
			$result['default_banned_rights'] = $reader->readObject();
		else:
			$result['default_banned_rights'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param attachmenubot bot Vector<user> users
 * @return AttachMenuBotsBot
 */

final class AttachMenuBotsBot extends Instance {
	public function request(object $bot,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x93bf667f);
		$writer->writeObject($bot);
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['bot'] = $reader->readObject();
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int min_date int max_date
 * @return StatsDateRangeDays
 */

final class StatsDateRangeDays extends Instance {
	public function request(int $min_date,int $max_date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb637edaf);
		$writer->writeInt($min_date);
		$writer->writeInt($max_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['min_date'] = $reader->readInt();
		$result['max_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypeDriverLicense extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6e425c4);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string markdown true rtl true noautolink Vector<inputrichfile> files
 * @return InputRichMessage
 */

final class InputRichMessageMarkdown extends Instance {
	public function request(string $markdown,null | bool $rtl = null,null | bool $noautolink = null,null | array $files = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4b572c);
		$flags = 0;
		$flags |= $rtl ? (1 << 0) : 0;
		$flags |= $noautolink ? (1 << 1) : 0;
		$flags |= is_null($files) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($markdown);
		if(is_null($files) === false):
			$writer->writeVector($files,'inputrichfile');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['rtl'] = boolval($flags & (1 << 0));
		$result['noautolink'] = boolval($flags & (1 << 1));
		$result['markdown'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['files'] = $reader->readVector('inputrichfile');
		else:
			$result['files'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> users
 * @return PrivacyRule
 */

final class PrivacyValueDisallowUsers extends Instance {
	public function request(array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe4621141);
		$writer->writeVector($users,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['users'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return JoinChatBotResult
 */

final class JoinChatBotResultDeclined extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xefa0194);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id textwithentities title Vector<inputpeer> pinned_peers Vector<inputpeer> include_peers Vector<inputpeer> exclude_peers true contacts true non_contacts true groups true broadcasts true bots true exclude_muted true exclude_read true exclude_archived true title_noanimate string emoticon int color
 * @return DialogFilter
 */

final class DialogFilter extends Instance {
	public function request(int $id,object $title,array $pinned_peers,array $include_peers,array $exclude_peers,null | bool $contacts = null,null | bool $non_contacts = null,null | bool $groups = null,null | bool $broadcasts = null,null | bool $bots = null,null | bool $exclude_muted = null,null | bool $exclude_read = null,null | bool $exclude_archived = null,null | bool $title_noanimate = null,null | string $emoticon = null,null | int $color = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaa472651);
		$flags = 0;
		$flags |= $contacts ? (1 << 0) : 0;
		$flags |= $non_contacts ? (1 << 1) : 0;
		$flags |= $groups ? (1 << 2) : 0;
		$flags |= $broadcasts ? (1 << 3) : 0;
		$flags |= $bots ? (1 << 4) : 0;
		$flags |= $exclude_muted ? (1 << 11) : 0;
		$flags |= $exclude_read ? (1 << 12) : 0;
		$flags |= $exclude_archived ? (1 << 13) : 0;
		$flags |= $title_noanimate ? (1 << 28) : 0;
		$flags |= is_null($emoticon) ? 0 : (1 << 25);
		$flags |= is_null($color) ? 0 : (1 << 27);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeObject($title);
		if(is_null($emoticon) === false):
			$writer->writeBytes($emoticon);
		endif;
		if(is_null($color) === false):
			$writer->writeInt($color);
		endif;
		$writer->writeVector($pinned_peers,'inputpeer');
		$writer->writeVector($include_peers,'inputpeer');
		$writer->writeVector($exclude_peers,'inputpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['contacts'] = boolval($flags & (1 << 0));
		$result['non_contacts'] = boolval($flags & (1 << 1));
		$result['groups'] = boolval($flags & (1 << 2));
		$result['broadcasts'] = boolval($flags & (1 << 3));
		$result['bots'] = boolval($flags & (1 << 4));
		$result['exclude_muted'] = boolval($flags & (1 << 11));
		$result['exclude_read'] = boolval($flags & (1 << 12));
		$result['exclude_archived'] = boolval($flags & (1 << 13));
		$result['title_noanimate'] = boolval($flags & (1 << 28));
		$result['id'] = $reader->readInt();
		$result['title'] = $reader->readObject();
		if($flags & (1 << 25)):
			$result['emoticon'] = $reader->readBytes();
		else:
			$result['emoticon'] = null;
		endif;
		if($flags & (1 << 27)):
			$result['color'] = $reader->readInt();
		else:
			$result['color'] = null;
		endif;
		$result['pinned_peers'] = $reader->readVector('inputpeer');
		$result['include_peers'] = $reader->readVector('inputpeer');
		$result['exclude_peers'] = $reader->readVector('inputpeer');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterDocument extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9eddf188);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarsTransactionPeer
 */

final class StarsTransactionPeerAPI extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf9677aad);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputrichmessage rich_message replymarkup reply_markup
 * @return InputBotInlineMessage
 */

final class InputBotInlineMessageRichMessage extends Instance {
	public function request(object $rich_message,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb43df56c);
		$flags = 0;
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		$writer->writeObject($rich_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		$result['rich_message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date stargift gift true name_hidden true unsaved true refunded true can_upgrade true pinned_to_top true upgrade_separate peer from_id textwithentities message int msg_id long saved_id long convert_stars long upgrade_stars int can_export_at long transfer_stars int can_transfer_at int can_resell_at Vector<int> collection_id string prepaid_upgrade_hash long drop_original_details_stars int gift_num int can_craft_at
 * @return SavedStarGift
 */

final class SavedStarGift extends Instance {
	public function request(int $date,object $gift,null | bool $name_hidden = null,null | bool $unsaved = null,null | bool $refunded = null,null | bool $can_upgrade = null,null | bool $pinned_to_top = null,null | bool $upgrade_separate = null,null | object $from_id = null,null | object $message = null,null | int $msg_id = null,null | int $saved_id = null,null | int $convert_stars = null,null | int $upgrade_stars = null,null | int $can_export_at = null,null | int $transfer_stars = null,null | int $can_transfer_at = null,null | int $can_resell_at = null,null | array $collection_id = null,null | string $prepaid_upgrade_hash = null,null | int $drop_original_details_stars = null,null | int $gift_num = null,null | int $can_craft_at = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x41df43fc);
		$flags = 0;
		$flags |= $name_hidden ? (1 << 0) : 0;
		$flags |= $unsaved ? (1 << 5) : 0;
		$flags |= $refunded ? (1 << 9) : 0;
		$flags |= $can_upgrade ? (1 << 10) : 0;
		$flags |= $pinned_to_top ? (1 << 12) : 0;
		$flags |= $upgrade_separate ? (1 << 17) : 0;
		$flags |= is_null($from_id) ? 0 : (1 << 1);
		$flags |= is_null($message) ? 0 : (1 << 2);
		$flags |= is_null($msg_id) ? 0 : (1 << 3);
		$flags |= is_null($saved_id) ? 0 : (1 << 11);
		$flags |= is_null($convert_stars) ? 0 : (1 << 4);
		$flags |= is_null($upgrade_stars) ? 0 : (1 << 6);
		$flags |= is_null($can_export_at) ? 0 : (1 << 7);
		$flags |= is_null($transfer_stars) ? 0 : (1 << 8);
		$flags |= is_null($can_transfer_at) ? 0 : (1 << 13);
		$flags |= is_null($can_resell_at) ? 0 : (1 << 14);
		$flags |= is_null($collection_id) ? 0 : (1 << 15);
		$flags |= is_null($prepaid_upgrade_hash) ? 0 : (1 << 16);
		$flags |= is_null($drop_original_details_stars) ? 0 : (1 << 18);
		$flags |= is_null($gift_num) ? 0 : (1 << 19);
		$flags |= is_null($can_craft_at) ? 0 : (1 << 20);
		$writer->writeInt($flags);
		if(is_null($from_id) === false):
			$writer->writeObject($from_id);
		endif;
		$writer->writeInt($date);
		$writer->writeObject($gift);
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		if(is_null($msg_id) === false):
			$writer->writeInt($msg_id);
		endif;
		if(is_null($saved_id) === false):
			$writer->writeLong($saved_id);
		endif;
		if(is_null($convert_stars) === false):
			$writer->writeLong($convert_stars);
		endif;
		if(is_null($upgrade_stars) === false):
			$writer->writeLong($upgrade_stars);
		endif;
		if(is_null($can_export_at) === false):
			$writer->writeInt($can_export_at);
		endif;
		if(is_null($transfer_stars) === false):
			$writer->writeLong($transfer_stars);
		endif;
		if(is_null($can_transfer_at) === false):
			$writer->writeInt($can_transfer_at);
		endif;
		if(is_null($can_resell_at) === false):
			$writer->writeInt($can_resell_at);
		endif;
		if(is_null($collection_id) === false):
			$writer->writeVector($collection_id,'int');
		endif;
		if(is_null($prepaid_upgrade_hash) === false):
			$writer->writeBytes($prepaid_upgrade_hash);
		endif;
		if(is_null($drop_original_details_stars) === false):
			$writer->writeLong($drop_original_details_stars);
		endif;
		if(is_null($gift_num) === false):
			$writer->writeInt($gift_num);
		endif;
		if(is_null($can_craft_at) === false):
			$writer->writeInt($can_craft_at);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['name_hidden'] = boolval($flags & (1 << 0));
		$result['unsaved'] = boolval($flags & (1 << 5));
		$result['refunded'] = boolval($flags & (1 << 9));
		$result['can_upgrade'] = boolval($flags & (1 << 10));
		$result['pinned_to_top'] = boolval($flags & (1 << 12));
		$result['upgrade_separate'] = boolval($flags & (1 << 17));
		if($flags & (1 << 1)):
			$result['from_id'] = $reader->readObject();
		else:
			$result['from_id'] = null;
		endif;
		$result['date'] = $reader->readInt();
		$result['gift'] = $reader->readObject();
		if($flags & (1 << 2)):
			$result['message'] = $reader->readObject();
		else:
			$result['message'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['msg_id'] = $reader->readInt();
		else:
			$result['msg_id'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['saved_id'] = $reader->readLong();
		else:
			$result['saved_id'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['convert_stars'] = $reader->readLong();
		else:
			$result['convert_stars'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['upgrade_stars'] = $reader->readLong();
		else:
			$result['upgrade_stars'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['can_export_at'] = $reader->readInt();
		else:
			$result['can_export_at'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['transfer_stars'] = $reader->readLong();
		else:
			$result['transfer_stars'] = null;
		endif;
		if($flags & (1 << 13)):
			$result['can_transfer_at'] = $reader->readInt();
		else:
			$result['can_transfer_at'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['can_resell_at'] = $reader->readInt();
		else:
			$result['can_resell_at'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['collection_id'] = $reader->readVector('int');
		else:
			$result['collection_id'] = null;
		endif;
		if($flags & (1 << 16)):
			$result['prepaid_upgrade_hash'] = $reader->readBytes();
		else:
			$result['prepaid_upgrade_hash'] = null;
		endif;
		if($flags & (1 << 18)):
			$result['drop_original_details_stars'] = $reader->readLong();
		else:
			$result['drop_original_details_stars'] = null;
		endif;
		if($flags & (1 << 19)):
			$result['gift_num'] = $reader->readInt();
		else:
			$result['gift_num'] = null;
		endif;
		if($flags & (1 << 20)):
			$result['can_craft_at'] = $reader->readInt();
		else:
			$result['can_craft_at'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url long access_hash
 * @return InputWebFileLocation
 */

final class InputWebFileLocation extends Instance {
	public function request(string $url,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc239d686);
		$writer->writeBytes($url);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash true need_check string country textwithentities text
 * @return FactCheck
 */

final class FactCheck extends Instance {
	public function request(int $hash,null | bool $need_check = null,null | string $country = null,null | object $text = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb89bfccf);
		$flags = 0;
		$flags |= $need_check ? (1 << 0) : 0;
		$flags |= is_null($country) ? 0 : (1 << 1);
		$flags |= is_null($text) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($country) === false):
			$writer->writeBytes($country);
		endif;
		if(is_null($text) === false):
			$writer->writeObject($text);
		endif;
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['need_check'] = boolval($flags & (1 << 0));
		if($flags & (1 << 1)):
			$result['country'] = $reader->readBytes();
		else:
			$result['country'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['text'] = $reader->readObject();
		else:
			$result['text'] = null;
		endif;
		$result['hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string address geopoint geo_point
 * @return BusinessLocation
 */

final class BusinessLocation extends Instance {
	public function request(string $address,null | object $geo_point = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xac5c1af7);
		$flags = 0;
		$flags |= is_null($geo_point) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($geo_point) === false):
			$writer->writeObject($geo_point);
		endif;
		$writer->writeBytes($address);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['geo_point'] = $reader->readObject();
		else:
			$result['geo_point'] = null;
		endif;
		$result['address'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message string url true invert_media true force_large_media true force_small_media true manual true safe Vector<messageentity> entities replymarkup reply_markup
 * @return BotInlineMessage
 */

final class BotInlineMessageMediaWebPage extends Instance {
	public function request(string $message,string $url,null | bool $invert_media = null,null | bool $force_large_media = null,null | bool $force_small_media = null,null | bool $manual = null,null | bool $safe = null,null | array $entities = null,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x809ad9a6);
		$flags = 0;
		$flags |= $invert_media ? (1 << 3) : 0;
		$flags |= $force_large_media ? (1 << 4) : 0;
		$flags |= $force_small_media ? (1 << 5) : 0;
		$flags |= $manual ? (1 << 7) : 0;
		$flags |= $safe ? (1 << 8) : 0;
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		$writer->writeBytes($url);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['invert_media'] = boolval($flags & (1 << 3));
		$result['force_large_media'] = boolval($flags & (1 << 4));
		$result['force_small_media'] = boolval($flags & (1 << 5));
		$result['manual'] = boolval($flags & (1 << 7));
		$result['safe'] = boolval($flags & (1 << 8));
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		$result['url'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true join true leave true invite true ban true unban true kick true unkick true promote true demote true info true settings true pinned true edit true delete true group_call true invites true send true forums true sub_extend true edit_rank
 * @return ChannelAdminLogEventsFilter
 */

final class ChannelAdminLogEventsFilter extends Instance {
	public function request(null | bool $join = null,null | bool $leave = null,null | bool $invite = null,null | bool $ban = null,null | bool $unban = null,null | bool $kick = null,null | bool $unkick = null,null | bool $promote = null,null | bool $demote = null,null | bool $info = null,null | bool $settings = null,null | bool $pinned = null,null | bool $edit = null,null | bool $delete = null,null | bool $group_call = null,null | bool $invites = null,null | bool $send = null,null | bool $forums = null,null | bool $sub_extend = null,null | bool $edit_rank = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xea107ae4);
		$flags = 0;
		$flags |= $join ? (1 << 0) : 0;
		$flags |= $leave ? (1 << 1) : 0;
		$flags |= $invite ? (1 << 2) : 0;
		$flags |= $ban ? (1 << 3) : 0;
		$flags |= $unban ? (1 << 4) : 0;
		$flags |= $kick ? (1 << 5) : 0;
		$flags |= $unkick ? (1 << 6) : 0;
		$flags |= $promote ? (1 << 7) : 0;
		$flags |= $demote ? (1 << 8) : 0;
		$flags |= $info ? (1 << 9) : 0;
		$flags |= $settings ? (1 << 10) : 0;
		$flags |= $pinned ? (1 << 11) : 0;
		$flags |= $edit ? (1 << 12) : 0;
		$flags |= $delete ? (1 << 13) : 0;
		$flags |= $group_call ? (1 << 14) : 0;
		$flags |= $invites ? (1 << 15) : 0;
		$flags |= $send ? (1 << 16) : 0;
		$flags |= $forums ? (1 << 17) : 0;
		$flags |= $sub_extend ? (1 << 18) : 0;
		$flags |= $edit_rank ? (1 << 19) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['join'] = boolval($flags & (1 << 0));
		$result['leave'] = boolval($flags & (1 << 1));
		$result['invite'] = boolval($flags & (1 << 2));
		$result['ban'] = boolval($flags & (1 << 3));
		$result['unban'] = boolval($flags & (1 << 4));
		$result['kick'] = boolval($flags & (1 << 5));
		$result['unkick'] = boolval($flags & (1 << 6));
		$result['promote'] = boolval($flags & (1 << 7));
		$result['demote'] = boolval($flags & (1 << 8));
		$result['info'] = boolval($flags & (1 << 9));
		$result['settings'] = boolval($flags & (1 << 10));
		$result['pinned'] = boolval($flags & (1 << 11));
		$result['edit'] = boolval($flags & (1 << 12));
		$result['delete'] = boolval($flags & (1 << 13));
		$result['group_call'] = boolval($flags & (1 << 14));
		$result['invites'] = boolval($flags & (1 << 15));
		$result['send'] = boolval($flags & (1 << 16));
		$result['forums'] = boolval($flags & (1 << 17));
		$result['sub_extend'] = boolval($flags & (1 << 18));
		$result['edit_rank'] = boolval($flags & (1 << 19));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateAutoSaveSettings extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xec05b097);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int requests_pending Vector<long> recent_requesters
 * @return Update
 */

final class UpdatePendingJoinRequests extends Instance {
	public function request(object $peer,int $requests_pending,array $recent_requesters) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7063c3db);
		$writer->writeObject($peer);
		$writer->writeInt($requests_pending);
		$writer->writeVector($recent_requesters,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['requests_pending'] = $reader->readInt();
		$result['recent_requesters'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SendMessageAction
 */

final class SendMessageCancelAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfd5ec8f5);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionToggleAutotranslation extends Instance {
	public function request(bool $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc517f77e);
		$writer->writeBool($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_value'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text
 * @return RichText
 */

final class TextPlain extends Instance {
	public function request(string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x744694e0);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<dialogpeer> order
 * @return Update
 */

final class UpdatePinnedSavedDialogs extends Instance {
	public function request(null | array $order = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x686c85a6);
		$flags = 0;
		$flags |= is_null($order) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($order) === false):
			$writer->writeVector($order,'dialogpeer');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['order'] = $reader->readVector('dialogpeer');
		else:
			$result['order'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string type bytes bytes
 * @return PhotoSize
 */

final class PhotoStrippedSize extends Instance {
	public function request(string $type,string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe0b0bc2e);
		$writer->writeBytes($type);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readBytes();
		$result['bytes'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text string url int button_id keyboardbuttonstyle style string fwd_text
 * @return KeyboardButton
 */

final class KeyboardButtonUrlAuth extends Instance {
	public function request(string $text,string $url,int $button_id,null | object $style = null,null | string $fwd_text = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf51006f9);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$flags |= is_null($fwd_text) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		if(is_null($fwd_text) === false):
			$writer->writeBytes($fwd_text);
		endif;
		$writer->writeBytes($url);
		$writer->writeInt($button_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['fwd_text'] = $reader->readBytes();
		else:
			$result['fwd_text'] = null;
		endif;
		$result['url'] = $reader->readBytes();
		$result['button_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long prev_value long new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeLinkedChat extends Instance {
	public function request(int $prev_value,int $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x50c7ac8);
		$writer->writeLong($prev_value);
		$writer->writeLong($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readLong();
		$result['new_value'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SendMessageAction
 */

final class SpeakingInGroupCallAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd92c2285);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash int premium_days string currency long amount true restore
 * @return InputStorePaymentPurpose
 */

final class InputStorePaymentAuthCode extends Instance {
	public function request(string $phone_number,string $phone_code_hash,int $premium_days,string $currency,int $amount,null | bool $restore = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3fc18057);
		$flags = 0;
		$flags |= $restore ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		$writer->writeInt($premium_days);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['restore'] = boolval($flags & (1 << 0));
		$result['phone_number'] = $reader->readBytes();
		$result['phone_code_hash'] = $reader->readBytes();
		$result['premium_days'] = $reader->readInt();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id long user_id bytes payload string currency long total_amount paymentrequestedinfo info string shipping_option_id
 * @return Update
 */

final class UpdateBotPrecheckoutQuery extends Instance {
	public function request(int $query_id,int $user_id,string $payload,string $currency,int $total_amount,null | object $info = null,null | string $shipping_option_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8caa9a96);
		$flags = 0;
		$flags |= is_null($info) ? 0 : (1 << 0);
		$flags |= is_null($shipping_option_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($query_id);
		$writer->writeLong($user_id);
		$writer->writeBytes($payload);
		if(is_null($info) === false):
			$writer->writeObject($info);
		endif;
		if(is_null($shipping_option_id) === false):
			$writer->writeBytes($shipping_option_id);
		endif;
		$writer->writeBytes($currency);
		$writer->writeLong($total_amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['query_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		$result['payload'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['info'] = $reader->readObject();
		else:
			$result['info'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['shipping_option_id'] = $reader->readBytes();
		else:
			$result['shipping_option_id'] = null;
		endif;
		$result['currency'] = $reader->readBytes();
		$result['total_amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return InputWallPaper
 */

final class InputWallPaperSlug extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x72091c80);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['slug'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id Vector<int> messages int pts int pts_count
 * @return Update
 */

final class UpdateDeleteChannelMessages extends Instance {
	public function request(int $channel_id,array $messages,int $pts,int $pts_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc32d5b12);
		$writer->writeLong($channel_id);
		$writer->writeVector($messages,'int');
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['messages'] = $reader->readVector('int');
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param webdomainexception exception true delete bool open_external_browser
 * @return Update
 */

final class UpdateWebBrowserException extends Instance {
	public function request(object $exception,null | bool $delete = null,null | bool $open_external_browser = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x140502d1);
		$flags = 0;
		$flags |= $delete ? (1 << 1) : 0;
		$flags |= is_null($open_external_browser) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($open_external_browser) === false):
			$writer->writeBool($open_external_browser);
		endif;
		$writer->writeObject($exception);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['delete'] = boolval($flags & (1 << 1));
		if($flags & (1 << 0)):
			$result['open_external_browser'] = $reader->readBool();
		else:
			$result['open_external_browser'] = null;
		endif;
		$result['exception'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputUser
 */

final class InputUserSelf extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf7c1b13f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text string query true same_peer keyboardbuttonstyle style Vector<inlinequerypeertype> peer_types
 * @return KeyboardButton
 */

final class KeyboardButtonSwitchInline extends Instance {
	public function request(string $text,string $query,null | bool $same_peer = null,null | object $style = null,null | array $peer_types = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x991399fc);
		$flags = 0;
		$flags |= $same_peer ? (1 << 0) : 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$flags |= is_null($peer_types) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		$writer->writeBytes($query);
		if(is_null($peer_types) === false):
			$writer->writeVector($peer_types,'inlinequerypeertype');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['same_peer'] = boolval($flags & (1 << 0));
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		$result['query'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['peer_types'] = $reader->readVector('inlinequerypeertype');
		else:
			$result['peer_types'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdatePtsChanged extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3354678f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarGiftAttributeRarity
 */

final class StarGiftAttributeRarityEpic extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x78fbf3a8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param game game
 * @return MessageMedia
 */

final class MessageMediaGame extends Instance {
	public function request(object $game) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfdb19008);
		$writer->writeObject($game);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['game'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return AttachMenuPeerType
 */

final class AttachMenuPeerTypePM extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf146d31f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return JoinChatBotResult
 */

final class JoinChatBotResultWebView extends Instance {
	public function request(string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd6e3b813);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string emoticon int msg_id datajson interaction
 * @return SendMessageAction
 */

final class SendMessageEmojiInteraction extends Instance {
	public function request(string $emoticon,int $msg_id,object $interaction) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x25972bcb);
		$writer->writeBytes($emoticon);
		$writer->writeInt($msg_id);
		$writer->writeObject($interaction);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['emoticon'] = $reader->readBytes();
		$result['msg_id'] = $reader->readInt();
		$result['interaction'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string key string value
 * @return LangPackString
 */

final class LangPackString extends Instance {
	public function request(string $key,string $value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcad181f6);
		$writer->writeBytes($key);
		$writer->writeBytes($value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['key'] = $reader->readBytes();
		$result['value'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true archive_and_mute_new_noncontact_peers true keep_archived_unmuted true keep_archived_folders true hide_read_marks true new_noncontact_peers_require_premium true display_gifts_button long noncontact_peers_paid_stars disallowedgiftssettings disallowed_gifts
 * @return GlobalPrivacySettings
 */

final class GlobalPrivacySettings extends Instance {
	public function request(null | bool $archive_and_mute_new_noncontact_peers = null,null | bool $keep_archived_unmuted = null,null | bool $keep_archived_folders = null,null | bool $hide_read_marks = null,null | bool $new_noncontact_peers_require_premium = null,null | bool $display_gifts_button = null,null | int $noncontact_peers_paid_stars = null,null | object $disallowed_gifts = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfe41b34f);
		$flags = 0;
		$flags |= $archive_and_mute_new_noncontact_peers ? (1 << 0) : 0;
		$flags |= $keep_archived_unmuted ? (1 << 1) : 0;
		$flags |= $keep_archived_folders ? (1 << 2) : 0;
		$flags |= $hide_read_marks ? (1 << 3) : 0;
		$flags |= $new_noncontact_peers_require_premium ? (1 << 4) : 0;
		$flags |= $display_gifts_button ? (1 << 7) : 0;
		$flags |= is_null($noncontact_peers_paid_stars) ? 0 : (1 << 5);
		$flags |= is_null($disallowed_gifts) ? 0 : (1 << 6);
		$writer->writeInt($flags);
		if(is_null($noncontact_peers_paid_stars) === false):
			$writer->writeLong($noncontact_peers_paid_stars);
		endif;
		if(is_null($disallowed_gifts) === false):
			$writer->writeObject($disallowed_gifts);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['archive_and_mute_new_noncontact_peers'] = boolval($flags & (1 << 0));
		$result['keep_archived_unmuted'] = boolval($flags & (1 << 1));
		$result['keep_archived_folders'] = boolval($flags & (1 << 2));
		$result['hide_read_marks'] = boolval($flags & (1 << 3));
		$result['new_noncontact_peers_require_premium'] = boolval($flags & (1 << 4));
		$result['display_gifts_button'] = boolval($flags & (1 << 7));
		if($flags & (1 << 5)):
			$result['noncontact_peers_paid_stars'] = $reader->readLong();
		else:
			$result['noncontact_peers_paid_stars'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['disallowed_gifts'] = $reader->readObject();
		else:
			$result['disallowed_gifts'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message int date true no_webpage true invert_media inputreplyto reply_to Vector<messageentity> entities inputmedia media long effect suggestedpost suggested_post richmessage rich_message
 * @return DraftMessage
 */

final class DraftMessage extends Instance {
	public function request(string $message,int $date,null | bool $no_webpage = null,null | bool $invert_media = null,null | object $reply_to = null,null | array $entities = null,null | object $media = null,null | int $effect = null,null | object $suggested_post = null,null | object $rich_message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x60fe3294);
		$flags = 0;
		$flags |= $no_webpage ? (1 << 1) : 0;
		$flags |= $invert_media ? (1 << 6) : 0;
		$flags |= is_null($reply_to) ? 0 : (1 << 4);
		$flags |= is_null($entities) ? 0 : (1 << 3);
		$flags |= is_null($media) ? 0 : (1 << 5);
		$flags |= is_null($effect) ? 0 : (1 << 7);
		$flags |= is_null($suggested_post) ? 0 : (1 << 8);
		$flags |= is_null($rich_message) ? 0 : (1 << 9);
		$writer->writeInt($flags);
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($media) === false):
			$writer->writeObject($media);
		endif;
		$writer->writeInt($date);
		if(is_null($effect) === false):
			$writer->writeLong($effect);
		endif;
		if(is_null($suggested_post) === false):
			$writer->writeObject($suggested_post);
		endif;
		if(is_null($rich_message) === false):
			$writer->writeObject($rich_message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['no_webpage'] = boolval($flags & (1 << 1));
		$result['invert_media'] = boolval($flags & (1 << 6));
		if($flags & (1 << 4)):
			$result['reply_to'] = $reader->readObject();
		else:
			$result['reply_to'] = null;
		endif;
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 3)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['media'] = $reader->readObject();
		else:
			$result['media'] = null;
		endif;
		$result['date'] = $reader->readInt();
		if($flags & (1 << 7)):
			$result['effect'] = $reader->readLong();
		else:
			$result['effect'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['suggested_post'] = $reader->readObject();
		else:
			$result['suggested_post'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['rich_message'] = $reader->readObject();
		else:
			$result['rich_message'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int top_message int read_inbox_max_id int read_outbox_max_id int unread_count int unread_mentions_count int unread_reactions_count int unread_poll_votes_count peernotifysettings notify_settings true pinned true unread_mark true view_forum_as_messages int pts draftmessage draft int folder_id int ttl_period
 * @return Dialog
 */

final class Dialog extends Instance {
	public function request(object $peer,int $top_message,int $read_inbox_max_id,int $read_outbox_max_id,int $unread_count,int $unread_mentions_count,int $unread_reactions_count,int $unread_poll_votes_count,object $notify_settings,null | bool $pinned = null,null | bool $unread_mark = null,null | bool $view_forum_as_messages = null,null | int $pts = null,null | object $draft = null,null | int $folder_id = null,null | int $ttl_period = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfc89f7f3);
		$flags = 0;
		$flags |= $pinned ? (1 << 2) : 0;
		$flags |= $unread_mark ? (1 << 3) : 0;
		$flags |= $view_forum_as_messages ? (1 << 6) : 0;
		$flags |= is_null($pts) ? 0 : (1 << 0);
		$flags |= is_null($draft) ? 0 : (1 << 1);
		$flags |= is_null($folder_id) ? 0 : (1 << 4);
		$flags |= is_null($ttl_period) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($top_message);
		$writer->writeInt($read_inbox_max_id);
		$writer->writeInt($read_outbox_max_id);
		$writer->writeInt($unread_count);
		$writer->writeInt($unread_mentions_count);
		$writer->writeInt($unread_reactions_count);
		$writer->writeInt($unread_poll_votes_count);
		$writer->writeObject($notify_settings);
		if(is_null($pts) === false):
			$writer->writeInt($pts);
		endif;
		if(is_null($draft) === false):
			$writer->writeObject($draft);
		endif;
		if(is_null($folder_id) === false):
			$writer->writeInt($folder_id);
		endif;
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pinned'] = boolval($flags & (1 << 2));
		$result['unread_mark'] = boolval($flags & (1 << 3));
		$result['view_forum_as_messages'] = boolval($flags & (1 << 6));
		$result['peer'] = $reader->readObject();
		$result['top_message'] = $reader->readInt();
		$result['read_inbox_max_id'] = $reader->readInt();
		$result['read_outbox_max_id'] = $reader->readInt();
		$result['unread_count'] = $reader->readInt();
		$result['unread_mentions_count'] = $reader->readInt();
		$result['unread_reactions_count'] = $reader->readInt();
		$result['unread_poll_votes_count'] = $reader->readInt();
		$result['notify_settings'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['pts'] = $reader->readInt();
		else:
			$result['pts'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['draft'] = $reader->readObject();
		else:
			$result['draft'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['folder_id'] = $reader->readInt();
		else:
			$result['folder_id'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['ttl_period'] = $reader->readInt();
		else:
			$result['ttl_period'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id long random_id
 * @return Update
 */

final class UpdateMessageID extends Instance {
	public function request(int $id,int $random_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4e90bfd6);
		$writer->writeInt($id);
		$writer->writeLong($random_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		$result['random_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id int invitations
 * @return StatsGroupTopInviter
 */

final class StatsGroupTopInviter extends Instance {
	public function request(int $user_id,int $invitations) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x535f779d);
		$writer->writeLong($user_id);
		$writer->writeInt($invitations);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['invitations'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length string language
 * @return MessageEntity
 */

final class MessageEntityPre extends Instance {
	public function request(int $offset,int $length,string $language) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x73924be0);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		$writer->writeBytes($language);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		$result['language'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string name int color
 * @return AttachMenuBotIconColor
 */

final class AttachMenuBotIconColor extends Instance {
	public function request(string $name,int $color) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4576f3f0);
		$writer->writeBytes($name);
		$writer->writeInt($color);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['name'] = $reader->readBytes();
		$result['color'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputAiComposeTone
 */

final class InputAiComposeToneID extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x773c080);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce int128 server_nonce int128 new_nonce_hash2
 * @return Set_client_DH_params_answer
 */

final class DhGenRetry extends Instance {
	public function request(int | string $nonce,int | string $server_nonce,int | string $new_nonce_hash2) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x46dc1fb9);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeLargeInt($new_nonce_hash2,128);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['new_nonce_hash2'] = $reader->readLargeInt(128);
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputStickerSet
 */

final class InputStickerSetID extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9de7a269);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarGiftAttributeRarity
 */

final class StarGiftAttributeRarityLegendary extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcef7e7a8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes option true chosen true correct int voters Vector<peer> recent_voters
 * @return PollAnswerVoters
 */

final class PollAnswerVoters extends Instance {
	public function request(string $option,null | bool $chosen = null,null | bool $correct = null,null | int $voters = null,null | array $recent_voters = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3645230a);
		$flags = 0;
		$flags |= $chosen ? (1 << 0) : 0;
		$flags |= $correct ? (1 << 1) : 0;
		$flags |= is_null($voters) ? 0 : (1 << 2);
		$flags |= is_null($recent_voters) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($option);
		if(is_null($voters) === false):
			$writer->writeInt($voters);
		endif;
		if(is_null($recent_voters) === false):
			$writer->writeVector($recent_voters,'peer');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['chosen'] = boolval($flags & (1 << 0));
		$result['correct'] = boolval($flags & (1 << 1));
		$result['option'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['voters'] = $reader->readInt();
		else:
			$result['voters'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['recent_voters'] = $reader->readVector('peer');
		else:
			$result['recent_voters'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param exportedchatinvite prev_invite exportedchatinvite new_invite
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionExportedInviteEdit extends Instance {
	public function request(object $prev_invite,object $new_invite) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe90ebb59);
		$writer->writeObject($prev_invite);
		$writer->writeObject($new_invite);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_invite'] = $reader->readObject();
		$result['new_invite'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes data bytes hash bytes secret
 * @return SecureCredentialsEncrypted
 */

final class SecureCredentialsEncrypted extends Instance {
	public function request(string $data,string $hash,string $secret) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x33f0ea47);
		$writer->writeBytes($data);
		$writer->writeBytes($hash);
		$writer->writeBytes($secret);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['data'] = $reader->readBytes();
		$result['hash'] = $reader->readBytes();
		$result['secret'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string connection_id message message int qts message reply_to_message
 * @return Update
 */

final class UpdateBotEditBusinessMessage extends Instance {
	public function request(string $connection_id,object $message,int $qts,null | object $reply_to_message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7df587c);
		$flags = 0;
		$flags |= is_null($reply_to_message) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($connection_id);
		$writer->writeObject($message);
		if(is_null($reply_to_message) === false):
			$writer->writeObject($reply_to_message);
		endif;
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['connection_id'] = $reader->readBytes();
		$result['message'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['reply_to_message'] = $reader->readObject();
		else:
			$result['reply_to_message'] = null;
		endif;
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long offset int limit bytes hash
 * @return FileHash
 */

final class FileHash extends Instance {
	public function request(int $offset,int $limit,string $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf39b035c);
		$writer->writeLong($offset);
		$writer->writeInt($limit);
		$writer->writeBytes($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readLong();
		$result['limit'] = $reader->readInt();
		$result['hash'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReportReason
 */

final class InputReportReasonPersonalDetails extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9ec7863d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int top_msg_id
 * @return NotifyPeer
 */

final class NotifyForumTopic extends Instance {
	public function request(object $peer,int $top_msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x226e6308);
		$writer->writeObject($peer);
		$writer->writeInt($top_msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['top_msg_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return DestroyAuthKeyRes
 */

final class DestroyAuthKeyOk extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf660e1d4);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessageAction
 */

final class MessageActionScreenshotTaken extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4792929b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return InputSavedStarGift
 */

final class InputSavedStarGiftSlug extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2085c238);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['slug'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterMyMentions extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc1f8e69a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<pageblock> blocks richtext title true open
 * @return PageBlock
 */

final class PageBlockDetails extends Instance {
	public function request(array $blocks,object $title,null | bool $open = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x76768bed);
		$flags = 0;
		$flags |= $open ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($blocks,'pageblock');
		$writer->writeObject($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['open'] = boolval($flags & (1 << 0));
		$result['blocks'] = $reader->readVector('pageblock');
		$result['title'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyPhoneP2P extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x39491cc8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int msg_id messagereactions reactions int top_msg_id peer saved_peer_id
 * @return Update
 */

final class UpdateMessageReactions extends Instance {
	public function request(object $peer,int $msg_id,object $reactions,null | int $top_msg_id = null,null | object $saved_peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1e297bfa);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		$writer->writeObject($reactions);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['top_msg_id'] = $reader->readInt();
		else:
			$result['top_msg_id'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['saved_peer_id'] = $reader->readObject();
		else:
			$result['saved_peer_id'] = null;
		endif;
		$result['reactions'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyForwards extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x69ec56a3);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BotCommandScope
 */

final class BotCommandScopeDefault extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2f6cb2ab);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypePassport extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3dac6a00);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string token
 * @return EmailVerification
 */

final class EmailVerificationGoogle extends Instance {
	public function request(string $token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdb909ec2);
		$writer->writeBytes($token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['token'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BaseTheme
 */

final class BaseThemeArctic extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5b11125a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SendMessageAction
 */

final class SendMessageChooseContactAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x628cbc6f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int start_minute int end_minute
 * @return BusinessWeeklyOpen
 */

final class BusinessWeeklyOpen extends Instance {
	public function request(int $start_minute,int $end_minute) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x120b1ab9);
		$writer->writeInt($start_minute);
		$writer->writeInt($end_minute);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['start_minute'] = $reader->readInt();
		$result['end_minute'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockFooter extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x48870999);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id long access_hash int date long admin_id long participant_id bytes g_a int folder_id
 * @return EncryptedChat
 */

final class EncryptedChatRequested extends Instance {
	public function request(int $id,int $access_hash,int $date,int $admin_id,int $participant_id,string $g_a,null | int $folder_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x48f1d94c);
		$flags = 0;
		$flags |= is_null($folder_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($folder_id) === false):
			$writer->writeInt($folder_id);
		endif;
		$writer->writeInt($id);
		$writer->writeLong($access_hash);
		$writer->writeInt($date);
		$writer->writeLong($admin_id);
		$writer->writeLong($participant_id);
		$writer->writeBytes($g_a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['folder_id'] = $reader->readInt();
		else:
			$result['folder_id'] = null;
		endif;
		$result['id'] = $reader->readInt();
		$result['access_hash'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['admin_id'] = $reader->readLong();
		$result['participant_id'] = $reader->readLong();
		$result['g_a'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityEmail extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x64e475c2);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityUnknown extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbb92ba95);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id string ip_address int port true ipv6 true media_only true tcpo_only true cdn true static true this_port_only bytes secret
 * @return DcOption
 */

final class DcOption extends Instance {
	public function request(int $id,string $ip_address,int $port,null | bool $ipv6 = null,null | bool $media_only = null,null | bool $tcpo_only = null,null | bool $cdn = null,null | bool $static = null,null | bool $this_port_only = null,null | string $secret = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x18b7a10d);
		$flags = 0;
		$flags |= $ipv6 ? (1 << 0) : 0;
		$flags |= $media_only ? (1 << 1) : 0;
		$flags |= $tcpo_only ? (1 << 2) : 0;
		$flags |= $cdn ? (1 << 3) : 0;
		$flags |= $static ? (1 << 4) : 0;
		$flags |= $this_port_only ? (1 << 5) : 0;
		$flags |= is_null($secret) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeBytes($ip_address);
		$writer->writeInt($port);
		if(is_null($secret) === false):
			$writer->writeBytes($secret);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['ipv6'] = boolval($flags & (1 << 0));
		$result['media_only'] = boolval($flags & (1 << 1));
		$result['tcpo_only'] = boolval($flags & (1 << 2));
		$result['cdn'] = boolval($flags & (1 << 3));
		$result['static'] = boolval($flags & (1 << 4));
		$result['this_port_only'] = boolval($flags & (1 << 5));
		$result['id'] = $reader->readInt();
		$result['ip_address'] = $reader->readBytes();
		$result['port'] = $reader->readInt();
		if($flags & (1 << 10)):
			$result['secret'] = $reader->readBytes();
		else:
			$result['secret'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateReadFeaturedEmojiStickers extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfb4c496c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int button_id Vector<requestedpeer> peers
 * @return MessageAction
 */

final class MessageActionRequestedPeerSentMe extends Instance {
	public function request(int $button_id,array $peers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x93b31848);
		$writer->writeInt($button_id);
		$writer->writeVector($peers,'requestedpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['button_id'] = $reader->readInt();
		$result['peers'] = $reader->readVector('requestedpeer');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument id
 * @return InputStickeredMedia
 */

final class InputStickeredMediaDocument extends Instance {
	public function request(object $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x438865b);
		$writer->writeObject($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool show_previews bool silent int mute_until notificationsound ios_sound notificationsound android_sound notificationsound other_sound bool stories_muted bool stories_hide_sender notificationsound stories_ios_sound notificationsound stories_android_sound notificationsound stories_other_sound
 * @return PeerNotifySettings
 */

final class PeerNotifySettings extends Instance {
	public function request(null | bool $show_previews = null,null | bool $silent = null,null | int $mute_until = null,null | object $ios_sound = null,null | object $android_sound = null,null | object $other_sound = null,null | bool $stories_muted = null,null | bool $stories_hide_sender = null,null | object $stories_ios_sound = null,null | object $stories_android_sound = null,null | object $stories_other_sound = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x99622c0c);
		$flags = 0;
		$flags |= is_null($show_previews) ? 0 : (1 << 0);
		$flags |= is_null($silent) ? 0 : (1 << 1);
		$flags |= is_null($mute_until) ? 0 : (1 << 2);
		$flags |= is_null($ios_sound) ? 0 : (1 << 3);
		$flags |= is_null($android_sound) ? 0 : (1 << 4);
		$flags |= is_null($other_sound) ? 0 : (1 << 5);
		$flags |= is_null($stories_muted) ? 0 : (1 << 6);
		$flags |= is_null($stories_hide_sender) ? 0 : (1 << 7);
		$flags |= is_null($stories_ios_sound) ? 0 : (1 << 8);
		$flags |= is_null($stories_android_sound) ? 0 : (1 << 9);
		$flags |= is_null($stories_other_sound) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($show_previews) === false):
			$writer->writeBool($show_previews);
		endif;
		if(is_null($silent) === false):
			$writer->writeBool($silent);
		endif;
		if(is_null($mute_until) === false):
			$writer->writeInt($mute_until);
		endif;
		if(is_null($ios_sound) === false):
			$writer->writeObject($ios_sound);
		endif;
		if(is_null($android_sound) === false):
			$writer->writeObject($android_sound);
		endif;
		if(is_null($other_sound) === false):
			$writer->writeObject($other_sound);
		endif;
		if(is_null($stories_muted) === false):
			$writer->writeBool($stories_muted);
		endif;
		if(is_null($stories_hide_sender) === false):
			$writer->writeBool($stories_hide_sender);
		endif;
		if(is_null($stories_ios_sound) === false):
			$writer->writeObject($stories_ios_sound);
		endif;
		if(is_null($stories_android_sound) === false):
			$writer->writeObject($stories_android_sound);
		endif;
		if(is_null($stories_other_sound) === false):
			$writer->writeObject($stories_other_sound);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['show_previews'] = $reader->readBool();
		else:
			$result['show_previews'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['silent'] = $reader->readBool();
		else:
			$result['silent'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['mute_until'] = $reader->readInt();
		else:
			$result['mute_until'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['ios_sound'] = $reader->readObject();
		else:
			$result['ios_sound'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['android_sound'] = $reader->readObject();
		else:
			$result['android_sound'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['other_sound'] = $reader->readObject();
		else:
			$result['other_sound'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['stories_muted'] = $reader->readBool();
		else:
			$result['stories_muted'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['stories_hide_sender'] = $reader->readBool();
		else:
			$result['stories_hide_sender'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['stories_ios_sound'] = $reader->readObject();
		else:
			$result['stories_ios_sound'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['stories_android_sound'] = $reader->readObject();
		else:
			$result['stories_android_sound'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['stories_other_sound'] = $reader->readObject();
		else:
			$result['stories_other_sound'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyRule
 */

final class PrivacyValueAllowContacts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfffe1bac);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string currency long total_amount bytes payload paymentcharge charge true recurring_init true recurring_used paymentrequestedinfo info string shipping_option_id int subscription_until_date
 * @return MessageAction
 */

final class MessageActionPaymentSentMe extends Instance {
	public function request(string $currency,int $total_amount,string $payload,object $charge,null | bool $recurring_init = null,null | bool $recurring_used = null,null | object $info = null,null | string $shipping_option_id = null,null | int $subscription_until_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xffa00ccc);
		$flags = 0;
		$flags |= $recurring_init ? (1 << 2) : 0;
		$flags |= $recurring_used ? (1 << 3) : 0;
		$flags |= is_null($info) ? 0 : (1 << 0);
		$flags |= is_null($shipping_option_id) ? 0 : (1 << 1);
		$flags |= is_null($subscription_until_date) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeBytes($currency);
		$writer->writeLong($total_amount);
		$writer->writeBytes($payload);
		if(is_null($info) === false):
			$writer->writeObject($info);
		endif;
		if(is_null($shipping_option_id) === false):
			$writer->writeBytes($shipping_option_id);
		endif;
		$writer->writeObject($charge);
		if(is_null($subscription_until_date) === false):
			$writer->writeInt($subscription_until_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['recurring_init'] = boolval($flags & (1 << 2));
		$result['recurring_used'] = boolval($flags & (1 << 3));
		$result['currency'] = $reader->readBytes();
		$result['total_amount'] = $reader->readLong();
		$result['payload'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['info'] = $reader->readObject();
		else:
			$result['info'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['shipping_option_id'] = $reader->readBytes();
		else:
			$result['shipping_option_id'] = null;
		endif;
		$result['charge'] = $reader->readObject();
		if($flags & (1 << 4)):
			$result['subscription_until_date'] = $reader->readInt();
		else:
			$result['subscription_until_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string data
 * @return DataJSON
 */

final class DataJSON extends Instance {
	public function request(string $data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7d748d04);
		$writer->writeBytes($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['data'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id chatadminrights admin_rights string rank
 * @return ChannelParticipant
 */

final class ChannelParticipantCreator extends Instance {
	public function request(int $user_id,object $admin_rights,null | string $rank = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2fe601d3);
		$flags = 0;
		$flags |= is_null($rank) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		$writer->writeObject($admin_rights);
		if(is_null($rank) === false):
			$writer->writeBytes($rank);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		$result['admin_rights'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['rank'] = $reader->readBytes();
		else:
			$result['rank'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateSavedGifs extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9375341e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return RecentMeUrl
 */

final class RecentMeUrlUnknown extends Instance {
	public function request(string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x46e1d13d);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text bytes option
 * @return SponsoredMessageReportOption
 */

final class SponsoredMessageReportOption extends Instance {
	public function request(string $text,string $option) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x430d3150);
		$writer->writeBytes($text);
		$writer->writeBytes($option);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readBytes();
		$result['option'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id int months textwithentities message
 * @return InputInvoice
 */

final class InputInvoicePremiumGiftStars extends Instance {
	public function request(object $user_id,int $months,null | object $message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdabab2ef);
		$flags = 0;
		$flags |= is_null($message) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($user_id);
		$writer->writeInt($months);
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['user_id'] = $reader->readObject();
		$result['months'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['message'] = $reader->readObject();
		else:
			$result['message'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true reply true read_messages true delete_sent_messages true delete_received_messages true edit_name true edit_bio true edit_profile_photo true edit_username true view_gifts true sell_gifts true change_gift_settings true transfer_and_upgrade_gifts true transfer_stars true manage_stories
 * @return BusinessBotRights
 */

final class BusinessBotRights extends Instance {
	public function request(null | bool $reply = null,null | bool $read_messages = null,null | bool $delete_sent_messages = null,null | bool $delete_received_messages = null,null | bool $edit_name = null,null | bool $edit_bio = null,null | bool $edit_profile_photo = null,null | bool $edit_username = null,null | bool $view_gifts = null,null | bool $sell_gifts = null,null | bool $change_gift_settings = null,null | bool $transfer_and_upgrade_gifts = null,null | bool $transfer_stars = null,null | bool $manage_stories = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa0624cf7);
		$flags = 0;
		$flags |= $reply ? (1 << 0) : 0;
		$flags |= $read_messages ? (1 << 1) : 0;
		$flags |= $delete_sent_messages ? (1 << 2) : 0;
		$flags |= $delete_received_messages ? (1 << 3) : 0;
		$flags |= $edit_name ? (1 << 4) : 0;
		$flags |= $edit_bio ? (1 << 5) : 0;
		$flags |= $edit_profile_photo ? (1 << 6) : 0;
		$flags |= $edit_username ? (1 << 7) : 0;
		$flags |= $view_gifts ? (1 << 8) : 0;
		$flags |= $sell_gifts ? (1 << 9) : 0;
		$flags |= $change_gift_settings ? (1 << 10) : 0;
		$flags |= $transfer_and_upgrade_gifts ? (1 << 11) : 0;
		$flags |= $transfer_stars ? (1 << 12) : 0;
		$flags |= $manage_stories ? (1 << 13) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['reply'] = boolval($flags & (1 << 0));
		$result['read_messages'] = boolval($flags & (1 << 1));
		$result['delete_sent_messages'] = boolval($flags & (1 << 2));
		$result['delete_received_messages'] = boolval($flags & (1 << 3));
		$result['edit_name'] = boolval($flags & (1 << 4));
		$result['edit_bio'] = boolval($flags & (1 << 5));
		$result['edit_profile_photo'] = boolval($flags & (1 << 6));
		$result['edit_username'] = boolval($flags & (1 << 7));
		$result['view_gifts'] = boolval($flags & (1 << 8));
		$result['sell_gifts'] = boolval($flags & (1 << 9));
		$result['change_gift_settings'] = boolval($flags & (1 << 10));
		$result['transfer_and_upgrade_gifts'] = boolval($flags & (1 << 11));
		$result['transfer_stars'] = boolval($flags & (1 << 12));
		$result['manage_stories'] = boolval($flags & (1 << 13));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer storyitem story
 * @return PublicForward
 */

final class PublicForwardStory extends Instance {
	public function request(object $peer,object $story) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xedf3add0);
		$writer->writeObject($peer);
		$writer->writeObject($story);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['story'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SendMessageAction
 */

final class SendMessageRecordAudioAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd52f73f7);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessageAction
 */

final class MessageActionHistoryClear extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9fbab604);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string pq string p string q int128 nonce int128 server_nonce int256 new_nonce int dc int expires_in
 * @return P_Q_inner_data
 */

final class PQInnerDataTempDc extends Instance {
	public function request(string $pq,string $p,string $q,int | string $nonce,int | string $server_nonce,int | string $new_nonce,int $dc,int $expires_in) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x56fddf88);
		$writer->writeBytes($pq);
		$writer->writeBytes($p);
		$writer->writeBytes($q);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeLargeInt($new_nonce,256);
		$writer->writeInt($dc);
		$writer->writeInt($expires_in);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pq'] = $reader->readBytes();
		$result['p'] = $reader->readBytes();
		$result['q'] = $reader->readBytes();
		$result['nonce'] = $reader->readLargeInt(128);
		$result['server_nonce'] = $reader->readLargeInt(128);
		$result['new_nonce'] = $reader->readLargeInt(256);
		$result['dc'] = $reader->readInt();
		$result['expires_in'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stargift gift
 * @return WebPageAttribute
 */

final class WebPageAttributeUniqueStarGift extends Instance {
	public function request(object $gift) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcf6f6db8);
		$writer->writeObject($gift);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['gift'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param chatparticipants participants
 * @return Update
 */

final class UpdateChatParticipants extends Instance {
	public function request(object $participants) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7761198);
		$writer->writeObject($participants);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['participants'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text keyboardbuttonstyle style bool quiz
 * @return KeyboardButton
 */

final class KeyboardButtonRequestPoll extends Instance {
	public function request(string $text,null | object $style = null,null | bool $quiz = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7a11d782);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$flags |= is_null($quiz) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		if(is_null($quiz) === false):
			$writer->writeBool($quiz);
		endif;
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['quiz'] = $reader->readBool();
		else:
			$result['quiz'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<richtext> texts
 * @return RichText
 */

final class TextConcat extends Instance {
	public function request(array $texts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7e6260d7);
		$writer->writeVector($texts,'richtext');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['texts'] = $reader->readVector('richtext');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string currency long amount string crypto_currency long crypto_amount string transaction_id
 * @return MessageAction
 */

final class MessageActionGiftTon extends Instance {
	public function request(string $currency,int $amount,string $crypto_currency,int $crypto_amount,null | string $transaction_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa8a3c699);
		$flags = 0;
		$flags |= is_null($transaction_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		$writer->writeBytes($crypto_currency);
		$writer->writeLong($crypto_amount);
		if(is_null($transaction_id) === false):
			$writer->writeBytes($transaction_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		$result['crypto_currency'] = $reader->readBytes();
		$result['crypto_amount'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['transaction_id'] = $reader->readBytes();
		else:
			$result['transaction_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param mediaareacoordinates coordinates long channel_id int msg_id
 * @return MediaArea
 */

final class MediaAreaChannelPost extends Instance {
	public function request(object $coordinates,int $channel_id,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x770416af);
		$writer->writeObject($coordinates);
		$writer->writeLong($channel_id);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['coordinates'] = $reader->readObject();
		$result['channel_id'] = $reader->readLong();
		$result['msg_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param phonecall phone_call
 * @return Update
 */

final class UpdatePhoneCall extends Instance {
	public function request(object $phone_call) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xab0f6b1e);
		$writer->writeObject($phone_call);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone_call'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyBirthday extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd65a11cc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot_id string short_name
 * @return InputBotApp
 */

final class InputBotAppShortName extends Instance {
	public function request(object $bot_id,string $short_name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x908c0407);
		$writer->writeObject($bot_id);
		$writer->writeBytes($short_name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['bot_id'] = $reader->readObject();
		$result['short_name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgeopoint geo_point true stopped int heading int period int proximity_notification_radius
 * @return InputMedia
 */

final class InputMediaGeoLive extends Instance {
	public function request(object $geo_point,null | bool $stopped = null,null | int $heading = null,null | int $period = null,null | int $proximity_notification_radius = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x971fa843);
		$flags = 0;
		$flags |= $stopped ? (1 << 0) : 0;
		$flags |= is_null($heading) ? 0 : (1 << 2);
		$flags |= is_null($period) ? 0 : (1 << 1);
		$flags |= is_null($proximity_notification_radius) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeObject($geo_point);
		if(is_null($heading) === false):
			$writer->writeInt($heading);
		endif;
		if(is_null($period) === false):
			$writer->writeInt($period);
		endif;
		if(is_null($proximity_notification_radius) === false):
			$writer->writeInt($proximity_notification_radius);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['stopped'] = boolval($flags & (1 << 0));
		$result['geo_point'] = $reader->readObject();
		if($flags & (1 << 2)):
			$result['heading'] = $reader->readInt();
		else:
			$result['heading'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['period'] = $reader->readInt();
		else:
			$result['period'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['proximity_notification_radius'] = $reader->readInt();
		else:
			$result['proximity_notification_radius'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyStarGiftsAutoSave extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe1732341);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputStickerSet
 */

final class InputStickerSetAnimatedEmojiAnimations extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcde3739);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param channelparticipant prev_participant channelparticipant new_participant
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantToggleBan extends Instance {
	public function request(object $prev_participant,object $new_participant) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe6d83d7e);
		$writer->writeObject($prev_participant);
		$writer->writeObject($new_participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_participant'] = $reader->readObject();
		$result['new_participant'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message
 * @return StoryReaction
 */

final class StoryReactionPublicForward extends Instance {
	public function request(object $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbbab2643);
		$writer->writeObject($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<securevaluetype> types
 * @return MessageAction
 */

final class MessageActionSecureValuesSent extends Instance {
	public function request(array $types) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd95c6154);
		$writer->writeVector($types,'securevaluetype');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['types'] = $reader->readVector('securevaluetype');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int progress
 * @return SendMessageAction
 */

final class SendMessageUploadAudioAction extends Instance {
	public function request(int $progress) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf351d7ab);
		$writer->writeInt($progress);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['progress'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterChatPhotos extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3a20ecb8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id
 * @return Update
 */

final class UpdateDeleteQuickReply extends Instance {
	public function request(int $shortcut_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x53e6f1ec);
		$writer->writeInt($shortcut_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['shortcut_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BusinessAwayMessageSchedule
 */

final class BusinessAwayMessageScheduleAlways extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc9b9e2b9);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateDialogFilters extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3504914f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string raw_id inputpasskeyresponse response
 * @return InputPasskeyCredential
 */

final class InputPasskeyCredentialPublicKey extends Instance {
	public function request(string $id,string $raw_id,object $response) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3c27b78f);
		$writer->writeBytes($id);
		$writer->writeBytes($raw_id);
		$writer->writeObject($response);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readBytes();
		$result['raw_id'] = $reader->readBytes();
		$result['response'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param encryptedmessage message int qts
 * @return Update
 */

final class UpdateNewEncryptedMessage extends Instance {
	public function request(object $message,int $qts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x12bcbd9a);
		$writer->writeObject($message);
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextMention extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcd24cf44);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return InputInvoice
 */

final class InputInvoiceSlug extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc326caef);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['slug'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true blur true motion int background_color int second_background_color int third_background_color int fourth_background_color int intensity int rotation string emoticon
 * @return WallPaperSettings
 */

final class WallPaperSettings extends Instance {
	public function request(null | bool $blur = null,null | bool $motion = null,null | int $background_color = null,null | int $second_background_color = null,null | int $third_background_color = null,null | int $fourth_background_color = null,null | int $intensity = null,null | int $rotation = null,null | string $emoticon = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x372efcd0);
		$flags = 0;
		$flags |= $blur ? (1 << 1) : 0;
		$flags |= $motion ? (1 << 2) : 0;
		$flags |= is_null($background_color) ? 0 : (1 << 0);
		$flags |= is_null($second_background_color) ? 0 : (1 << 4);
		$flags |= is_null($third_background_color) ? 0 : (1 << 5);
		$flags |= is_null($fourth_background_color) ? 0 : (1 << 6);
		$flags |= is_null($intensity) ? 0 : (1 << 3);
		$flags |= is_null($rotation) ? 0 : (1 << 4);
		$flags |= is_null($emoticon) ? 0 : (1 << 7);
		$writer->writeInt($flags);
		if(is_null($background_color) === false):
			$writer->writeInt($background_color);
		endif;
		if(is_null($second_background_color) === false):
			$writer->writeInt($second_background_color);
		endif;
		if(is_null($third_background_color) === false):
			$writer->writeInt($third_background_color);
		endif;
		if(is_null($fourth_background_color) === false):
			$writer->writeInt($fourth_background_color);
		endif;
		if(is_null($intensity) === false):
			$writer->writeInt($intensity);
		endif;
		if(is_null($rotation) === false):
			$writer->writeInt($rotation);
		endif;
		if(is_null($emoticon) === false):
			$writer->writeBytes($emoticon);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['blur'] = boolval($flags & (1 << 1));
		$result['motion'] = boolval($flags & (1 << 2));
		if($flags & (1 << 0)):
			$result['background_color'] = $reader->readInt();
		else:
			$result['background_color'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['second_background_color'] = $reader->readInt();
		else:
			$result['second_background_color'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['third_background_color'] = $reader->readInt();
		else:
			$result['third_background_color'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['fourth_background_color'] = $reader->readInt();
		else:
			$result['fourth_background_color'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['intensity'] = $reader->readInt();
		else:
			$result['intensity'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['rotation'] = $reader->readInt();
		else:
			$result['rotation'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['emoticon'] = $reader->readBytes();
		else:
			$result['emoticon'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext title Vector<pagetablerow> rows true bordered true striped
 * @return PageBlock
 */

final class PageBlockTable extends Instance {
	public function request(object $title,array $rows,null | bool $bordered = null,null | bool $striped = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbf4dea82);
		$flags = 0;
		$flags |= $bordered ? (1 << 0) : 0;
		$flags |= $striped ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($title);
		$writer->writeVector($rows,'pagetablerow');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['bordered'] = boolval($flags & (1 << 0));
		$result['striped'] = boolval($flags & (1 << 1));
		$result['title'] = $reader->readObject();
		$result['rows'] = $reader->readVector('pagetablerow');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text inputuser user_id keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class InputKeyboardButtonUserProfile extends Instance {
	public function request(string $text,object $user_id,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7d5e07c7);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		$result['user_id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int code string text
 * @return Error
 */

final class ErrorObject extends Instance {
	public function request(int $code,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc4b9f9bb);
		$writer->writeInt($code);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['code'] = $reader->readInt();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message
 * @return MessageAction
 */

final class MessageActionCustomAction extends Instance {
	public function request(string $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfae69f56);
		$writer->writeBytes($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer
 * @return NotifyPeer
 */

final class NotifyPeer extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9fd40bd8);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PageBlock
 */

final class PageBlockUnsupported extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x13567e8a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long collectible_id int until
 * @return EmojiStatus
 */

final class InputEmojiStatusCollectible extends Instance {
	public function request(int $collectible_id,null | int $until = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7141dbf);
		$flags = 0;
		$flags |= is_null($until) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($collectible_id);
		if(is_null($until) === false):
			$writer->writeInt($until);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['collectible_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['until'] = $reader->readInt();
		else:
			$result['until'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id long channel_id
 * @return InputPeer
 */

final class InputPeerChannelFromMessage extends Instance {
	public function request(object $peer,int $msg_id,int $channel_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd2a0840);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeLong($channel_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		$result['channel_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stickerset true masks true emojis
 * @return Update
 */

final class UpdateMoveStickerSetToTop extends Instance {
	public function request(int $stickerset,null | bool $masks = null,null | bool $emojis = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x86fccf85);
		$flags = 0;
		$flags |= $masks ? (1 << 0) : 0;
		$flags |= $emojis ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($stickerset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['masks'] = boolval($flags & (1 << 0));
		$result['emojis'] = boolval($flags & (1 << 1));
		$result['stickerset'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int progress
 * @return SendMessageAction
 */

final class SendMessageHistoryImportAction extends Instance {
	public function request(int $progress) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdbda9246);
		$writer->writeInt($progress);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['progress'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param dialogfilter filter string description
 * @return DialogFilterSuggested
 */

final class DialogFilterSuggested extends Instance {
	public function request(object $filter,string $description) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x77744d4a);
		$writer->writeObject($filter);
		$writer->writeBytes($description);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['filter'] = $reader->readObject();
		$result['description'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length int date true relative true short_time true long_time true short_date true long_date true day_of_week
 * @return MessageEntity
 */

final class MessageEntityFormattedDate extends Instance {
	public function request(int $offset,int $length,int $date,null | bool $relative = null,null | bool $short_time = null,null | bool $long_time = null,null | bool $short_date = null,null | bool $long_date = null,null | bool $day_of_week = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x904ac7c7);
		$flags = 0;
		$flags |= $relative ? (1 << 0) : 0;
		$flags |= $short_time ? (1 << 1) : 0;
		$flags |= $long_time ? (1 << 2) : 0;
		$flags |= $short_date ? (1 << 3) : 0;
		$flags |= $long_date ? (1 << 4) : 0;
		$flags |= $day_of_week ? (1 << 5) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['relative'] = boolval($flags & (1 << 0));
		$result['short_time'] = boolval($flags & (1 << 1));
		$result['long_time'] = boolval($flags & (1 << 2));
		$result['short_date'] = boolval($flags & (1 << 3));
		$result['long_date'] = boolval($flags & (1 << 4));
		$result['day_of_week'] = boolval($flags & (1 << 5));
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int num int duration
 * @return StarGiftAuctionRound
 */

final class StarGiftAuctionRound extends Instance {
	public function request(int $num,int $duration) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3aae0528);
		$writer->writeInt($num);
		$writer->writeInt($duration);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['num'] = $reader->readInt();
		$result['duration'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long req_msg_id bytes info
 * @return MsgsStateInfo
 */

final class MsgsStateInfo extends Instance {
	public function request(int $req_msg_id,string $info) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4deb57d);
		$writer->writeLong($req_msg_id);
		$writer->writeBytes($info);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['req_msg_id'] = $reader->readLong();
		$result['info'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type securedata data inputsecurefile front_side inputsecurefile reverse_side inputsecurefile selfie Vector<inputsecurefile> translation Vector<inputsecurefile> files secureplaindata plain_data
 * @return InputSecureValue
 */

final class InputSecureValue extends Instance {
	public function request(object $type,null | object $data = null,null | object $front_side = null,null | object $reverse_side = null,null | object $selfie = null,null | array $translation = null,null | array $files = null,null | object $plain_data = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdb21d0a7);
		$flags = 0;
		$flags |= is_null($data) ? 0 : (1 << 0);
		$flags |= is_null($front_side) ? 0 : (1 << 1);
		$flags |= is_null($reverse_side) ? 0 : (1 << 2);
		$flags |= is_null($selfie) ? 0 : (1 << 3);
		$flags |= is_null($translation) ? 0 : (1 << 6);
		$flags |= is_null($files) ? 0 : (1 << 4);
		$flags |= is_null($plain_data) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeObject($type);
		if(is_null($data) === false):
			$writer->writeObject($data);
		endif;
		if(is_null($front_side) === false):
			$writer->writeObject($front_side);
		endif;
		if(is_null($reverse_side) === false):
			$writer->writeObject($reverse_side);
		endif;
		if(is_null($selfie) === false):
			$writer->writeObject($selfie);
		endif;
		if(is_null($translation) === false):
			$writer->writeVector($translation,'inputsecurefile');
		endif;
		if(is_null($files) === false):
			$writer->writeVector($files,'inputsecurefile');
		endif;
		if(is_null($plain_data) === false):
			$writer->writeObject($plain_data);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['type'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['data'] = $reader->readObject();
		else:
			$result['data'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['front_side'] = $reader->readObject();
		else:
			$result['front_side'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['reverse_side'] = $reader->readObject();
		else:
			$result['reverse_side'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['selfie'] = $reader->readObject();
		else:
			$result['selfie'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['translation'] = $reader->readVector('inputsecurefile');
		else:
			$result['translation'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['files'] = $reader->readVector('inputsecurefile');
		else:
			$result['files'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['plain_data'] = $reader->readObject();
		else:
			$result['plain_data'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id webpage webpage int pts int pts_count
 * @return Update
 */

final class UpdateChannelWebPage extends Instance {
	public function request(int $channel_id,object $webpage,int $pts,int $pts_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2f2ba99f);
		$writer->writeLong($channel_id);
		$writer->writeObject($webpage);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		$result['webpage'] = $reader->readObject();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id long user_id
 * @return InputUser
 */

final class InputUserFromMessage extends Instance {
	public function request(object $peer,int $msg_id,int $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1da448e2);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeLong($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string command string description
 * @return BotCommand
 */

final class BotCommand extends Instance {
	public function request(string $command,string $description) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc27ac8c7);
		$writer->writeBytes($command);
		$writer->writeBytes($description);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['command'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> msg_ids
 * @return MsgResendReq
 */

final class MsgResendReq extends Instance {
	public function request(array $msg_ids) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7d861a08);
		$writer->writeVector($msg_ids,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_ids'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateRecentEmojiStatuses extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x30f443db);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot_id string short_name
 * @return InputGame
 */

final class InputGameShortName extends Instance {
	public function request(object $bot_id,string $short_name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc331e80a);
		$writer->writeObject($bot_id);
		$writer->writeBytes($short_name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['bot_id'] = $reader->readObject();
		$result['short_name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param storiesstealthmode stealth_mode
 * @return Update
 */

final class UpdateStoriesStealthMode extends Instance {
	public function request(object $stealth_mode) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2c084dc1);
		$writer->writeObject($stealth_mode);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['stealth_mode'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bad_msg_id int bad_msg_seqno int error_code
 * @return BadMsgNotification
 */

final class BadMsgNotification extends Instance {
	public function request(int $bad_msg_id,int $bad_msg_seqno,int $error_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa7eff811);
		$writer->writeLong($bad_msg_id);
		$writer->writeInt($bad_msg_seqno);
		$writer->writeInt($error_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['bad_msg_id'] = $reader->readLong();
		$result['bad_msg_seqno'] = $reader->readInt();
		$result['error_code'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<securevalue> values securecredentialsencrypted credentials
 * @return MessageAction
 */

final class MessageActionSecureValuesSentMe extends Instance {
	public function request(array $values,object $credentials) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1b287353);
		$writer->writeVector($values,'securevalue');
		$writer->writeObject($credentials);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['values'] = $reader->readVector('securevalue');
		$result['credentials'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message int pts int pts_count
 * @return Update
 */

final class UpdateEditMessage extends Instance {
	public function request(object $message,int $pts,int $pts_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe40370a3);
		$writer->writeObject($message);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug inputpeer to_id true ton
 * @return InputInvoice
 */

final class InputInvoiceStarGiftResale extends Instance {
	public function request(string $slug,object $to_id,null | bool $ton = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc39f5324);
		$flags = 0;
		$flags |= $ton ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($slug);
		$writer->writeObject($to_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['ton'] = boolval($flags & (1 << 0));
		$result['slug'] = $reader->readBytes();
		$result['to_id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id
 * @return MessageAction
 */

final class MessageActionChatDeleteUser extends Instance {
	public function request(int $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa43f30cc);
		$writer->writeLong($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url int size string mime_type Vector<documentattribute> attributes
 * @return WebDocument
 */

final class WebDocumentNoProxy extends Instance {
	public function request(string $url,int $size,string $mime_type,array $attributes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf9c8bcc6);
		$writer->writeBytes($url);
		$writer->writeInt($size);
		$writer->writeBytes($mime_type);
		$writer->writeVector($attributes,'documentattribute');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['size'] = $reader->readInt();
		$result['mime_type'] = $reader->readBytes();
		$result['attributes'] = $reader->readVector('documentattribute');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Updates
 */

final class UpdatesTooLong extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe317af7e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButtonGame extends Instance {
	public function request(string $text,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x89c590f9);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true by_me
 * @return UserStatus
 */

final class UserStatusRecently extends Instance {
	public function request(null | bool $by_me = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7b197dc8);
		$flags = 0;
		$flags |= $by_me ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['by_me'] = boolval($flags & (1 << 0));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length long document_id
 * @return MessageEntity
 */

final class MessageEntityCustomEmoji extends Instance {
	public function request(int $offset,int $length,int $document_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc8cf05f8);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		$writer->writeLong($document_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		$result['document_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes data bytes data_hash bytes secret
 * @return SecureData
 */

final class SecureData extends Instance {
	public function request(string $data,string $data_hash,string $secret) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8aeabec3);
		$writer->writeBytes($data);
		$writer->writeBytes($data_hash);
		$writer->writeBytes($secret);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['data'] = $reader->readBytes();
		$result['data_hash'] = $reader->readBytes();
		$result['secret'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long game_id int score
 * @return MessageAction
 */

final class MessageActionGameScore extends Instance {
	public function request(int $game_id,int $score) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x92a72876);
		$writer->writeLong($game_id);
		$writer->writeInt($score);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['game_id'] = $reader->readLong();
		$result['score'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterPhotoVideo extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x56e9f0e4);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer_id int date reaction reaction
 * @return StoryReaction
 */

final class StoryReaction extends Instance {
	public function request(object $peer_id,int $date,object $reaction) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6090d6d5);
		$writer->writeObject($peer_id);
		$writer->writeInt($date);
		$writer->writeObject($reaction);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer_id'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		$result['reaction'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int days string slug true via_giveaway true unclaimed peer boost_peer string currency long amount string crypto_currency long crypto_amount textwithentities message
 * @return MessageAction
 */

final class MessageActionGiftCode extends Instance {
	public function request(int $days,string $slug,null | bool $via_giveaway = null,null | bool $unclaimed = null,null | object $boost_peer = null,null | string $currency = null,null | int $amount = null,null | string $crypto_currency = null,null | int $crypto_amount = null,null | object $message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31c48347);
		$flags = 0;
		$flags |= $via_giveaway ? (1 << 0) : 0;
		$flags |= $unclaimed ? (1 << 5) : 0;
		$flags |= is_null($boost_peer) ? 0 : (1 << 1);
		$flags |= is_null($currency) ? 0 : (1 << 2);
		$flags |= is_null($amount) ? 0 : (1 << 2);
		$flags |= is_null($crypto_currency) ? 0 : (1 << 3);
		$flags |= is_null($crypto_amount) ? 0 : (1 << 3);
		$flags |= is_null($message) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		if(is_null($boost_peer) === false):
			$writer->writeObject($boost_peer);
		endif;
		$writer->writeInt($days);
		$writer->writeBytes($slug);
		if(is_null($currency) === false):
			$writer->writeBytes($currency);
		endif;
		if(is_null($amount) === false):
			$writer->writeLong($amount);
		endif;
		if(is_null($crypto_currency) === false):
			$writer->writeBytes($crypto_currency);
		endif;
		if(is_null($crypto_amount) === false):
			$writer->writeLong($crypto_amount);
		endif;
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['via_giveaway'] = boolval($flags & (1 << 0));
		$result['unclaimed'] = boolval($flags & (1 << 5));
		if($flags & (1 << 1)):
			$result['boost_peer'] = $reader->readObject();
		else:
			$result['boost_peer'] = null;
		endif;
		$result['days'] = $reader->readInt();
		$result['slug'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['currency'] = $reader->readBytes();
		else:
			$result['currency'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['amount'] = $reader->readLong();
		else:
			$result['amount'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['crypto_currency'] = $reader->readBytes();
		else:
			$result['crypto_currency'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['crypto_amount'] = $reader->readLong();
		else:
			$result['crypto_amount'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['message'] = $reader->readObject();
		else:
			$result['message'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return TopPeerCategory
 */

final class TopPeerCategoryChannels extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x161d9628);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message prev_message message new_message
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionEditMessage extends Instance {
	public function request(object $prev_message,object $new_message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x709b2405);
		$writer->writeObject($prev_message);
		$writer->writeObject($new_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_message'] = $reader->readObject();
		$result['new_message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return TopPeerCategory
 */

final class TopPeerCategoryGroups extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd17a14a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterVoice extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x50f5c392);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long first_msg_id long unique_id long server_salt
 * @return NewSession
 */

final class NewSessionCreated extends Instance {
	public function request(int $first_msg_id,int $unique_id,int $server_salt) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9ec20908);
		$writer->writeLong($first_msg_id);
		$writer->writeLong($unique_id);
		$writer->writeLong($server_salt);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['first_msg_id'] = $reader->readLong();
		$result['unique_id'] = $reader->readLong();
		$result['server_salt'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id
 * @return Update
 */

final class UpdateUser extends Instance {
	public function request(int $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x20529438);
		$writer->writeLong($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text string copy_text keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButtonCopy extends Instance {
	public function request(string $text,string $copy_text,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbcc4af10);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		$writer->writeBytes($copy_text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		$result['copy_text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text long user_id
 * @return RichText
 */

final class TextMentionName extends Instance {
	public function request(object $text,int $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1a9fbfc);
		$writer->writeObject($text);
		$writer->writeLong($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		$result['user_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SendMessageAction
 */

final class SendMessageTypingAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x16bf744e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeySavedMusic extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4dbe9226);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param starsamount price
 * @return MessageAction
 */

final class MessageActionSuggestedPostSuccess extends Instance {
	public function request(object $price) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x95ddcf69);
		$writer->writeObject($price);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['price'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long volume_id int local_id long secret bytes file_reference
 * @return InputFileLocation
 */

final class InputFileLocation extends Instance {
	public function request(int $volume_id,int $local_id,int $secret,string $file_reference) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdfdaabe1);
		$writer->writeLong($volume_id);
		$writer->writeInt($local_id);
		$writer->writeLong($secret);
		$writer->writeBytes($file_reference);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['volume_id'] = $reader->readLong();
		$result['local_id'] = $reader->readInt();
		$result['secret'] = $reader->readLong();
		$result['file_reference'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long gift_id long bid_amount true hide_name true update_bid inputpeer peer textwithentities message
 * @return InputInvoice
 */

final class InputInvoiceStarGiftAuctionBid extends Instance {
	public function request(int $gift_id,int $bid_amount,null | bool $hide_name = null,null | bool $update_bid = null,null | object $peer = null,null | object $message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1ecafa10);
		$flags = 0;
		$flags |= $hide_name ? (1 << 0) : 0;
		$flags |= $update_bid ? (1 << 2) : 0;
		$flags |= is_null($peer) ? 0 : (1 << 3);
		$flags |= is_null($message) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		$writer->writeLong($gift_id);
		$writer->writeLong($bid_amount);
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['hide_name'] = boolval($flags & (1 << 0));
		$result['update_bid'] = boolval($flags & (1 << 2));
		if($flags & (1 << 3)):
			$result['peer'] = $reader->readObject();
		else:
			$result['peer'] = null;
		endif;
		$result['gift_id'] = $reader->readLong();
		$result['bid_amount'] = $reader->readLong();
		if($flags & (1 << 1)):
			$result['message'] = $reader->readObject();
		else:
			$result['message'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string type int w int h int size double video_start_ts
 * @return VideoSize
 */

final class VideoSize extends Instance {
	public function request(string $type,int $w,int $h,int $size,null | float $video_start_ts = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xde33b094);
		$flags = 0;
		$flags |= is_null($video_start_ts) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($type);
		$writer->writeInt($w);
		$writer->writeInt($h);
		$writer->writeInt($size);
		if(is_null($video_start_ts) === false):
			$writer->writeDouble($video_start_ts);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['type'] = $reader->readBytes();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		$result['size'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['video_start_ts'] = $reader->readDouble();
		else:
			$result['video_start_ts'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int prev_value int new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeHistoryTTL extends Instance {
	public function request(int $prev_value,int $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6e941a38);
		$writer->writeInt($prev_value);
		$writer->writeInt($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readInt();
		$result['new_value'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true small inputdocument document string title string performer
 * @return InputWebFileLocation
 */

final class InputWebFileAudioAlbumThumbLocation extends Instance {
	public function request(null | bool $small = null,null | object $document = null,null | string $title = null,null | string $performer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf46fe924);
		$flags = 0;
		$flags |= $small ? (1 << 2) : 0;
		$flags |= is_null($document) ? 0 : (1 << 0);
		$flags |= is_null($title) ? 0 : (1 << 1);
		$flags |= is_null($performer) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($document) === false):
			$writer->writeObject($document);
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($performer) === false):
			$writer->writeBytes($performer);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['small'] = boolval($flags & (1 << 2));
		if($flags & (1 << 0)):
			$result['document'] = $reader->readObject();
		else:
			$result['document'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['performer'] = $reader->readBytes();
		else:
			$result['performer'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richmessage rich_message replymarkup reply_markup
 * @return BotInlineMessage
 */

final class BotInlineMessageRichMessage extends Instance {
	public function request(object $rich_message,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa617e7b);
		$flags = 0;
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		$writer->writeObject($rich_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		$result['rich_message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PaidReactionPrivacy
 */

final class PaidReactionPrivacyDefault extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x206ad49e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id int launch_msg_id int winners_count int unclaimed_count Vector<long> winners int until_date true only_new_subscribers true refunded int additional_peers_count int months long stars string prize_description
 * @return MessageMedia
 */

final class MessageMediaGiveawayResults extends Instance {
	public function request(int $channel_id,int $launch_msg_id,int $winners_count,int $unclaimed_count,array $winners,int $until_date,null | bool $only_new_subscribers = null,null | bool $refunded = null,null | int $additional_peers_count = null,null | int $months = null,null | int $stars = null,null | string $prize_description = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xceaa3ea1);
		$flags = 0;
		$flags |= $only_new_subscribers ? (1 << 0) : 0;
		$flags |= $refunded ? (1 << 2) : 0;
		$flags |= is_null($additional_peers_count) ? 0 : (1 << 3);
		$flags |= is_null($months) ? 0 : (1 << 4);
		$flags |= is_null($stars) ? 0 : (1 << 5);
		$flags |= is_null($prize_description) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($channel_id);
		if(is_null($additional_peers_count) === false):
			$writer->writeInt($additional_peers_count);
		endif;
		$writer->writeInt($launch_msg_id);
		$writer->writeInt($winners_count);
		$writer->writeInt($unclaimed_count);
		$writer->writeVector($winners,'long');
		if(is_null($months) === false):
			$writer->writeInt($months);
		endif;
		if(is_null($stars) === false):
			$writer->writeLong($stars);
		endif;
		if(is_null($prize_description) === false):
			$writer->writeBytes($prize_description);
		endif;
		$writer->writeInt($until_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['only_new_subscribers'] = boolval($flags & (1 << 0));
		$result['refunded'] = boolval($flags & (1 << 2));
		$result['channel_id'] = $reader->readLong();
		if($flags & (1 << 3)):
			$result['additional_peers_count'] = $reader->readInt();
		else:
			$result['additional_peers_count'] = null;
		endif;
		$result['launch_msg_id'] = $reader->readInt();
		$result['winners_count'] = $reader->readInt();
		$result['unclaimed_count'] = $reader->readInt();
		$result['winners'] = $reader->readVector('long');
		if($flags & (1 << 4)):
			$result['months'] = $reader->readInt();
		else:
			$result['months'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['stars'] = $reader->readLong();
		else:
			$result['stars'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['prize_description'] = $reader->readBytes();
		else:
			$result['prize_description'] = null;
		endif;
		$result['until_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type bytes data_hash string field string text
 * @return SecureValueError
 */

final class SecureValueErrorData extends Instance {
	public function request(object $type,string $data_hash,string $field,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe8a40bd9);
		$writer->writeObject($type);
		$writer->writeBytes($data_hash);
		$writer->writeBytes($field);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readObject();
		$result['data_hash'] = $reader->readBytes();
		$result['field'] = $reader->readBytes();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyRule
 */

final class PrivacyValueAllowAll extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x65427b82);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PhoneCallDiscardReason
 */

final class PhoneCallDiscardReasonMissed extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x85e42301);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SendMessageAction
 */

final class SendMessageGamePlayAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdd6a8f48);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int max_id int pts int pts_count
 * @return Update
 */

final class UpdateReadHistoryOutbox extends Instance {
	public function request(object $peer,int $max_id,int $pts,int $pts_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2f2f21bf);
		$writer->writeObject($peer);
		$writer->writeInt($max_id);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['max_id'] = $reader->readInt();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyStarGiftsAutoSave extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2ca4fdf8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPeer
 */

final class InputPeerEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7f3b18ea);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param stargiftattributeid attribute int count
 * @return StarGiftAttributeCounter
 */

final class StarGiftAttributeCounter extends Instance {
	public function request(object $attribute,int $count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2eb1b658);
		$writer->writeObject($attribute);
		$writer->writeInt($count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['attribute'] = $reader->readObject();
		$result['count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return TopPeerCategory
 */

final class TopPeerCategoryBotsPM extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xab661b5b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionToggleSignatureProfiles extends Instance {
	public function request(bool $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x60a79c79);
		$writer->writeBool($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_value'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionStartGroupCall extends Instance {
	public function request(object $call) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x23209745);
		$writer->writeObject($call);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['call'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BaseTheme
 */

final class BaseThemeClassic extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc3a12462);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text richtext caption
 * @return PageBlock
 */

final class PageBlockBlockquote extends Instance {
	public function request(object $text,object $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x263d7c26);
		$writer->writeObject($text);
		$writer->writeObject($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		$result['caption'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int total_daily int remains long stars_amount true query_is_free int wait_till
 * @return SearchPostsFlood
 */

final class SearchPostsFlood extends Instance {
	public function request(int $total_daily,int $remains,int $stars_amount,null | bool $query_is_free = null,null | int $wait_till = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e0b5b6a);
		$flags = 0;
		$flags |= $query_is_free ? (1 << 0) : 0;
		$flags |= is_null($wait_till) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeInt($total_daily);
		$writer->writeInt($remains);
		if(is_null($wait_till) === false):
			$writer->writeInt($wait_till);
		endif;
		$writer->writeLong($stars_amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['query_is_free'] = boolval($flags & (1 << 0));
		$result['total_daily'] = $reader->readInt();
		$result['remains'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['wait_till'] = $reader->readInt();
		else:
			$result['wait_till'] = null;
		endif;
		$result['stars_amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ProfileTab
 */

final class ProfileTabMusic extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9f27d26e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true payer_initiated
 * @return MessageAction
 */

final class MessageActionSuggestedPostRefund extends Instance {
	public function request(null | bool $payer_initiated = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x69f916f8);
		$flags = 0;
		$flags |= $payer_initiated ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['payer_initiated'] = boolval($flags & (1 << 0));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext title Vector<pagerelatedarticle> articles
 * @return PageBlock
 */

final class PageBlockRelatedArticles extends Instance {
	public function request(object $title,array $articles) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x16115a96);
		$writer->writeObject($title);
		$writer->writeVector($articles,'pagerelatedarticle');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readObject();
		$result['articles'] = $reader->readVector('pagerelatedarticle');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyRule
 */

final class InputPrivacyValueAllowCloseFriends extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2f453e49);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url long access_hash int size string mime_type Vector<documentattribute> attributes
 * @return WebDocument
 */

final class WebDocument extends Instance {
	public function request(string $url,int $access_hash,int $size,string $mime_type,array $attributes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1c570ed1);
		$writer->writeBytes($url);
		$writer->writeLong($access_hash);
		$writer->writeInt($size);
		$writer->writeBytes($mime_type);
		$writer->writeVector($attributes,'documentattribute');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['access_hash'] = $reader->readLong();
		$result['size'] = $reader->readInt();
		$result['mime_type'] = $reader->readBytes();
		$result['attributes'] = $reader->readVector('documentattribute');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param messages.stickerset stickerset
 * @return Update
 */

final class UpdateNewStickerSet extends Instance {
	public function request(object $stickerset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x688a30aa);
		$writer->writeObject($stickerset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['stickerset'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantJoin extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x183040d3);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true attach_menu true from_request string domain botapp app
 * @return MessageAction
 */

final class MessageActionBotAllowed extends Instance {
	public function request(null | bool $attach_menu = null,null | bool $from_request = null,null | string $domain = null,null | object $app = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc516d679);
		$flags = 0;
		$flags |= $attach_menu ? (1 << 1) : 0;
		$flags |= $from_request ? (1 << 3) : 0;
		$flags |= is_null($domain) ? 0 : (1 << 0);
		$flags |= is_null($app) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($domain) === false):
			$writer->writeBytes($domain);
		endif;
		if(is_null($app) === false):
			$writer->writeObject($app);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['attach_menu'] = boolval($flags & (1 << 1));
		$result['from_request'] = boolval($flags & (1 << 3));
		if($flags & (1 << 0)):
			$result['domain'] = $reader->readBytes();
		else:
			$result['domain'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['app'] = $reader->readObject();
		else:
			$result['app'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyKey
 */

final class InputPrivacyKeyChatInvite extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbdfb0426);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type bytes hash string text
 * @return SecureValueError
 */

final class SecureValueError extends Instance {
	public function request(object $type,string $hash,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x869d758f);
		$writer->writeObject($type);
		$writer->writeBytes($hash);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readObject();
		$result['hash'] = $reader->readBytes();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param mediaareacoordinates coordinates geopoint geo string title string address string provider string venue_id string venue_type
 * @return MediaArea
 */

final class MediaAreaVenue extends Instance {
	public function request(object $coordinates,object $geo,string $title,string $address,string $provider,string $venue_id,string $venue_type) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbe82db9c);
		$writer->writeObject($coordinates);
		$writer->writeObject($geo);
		$writer->writeBytes($title);
		$writer->writeBytes($address);
		$writer->writeBytes($provider);
		$writer->writeBytes($venue_id);
		$writer->writeBytes($venue_type);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['coordinates'] = $reader->readObject();
		$result['geo'] = $reader->readObject();
		$result['title'] = $reader->readBytes();
		$result['address'] = $reader->readBytes();
		$result['provider'] = $reader->readBytes();
		$result['venue_id'] = $reader->readBytes();
		$result['venue_type'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer Vector<bytes> options int date
 * @return MessagePeerVote
 */

final class MessagePeerVoteMultiple extends Instance {
	public function request(object $peer,array $options,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4628f6e6);
		$writer->writeObject($peer);
		$writer->writeVector($options,'bytes');
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['options'] = $reader->readVector('bytes');
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long audio_id pagecaption caption
 * @return PageBlock
 */

final class PageBlockAudio extends Instance {
	public function request(int $audio_id,object $caption) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x804361ea);
		$writer->writeLong($audio_id);
		$writer->writeObject($caption);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['audio_id'] = $reader->readLong();
		$result['caption'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputsavedstargift stargift
 * @return InputInvoice
 */

final class InputInvoiceStarGiftDropOriginalDetails extends Instance {
	public function request(object $stargift) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x923d8d1);
		$writer->writeObject($stargift);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['stargift'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypeAddress extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcbe31e26);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int msg_id
 * @return InputSavedStarGift
 */

final class InputSavedStarGiftUser extends Instance {
	public function request(int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x69279795);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string error
 * @return StatsGraph
 */

final class StatsGraphError extends Instance {
	public function request(string $error) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbedc9822);
		$writer->writeBytes($error);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['error'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string source
 * @return PageBlock
 */

final class PageBlockMath extends Instance {
	public function request(string $source) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x59080c20);
		$writer->writeBytes($source);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['source'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param textwithentities from textwithentities to
 * @return AiComposeToneExample
 */

final class AiComposeToneExample extends Instance {
	public function request(object $from,object $to) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf1d628ec);
		$writer->writeObject($from);
		$writer->writeObject($to);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['from'] = $reader->readObject();
		$result['to'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterPoll extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfa2bc90a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash long size int dc_id int date bytes file_hash bytes secret
 * @return SecureFile
 */

final class SecureFile extends Instance {
	public function request(int $id,int $access_hash,int $size,int $dc_id,int $date,string $file_hash,string $secret) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7d09c27e);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeLong($size);
		$writer->writeInt($dc_id);
		$writer->writeInt($date);
		$writer->writeBytes($file_hash);
		$writer->writeBytes($secret);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['size'] = $reader->readLong();
		$result['dc_id'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['file_hash'] = $reader->readBytes();
		$result['secret'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer_id int date
 * @return PeerBlocked
 */

final class PeerBlocked extends Instance {
	public function request(object $peer_id,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe8fd8014);
		$writer->writeObject($peer_id);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer_id'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return AttachMenuPeerType
 */

final class AttachMenuPeerTypeBroadcast extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7bfbdefc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockSubheader extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf12bb6e1);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReportReason
 */

final class InputReportReasonIllegalDrugs extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa8eb2be);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long req_msg_id int now Vector<future_salt> salts
 * @return FutureSalts
 */

final class FutureSalts extends Instance {
	public function request(int $req_msg_id,int $now,array $salts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xae500895);
		$writer->writeLong($req_msg_id);
		$writer->writeInt($now);
		$writer->writeVector($salts,'future_salt');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['req_msg_id'] = $reader->readLong();
		$result['now'] = $reader->readInt();
		$result['salts'] = $reader->readVector('future_salt');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long random_id int chat_id int date bytes bytes encryptedfile file
 * @return EncryptedMessage
 */

final class EncryptedMessage extends Instance {
	public function request(int $random_id,int $chat_id,int $date,string $bytes,object $file) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xed18c118);
		$writer->writeLong($random_id);
		$writer->writeInt($chat_id);
		$writer->writeInt($date);
		$writer->writeBytes($bytes);
		$writer->writeObject($file);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['random_id'] = $reader->readLong();
		$result['chat_id'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['bytes'] = $reader->readBytes();
		$result['file'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return RichText
 */

final class TextEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdc3d824f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long document_id string alt
 * @return RichText
 */

final class TextCustomEmoji extends Instance {
	public function request(int $document_id,string $alt) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa26156c0);
		$writer->writeLong($document_id);
		$writer->writeBytes($alt);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['document_id'] = $reader->readLong();
		$result['alt'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id emojistatus emoji_status
 * @return Update
 */

final class UpdateUserEmojiStatus extends Instance {
	public function request(int $user_id,object $emoji_status) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x28373599);
		$writer->writeLong($user_id);
		$writer->writeObject($emoji_status);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['emoji_status'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call int sub_chain_id Vector<bytes> blocks int next_offset
 * @return Update
 */

final class UpdateGroupCallChainBlocks extends Instance {
	public function request(object $call,int $sub_chain_id,array $blocks,int $next_offset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa477288f);
		$writer->writeObject($call);
		$writer->writeInt($sub_chain_id);
		$writer->writeVector($blocks,'bytes');
		$writer->writeInt($next_offset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['call'] = $reader->readObject();
		$result['sub_chain_id'] = $reader->readInt();
		$result['blocks'] = $reader->readVector('bytes');
		$result['next_offset'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars string currency long amount inputpeer spend_purpose_peer
 * @return InputStorePaymentPurpose
 */

final class InputStorePaymentStarsTopup extends Instance {
	public function request(int $stars,string $currency,int $amount,null | object $spend_purpose_peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf9a2a6cb);
		$flags = 0;
		$flags |= is_null($spend_purpose_peer) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($stars);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		if(is_null($spend_purpose_peer) === false):
			$writer->writeObject($spend_purpose_peer);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['stars'] = $reader->readLong();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['spend_purpose_peer'] = $reader->readObject();
		else:
			$result['spend_purpose_peer'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputNotifyPeer
 */

final class InputNotifyBroadcasts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb1db7c7e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars_amount
 * @return RequirementToContact
 */

final class RequirementToContactPaidMessages extends Instance {
	public function request(int $stars_amount) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb4f67e93);
		$writer->writeLong($stars_amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['stars_amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return TopPeerCategory
 */

final class TopPeerCategoryPhoneCalls extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1e76a78c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title long icon_emoji_id Vector<string> emoticons
 * @return EmojiGroup
 */

final class EmojiGroupGreeting extends Instance {
	public function request(string $title,int $icon_emoji_id,array $emoticons) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x80d26cc7);
		$writer->writeBytes($title);
		$writer->writeLong($icon_emoji_id);
		$writer->writeVector($emoticons,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readBytes();
		$result['icon_emoji_id'] = $reader->readLong();
		$result['emoticons'] = $reader->readVector('string');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true reply_to_scheduled true forum_topic true quote true reply_to_ephemeral int reply_to_msg_id peer reply_to_peer_id messagefwdheader reply_from messagemedia reply_media int reply_to_top_id string quote_text Vector<messageentity> quote_entities int quote_offset int todo_item_id bytes poll_option
 * @return MessageReplyHeader
 */

final class MessageReplyHeader extends Instance {
	public function request(null | bool $reply_to_scheduled = null,null | bool $forum_topic = null,null | bool $quote = null,null | bool $reply_to_ephemeral = null,null | int $reply_to_msg_id = null,null | object $reply_to_peer_id = null,null | object $reply_from = null,null | object $reply_media = null,null | int $reply_to_top_id = null,null | string $quote_text = null,null | array $quote_entities = null,null | int $quote_offset = null,null | int $todo_item_id = null,null | string $poll_option = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1b97dd66);
		$flags = 0;
		$flags |= $reply_to_scheduled ? (1 << 2) : 0;
		$flags |= $forum_topic ? (1 << 3) : 0;
		$flags |= $quote ? (1 << 9) : 0;
		$flags |= $reply_to_ephemeral ? (1 << 13) : 0;
		$flags |= is_null($reply_to_msg_id) ? 0 : (1 << 4);
		$flags |= is_null($reply_to_peer_id) ? 0 : (1 << 0);
		$flags |= is_null($reply_from) ? 0 : (1 << 5);
		$flags |= is_null($reply_media) ? 0 : (1 << 8);
		$flags |= is_null($reply_to_top_id) ? 0 : (1 << 1);
		$flags |= is_null($quote_text) ? 0 : (1 << 6);
		$flags |= is_null($quote_entities) ? 0 : (1 << 7);
		$flags |= is_null($quote_offset) ? 0 : (1 << 10);
		$flags |= is_null($todo_item_id) ? 0 : (1 << 11);
		$flags |= is_null($poll_option) ? 0 : (1 << 12);
		$writer->writeInt($flags);
		if(is_null($reply_to_msg_id) === false):
			$writer->writeInt($reply_to_msg_id);
		endif;
		if(is_null($reply_to_peer_id) === false):
			$writer->writeObject($reply_to_peer_id);
		endif;
		if(is_null($reply_from) === false):
			$writer->writeObject($reply_from);
		endif;
		if(is_null($reply_media) === false):
			$writer->writeObject($reply_media);
		endif;
		if(is_null($reply_to_top_id) === false):
			$writer->writeInt($reply_to_top_id);
		endif;
		if(is_null($quote_text) === false):
			$writer->writeBytes($quote_text);
		endif;
		if(is_null($quote_entities) === false):
			$writer->writeVector($quote_entities,'messageentity');
		endif;
		if(is_null($quote_offset) === false):
			$writer->writeInt($quote_offset);
		endif;
		if(is_null($todo_item_id) === false):
			$writer->writeInt($todo_item_id);
		endif;
		if(is_null($poll_option) === false):
			$writer->writeBytes($poll_option);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['reply_to_scheduled'] = boolval($flags & (1 << 2));
		$result['forum_topic'] = boolval($flags & (1 << 3));
		$result['quote'] = boolval($flags & (1 << 9));
		$result['reply_to_ephemeral'] = boolval($flags & (1 << 13));
		if($flags & (1 << 4)):
			$result['reply_to_msg_id'] = $reader->readInt();
		else:
			$result['reply_to_msg_id'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['reply_to_peer_id'] = $reader->readObject();
		else:
			$result['reply_to_peer_id'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['reply_from'] = $reader->readObject();
		else:
			$result['reply_from'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['reply_media'] = $reader->readObject();
		else:
			$result['reply_media'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['reply_to_top_id'] = $reader->readInt();
		else:
			$result['reply_to_top_id'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['quote_text'] = $reader->readBytes();
		else:
			$result['quote_text'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['quote_entities'] = $reader->readVector('messageentity');
		else:
			$result['quote_entities'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['quote_offset'] = $reader->readInt();
		else:
			$result['quote_offset'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['todo_item_id'] = $reader->readInt();
		else:
			$result['todo_item_id'] = null;
		endif;
		if($flags & (1 << 12)):
			$result['poll_option'] = $reader->readBytes();
		else:
			$result['poll_option'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockHeading1 extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbaff072f);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string label long amount
 * @return LabeledPrice
 */

final class LabeledPrice extends Instance {
	public function request(string $label,int $amount) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcb296bf8);
		$writer->writeBytes($label);
		$writer->writeLong($amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['label'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntitySpoiler extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x32ca960f);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityUnderline extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9c4e7e8b);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BaseTheme
 */

final class BaseThemeDay extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfbd81688);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickerset prev_stickerset inputstickerset new_stickerset
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeEmojiStickerSet extends Instance {
	public function request(object $prev_stickerset,object $new_stickerset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x46d840ab);
		$writer->writeObject($prev_stickerset);
		$writer->writeObject($new_stickerset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_stickerset'] = $reader->readObject();
		$result['new_stickerset'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantLeave extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf89777f2);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param user bot string domain true request_write_access true request_phone_number true match_codes_first true is_app string browser string platform string ip string region Vector<string> match_codes long user_id_hint string verified_app_name
 * @return UrlAuthResult
 */

final class UrlAuthResultRequest extends Instance {
	public function request(object $bot,string $domain,null | bool $request_write_access = null,null | bool $request_phone_number = null,null | bool $match_codes_first = null,null | bool $is_app = null,null | string $browser = null,null | string $platform = null,null | string $ip = null,null | string $region = null,null | array $match_codes = null,null | int $user_id_hint = null,null | string $verified_app_name = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3cd623ec);
		$flags = 0;
		$flags |= $request_write_access ? (1 << 0) : 0;
		$flags |= $request_phone_number ? (1 << 1) : 0;
		$flags |= $match_codes_first ? (1 << 5) : 0;
		$flags |= $is_app ? (1 << 6) : 0;
		$flags |= is_null($browser) ? 0 : (1 << 2);
		$flags |= is_null($platform) ? 0 : (1 << 2);
		$flags |= is_null($ip) ? 0 : (1 << 2);
		$flags |= is_null($region) ? 0 : (1 << 2);
		$flags |= is_null($match_codes) ? 0 : (1 << 3);
		$flags |= is_null($user_id_hint) ? 0 : (1 << 4);
		$flags |= is_null($verified_app_name) ? 0 : (1 << 7);
		$writer->writeInt($flags);
		$writer->writeObject($bot);
		$writer->writeBytes($domain);
		if(is_null($browser) === false):
			$writer->writeBytes($browser);
		endif;
		if(is_null($platform) === false):
			$writer->writeBytes($platform);
		endif;
		if(is_null($ip) === false):
			$writer->writeBytes($ip);
		endif;
		if(is_null($region) === false):
			$writer->writeBytes($region);
		endif;
		if(is_null($match_codes) === false):
			$writer->writeVector($match_codes,'string');
		endif;
		if(is_null($user_id_hint) === false):
			$writer->writeLong($user_id_hint);
		endif;
		if(is_null($verified_app_name) === false):
			$writer->writeBytes($verified_app_name);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['request_write_access'] = boolval($flags & (1 << 0));
		$result['request_phone_number'] = boolval($flags & (1 << 1));
		$result['match_codes_first'] = boolval($flags & (1 << 5));
		$result['is_app'] = boolval($flags & (1 << 6));
		$result['bot'] = $reader->readObject();
		$result['domain'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['browser'] = $reader->readBytes();
		else:
			$result['browser'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['platform'] = $reader->readBytes();
		else:
			$result['platform'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['ip'] = $reader->readBytes();
		else:
			$result['ip'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['region'] = $reader->readBytes();
		else:
			$result['region'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['match_codes'] = $reader->readVector('string');
		else:
			$result['match_codes'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['user_id_hint'] = $reader->readLong();
		else:
			$result['user_id_hint'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['verified_app_name'] = $reader->readBytes();
		else:
			$result['verified_app_name'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return InputGroupCall
 */

final class InputGroupCallSlug extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfe06823f);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['slug'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputfile file true spoiler true live_photo Vector<inputdocument> stickers int ttl_seconds inputdocument video
 * @return InputMedia
 */

final class InputMediaUploadedPhoto extends Instance {
	public function request(object $file,null | bool $spoiler = null,null | bool $live_photo = null,null | array $stickers = null,null | int $ttl_seconds = null,null | object $video = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7d8375da);
		$flags = 0;
		$flags |= $spoiler ? (1 << 2) : 0;
		$flags |= $live_photo ? (1 << 3) : 0;
		$flags |= is_null($stickers) ? 0 : (1 << 0);
		$flags |= is_null($ttl_seconds) ? 0 : (1 << 1);
		$flags |= is_null($video) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeObject($file);
		if(is_null($stickers) === false):
			$writer->writeVector($stickers,'inputdocument');
		endif;
		if(is_null($ttl_seconds) === false):
			$writer->writeInt($ttl_seconds);
		endif;
		if(is_null($video) === false):
			$writer->writeObject($video);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['spoiler'] = boolval($flags & (1 << 2));
		$result['live_photo'] = boolval($flags & (1 << 3));
		$result['file'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['stickers'] = $reader->readVector('inputdocument');
		else:
			$result['stickers'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['ttl_seconds'] = $reader->readInt();
		else:
			$result['ttl_seconds'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['video'] = $reader->readObject();
		else:
			$result['video'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputStickerSet
 */

final class InputStickerSetEmojiChannelDefaultStatuses extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x49748553);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int duration true voice string title string performer bytes waveform
 * @return DocumentAttribute
 */

final class DocumentAttributeAudio extends Instance {
	public function request(int $duration,null | bool $voice = null,null | string $title = null,null | string $performer = null,null | string $waveform = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9852f9c6);
		$flags = 0;
		$flags |= $voice ? (1 << 10) : 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$flags |= is_null($performer) ? 0 : (1 << 1);
		$flags |= is_null($waveform) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeInt($duration);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($performer) === false):
			$writer->writeBytes($performer);
		endif;
		if(is_null($waveform) === false):
			$writer->writeBytes($waveform);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['voice'] = boolval($flags & (1 << 10));
		$result['duration'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['performer'] = $reader->readBytes();
		else:
			$result['performer'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['waveform'] = $reader->readBytes();
		else:
			$result['waveform'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call groupcallmessage message
 * @return Update
 */

final class UpdateGroupCallMessage extends Instance {
	public function request(object $call,object $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd8326f0d);
		$writer->writeObject($call);
		$writer->writeObject($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['call'] = $reader->readObject();
		$result['message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string type botinlinemessage send_message photo photo document document string title string description
 * @return BotInlineResult
 */

final class BotInlineMediaResult extends Instance {
	public function request(string $id,string $type,object $send_message,null | object $photo = null,null | object $document = null,null | string $title = null,null | string $description = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x17db940b);
		$flags = 0;
		$flags |= is_null($photo) ? 0 : (1 << 0);
		$flags |= is_null($document) ? 0 : (1 << 1);
		$flags |= is_null($title) ? 0 : (1 << 2);
		$flags |= is_null($description) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeBytes($id);
		$writer->writeBytes($type);
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		if(is_null($document) === false):
			$writer->writeObject($document);
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($description) === false):
			$writer->writeBytes($description);
		endif;
		$writer->writeObject($send_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readBytes();
		$result['type'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['document'] = $reader->readObject();
		else:
			$result['document'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['description'] = $reader->readBytes();
		else:
			$result['description'] = null;
		endif;
		$result['send_message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> channels int quantity int until_date true only_new_subscribers true winners_are_visible Vector<string> countries_iso2 string prize_description int months long stars
 * @return MessageMedia
 */

final class MessageMediaGiveaway extends Instance {
	public function request(array $channels,int $quantity,int $until_date,null | bool $only_new_subscribers = null,null | bool $winners_are_visible = null,null | array $countries_iso2 = null,null | string $prize_description = null,null | int $months = null,null | int $stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaa073beb);
		$flags = 0;
		$flags |= $only_new_subscribers ? (1 << 0) : 0;
		$flags |= $winners_are_visible ? (1 << 2) : 0;
		$flags |= is_null($countries_iso2) ? 0 : (1 << 1);
		$flags |= is_null($prize_description) ? 0 : (1 << 3);
		$flags |= is_null($months) ? 0 : (1 << 4);
		$flags |= is_null($stars) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeVector($channels,'long');
		if(is_null($countries_iso2) === false):
			$writer->writeVector($countries_iso2,'string');
		endif;
		if(is_null($prize_description) === false):
			$writer->writeBytes($prize_description);
		endif;
		$writer->writeInt($quantity);
		if(is_null($months) === false):
			$writer->writeInt($months);
		endif;
		if(is_null($stars) === false):
			$writer->writeLong($stars);
		endif;
		$writer->writeInt($until_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['only_new_subscribers'] = boolval($flags & (1 << 0));
		$result['winners_are_visible'] = boolval($flags & (1 << 2));
		$result['channels'] = $reader->readVector('long');
		if($flags & (1 << 1)):
			$result['countries_iso2'] = $reader->readVector('string');
		else:
			$result['countries_iso2'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['prize_description'] = $reader->readBytes();
		else:
			$result['prize_description'] = null;
		endif;
		$result['quantity'] = $reader->readInt();
		if($flags & (1 << 4)):
			$result['months'] = $reader->readInt();
		else:
			$result['months'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['stars'] = $reader->readLong();
		else:
			$result['stars'] = null;
		endif;
		$result['until_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int active_until_date int cooldown_until_date
 * @return StoriesStealthMode
 */

final class StoriesStealthMode extends Instance {
	public function request(null | int $active_until_date = null,null | int $cooldown_until_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x712e27fd);
		$flags = 0;
		$flags |= is_null($active_until_date) ? 0 : (1 << 0);
		$flags |= is_null($cooldown_until_date) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($active_until_date) === false):
			$writer->writeInt($active_until_date);
		endif;
		if(is_null($cooldown_until_date) === false):
			$writer->writeInt($cooldown_until_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['active_until_date'] = $reader->readInt();
		else:
			$result['active_until_date'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['cooldown_until_date'] = $reader->readInt();
		else:
			$result['cooldown_until_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarsTransactionPeer
 */

final class StarsTransactionPeerFragment extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe92fd902);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id long access_hash
 * @return InputUser
 */

final class InputUser extends Instance {
	public function request(int $user_id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf21158c6);
		$writer->writeLong($user_id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id long client_id
 * @return ImportedContact
 */

final class ImportedContact extends Instance {
	public function request(int $user_id,int $client_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc13e3c50);
		$writer->writeLong($user_id);
		$writer->writeLong($client_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['client_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson json string zoom_token
 * @return StatsGraph
 */

final class StatsGraph extends Instance {
	public function request(object $json,null | string $zoom_token = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ea464b6);
		$flags = 0;
		$flags |= is_null($zoom_token) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($json);
		if(is_null($zoom_token) === false):
			$writer->writeBytes($zoom_token);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['json'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['zoom_token'] = $reader->readBytes();
		else:
			$result['zoom_token'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Null
 */

final class NullObject extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x56730bcc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone
 * @return SecurePlainData
 */

final class SecurePlainPhone extends Instance {
	public function request(string $phone) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7d6099dd);
		$writer->writeBytes($phone);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['phone'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return JSONValue
 */

final class JsonNull extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3f6d7b68);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long icon string company true can_modify_custom_description string custom_description
 * @return BotVerifierSettings
 */

final class BotVerifierSettings extends Instance {
	public function request(int $icon,string $company,null | bool $can_modify_custom_description = null,null | string $custom_description = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb0cd6617);
		$flags = 0;
		$flags |= $can_modify_custom_description ? (1 << 1) : 0;
		$flags |= is_null($custom_description) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($icon);
		$writer->writeBytes($company);
		if(is_null($custom_description) === false):
			$writer->writeBytes($custom_description);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['can_modify_custom_description'] = boolval($flags & (1 << 1));
		$result['icon'] = $reader->readLong();
		$result['company'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['custom_description'] = $reader->readBytes();
		else:
			$result['custom_description'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<string> prev_value Vector<string> new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeUsernames extends Instance {
	public function request(array $prev_value,array $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf04fb3a9);
		$writer->writeVector($prev_value,'string');
		$writer->writeVector($new_value,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readVector('string');
		$result['new_value'] = $reader->readVector('string');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url string name
 * @return BankCardOpenUrl
 */

final class BankCardOpenUrl extends Instance {
	public function request(string $url,string $name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf568028a);
		$writer->writeBytes($url);
		$writer->writeBytes($name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long new_creator_id
 * @return MessageAction
 */

final class MessageActionChangeCreator extends Instance {
	public function request(int $new_creator_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe188503b);
		$writer->writeLong($new_creator_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_creator_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int date
 * @return DraftMessage
 */

final class DraftMessageEmpty extends Instance {
	public function request(null | int $date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1b0c841a);
		$flags = 0;
		$flags |= is_null($date) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($date) === false):
			$writer->writeInt($date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['date'] = $reader->readInt();
		else:
			$result['date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReportReason
 */

final class InputReportReasonGeoIrrelevant extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdbd4feed);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id peer from_id int date textwithentities message true from_admin long paid_message_stars
 * @return GroupCallMessage
 */

final class GroupCallMessage extends Instance {
	public function request(int $id,object $from_id,int $date,object $message,null | bool $from_admin = null,null | int $paid_message_stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1a8afc7e);
		$flags = 0;
		$flags |= $from_admin ? (1 << 1) : 0;
		$flags |= is_null($paid_message_stars) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeObject($from_id);
		$writer->writeInt($date);
		$writer->writeObject($message);
		if(is_null($paid_message_stars) === false):
			$writer->writeLong($paid_message_stars);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['from_admin'] = boolval($flags & (1 << 1));
		$result['id'] = $reader->readInt();
		$result['from_id'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		$result['message'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['paid_message_stars'] = $reader->readLong();
		else:
			$result['paid_message_stars'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return DialogFilter
 */

final class DialogFilterDefault extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x363293ae);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterGeo extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe7026d0d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextSpoiler extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4c2a5d62);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q
 * @return ChannelParticipantsFilter
 */

final class ChannelParticipantsSearch extends Instance {
	public function request(string $q) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x656ac4b);
		$writer->writeBytes($q);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['q'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id int deleted int kicked int banned
 * @return StatsGroupTopAdmin
 */

final class StatsGroupTopAdmin extends Instance {
	public function request(int $user_id,int $deleted,int $kicked,int $banned) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd7584c87);
		$writer->writeLong($user_id);
		$writer->writeInt($deleted);
		$writer->writeInt($kicked);
		$writer->writeInt($banned);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['deleted'] = $reader->readInt();
		$result['kicked'] = $reader->readInt();
		$result['banned'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id int date long user_id channeladminlogeventaction action
 * @return ChannelAdminLogEvent
 */

final class ChannelAdminLogEvent extends Instance {
	public function request(int $id,int $date,int $user_id,object $action) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1fad68cd);
		$writer->writeLong($id);
		$writer->writeInt($date);
		$writer->writeLong($user_id);
		$writer->writeObject($action);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		$result['action'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class BoolFalse extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbc799737);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type bytes file_hash string text
 * @return SecureValueError
 */

final class SecureValueErrorTranslationFile extends Instance {
	public function request(object $type,string $file_hash,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa1144770);
		$writer->writeObject($type);
		$writer->writeBytes($file_hash);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readObject();
		$result['file_hash'] = $reader->readBytes();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessagesFilter
 */

final class InputMessagesFilterPhotos extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9609a51c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> users
 * @return MessageAction
 */

final class MessageActionChatAddUser extends Instance {
	public function request(array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x15cefd00);
		$writer->writeVector($users,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['users'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string title Vector<labeledprice> prices
 * @return ShippingOption
 */

final class ShippingOption extends Instance {
	public function request(string $id,string $title,array $prices) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb6213cdf);
		$writer->writeBytes($id);
		$writer->writeBytes($title);
		$writer->writeVector($prices,'labeledprice');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readBytes();
		$result['title'] = $reader->readBytes();
		$result['prices'] = $reader->readVector('labeledprice');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int start_date int end_date long average_price int listed_count int fragment_listed_count string fragment_listed_url
 * @return StarGiftAuctionState
 */

final class StarGiftAuctionStateFinished extends Instance {
	public function request(int $start_date,int $end_date,int $average_price,null | int $listed_count = null,null | int $fragment_listed_count = null,null | string $fragment_listed_url = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x972dabbf);
		$flags = 0;
		$flags |= is_null($listed_count) ? 0 : (1 << 0);
		$flags |= is_null($fragment_listed_count) ? 0 : (1 << 1);
		$flags |= is_null($fragment_listed_url) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeInt($start_date);
		$writer->writeInt($end_date);
		$writer->writeLong($average_price);
		if(is_null($listed_count) === false):
			$writer->writeInt($listed_count);
		endif;
		if(is_null($fragment_listed_count) === false):
			$writer->writeInt($fragment_listed_count);
		endif;
		if(is_null($fragment_listed_url) === false):
			$writer->writeBytes($fragment_listed_url);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['start_date'] = $reader->readInt();
		$result['end_date'] = $reader->readInt();
		$result['average_price'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['listed_count'] = $reader->readInt();
		else:
			$result['listed_count'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['fragment_listed_count'] = $reader->readInt();
		else:
			$result['fragment_listed_count'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['fragment_listed_url'] = $reader->readBytes();
		else:
			$result['fragment_listed_url'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string emoticon
 * @return InputChatTheme
 */

final class InputChatTheme extends Instance {
	public function request(string $emoticon) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc93de95c);
		$writer->writeBytes($emoticon);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['emoticon'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockHeader extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbfd064ec);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return JoinChatBotResult
 */

final class JoinChatBotResultQueued extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x98a3a840);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstorepaymentpurpose purpose
 * @return InputInvoice
 */

final class InputInvoicePremiumAuthCode extends Instance {
	public function request(object $purpose) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e77f614);
		$writer->writeObject($purpose);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['purpose'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param double value
 * @return JSONValue
 */

final class JsonNumber extends Instance {
	public function request(float $value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2be0dfa4);
		$writer->writeDouble($value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['value'] = $reader->readDouble();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return RequirementToContact
 */

final class RequirementToContactEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x50a9839);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id string ip string ipv6 int port bytes peer_tag true tcp
 * @return PhoneConnection
 */

final class PhoneConnection extends Instance {
	public function request(int $id,string $ip,string $ipv6,int $port,string $peer_tag,null | bool $tcp = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9cc123c7);
		$flags = 0;
		$flags |= $tcp ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeBytes($ip);
		$writer->writeBytes($ipv6);
		$writer->writeInt($port);
		$writer->writeBytes($peer_tag);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['tcp'] = boolval($flags & (1 << 0));
		$result['id'] = $reader->readLong();
		$result['ip'] = $reader->readBytes();
		$result['ipv6'] = $reader->readBytes();
		$result['port'] = $reader->readInt();
		$result['peer_tag'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string endpoint Vector<groupcallparticipantvideosourcegroup> source_groups true paused int audio_source
 * @return GroupCallParticipantVideo
 */

final class GroupCallParticipantVideo extends Instance {
	public function request(string $endpoint,array $source_groups,null | bool $paused = null,null | int $audio_source = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x67753ac8);
		$flags = 0;
		$flags |= $paused ? (1 << 0) : 0;
		$flags |= is_null($audio_source) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($endpoint);
		$writer->writeVector($source_groups,'groupcallparticipantvideosourcegroup');
		if(is_null($audio_source) === false):
			$writer->writeInt($audio_source);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['paused'] = boolval($flags & (1 << 0));
		$result['endpoint'] = $reader->readBytes();
		$result['source_groups'] = $reader->readVector('groupcallparticipantvideosourcegroup');
		if($flags & (1 << 1)):
			$result['audio_source'] = $reader->readInt();
		else:
			$result['audio_source'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long nonce long temp_auth_key_id long perm_auth_key_id long temp_session_id int expires_at
 * @return BindAuthKeyInner
 */

final class BindAuthKeyInner extends Instance {
	public function request(int $nonce,int $temp_auth_key_id,int $perm_auth_key_id,int $temp_session_id,int $expires_at) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x75a3f765);
		$writer->writeLong($nonce);
		$writer->writeLong($temp_auth_key_id);
		$writer->writeLong($perm_auth_key_id);
		$writer->writeLong($temp_session_id);
		$writer->writeInt($expires_at);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['nonce'] = $reader->readLong();
		$result['temp_auth_key_id'] = $reader->readLong();
		$result['perm_auth_key_id'] = $reader->readLong();
		$result['temp_session_id'] = $reader->readLong();
		$result['expires_at'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string platform string reason string text
 * @return RestrictionReason
 */

final class RestrictionReason extends Instance {
	public function request(string $platform,string $reason,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd072acb4);
		$writer->writeBytes($platform);
		$writer->writeBytes($reason);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['platform'] = $reader->readBytes();
		$result['reason'] = $reader->readBytes();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int chat_id int max_date int date
 * @return Update
 */

final class UpdateEncryptedMessagesRead extends Instance {
	public function request(int $chat_id,int $max_date,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x38fe25b7);
		$writer->writeInt($chat_id);
		$writer->writeInt($max_date);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readInt();
		$result['max_date'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BotCommandScope
 */

final class BotCommandScopeChatAdmins extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb9aa606a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int dc_id string public_key
 * @return CdnPublicKey
 */

final class CdnPublicKey extends Instance {
	public function request(int $dc_id,string $public_key) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc982eaba);
		$writer->writeInt($dc_id);
		$writer->writeBytes($public_key);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['dc_id'] = $reader->readInt();
		$result['public_key'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id long user_id string connection_id message message long chat_instance message reply_to_message bytes data
 * @return Update
 */

final class UpdateBusinessBotCallbackQuery extends Instance {
	public function request(int $query_id,int $user_id,string $connection_id,object $message,int $chat_instance,null | object $reply_to_message = null,null | string $data = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1ea2fda7);
		$flags = 0;
		$flags |= is_null($reply_to_message) ? 0 : (1 << 2);
		$flags |= is_null($data) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($query_id);
		$writer->writeLong($user_id);
		$writer->writeBytes($connection_id);
		$writer->writeObject($message);
		if(is_null($reply_to_message) === false):
			$writer->writeObject($reply_to_message);
		endif;
		$writer->writeLong($chat_instance);
		if(is_null($data) === false):
			$writer->writeBytes($data);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['query_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		$result['connection_id'] = $reader->readBytes();
		$result['message'] = $reader->readObject();
		if($flags & (1 << 2)):
			$result['reply_to_message'] = $reader->readObject();
		else:
			$result['reply_to_message'] = null;
		endif;
		$result['chat_instance'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['data'] = $reader->readBytes();
		else:
			$result['data'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id
 * @return InputQuickReplyShortcut
 */

final class InputQuickReplyShortcutId extends Instance {
	public function request(int $shortcut_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1190cf1);
		$writer->writeInt($shortcut_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['shortcut_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return PageBlock
 */

final class PageBlockHeading6 extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x682a41a9);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return RpcDropAnswer
 */

final class RpcAnswerDroppedRunning extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcd78e586);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long admin_id int invites_count int revoked_invites_count
 * @return ChatAdminWithInvites
 */

final class ChatAdminWithInvites extends Instance {
	public function request(int $admin_id,int $invites_count,int $revoked_invites_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf2ecef23);
		$writer->writeLong($admin_id);
		$writer->writeInt($invites_count);
		$writer->writeInt($revoked_invites_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['admin_id'] = $reader->readLong();
		$result['invites_count'] = $reader->readInt();
		$result['revoked_invites_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash string title true broadcast true megagroup true monoforum int until_date
 * @return Chat
 */

final class ChannelForbidden extends Instance {
	public function request(int $id,int $access_hash,string $title,null | bool $broadcast = null,null | bool $megagroup = null,null | bool $monoforum = null,null | int $until_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x17d493d5);
		$flags = 0;
		$flags |= $broadcast ? (1 << 5) : 0;
		$flags |= $megagroup ? (1 << 8) : 0;
		$flags |= $monoforum ? (1 << 10) : 0;
		$flags |= is_null($until_date) ? 0 : (1 << 16);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($title);
		if(is_null($until_date) === false):
			$writer->writeInt($until_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['broadcast'] = boolval($flags & (1 << 5));
		$result['megagroup'] = boolval($flags & (1 << 8));
		$result['monoforum'] = boolval($flags & (1 << 10));
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['title'] = $reader->readBytes();
		if($flags & (1 << 16)):
			$result['until_date'] = $reader->readInt();
		else:
			$result['until_date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text string url keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButtonSimpleWebView extends Instance {
	public function request(string $text,string $url,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe15c4370);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id message message int qts Vector<message> reference_messages
 * @return Update
 */

final class UpdateBotGuestChatQuery extends Instance {
	public function request(int $query_id,object $message,int $qts,null | array $reference_messages = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcdd4093d);
		$flags = 0;
		$flags |= is_null($reference_messages) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($query_id);
		$writer->writeObject($message);
		if(is_null($reference_messages) === false):
			$writer->writeVector($reference_messages,'message');
		endif;
		$writer->writeInt($qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['query_id'] = $reader->readLong();
		$result['message'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['reference_messages'] = $reader->readVector('message');
		else:
			$result['reference_messages'] = null;
		endif;
		$result['qts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param basetheme base_theme int accent_color true message_colors_animated int outbox_accent_color Vector<int> message_colors wallpaper wallpaper
 * @return ThemeSettings
 */

final class ThemeSettings extends Instance {
	public function request(object $base_theme,int $accent_color,null | bool $message_colors_animated = null,null | int $outbox_accent_color = null,null | array $message_colors = null,null | object $wallpaper = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfa58b6d4);
		$flags = 0;
		$flags |= $message_colors_animated ? (1 << 2) : 0;
		$flags |= is_null($outbox_accent_color) ? 0 : (1 << 3);
		$flags |= is_null($message_colors) ? 0 : (1 << 0);
		$flags |= is_null($wallpaper) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($base_theme);
		$writer->writeInt($accent_color);
		if(is_null($outbox_accent_color) === false):
			$writer->writeInt($outbox_accent_color);
		endif;
		if(is_null($message_colors) === false):
			$writer->writeVector($message_colors,'int');
		endif;
		if(is_null($wallpaper) === false):
			$writer->writeObject($wallpaper);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['message_colors_animated'] = boolval($flags & (1 << 2));
		$result['base_theme'] = $reader->readObject();
		$result['accent_color'] = $reader->readInt();
		if($flags & (1 << 3)):
			$result['outbox_accent_color'] = $reader->readInt();
		else:
			$result['outbox_accent_color'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['message_colors'] = $reader->readVector('int');
		else:
			$result['message_colors'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['wallpaper'] = $reader->readObject();
		else:
			$result['wallpaper'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id peer saved_peer_id true exception
 * @return Update
 */

final class UpdateMonoForumNoPaidException extends Instance {
	public function request(int $channel_id,object $saved_peer_id,null | bool $exception = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9f812b08);
		$flags = 0;
		$flags |= $exception ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($channel_id);
		$writer->writeObject($saved_peer_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['exception'] = boolval($flags & (1 << 0));
		$result['channel_id'] = $reader->readLong();
		$result['saved_peer_id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string alt inputstickerset stickerset true mask maskcoords mask_coords
 * @return DocumentAttribute
 */

final class DocumentAttributeSticker extends Instance {
	public function request(string $alt,object $stickerset,null | bool $mask = null,null | object $mask_coords = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6319d612);
		$flags = 0;
		$flags |= $mask ? (1 << 1) : 0;
		$flags |= is_null($mask_coords) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($alt);
		$writer->writeObject($stickerset);
		if(is_null($mask_coords) === false):
			$writer->writeObject($mask_coords);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['mask'] = boolval($flags & (1 << 1));
		$result['alt'] = $reader->readBytes();
		$result['stickerset'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['mask_coords'] = $reader->readObject();
		else:
			$result['mask_coords'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param encryptedchat chat int date
 * @return Update
 */

final class UpdateEncryption extends Instance {
	public function request(object $chat,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb4a2e88d);
		$writer->writeObject($chat);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarsTransactionPeer
 */

final class StarsTransactionPeerPlayMarket extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7b560a0b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int story_id int views int forwards int reactions
 * @return PostInteractionCounters
 */

final class PostInteractionCountersStory extends Instance {
	public function request(int $story_id,int $views,int $forwards,int $reactions) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8a480e27);
		$writer->writeInt($story_id);
		$writer->writeInt($views);
		$writer->writeInt($forwards);
		$writer->writeInt($reactions);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['story_id'] = $reader->readInt();
		$result['views'] = $reader->readInt();
		$result['forwards'] = $reader->readInt();
		$result['reactions'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer Vector<int> messages Vector<int> sent_messages
 * @return Update
 */

final class UpdateDeleteScheduledMessages extends Instance {
	public function request(object $peer,array $messages,null | array $sent_messages = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf2a71983);
		$flags = 0;
		$flags |= is_null($sent_messages) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeVector($messages,'int');
		if(is_null($sent_messages) === false):
			$writer->writeVector($sent_messages,'int');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['peer'] = $reader->readObject();
		$result['messages'] = $reader->readVector('int');
		if($flags & (1 << 0)):
			$result['sent_messages'] = $reader->readVector('int');
		else:
			$result['sent_messages'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id int max_id int still_unread_count int pts int folder_id
 * @return Update
 */

final class UpdateReadChannelInbox extends Instance {
	public function request(int $channel_id,int $max_id,int $still_unread_count,int $pts,null | int $folder_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x922e6e10);
		$flags = 0;
		$flags |= is_null($folder_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($folder_id) === false):
			$writer->writeInt($folder_id);
		endif;
		$writer->writeLong($channel_id);
		$writer->writeInt($max_id);
		$writer->writeInt($still_unread_count);
		$writer->writeInt($pts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['folder_id'] = $reader->readInt();
		else:
			$result['folder_id'] = null;
		endif;
		$result['channel_id'] = $reader->readLong();
		$result['max_id'] = $reader->readInt();
		$result['still_unread_count'] = $reader->readInt();
		$result['pts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call true rtmp_stream
 * @return MessageMedia
 */

final class MessageMediaVideoStream extends Instance {
	public function request(object $call,null | bool $rtmp_stream = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xca5cab89);
		$flags = 0;
		$flags |= $rtmp_stream ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($call);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['rtmp_stream'] = boolval($flags & (1 << 0));
		$result['call'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param notificationsound sound bool show_previews reactionnotificationsfrom messages_notify_from reactionnotificationsfrom stories_notify_from reactionnotificationsfrom poll_votes_notify_from
 * @return ReactionsNotifySettings
 */

final class ReactionsNotifySettings extends Instance {
	public function request(object $sound,bool $show_previews,null | object $messages_notify_from = null,null | object $stories_notify_from = null,null | object $poll_votes_notify_from = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x71e4ea58);
		$flags = 0;
		$flags |= is_null($messages_notify_from) ? 0 : (1 << 0);
		$flags |= is_null($stories_notify_from) ? 0 : (1 << 1);
		$flags |= is_null($poll_votes_notify_from) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($messages_notify_from) === false):
			$writer->writeObject($messages_notify_from);
		endif;
		if(is_null($stories_notify_from) === false):
			$writer->writeObject($stories_notify_from);
		endif;
		if(is_null($poll_votes_notify_from) === false):
			$writer->writeObject($poll_votes_notify_from);
		endif;
		$writer->writeObject($sound);
		$writer->writeBool($show_previews);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['messages_notify_from'] = $reader->readObject();
		else:
			$result['messages_notify_from'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['stories_notify_from'] = $reader->readObject();
		else:
			$result['stories_notify_from'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['poll_votes_notify_from'] = $reader->readObject();
		else:
			$result['poll_votes_notify_from'] = null;
		endif;
		$result['sound'] = $reader->readObject();
		$result['show_previews'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputStickerSet
 */

final class InputStickerSetEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xffb62b95);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string link string message int views Vector<messageentity> entities string title
 * @return BusinessChatLink
 */

final class BusinessChatLink extends Instance {
	public function request(string $link,string $message,int $views,null | array $entities = null,null | string $title = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb4ae666f);
		$flags = 0;
		$flags |= is_null($entities) ? 0 : (1 << 0);
		$flags |= is_null($title) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($link);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		$writer->writeInt($views);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['link'] = $reader->readBytes();
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		$result['views'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int story_id reaction reaction
 * @return Update
 */

final class UpdateSentStoryReaction extends Instance {
	public function request(object $peer,int $story_id,object $reaction) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7d627683);
		$writer->writeObject($peer);
		$writer->writeInt($story_id);
		$writer->writeObject($reaction);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['story_id'] = $reader->readInt();
		$result['reaction'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return InputAiComposeTone
 */

final class InputAiComposeToneSlug extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1fa01357);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['slug'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputsavedstargift stargift inputpeer to_id
 * @return InputInvoice
 */

final class InputInvoiceStarGiftTransfer extends Instance {
	public function request(object $stargift,object $to_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4a5f5bd9);
		$writer->writeObject($stargift);
		$writer->writeObject($to_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['stargift'] = $reader->readObject();
		$result['to_id'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message true no_webpage true invert_media Vector<messageentity> entities replymarkup reply_markup
 * @return InputBotInlineMessage
 */

final class InputBotInlineMessageText extends Instance {
	public function request(string $message,null | bool $no_webpage = null,null | bool $invert_media = null,null | array $entities = null,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3dcd7a87);
		$flags = 0;
		$flags |= $no_webpage ? (1 << 0) : 0;
		$flags |= $invert_media ? (1 << 3) : 0;
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['no_webpage'] = boolval($flags & (1 << 0));
		$result['invert_media'] = boolval($flags & (1 << 3));
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson data true save
 * @return InputPaymentCredentials
 */

final class InputPaymentCredentials extends Instance {
	public function request(object $data,null | bool $save = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3417d728);
		$flags = 0;
		$flags |= $save ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['save'] = boolval($flags & (1 << 0));
		$result['data'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return NotifyPeer
 */

final class NotifyBroadcasts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd612e8ef);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer draftmessage draft int top_msg_id peer saved_peer_id
 * @return Update
 */

final class UpdateDraftMessage extends Instance {
	public function request(object $peer,object $draft,null | int $top_msg_id = null,null | object $saved_peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xedfc111e);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		$writer->writeObject($draft);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['peer'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['top_msg_id'] = $reader->readInt();
		else:
			$result['top_msg_id'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['saved_peer_id'] = $reader->readObject();
		else:
			$result['saved_peer_id'] = null;
		endif;
		$result['draft'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title string description invoice invoice bytes payload datajson provider_data inputwebdocument photo string provider string start_param inputmedia extended_media
 * @return InputMedia
 */

final class InputMediaInvoice extends Instance {
	public function request(string $title,string $description,object $invoice,string $payload,object $provider_data,null | object $photo = null,null | string $provider = null,null | string $start_param = null,null | object $extended_media = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x405fef0d);
		$flags = 0;
		$flags |= is_null($photo) ? 0 : (1 << 0);
		$flags |= is_null($provider) ? 0 : (1 << 3);
		$flags |= is_null($start_param) ? 0 : (1 << 1);
		$flags |= is_null($extended_media) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($title);
		$writer->writeBytes($description);
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		$writer->writeObject($invoice);
		$writer->writeBytes($payload);
		if(is_null($provider) === false):
			$writer->writeBytes($provider);
		endif;
		$writer->writeObject($provider_data);
		if(is_null($start_param) === false):
			$writer->writeBytes($start_param);
		endif;
		if(is_null($extended_media) === false):
			$writer->writeObject($extended_media);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['title'] = $reader->readBytes();
		$result['description'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		$result['invoice'] = $reader->readObject();
		$result['payload'] = $reader->readBytes();
		if($flags & (1 << 3)):
			$result['provider'] = $reader->readBytes();
		else:
			$result['provider'] = null;
		endif;
		$result['provider_data'] = $reader->readObject();
		if($flags & (1 << 1)):
			$result['start_param'] = $reader->readBytes();
		else:
			$result['start_param'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['extended_media'] = $reader->readObject();
		else:
			$result['extended_media'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text bytes data true requires_password keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButtonCallback extends Instance {
	public function request(string $text,string $data,null | bool $requires_password = null,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe62bc960);
		$flags = 0;
		$flags |= $requires_password ? (1 << 0) : 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		$writer->writeBytes($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['requires_password'] = boolval($flags & (1 << 0));
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		$result['data'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pos long amount int date
 * @return AuctionBidLevel
 */

final class AuctionBidLevel extends Instance {
	public function request(int $pos,int $amount,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x310240cc);
		$writer->writeInt($pos);
		$writer->writeLong($amount);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['pos'] = $reader->readInt();
		$result['amount'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true nopremium true spoiler true video true round true voice document document Vector<document> alt_documents photo video_cover int video_timestamp int ttl_seconds
 * @return MessageMedia
 */

final class MessageMediaDocument extends Instance {
	public function request(null | bool $nopremium = null,null | bool $spoiler = null,null | bool $video = null,null | bool $round = null,null | bool $voice = null,null | object $document = null,null | array $alt_documents = null,null | object $video_cover = null,null | int $video_timestamp = null,null | int $ttl_seconds = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x52d8ccd9);
		$flags = 0;
		$flags |= $nopremium ? (1 << 3) : 0;
		$flags |= $spoiler ? (1 << 4) : 0;
		$flags |= $video ? (1 << 6) : 0;
		$flags |= $round ? (1 << 7) : 0;
		$flags |= $voice ? (1 << 8) : 0;
		$flags |= is_null($document) ? 0 : (1 << 0);
		$flags |= is_null($alt_documents) ? 0 : (1 << 5);
		$flags |= is_null($video_cover) ? 0 : (1 << 9);
		$flags |= is_null($video_timestamp) ? 0 : (1 << 10);
		$flags |= is_null($ttl_seconds) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($document) === false):
			$writer->writeObject($document);
		endif;
		if(is_null($alt_documents) === false):
			$writer->writeVector($alt_documents,'document');
		endif;
		if(is_null($video_cover) === false):
			$writer->writeObject($video_cover);
		endif;
		if(is_null($video_timestamp) === false):
			$writer->writeInt($video_timestamp);
		endif;
		if(is_null($ttl_seconds) === false):
			$writer->writeInt($ttl_seconds);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['nopremium'] = boolval($flags & (1 << 3));
		$result['spoiler'] = boolval($flags & (1 << 4));
		$result['video'] = boolval($flags & (1 << 6));
		$result['round'] = boolval($flags & (1 << 7));
		$result['voice'] = boolval($flags & (1 << 8));
		if($flags & (1 << 0)):
			$result['document'] = $reader->readObject();
		else:
			$result['document'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['alt_documents'] = $reader->readVector('document');
		else:
			$result['alt_documents'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['video_cover'] = $reader->readObject();
		else:
			$result['video_cover'] = null;
		endif;
		if($flags & (1 << 10)):
			$result['video_timestamp'] = $reader->readInt();
		else:
			$result['video_timestamp'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['ttl_seconds'] = $reader->readInt();
		else:
			$result['ttl_seconds'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url int date long bot_id int commission_permille long participants long revenue true revoked int duration_months
 * @return ConnectedBotStarRef
 */

final class ConnectedBotStarRef extends Instance {
	public function request(string $url,int $date,int $bot_id,int $commission_permille,int $participants,int $revenue,null | bool $revoked = null,null | int $duration_months = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x19a13f71);
		$flags = 0;
		$flags |= $revoked ? (1 << 1) : 0;
		$flags |= is_null($duration_months) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($url);
		$writer->writeInt($date);
		$writer->writeLong($bot_id);
		$writer->writeInt($commission_permille);
		if(is_null($duration_months) === false):
			$writer->writeInt($duration_months);
		endif;
		$writer->writeLong($participants);
		$writer->writeLong($revenue);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['revoked'] = boolval($flags & (1 << 1));
		$result['url'] = $reader->readBytes();
		$result['date'] = $reader->readInt();
		$result['bot_id'] = $reader->readLong();
		$result['commission_permille'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['duration_months'] = $reader->readInt();
		else:
			$result['duration_months'] = null;
		endif;
		$result['participants'] = $reader->readLong();
		$result['revenue'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id long random_id
 * @return Update
 */

final class UpdateStoryID extends Instance {
	public function request(int $id,int $random_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1bf335b9);
		$writer->writeInt($id);
		$writer->writeLong($random_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		$result['random_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityMention extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfa04579d);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url true force_large_media true force_small_media true optional
 * @return InputMedia
 */

final class InputMediaWebPage extends Instance {
	public function request(string $url,null | bool $force_large_media = null,null | bool $force_small_media = null,null | bool $optional = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc21b8849);
		$flags = 0;
		$flags |= $force_large_media ? (1 << 0) : 0;
		$flags |= $force_small_media ? (1 << 1) : 0;
		$flags |= $optional ? (1 << 2) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['force_large_media'] = boolval($flags & (1 << 0));
		$result['force_small_media'] = boolval($flags & (1 << 1));
		$result['optional'] = boolval($flags & (1 << 2));
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id string type inputbotinlinemessage send_message string title string description string url inputwebdocument thumb inputwebdocument content
 * @return InputBotInlineResult
 */

final class InputBotInlineResult extends Instance {
	public function request(string $id,string $type,object $send_message,null | string $title = null,null | string $description = null,null | string $url = null,null | object $thumb = null,null | object $content = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x88bf9319);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 1);
		$flags |= is_null($description) ? 0 : (1 << 2);
		$flags |= is_null($url) ? 0 : (1 << 3);
		$flags |= is_null($thumb) ? 0 : (1 << 4);
		$flags |= is_null($content) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeBytes($id);
		$writer->writeBytes($type);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($description) === false):
			$writer->writeBytes($description);
		endif;
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		if(is_null($thumb) === false):
			$writer->writeObject($thumb);
		endif;
		if(is_null($content) === false):
			$writer->writeObject($content);
		endif;
		$writer->writeObject($send_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readBytes();
		$result['type'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['description'] = $reader->readBytes();
		else:
			$result['description'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['url'] = $reader->readBytes();
		else:
			$result['url'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['thumb'] = $reader->readObject();
		else:
			$result['thumb'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['content'] = $reader->readObject();
		else:
			$result['content'] = null;
		endif;
		$result['send_message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string country_iso2 string state string city string street
 * @return GeoPointAddress
 */

final class GeoPointAddress extends Instance {
	public function request(string $country_iso2,null | string $state = null,null | string $city = null,null | string $street = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xde4c5d93);
		$flags = 0;
		$flags |= is_null($state) ? 0 : (1 << 0);
		$flags |= is_null($city) ? 0 : (1 << 1);
		$flags |= is_null($street) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($country_iso2);
		if(is_null($state) === false):
			$writer->writeBytes($state);
		endif;
		if(is_null($city) === false):
			$writer->writeBytes($city);
		endif;
		if(is_null($street) === false):
			$writer->writeBytes($street);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['country_iso2'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['state'] = $reader->readBytes();
		else:
			$result['state'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['city'] = $reader->readBytes();
		else:
			$result['city'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['street'] = $reader->readBytes();
		else:
			$result['street'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param mediaareacoordinates coordinates string slug
 * @return MediaArea
 */

final class MediaAreaStarGift extends Instance {
	public function request(object $coordinates,string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5787686d);
		$writer->writeObject($coordinates);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['coordinates'] = $reader->readObject();
		$result['slug'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id long inviter_id int date string rank
 * @return ChatParticipant
 */

final class ChatParticipantAdmin extends Instance {
	public function request(int $user_id,int $inviter_id,int $date,null | string $rank = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x360d5d2);
		$flags = 0;
		$flags |= is_null($rank) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		$writer->writeLong($inviter_id);
		$writer->writeInt($date);
		if(is_null($rank) === false):
			$writer->writeBytes($rank);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		$result['inviter_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['rank'] = $reader->readBytes();
		else:
			$result['rank'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param textwithentities text bytes option messagemedia media peer added_by int date
 * @return PollAnswer
 */

final class PollAnswer extends Instance {
	public function request(object $text,string $option,null | object $media = null,null | object $added_by = null,null | int $date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4b7d786a);
		$flags = 0;
		$flags |= is_null($media) ? 0 : (1 << 0);
		$flags |= is_null($added_by) ? 0 : (1 << 1);
		$flags |= is_null($date) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($text);
		$writer->writeBytes($option);
		if(is_null($media) === false):
			$writer->writeObject($media);
		endif;
		if(is_null($added_by) === false):
			$writer->writeObject($added_by);
		endif;
		if(is_null($date) === false):
			$writer->writeInt($date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['text'] = $reader->readObject();
		$result['option'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['media'] = $reader->readObject();
		else:
			$result['media'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['added_by'] = $reader->readObject();
		else:
			$result['added_by'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['date'] = $reader->readInt();
		else:
			$result['date'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int max_id
 * @return Update
 */

final class UpdateReadStories extends Instance {
	public function request(object $peer,int $max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf74e932b);
		$writer->writeObject($peer);
		$writer->writeInt($max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['max_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param privacykey key Vector<privacyrule> rules
 * @return Update
 */

final class UpdatePrivacy extends Instance {
	public function request(object $key,array $rules) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xee3b272a);
		$writer->writeObject($key);
		$writer->writeVector($rules,'privacyrule');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['key'] = $reader->readObject();
		$result['rules'] = $reader->readVector('privacyrule');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id int date
 * @return ReadParticipantDate
 */

final class ReadParticipantDate extends Instance {
	public function request(int $user_id,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4a4ff172);
		$writer->writeLong($user_id);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Update
 */

final class UpdateAiComposeTones extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c0f91fb);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param messages.emojigameinfo info
 * @return Update
 */

final class UpdateEmojiGameInfo extends Instance {
	public function request(object $info) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfb9c547a);
		$writer->writeObject($info);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['info'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BaseTheme
 */

final class BaseThemeNight extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb7b31ea8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SendMessageAction
 */

final class SendMessageRecordRoundAction extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x88f27fbc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputuser> users
 * @return InputPrivacyRule
 */

final class InputPrivacyValueAllowUsers extends Instance {
	public function request(array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x131cc67f);
		$writer->writeVector($users,'inputuser');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['users'] = $reader->readVector('inputuser');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer autosavesettings settings
 * @return AutoSaveException
 */

final class AutoSaveException extends Instance {
	public function request(object $peer,object $settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x81602d47);
		$writer->writeObject($peer);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['settings'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string token
 * @return StatsGraph
 */

final class StatsGraphAsync extends Instance {
	public function request(string $token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4a27eb2d);
		$writer->writeBytes($token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['token'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id peersettings settings peernotifysettings notify_settings int common_chats_count true blocked true phone_calls_available true phone_calls_private true can_pin_message true has_scheduled true video_calls_available true voice_messages_forbidden true translations_disabled true stories_pinned_available true blocked_my_stories_from true wallpaper_overridden true contact_require_premium true read_dates_private true sponsored_enabled true can_view_revenue true bot_can_manage_emoji_status true display_gifts_button true noforwards_my_enabled true noforwards_peer_enabled true unofficial_security_risk string about photo personal_photo photo profile_photo photo fallback_photo botinfo bot_info int pinned_msg_id int folder_id int ttl_period chattheme theme string private_forward_name chatadminrights bot_group_admin_rights chatadminrights bot_broadcast_admin_rights wallpaper wallpaper peerstories stories businessworkhours business_work_hours businesslocation business_location businessgreetingmessage business_greeting_message businessawaymessage business_away_message businessintro business_intro birthday birthday long personal_channel_id int personal_channel_message int stargifts_count starrefprogram starref_program botverification bot_verification long send_paid_messages_stars disallowedgiftssettings disallowed_gifts starsrating stars_rating starsrating stars_my_pending_rating int stars_my_pending_rating_date profiletab main_tab document saved_music textwithentities note long bot_manager_id
 * @return UserFull
 */

final class UserFull extends Instance {
	public function request(int $id,object $settings,object $notify_settings,int $common_chats_count,null | bool $blocked = null,null | bool $phone_calls_available = null,null | bool $phone_calls_private = null,null | bool $can_pin_message = null,null | bool $has_scheduled = null,null | bool $video_calls_available = null,null | bool $voice_messages_forbidden = null,null | bool $translations_disabled = null,null | bool $stories_pinned_available = null,null | bool $blocked_my_stories_from = null,null | bool $wallpaper_overridden = null,null | bool $contact_require_premium = null,null | bool $read_dates_private = null,null | bool $sponsored_enabled = null,null | bool $can_view_revenue = null,null | bool $bot_can_manage_emoji_status = null,null | bool $display_gifts_button = null,null | bool $noforwards_my_enabled = null,null | bool $noforwards_peer_enabled = null,null | bool $unofficial_security_risk = null,null | string $about = null,null | object $personal_photo = null,null | object $profile_photo = null,null | object $fallback_photo = null,null | object $bot_info = null,null | int $pinned_msg_id = null,null | int $folder_id = null,null | int $ttl_period = null,null | object $theme = null,null | string $private_forward_name = null,null | object $bot_group_admin_rights = null,null | object $bot_broadcast_admin_rights = null,null | object $wallpaper = null,null | object $stories = null,null | object $business_work_hours = null,null | object $business_location = null,null | object $business_greeting_message = null,null | object $business_away_message = null,null | object $business_intro = null,null | object $birthday = null,null | int $personal_channel_id = null,null | int $personal_channel_message = null,null | int $stargifts_count = null,null | object $starref_program = null,null | object $bot_verification = null,null | int $send_paid_messages_stars = null,null | object $disallowed_gifts = null,null | object $stars_rating = null,null | object $stars_my_pending_rating = null,null | int $stars_my_pending_rating_date = null,null | object $main_tab = null,null | object $saved_music = null,null | object $note = null,null | int $bot_manager_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6cbe645);
		$flags = 0;
		$flags |= $blocked ? (1 << 0) : 0;
		$flags |= $phone_calls_available ? (1 << 4) : 0;
		$flags |= $phone_calls_private ? (1 << 5) : 0;
		$flags |= $can_pin_message ? (1 << 7) : 0;
		$flags |= $has_scheduled ? (1 << 12) : 0;
		$flags |= $video_calls_available ? (1 << 13) : 0;
		$flags |= $voice_messages_forbidden ? (1 << 20) : 0;
		$flags |= $translations_disabled ? (1 << 23) : 0;
		$flags |= $stories_pinned_available ? (1 << 26) : 0;
		$flags |= $blocked_my_stories_from ? (1 << 27) : 0;
		$flags |= $wallpaper_overridden ? (1 << 28) : 0;
		$flags |= $contact_require_premium ? (1 << 29) : 0;
		$flags |= $read_dates_private ? (1 << 30) : 0;
		$flags |= is_null($about) ? 0 : (1 << 1);
		$flags |= is_null($personal_photo) ? 0 : (1 << 21);
		$flags |= is_null($profile_photo) ? 0 : (1 << 2);
		$flags |= is_null($fallback_photo) ? 0 : (1 << 22);
		$flags |= is_null($bot_info) ? 0 : (1 << 3);
		$flags |= is_null($pinned_msg_id) ? 0 : (1 << 6);
		$flags |= is_null($folder_id) ? 0 : (1 << 11);
		$flags |= is_null($ttl_period) ? 0 : (1 << 14);
		$flags |= is_null($theme) ? 0 : (1 << 15);
		$flags |= is_null($private_forward_name) ? 0 : (1 << 16);
		$flags |= is_null($bot_group_admin_rights) ? 0 : (1 << 17);
		$flags |= is_null($bot_broadcast_admin_rights) ? 0 : (1 << 18);
		$flags |= is_null($wallpaper) ? 0 : (1 << 24);
		$flags |= is_null($stories) ? 0 : (1 << 25);
		$writer->writeInt($flags);
		$flags2 = 0;
		$flags2 |= $sponsored_enabled ? (1 << 7) : 0;
		$flags2 |= $can_view_revenue ? (1 << 9) : 0;
		$flags2 |= $bot_can_manage_emoji_status ? (1 << 10) : 0;
		$flags2 |= $display_gifts_button ? (1 << 16) : 0;
		$flags2 |= $noforwards_my_enabled ? (1 << 23) : 0;
		$flags2 |= $noforwards_peer_enabled ? (1 << 24) : 0;
		$flags2 |= $unofficial_security_risk ? (1 << 26) : 0;
		$flags2 |= is_null($business_work_hours) ? 0 : (1 << 0);
		$flags2 |= is_null($business_location) ? 0 : (1 << 1);
		$flags2 |= is_null($business_greeting_message) ? 0 : (1 << 2);
		$flags2 |= is_null($business_away_message) ? 0 : (1 << 3);
		$flags2 |= is_null($business_intro) ? 0 : (1 << 4);
		$flags2 |= is_null($birthday) ? 0 : (1 << 5);
		$flags2 |= is_null($personal_channel_id) ? 0 : (1 << 6);
		$flags2 |= is_null($personal_channel_message) ? 0 : (1 << 6);
		$flags2 |= is_null($stargifts_count) ? 0 : (1 << 8);
		$flags2 |= is_null($starref_program) ? 0 : (1 << 11);
		$flags2 |= is_null($bot_verification) ? 0 : (1 << 12);
		$flags2 |= is_null($send_paid_messages_stars) ? 0 : (1 << 14);
		$flags2 |= is_null($disallowed_gifts) ? 0 : (1 << 15);
		$flags2 |= is_null($stars_rating) ? 0 : (1 << 17);
		$flags2 |= is_null($stars_my_pending_rating) ? 0 : (1 << 18);
		$flags2 |= is_null($stars_my_pending_rating_date) ? 0 : (1 << 18);
		$flags2 |= is_null($main_tab) ? 0 : (1 << 20);
		$flags2 |= is_null($saved_music) ? 0 : (1 << 21);
		$flags2 |= is_null($note) ? 0 : (1 << 22);
		$flags2 |= is_null($bot_manager_id) ? 0 : (1 << 25);
		$writer->writeInt($flags2);
		$writer->writeLong($id);
		if(is_null($about) === false):
			$writer->writeBytes($about);
		endif;
		$writer->writeObject($settings);
		if(is_null($personal_photo) === false):
			$writer->writeObject($personal_photo);
		endif;
		if(is_null($profile_photo) === false):
			$writer->writeObject($profile_photo);
		endif;
		if(is_null($fallback_photo) === false):
			$writer->writeObject($fallback_photo);
		endif;
		$writer->writeObject($notify_settings);
		if(is_null($bot_info) === false):
			$writer->writeObject($bot_info);
		endif;
		if(is_null($pinned_msg_id) === false):
			$writer->writeInt($pinned_msg_id);
		endif;
		$writer->writeInt($common_chats_count);
		if(is_null($folder_id) === false):
			$writer->writeInt($folder_id);
		endif;
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		if(is_null($theme) === false):
			$writer->writeObject($theme);
		endif;
		if(is_null($private_forward_name) === false):
			$writer->writeBytes($private_forward_name);
		endif;
		if(is_null($bot_group_admin_rights) === false):
			$writer->writeObject($bot_group_admin_rights);
		endif;
		if(is_null($bot_broadcast_admin_rights) === false):
			$writer->writeObject($bot_broadcast_admin_rights);
		endif;
		if(is_null($wallpaper) === false):
			$writer->writeObject($wallpaper);
		endif;
		if(is_null($stories) === false):
			$writer->writeObject($stories);
		endif;
		if(is_null($business_work_hours) === false):
			$writer->writeObject($business_work_hours);
		endif;
		if(is_null($business_location) === false):
			$writer->writeObject($business_location);
		endif;
		if(is_null($business_greeting_message) === false):
			$writer->writeObject($business_greeting_message);
		endif;
		if(is_null($business_away_message) === false):
			$writer->writeObject($business_away_message);
		endif;
		if(is_null($business_intro) === false):
			$writer->writeObject($business_intro);
		endif;
		if(is_null($birthday) === false):
			$writer->writeObject($birthday);
		endif;
		if(is_null($personal_channel_id) === false):
			$writer->writeLong($personal_channel_id);
		endif;
		if(is_null($personal_channel_message) === false):
			$writer->writeInt($personal_channel_message);
		endif;
		if(is_null($stargifts_count) === false):
			$writer->writeInt($stargifts_count);
		endif;
		if(is_null($starref_program) === false):
			$writer->writeObject($starref_program);
		endif;
		if(is_null($bot_verification) === false):
			$writer->writeObject($bot_verification);
		endif;
		if(is_null($send_paid_messages_stars) === false):
			$writer->writeLong($send_paid_messages_stars);
		endif;
		if(is_null($disallowed_gifts) === false):
			$writer->writeObject($disallowed_gifts);
		endif;
		if(is_null($stars_rating) === false):
			$writer->writeObject($stars_rating);
		endif;
		if(is_null($stars_my_pending_rating) === false):
			$writer->writeObject($stars_my_pending_rating);
		endif;
		if(is_null($stars_my_pending_rating_date) === false):
			$writer->writeInt($stars_my_pending_rating_date);
		endif;
		if(is_null($main_tab) === false):
			$writer->writeObject($main_tab);
		endif;
		if(is_null($saved_music) === false):
			$writer->writeObject($saved_music);
		endif;
		if(is_null($note) === false):
			$writer->writeObject($note);
		endif;
		if(is_null($bot_manager_id) === false):
			$writer->writeLong($bot_manager_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['blocked'] = boolval($flags & (1 << 0));
		$result['phone_calls_available'] = boolval($flags & (1 << 4));
		$result['phone_calls_private'] = boolval($flags & (1 << 5));
		$result['can_pin_message'] = boolval($flags & (1 << 7));
		$result['has_scheduled'] = boolval($flags & (1 << 12));
		$result['video_calls_available'] = boolval($flags & (1 << 13));
		$result['voice_messages_forbidden'] = boolval($flags & (1 << 20));
		$result['translations_disabled'] = boolval($flags & (1 << 23));
		$result['stories_pinned_available'] = boolval($flags & (1 << 26));
		$result['blocked_my_stories_from'] = boolval($flags & (1 << 27));
		$result['wallpaper_overridden'] = boolval($flags & (1 << 28));
		$result['contact_require_premium'] = boolval($flags & (1 << 29));
		$result['read_dates_private'] = boolval($flags & (1 << 30));
		$flags2 = $reader->readInt();
		$result['sponsored_enabled'] = boolval($flags2 & (1 << 7));
		$result['can_view_revenue'] = boolval($flags2 & (1 << 9));
		$result['bot_can_manage_emoji_status'] = boolval($flags2 & (1 << 10));
		$result['display_gifts_button'] = boolval($flags2 & (1 << 16));
		$result['noforwards_my_enabled'] = boolval($flags2 & (1 << 23));
		$result['noforwards_peer_enabled'] = boolval($flags2 & (1 << 24));
		$result['unofficial_security_risk'] = boolval($flags2 & (1 << 26));
		$result['id'] = $reader->readLong();
		if($flags & (1 << 1)):
			$result['about'] = $reader->readBytes();
		else:
			$result['about'] = null;
		endif;
		$result['settings'] = $reader->readObject();
		if($flags & (1 << 21)):
			$result['personal_photo'] = $reader->readObject();
		else:
			$result['personal_photo'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['profile_photo'] = $reader->readObject();
		else:
			$result['profile_photo'] = null;
		endif;
		if($flags & (1 << 22)):
			$result['fallback_photo'] = $reader->readObject();
		else:
			$result['fallback_photo'] = null;
		endif;
		$result['notify_settings'] = $reader->readObject();
		if($flags & (1 << 3)):
			$result['bot_info'] = $reader->readObject();
		else:
			$result['bot_info'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['pinned_msg_id'] = $reader->readInt();
		else:
			$result['pinned_msg_id'] = null;
		endif;
		$result['common_chats_count'] = $reader->readInt();
		if($flags & (1 << 11)):
			$result['folder_id'] = $reader->readInt();
		else:
			$result['folder_id'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['ttl_period'] = $reader->readInt();
		else:
			$result['ttl_period'] = null;
		endif;
		if($flags & (1 << 15)):
			$result['theme'] = $reader->readObject();
		else:
			$result['theme'] = null;
		endif;
		if($flags & (1 << 16)):
			$result['private_forward_name'] = $reader->readBytes();
		else:
			$result['private_forward_name'] = null;
		endif;
		if($flags & (1 << 17)):
			$result['bot_group_admin_rights'] = $reader->readObject();
		else:
			$result['bot_group_admin_rights'] = null;
		endif;
		if($flags & (1 << 18)):
			$result['bot_broadcast_admin_rights'] = $reader->readObject();
		else:
			$result['bot_broadcast_admin_rights'] = null;
		endif;
		if($flags & (1 << 24)):
			$result['wallpaper'] = $reader->readObject();
		else:
			$result['wallpaper'] = null;
		endif;
		if($flags & (1 << 25)):
			$result['stories'] = $reader->readObject();
		else:
			$result['stories'] = null;
		endif;
		if($flags2 & (1 << 0)):
			$result['business_work_hours'] = $reader->readObject();
		else:
			$result['business_work_hours'] = null;
		endif;
		if($flags2 & (1 << 1)):
			$result['business_location'] = $reader->readObject();
		else:
			$result['business_location'] = null;
		endif;
		if($flags2 & (1 << 2)):
			$result['business_greeting_message'] = $reader->readObject();
		else:
			$result['business_greeting_message'] = null;
		endif;
		if($flags2 & (1 << 3)):
			$result['business_away_message'] = $reader->readObject();
		else:
			$result['business_away_message'] = null;
		endif;
		if($flags2 & (1 << 4)):
			$result['business_intro'] = $reader->readObject();
		else:
			$result['business_intro'] = null;
		endif;
		if($flags2 & (1 << 5)):
			$result['birthday'] = $reader->readObject();
		else:
			$result['birthday'] = null;
		endif;
		if($flags2 & (1 << 6)):
			$result['personal_channel_id'] = $reader->readLong();
		else:
			$result['personal_channel_id'] = null;
		endif;
		if($flags2 & (1 << 6)):
			$result['personal_channel_message'] = $reader->readInt();
		else:
			$result['personal_channel_message'] = null;
		endif;
		if($flags2 & (1 << 8)):
			$result['stargifts_count'] = $reader->readInt();
		else:
			$result['stargifts_count'] = null;
		endif;
		if($flags2 & (1 << 11)):
			$result['starref_program'] = $reader->readObject();
		else:
			$result['starref_program'] = null;
		endif;
		if($flags2 & (1 << 12)):
			$result['bot_verification'] = $reader->readObject();
		else:
			$result['bot_verification'] = null;
		endif;
		if($flags2 & (1 << 14)):
			$result['send_paid_messages_stars'] = $reader->readLong();
		else:
			$result['send_paid_messages_stars'] = null;
		endif;
		if($flags2 & (1 << 15)):
			$result['disallowed_gifts'] = $reader->readObject();
		else:
			$result['disallowed_gifts'] = null;
		endif;
		if($flags2 & (1 << 17)):
			$result['stars_rating'] = $reader->readObject();
		else:
			$result['stars_rating'] = null;
		endif;
		if($flags2 & (1 << 18)):
			$result['stars_my_pending_rating'] = $reader->readObject();
		else:
			$result['stars_my_pending_rating'] = null;
		endif;
		if($flags2 & (1 << 18)):
			$result['stars_my_pending_rating_date'] = $reader->readInt();
		else:
			$result['stars_my_pending_rating_date'] = null;
		endif;
		if($flags2 & (1 << 20)):
			$result['main_tab'] = $reader->readObject();
		else:
			$result['main_tab'] = null;
		endif;
		if($flags2 & (1 << 21)):
			$result['saved_music'] = $reader->readObject();
		else:
			$result['saved_music'] = null;
		endif;
		if($flags2 & (1 << 22)):
			$result['note'] = $reader->readObject();
		else:
			$result['note'] = null;
		endif;
		if($flags2 & (1 << 25)):
			$result['bot_manager_id'] = $reader->readLong();
		else:
			$result['bot_manager_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer true wallpaper_overridden wallpaper wallpaper
 * @return Update
 */

final class UpdatePeerWallpaper extends Instance {
	public function request(object $peer,null | bool $wallpaper_overridden = null,null | object $wallpaper = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xae3f101d);
		$flags = 0;
		$flags |= $wallpaper_overridden ? (1 << 1) : 0;
		$flags |= is_null($wallpaper) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($wallpaper) === false):
			$writer->writeObject($wallpaper);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['wallpaper_overridden'] = boolval($flags & (1 << 1));
		$result['peer'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['wallpaper'] = $reader->readObject();
		else:
			$result['wallpaper'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text string language
 * @return PageBlock
 */

final class PageBlockPreformatted extends Instance {
	public function request(object $text,string $language) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc070d93e);
		$writer->writeObject($text);
		$writer->writeBytes($language);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		$result['language'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int period
 * @return DefaultHistoryTTL
 */

final class DefaultHistoryTTL extends Instance {
	public function request(int $period) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x43b46b20);
		$writer->writeInt($period);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['period'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars string currency long amount true extended string store_product
 * @return StarsGiftOption
 */

final class StarsGiftOption extends Instance {
	public function request(int $stars,string $currency,int $amount,null | bool $extended = null,null | string $store_product = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5e0589f1);
		$flags = 0;
		$flags |= $extended ? (1 << 1) : 0;
		$flags |= is_null($store_product) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($stars);
		if(is_null($store_product) === false):
			$writer->writeBytes($store_product);
		endif;
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['extended'] = boolval($flags & (1 << 1));
		$result['stars'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['store_product'] = $reader->readBytes();
		else:
			$result['store_product'] = null;
		endif;
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgeopoint geo_point
 * @return InputMedia
 */

final class InputMediaGeoPoint extends Instance {
	public function request(object $geo_point) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf9c44144);
		$writer->writeObject($geo_point);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['geo_point'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true open_external_browser true display_close_button
 * @return Update
 */

final class UpdateWebBrowserSettings extends Instance {
	public function request(null | bool $open_external_browser = null,null | bool $display_close_button = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc39a2ade);
		$flags = 0;
		$flags |= $open_external_browser ? (1 << 0) : 0;
		$flags |= $display_close_button ? (1 << 1) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['open_external_browser'] = boolval($flags & (1 << 0));
		$result['display_close_button'] = boolval($flags & (1 << 1));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param forumtopic topic
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionDeleteTopic extends Instance {
	public function request(object $topic) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xae168909);
		$writer->writeObject($topic);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['topic'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id userstatus status
 * @return ContactStatus
 */

final class ContactStatus extends Instance {
	public function request(int $user_id,object $status) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x16d9703b);
		$writer->writeLong($user_id);
		$writer->writeObject($status);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['status'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int msg_id long view_id int time_in_view_ms int active_time_in_view_ms int height_to_viewport_ratio_permille int seen_range_ratio_permille
 * @return InputMessageReadMetric
 */

final class InputMessageReadMetric extends Instance {
	public function request(int $msg_id,int $view_id,int $time_in_view_ms,int $active_time_in_view_ms,int $height_to_viewport_ratio_permille,int $seen_range_ratio_permille) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x402b4495);
		$writer->writeInt($msg_id);
		$writer->writeLong($view_id);
		$writer->writeInt($time_in_view_ms);
		$writer->writeInt($active_time_in_view_ms);
		$writer->writeInt($height_to_viewport_ratio_permille);
		$writer->writeInt($seen_range_ratio_permille);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_id'] = $reader->readInt();
		$result['view_id'] = $reader->readLong();
		$result['time_in_view_ms'] = $reader->readInt();
		$result['active_time_in_view_ms'] = $reader->readInt();
		$result['height_to_viewport_ratio_permille'] = $reader->readInt();
		$result['seen_range_ratio_permille'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id long user_id bytes payload postaddress shipping_address
 * @return Update
 */

final class UpdateBotShippingQuery extends Instance {
	public function request(int $query_id,int $user_id,string $payload,object $shipping_address) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb5aefd7d);
		$writer->writeLong($query_id);
		$writer->writeLong($user_id);
		$writer->writeBytes($payload);
		$writer->writeObject($shipping_address);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['query_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		$result['payload'] = $reader->readBytes();
		$result['shipping_address'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param forumtopic topic
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionCreateTopic extends Instance {
	public function request(object $topic) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x58707d28);
		$writer->writeObject($topic);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['topic'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param securevaluetype type bytes file_hash string text
 * @return SecureValueError
 */

final class SecureValueErrorReverseSide extends Instance {
	public function request(object $type,string $file_hash,string $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x868a2aa5);
		$writer->writeObject($type);
		$writer->writeBytes($file_hash);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readObject();
		$result['file_hash'] = $reader->readBytes();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string key
 * @return LangPackString
 */

final class LangPackStringDeleted extends Instance {
	public function request(string $key) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2979eeb2);
		$writer->writeBytes($key);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['key'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyStatusTimestamp extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbc2eab30);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return UrlAuthResult
 */

final class UrlAuthResultAccepted extends Instance {
	public function request(null | string $url = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x623a8fa0);
		$flags = 0;
		$flags |= is_null($url) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['url'] = $reader->readBytes();
		else:
			$result['url'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return DocumentAttribute
 */

final class DocumentAttributeAnimated extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x11b58939);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id
 * @return InputMessage
 */

final class InputMessageReplyTo extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbad88395);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReportReason
 */

final class InputReportReasonFake extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf5ddd6e7);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return EmojiStatus
 */

final class EmojiStatusEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2de11aae);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string prev_value string new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionChangeUsername extends Instance {
	public function request(string $prev_value,string $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6a4afc38);
		$writer->writeBytes($prev_value);
		$writer->writeBytes($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readBytes();
		$result['new_value'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return True
 */

final class TrueObject extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3fedd339);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string currency long amount int days string crypto_currency long crypto_amount textwithentities message
 * @return MessageAction
 */

final class MessageActionGiftPremium extends Instance {
	public function request(string $currency,int $amount,int $days,null | string $crypto_currency = null,null | int $crypto_amount = null,null | object $message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x48e91302);
		$flags = 0;
		$flags |= is_null($crypto_currency) ? 0 : (1 << 0);
		$flags |= is_null($crypto_amount) ? 0 : (1 << 0);
		$flags |= is_null($message) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		$writer->writeInt($days);
		if(is_null($crypto_currency) === false):
			$writer->writeBytes($crypto_currency);
		endif;
		if(is_null($crypto_amount) === false):
			$writer->writeLong($crypto_amount);
		endif;
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		$result['days'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['crypto_currency'] = $reader->readBytes();
		else:
			$result['crypto_currency'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['crypto_amount'] = $reader->readLong();
		else:
			$result['crypto_amount'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['message'] = $reader->readObject();
		else:
			$result['message'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionToggleInvites extends Instance {
	public function request(bool $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1b7907ae);
		$writer->writeBool($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_value'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return TopPeerCategory
 */

final class TopPeerCategoryBotsGuestChat extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c24f3dd);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id int months int quantity int date
 * @return PrepaidGiveaway
 */

final class PrepaidGiveaway extends Instance {
	public function request(int $id,int $months,int $quantity,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb2539d54);
		$writer->writeLong($id);
		$writer->writeInt($months);
		$writer->writeInt($quantity);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['months'] = $reader->readInt();
		$result['quantity'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id textwithentities title
 * @return TodoItem
 */

final class TodoItem extends Instance {
	public function request(int $id,object $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcba9a52f);
		$writer->writeInt($id);
		$writer->writeObject($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		$result['title'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer peersettings settings
 * @return Update
 */

final class UpdatePeerSettings extends Instance {
	public function request(object $peer,object $settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6a7e7366);
		$writer->writeObject($peer);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['settings'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool prev_value bool new_value
 * @return MessageAction
 */

final class MessageActionNoForwardsToggle extends Instance {
	public function request(bool $prev_value,bool $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbf7d6572);
		$writer->writeBool($prev_value);
		$writer->writeBool($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['prev_value'] = $reader->readBool();
		$result['new_value'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param exportedchatinvite invite long approved_by
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionParticipantJoinByRequest extends Instance {
	public function request(object $invite,int $approved_by) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xafb6144a);
		$writer->writeObject($invite);
		$writer->writeLong($approved_by);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['invite'] = $reader->readObject();
		$result['approved_by'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long contact_id birthday birthday
 * @return ContactBirthday
 */

final class ContactBirthday extends Instance {
	public function request(int $contact_id,object $birthday) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1d998733);
		$writer->writeLong($contact_id);
		$writer->writeObject($birthday);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['contact_id'] = $reader->readLong();
		$result['birthday'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param auth.sentcode sent_code
 * @return Update
 */

final class UpdateSentPhoneCode extends Instance {
	public function request(object $sent_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x504aa18f);
		$writer->writeObject($sent_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['sent_code'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id int date int expire_date true close_friends true live
 * @return StoryItem
 */

final class StoryItemSkipped extends Instance {
	public function request(int $id,int $date,int $expire_date,null | bool $close_friends = null,null | bool $live = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xffadc913);
		$flags = 0;
		$flags |= $close_friends ? (1 << 8) : 0;
		$flags |= $live ? (1 << 9) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeInt($date);
		$writer->writeInt($expire_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['close_friends'] = boolval($flags & (1 << 8));
		$result['live'] = boolval($flags & (1 << 9));
		$result['id'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['expire_date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title long chat_id
 * @return MessageAction
 */

final class MessageActionChannelMigrateFrom extends Instance {
	public function request(string $title,int $chat_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xea3948e9);
		$writer->writeBytes($title);
		$writer->writeLong($chat_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readBytes();
		$result['chat_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id
 * @return InputWallPaper
 */

final class InputWallPaperNoFile extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x967a462e);
		$writer->writeLong($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int backdrop_id
 * @return StarGiftAttributeId
 */

final class StarGiftAttributeIdBackdrop extends Instance {
	public function request(int $backdrop_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1f01c757);
		$writer->writeInt($backdrop_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['backdrop_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputPrivacyRule
 */

final class InputPrivacyValueAllowContacts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd09e07b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputCheckPasswordSRP
 */

final class InputCheckPasswordEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9880f658);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id true default true dark wallpapersettings settings
 * @return WallPaper
 */

final class WallPaperNoFile extends Instance {
	public function request(int $id,null | bool $default = null,null | bool $dark = null,null | object $settings = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe0804116);
		$writer->writeLong($id);
		$flags = 0;
		$flags |= $default ? (1 << 1) : 0;
		$flags |= $dark ? (1 << 4) : 0;
		$flags |= is_null($settings) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($settings) === false):
			$writer->writeObject($settings);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$flags = $reader->readInt();
		$result['default'] = boolval($flags & (1 << 1));
		$result['dark'] = boolval($flags & (1 << 4));
		if($flags & (1 << 2)):
			$result['settings'] = $reader->readObject();
		else:
			$result['settings'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param mediaareacoordinates coordinates long query_id string result_id
 * @return MediaArea
 */

final class InputMediaAreaVenue extends Instance {
	public function request(object $coordinates,int $query_id,string $result_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb282217f);
		$writer->writeObject($coordinates);
		$writer->writeLong($query_id);
		$writer->writeBytes($result_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['coordinates'] = $reader->readObject();
		$result['query_id'] = $reader->readLong();
		$result['result_id'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputNotifyPeer
 */

final class InputNotifyUsers extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x193b4417);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return BotCommandScope
 */

final class BotCommandScopeChats extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6fe1a881);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyRule
 */

final class PrivacyValueAllowBots extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x21461b5d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ChannelParticipantsFilter
 */

final class ChannelParticipantsAdmins extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb4608969);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickerset stickerset int thumb_version
 * @return InputFileLocation
 */

final class InputStickerSetThumb extends Instance {
	public function request(object $stickerset,int $thumb_version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9d84f3db);
		$writer->writeObject($stickerset);
		$writer->writeInt($thumb_version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['stickerset'] = $reader->readObject();
		$result['thumb_version'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyPhoneCall extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3d662b7b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> order true masks true emojis
 * @return Update
 */

final class UpdateStickerSetsOrder extends Instance {
	public function request(array $order,null | bool $masks = null,null | bool $emojis = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbb2d201);
		$flags = 0;
		$flags |= $masks ? (1 << 0) : 0;
		$flags |= $emojis ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($order,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['masks'] = boolval($flags & (1 << 0));
		$result['emojis'] = boolval($flags & (1 << 1));
		$result['order'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id
 * @return InputMessage
 */

final class InputMessageID extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa676a322);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true allow_custom
 * @return ChatReactions
 */

final class ChatReactionsAll extends Instance {
	public function request(null | bool $allow_custom = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x52928bca);
		$flags = 0;
		$flags |= $allow_custom ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['allow_custom'] = boolval($flags & (1 << 0));
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> msg_ids
 * @return MsgsStateReq
 */

final class MsgsStateReq extends Instance {
	public function request(array $msg_ids) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xda69fb52);
		$writer->writeVector($msg_ids,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_ids'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return MessageAction
 */

final class MessageActionChatDeletePhoto extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x95e3fbef);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title long icon_emoji_id
 * @return EmojiGroup
 */

final class EmojiGroupPremium extends Instance {
	public function request(string $title,int $icon_emoji_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x93bcf34);
		$writer->writeBytes($title);
		$writer->writeLong($icon_emoji_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['title'] = $reader->readBytes();
		$result['icon_emoji_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int cached_page_views
 * @return WebPage
 */

final class WebPageNotModified extends Instance {
	public function request(null | int $cached_page_views = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7311ca11);
		$flags = 0;
		$flags |= is_null($cached_page_views) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($cached_page_views) === false):
			$writer->writeInt($cached_page_views);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['cached_page_views'] = $reader->readInt();
		else:
			$result['cached_page_views'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int users int months string currency long amount string store_product int store_quantity
 * @return PremiumGiftCodeOption
 */

final class PremiumGiftCodeOption extends Instance {
	public function request(int $users,int $months,string $currency,int $amount,null | string $store_product = null,null | int $store_quantity = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x257e962b);
		$flags = 0;
		$flags |= is_null($store_product) ? 0 : (1 << 0);
		$flags |= is_null($store_quantity) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeInt($users);
		$writer->writeInt($months);
		if(is_null($store_product) === false):
			$writer->writeBytes($store_product);
		endif;
		if(is_null($store_quantity) === false):
			$writer->writeInt($store_quantity);
		endif;
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['users'] = $reader->readInt();
		$result['months'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['store_product'] = $reader->readBytes();
		else:
			$result['store_product'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['store_quantity'] = $reader->readInt();
		else:
			$result['store_quantity'] = null;
		endif;
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string hash
 * @return InputInvoice
 */

final class InputInvoiceStarGiftPrepaidUpgrade extends Instance {
	public function request(object $peer,string $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9a0b48b8);
		$writer->writeObject($peer);
		$writer->writeBytes($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['hash'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_code
 * @return Update
 */

final class UpdateLangPackTooLong extends Instance {
	public function request(string $lang_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x46560264);
		$writer->writeBytes($lang_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['lang_code'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyRule
 */

final class PrivacyValueAllowCloseFriends extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf7e8d89b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool new_value
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionToggleForum extends Instance {
	public function request(bool $new_value) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2cc6383);
		$writer->writeBool($new_value);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['new_value'] = $reader->readBool();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param geopoint geo string title string address string provider string venue_id string venue_type
 * @return MessageMedia
 */

final class MessageMediaVenue extends Instance {
	public function request(object $geo,string $title,string $address,string $provider,string $venue_id,string $venue_type) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2ec0533f);
		$writer->writeObject($geo);
		$writer->writeBytes($title);
		$writer->writeBytes($address);
		$writer->writeBytes($provider);
		$writer->writeBytes($venue_id);
		$writer->writeBytes($venue_type);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['geo'] = $reader->readObject();
		$result['title'] = $reader->readBytes();
		$result['address'] = $reader->readBytes();
		$result['provider'] = $reader->readBytes();
		$result['venue_id'] = $reader->readBytes();
		$result['venue_type'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id datajson data int timeout
 * @return Update
 */

final class UpdateBotWebhookJSONQuery extends Instance {
	public function request(int $query_id,object $data,int $timeout) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9b9240a6);
		$writer->writeLong($query_id);
		$writer->writeObject($data);
		$writer->writeInt($timeout);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['query_id'] = $reader->readLong();
		$result['data'] = $reader->readObject();
		$result['timeout'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long channel_id
 * @return MessageAction
 */

final class MessageActionChatMigrateTo extends Instance {
	public function request(int $channel_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe1037f92);
		$writer->writeLong($channel_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['channel_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypeTemporaryRegistration extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xea02ec33);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return PrivacyKey
 */

final class PrivacyKeyBirthday extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2000a518);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id int date peer peer string title int icon_color int top_message int read_inbox_max_id int read_outbox_max_id int unread_count int unread_mentions_count int unread_reactions_count int unread_poll_votes_count peer from_id peernotifysettings notify_settings true my true closed true pinned true short true hidden true title_missing long icon_emoji_id draftmessage draft
 * @return ForumTopic
 */

final class ForumTopic extends Instance {
	public function request(int $id,int $date,object $peer,string $title,int $icon_color,int $top_message,int $read_inbox_max_id,int $read_outbox_max_id,int $unread_count,int $unread_mentions_count,int $unread_reactions_count,int $unread_poll_votes_count,object $from_id,object $notify_settings,null | bool $my = null,null | bool $closed = null,null | bool $pinned = null,null | bool $short = null,null | bool $hidden = null,null | bool $title_missing = null,null | int $icon_emoji_id = null,null | object $draft = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfcdad815);
		$flags = 0;
		$flags |= $my ? (1 << 1) : 0;
		$flags |= $closed ? (1 << 2) : 0;
		$flags |= $pinned ? (1 << 3) : 0;
		$flags |= $short ? (1 << 5) : 0;
		$flags |= $hidden ? (1 << 6) : 0;
		$flags |= $title_missing ? (1 << 7) : 0;
		$flags |= is_null($icon_emoji_id) ? 0 : (1 << 0);
		$flags |= is_null($draft) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeInt($date);
		$writer->writeObject($peer);
		$writer->writeBytes($title);
		$writer->writeInt($icon_color);
		if(is_null($icon_emoji_id) === false):
			$writer->writeLong($icon_emoji_id);
		endif;
		$writer->writeInt($top_message);
		$writer->writeInt($read_inbox_max_id);
		$writer->writeInt($read_outbox_max_id);
		$writer->writeInt($unread_count);
		$writer->writeInt($unread_mentions_count);
		$writer->writeInt($unread_reactions_count);
		$writer->writeInt($unread_poll_votes_count);
		$writer->writeObject($from_id);
		$writer->writeObject($notify_settings);
		if(is_null($draft) === false):
			$writer->writeObject($draft);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['my'] = boolval($flags & (1 << 1));
		$result['closed'] = boolval($flags & (1 << 2));
		$result['pinned'] = boolval($flags & (1 << 3));
		$result['short'] = boolval($flags & (1 << 5));
		$result['hidden'] = boolval($flags & (1 << 6));
		$result['title_missing'] = boolval($flags & (1 << 7));
		$result['id'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		$result['peer'] = $reader->readObject();
		$result['title'] = $reader->readBytes();
		$result['icon_color'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['icon_emoji_id'] = $reader->readLong();
		else:
			$result['icon_emoji_id'] = null;
		endif;
		$result['top_message'] = $reader->readInt();
		$result['read_inbox_max_id'] = $reader->readInt();
		$result['read_outbox_max_id'] = $reader->readInt();
		$result['unread_count'] = $reader->readInt();
		$result['unread_mentions_count'] = $reader->readInt();
		$result['unread_reactions_count'] = $reader->readInt();
		$result['unread_poll_votes_count'] = $reader->readInt();
		$result['from_id'] = $reader->readObject();
		$result['notify_settings'] = $reader->readObject();
		if($flags & (1 << 4)):
			$result['draft'] = $reader->readObject();
		else:
			$result['draft'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int chat_id
 * @return Update
 */

final class UpdateEncryptedChatTyping extends Instance {
	public function request(int $chat_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1710f156);
		$writer->writeInt($chat_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash int date long admin_id long participant_id bytes g_a_hash phonecallprotocol protocol true video
 * @return PhoneCall
 */

final class PhoneCallRequested extends Instance {
	public function request(int $id,int $access_hash,int $date,int $admin_id,int $participant_id,string $g_a_hash,object $protocol,null | bool $video = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x14b0ed0c);
		$flags = 0;
		$flags |= $video ? (1 << 6) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeInt($date);
		$writer->writeLong($admin_id);
		$writer->writeLong($participant_id);
		$writer->writeBytes($g_a_hash);
		$writer->writeObject($protocol);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['video'] = boolval($flags & (1 << 6));
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['admin_id'] = $reader->readLong();
		$result['participant_id'] = $reader->readLong();
		$result['g_a_hash'] = $reader->readBytes();
		$result['protocol'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long stars inputpeer boost_peer long random_id int until_date string currency long amount int users true only_new_subscribers true winners_are_visible Vector<inputpeer> additional_peers Vector<string> countries_iso2 string prize_description
 * @return InputStorePaymentPurpose
 */

final class InputStorePaymentStarsGiveaway extends Instance {
	public function request(int $stars,object $boost_peer,int $random_id,int $until_date,string $currency,int $amount,int $users,null | bool $only_new_subscribers = null,null | bool $winners_are_visible = null,null | array $additional_peers = null,null | array $countries_iso2 = null,null | string $prize_description = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x751f08fa);
		$flags = 0;
		$flags |= $only_new_subscribers ? (1 << 0) : 0;
		$flags |= $winners_are_visible ? (1 << 3) : 0;
		$flags |= is_null($additional_peers) ? 0 : (1 << 1);
		$flags |= is_null($countries_iso2) ? 0 : (1 << 2);
		$flags |= is_null($prize_description) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeLong($stars);
		$writer->writeObject($boost_peer);
		if(is_null($additional_peers) === false):
			$writer->writeVector($additional_peers,'inputpeer');
		endif;
		if(is_null($countries_iso2) === false):
			$writer->writeVector($countries_iso2,'string');
		endif;
		if(is_null($prize_description) === false):
			$writer->writeBytes($prize_description);
		endif;
		$writer->writeLong($random_id);
		$writer->writeInt($until_date);
		$writer->writeBytes($currency);
		$writer->writeLong($amount);
		$writer->writeInt($users);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['only_new_subscribers'] = boolval($flags & (1 << 0));
		$result['winners_are_visible'] = boolval($flags & (1 << 3));
		$result['stars'] = $reader->readLong();
		$result['boost_peer'] = $reader->readObject();
		if($flags & (1 << 1)):
			$result['additional_peers'] = $reader->readVector('inputpeer');
		else:
			$result['additional_peers'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['countries_iso2'] = $reader->readVector('string');
		else:
			$result['countries_iso2'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['prize_description'] = $reader->readBytes();
		else:
			$result['prize_description'] = null;
		endif;
		$result['random_id'] = $reader->readLong();
		$result['until_date'] = $reader->readInt();
		$result['currency'] = $reader->readBytes();
		$result['amount'] = $reader->readLong();
		$result['users'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<pagelistordereditem> items true reversed int start string type
 * @return PageBlock
 */

final class PageBlockOrderedList extends Instance {
	public function request(array $items,null | bool $reversed = null,null | int $start = null,null | string $type = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1fd6f6c1);
		$flags = 0;
		$flags |= $reversed ? (1 << 2) : 0;
		$flags |= is_null($start) ? 0 : (1 << 0);
		$flags |= is_null($type) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeVector($items,'pagelistordereditem');
		if(is_null($start) === false):
			$writer->writeInt($start);
		endif;
		if(is_null($type) === false):
			$writer->writeBytes($type);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['reversed'] = boolval($flags & (1 << 2));
		$result['items'] = $reader->readVector('pagelistordereditem');
		if($flags & (1 << 0)):
			$result['start'] = $reader->readInt();
		else:
			$result['start'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['type'] = $reader->readBytes();
		else:
			$result['type'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<pagelistitem> items
 * @return PageBlock
 */

final class PageBlockList extends Instance {
	public function request(array $items) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe4e88011);
		$writer->writeVector($items,'pagelistitem');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['items'] = $reader->readVector('pagelistitem');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message
 * @return ChannelAdminLogEventAction
 */

final class ChannelAdminLogEventActionDeleteMessage extends Instance {
	public function request(object $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x42e047bb);
		$writer->writeObject($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer
 * @return ChannelParticipant
 */

final class ChannelParticipantLeft extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1b03f006);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButtonBuy extends Instance {
	public function request(string $text,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3fa53905);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int length
 * @return MessageEntity
 */

final class MessageEntityBold extends Instance {
	public function request(int $offset,int $length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd610bc9);
		$writer->writeInt($offset);
		$writer->writeInt($length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['offset'] = $reader->readInt();
		$result['length'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputEncryptedFile
 */

final class InputEncryptedFileEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1837c364);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash bytes file_reference
 * @return InputPhoto
 */

final class InputPhoto extends Instance {
	public function request(int $id,int $access_hash,string $file_reference) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3bb3b94a);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($file_reference);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['file_reference'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputMedia
 */

final class InputMediaEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9664f57f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ChatReactions
 */

final class ChatReactionsNone extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeafc32bc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id long user_id string query string offset geopoint geo inlinequerypeertype peer_type
 * @return Update
 */

final class UpdateBotInlineQuery extends Instance {
	public function request(int $query_id,int $user_id,string $query,string $offset,null | object $geo = null,null | object $peer_type = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x496f379c);
		$flags = 0;
		$flags |= is_null($geo) ? 0 : (1 << 0);
		$flags |= is_null($peer_type) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($query_id);
		$writer->writeLong($user_id);
		$writer->writeBytes($query);
		if(is_null($geo) === false):
			$writer->writeObject($geo);
		endif;
		if(is_null($peer_type) === false):
			$writer->writeObject($peer_type);
		endif;
		$writer->writeBytes($offset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['query_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		$result['query'] = $reader->readBytes();
		if($flags & (1 << 0)):
			$result['geo'] = $reader->readObject();
		else:
			$result['geo'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['peer_type'] = $reader->readObject();
		else:
			$result['peer_type'] = null;
		endif;
		$result['offset'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true single_use true selective string placeholder
 * @return ReplyMarkup
 */

final class ReplyKeyboardForceReply extends Instance {
	public function request(null | bool $single_use = null,null | bool $selective = null,null | string $placeholder = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x86b40b08);
		$flags = 0;
		$flags |= $single_use ? (1 << 1) : 0;
		$flags |= $selective ? (1 << 2) : 0;
		$flags |= is_null($placeholder) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($placeholder) === false):
			$writer->writeBytes($placeholder);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['single_use'] = boolval($flags & (1 << 1));
		$result['selective'] = boolval($flags & (1 << 2));
		if($flags & (1 << 3)):
			$result['placeholder'] = $reader->readBytes();
		else:
			$result['placeholder'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int day int month int year
 * @return Birthday
 */

final class Birthday extends Instance {
	public function request(int $day,int $month,null | int $year = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c8e1e06);
		$flags = 0;
		$flags |= is_null($year) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($day);
		$writer->writeInt($month);
		if(is_null($year) === false):
			$writer->writeInt($year);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['day'] = $reader->readInt();
		$result['month'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['year'] = $reader->readInt();
		else:
			$result['year'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param geopoint geo_point string address
 * @return ChannelLocation
 */

final class ChannelLocation extends Instance {
	public function request(object $geo_point,string $address) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x209b82db);
		$writer->writeObject($geo_point);
		$writer->writeBytes($address);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['geo_point'] = $reader->readObject();
		$result['address'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bot_id
 * @return MessageAction
 */

final class MessageActionManagedBotCreated extends Instance {
	public function request(int $bot_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x16605e3e);
		$writer->writeLong($bot_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['bot_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true has_preview_medias long user_id string description photo description_photo document description_document Vector<botcommand> commands botmenubutton menu_button string privacy_policy_url botappsettings app_settings botverifiersettings verifier_settings
 * @return BotInfo
 */

final class BotInfo extends Instance {
	public function request(null | bool $has_preview_medias = null,null | int $user_id = null,null | string $description = null,null | object $description_photo = null,null | object $description_document = null,null | array $commands = null,null | object $menu_button = null,null | string $privacy_policy_url = null,null | object $app_settings = null,null | object $verifier_settings = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4d8a0299);
		$flags = 0;
		$flags |= $has_preview_medias ? (1 << 6) : 0;
		$flags |= is_null($user_id) ? 0 : (1 << 0);
		$flags |= is_null($description) ? 0 : (1 << 1);
		$flags |= is_null($description_photo) ? 0 : (1 << 4);
		$flags |= is_null($description_document) ? 0 : (1 << 5);
		$flags |= is_null($commands) ? 0 : (1 << 2);
		$flags |= is_null($menu_button) ? 0 : (1 << 3);
		$flags |= is_null($privacy_policy_url) ? 0 : (1 << 7);
		$flags |= is_null($app_settings) ? 0 : (1 << 8);
		$flags |= is_null($verifier_settings) ? 0 : (1 << 9);
		$writer->writeInt($flags);
		if(is_null($user_id) === false):
			$writer->writeLong($user_id);
		endif;
		if(is_null($description) === false):
			$writer->writeBytes($description);
		endif;
		if(is_null($description_photo) === false):
			$writer->writeObject($description_photo);
		endif;
		if(is_null($description_document) === false):
			$writer->writeObject($description_document);
		endif;
		if(is_null($commands) === false):
			$writer->writeVector($commands,'botcommand');
		endif;
		if(is_null($menu_button) === false):
			$writer->writeObject($menu_button);
		endif;
		if(is_null($privacy_policy_url) === false):
			$writer->writeBytes($privacy_policy_url);
		endif;
		if(is_null($app_settings) === false):
			$writer->writeObject($app_settings);
		endif;
		if(is_null($verifier_settings) === false):
			$writer->writeObject($verifier_settings);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['has_preview_medias'] = boolval($flags & (1 << 6));
		if($flags & (1 << 0)):
			$result['user_id'] = $reader->readLong();
		else:
			$result['user_id'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['description'] = $reader->readBytes();
		else:
			$result['description'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['description_photo'] = $reader->readObject();
		else:
			$result['description_photo'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['description_document'] = $reader->readObject();
		else:
			$result['description_document'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['commands'] = $reader->readVector('botcommand');
		else:
			$result['commands'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['menu_button'] = $reader->readObject();
		else:
			$result['menu_button'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['privacy_policy_url'] = $reader->readBytes();
		else:
			$result['privacy_policy_url'] = null;
		endif;
		if($flags & (1 << 8)):
			$result['app_settings'] = $reader->readObject();
		else:
			$result['app_settings'] = null;
		endif;
		if($flags & (1 << 9)):
			$result['verifier_settings'] = $reader->readObject();
		else:
			$result['verifier_settings'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int msg_id long transcription_id string text true pending
 * @return Update
 */

final class UpdateTranscribedAudio extends Instance {
	public function request(object $peer,int $msg_id,int $transcription_id,string $text,null | bool $pending = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x84cd5a);
		$flags = 0;
		$flags |= $pending ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeLong($transcription_id);
		$writer->writeBytes($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['pending'] = boolval($flags & (1 << 0));
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		$result['transcription_id'] = $reader->readLong();
		$result['text'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bot_id string short_name Vector<attachmenuboticon> icons true inactive true has_settings true request_write_access true show_in_attach_menu true show_in_side_menu true side_menu_disclaimer_needed Vector<attachmenupeertype> peer_types
 * @return AttachMenuBot
 */

final class AttachMenuBot extends Instance {
	public function request(int $bot_id,string $short_name,array $icons,null | bool $inactive = null,null | bool $has_settings = null,null | bool $request_write_access = null,null | bool $show_in_attach_menu = null,null | bool $show_in_side_menu = null,null | bool $side_menu_disclaimer_needed = null,null | array $peer_types = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd90d8dfe);
		$flags = 0;
		$flags |= $inactive ? (1 << 0) : 0;
		$flags |= $has_settings ? (1 << 1) : 0;
		$flags |= $request_write_access ? (1 << 2) : 0;
		$flags |= $show_in_attach_menu ? (1 << 3) : 0;
		$flags |= $show_in_side_menu ? (1 << 4) : 0;
		$flags |= $side_menu_disclaimer_needed ? (1 << 5) : 0;
		$flags |= is_null($peer_types) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeLong($bot_id);
		$writer->writeBytes($short_name);
		if(is_null($peer_types) === false):
			$writer->writeVector($peer_types,'attachmenupeertype');
		endif;
		$writer->writeVector($icons,'attachmenuboticon');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['inactive'] = boolval($flags & (1 << 0));
		$result['has_settings'] = boolval($flags & (1 << 1));
		$result['request_write_access'] = boolval($flags & (1 << 2));
		$result['show_in_attach_menu'] = boolval($flags & (1 << 3));
		$result['show_in_side_menu'] = boolval($flags & (1 << 4));
		$result['side_menu_disclaimer_needed'] = boolval($flags & (1 << 5));
		$result['bot_id'] = $reader->readLong();
		$result['short_name'] = $reader->readBytes();
		if($flags & (1 << 3)):
			$result['peer_types'] = $reader->readVector('attachmenupeertype');
		else:
			$result['peer_types'] = null;
		endif;
		$result['icons'] = $reader->readVector('attachmenuboticon');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id
 * @return InputInvoice
 */

final class InputInvoiceMessage extends Instance {
	public function request(object $peer,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc5b56859);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int boosts
 * @return MessageAction
 */

final class MessageActionBoostApply extends Instance {
	public function request(int $boosts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcc02aa6d);
		$writer->writeInt($boosts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['boosts'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer_id storyitem story true blocked true blocked_my_stories_from
 * @return StoryView
 */

final class StoryViewPublicRepost extends Instance {
	public function request(object $peer_id,object $story,null | bool $blocked = null,null | bool $blocked_my_stories_from = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd74cf49);
		$flags = 0;
		$flags |= $blocked ? (1 << 0) : 0;
		$flags |= $blocked_my_stories_from ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer_id);
		$writer->writeObject($story);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['blocked'] = boolval($flags & (1 << 0));
		$result['blocked_my_stories_from'] = boolval($flags & (1 << 1));
		$result['peer_id'] = $reader->readObject();
		$result['story'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return UserProfilePhoto
 */

final class UserProfilePhotoEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4f11bae1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param birthday birthday
 * @return MessageAction
 */

final class MessageActionSuggestBirthday extends Instance {
	public function request(object $birthday) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2c8f2a25);
		$writer->writeObject($birthday);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['birthday'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id long access_hash
 * @return InputPeer
 */

final class InputPeerUser extends Instance {
	public function request(int $user_id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdde8a54c);
		$writer->writeLong($user_id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['user_id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int num int duration int extend_top int extend_window
 * @return StarGiftAuctionRound
 */

final class StarGiftAuctionRoundExtendable extends Instance {
	public function request(int $num,int $duration,int $extend_top,int $extend_window) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaa021e5);
		$writer->writeInt($num);
		$writer->writeInt($duration);
		$writer->writeInt($extend_top);
		$writer->writeInt($extend_window);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['num'] = $reader->readInt();
		$result['duration'] = $reader->readInt();
		$result['extend_top'] = $reader->readInt();
		$result['extend_window'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id long user_id peer peer int msg_id long chat_instance bytes data string game_short_name
 * @return Update
 */

final class UpdateBotCallbackQuery extends Instance {
	public function request(int $query_id,int $user_id,object $peer,int $msg_id,int $chat_instance,null | string $data = null,null | string $game_short_name = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb9cfc48d);
		$flags = 0;
		$flags |= is_null($data) ? 0 : (1 << 0);
		$flags |= is_null($game_short_name) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($query_id);
		$writer->writeLong($user_id);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeLong($chat_instance);
		if(is_null($data) === false):
			$writer->writeBytes($data);
		endif;
		if(is_null($game_short_name) === false):
			$writer->writeBytes($game_short_name);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['query_id'] = $reader->readLong();
		$result['user_id'] = $reader->readLong();
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		$result['chat_instance'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['data'] = $reader->readBytes();
		else:
			$result['data'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['game_short_name'] = $reader->readBytes();
		else:
			$result['game_short_name'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int was_online
 * @return UserStatus
 */

final class UserStatusOffline extends Instance {
	public function request(int $was_online) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c703f);
		$writer->writeInt($was_online);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['was_online'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string shortcut
 * @return InputQuickReplyShortcut
 */

final class InputQuickReplyShortcut extends Instance {
	public function request(string $shortcut) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x24596d41);
		$writer->writeBytes($shortcut);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['shortcut'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return SecureValueType
 */

final class SecureValueTypeEmail extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8e3ca7ee);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id long from_id long chat_id string message int pts int pts_count int date true out true mentioned true media_unread true silent messagefwdheader fwd_from long via_bot_id messagereplyheader reply_to Vector<messageentity> entities int ttl_period
 * @return Updates
 */

final class UpdateShortChatMessage extends Instance {
	public function request(int $id,int $from_id,int $chat_id,string $message,int $pts,int $pts_count,int $date,null | bool $out = null,null | bool $mentioned = null,null | bool $media_unread = null,null | bool $silent = null,null | object $fwd_from = null,null | int $via_bot_id = null,null | object $reply_to = null,null | array $entities = null,null | int $ttl_period = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4d6deea5);
		$flags = 0;
		$flags |= $out ? (1 << 1) : 0;
		$flags |= $mentioned ? (1 << 4) : 0;
		$flags |= $media_unread ? (1 << 5) : 0;
		$flags |= $silent ? (1 << 13) : 0;
		$flags |= is_null($fwd_from) ? 0 : (1 << 2);
		$flags |= is_null($via_bot_id) ? 0 : (1 << 11);
		$flags |= is_null($reply_to) ? 0 : (1 << 3);
		$flags |= is_null($entities) ? 0 : (1 << 7);
		$flags |= is_null($ttl_period) ? 0 : (1 << 25);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		$writer->writeLong($from_id);
		$writer->writeLong($chat_id);
		$writer->writeBytes($message);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		$writer->writeInt($date);
		if(is_null($fwd_from) === false):
			$writer->writeObject($fwd_from);
		endif;
		if(is_null($via_bot_id) === false):
			$writer->writeLong($via_bot_id);
		endif;
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['out'] = boolval($flags & (1 << 1));
		$result['mentioned'] = boolval($flags & (1 << 4));
		$result['media_unread'] = boolval($flags & (1 << 5));
		$result['silent'] = boolval($flags & (1 << 13));
		$result['id'] = $reader->readInt();
		$result['from_id'] = $reader->readLong();
		$result['chat_id'] = $reader->readLong();
		$result['message'] = $reader->readBytes();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 2)):
			$result['fwd_from'] = $reader->readObject();
		else:
			$result['fwd_from'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['via_bot_id'] = $reader->readLong();
		else:
			$result['via_bot_id'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['reply_to'] = $reader->readObject();
		else:
			$result['reply_to'] = null;
		endif;
		if($flags & (1 << 7)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 25)):
			$result['ttl_period'] = $reader->readInt();
		else:
			$result['ttl_period'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return InputDialogPeer
 */

final class InputDialogPeer extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfcaafeb7);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long session_id
 * @return DestroySessionRes
 */

final class DestroySessionNone extends Instance {
	public function request(int $session_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x62d350c9);
		$writer->writeLong($session_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['session_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id true self true contact true mutual_contact true deleted true bot true bot_chat_history true bot_nochats true verified true restricted true min true bot_inline_geo true support true scam true apply_min_photo true fake true bot_attach_menu true premium true attach_menu_enabled true bot_can_edit true close_friend true stories_hidden true stories_unavailable true contact_require_premium true bot_business true bot_has_main_app true bot_forum_view true bot_forum_can_manage_topics true bot_can_manage_bots true bot_guestchat true bot_guard long access_hash string first_name string last_name string username string phone userprofilephoto photo userstatus status int bot_info_version Vector<restrictionreason> restriction_reason string bot_inline_placeholder string lang_code emojistatus emoji_status Vector<username> usernames recentstory stories_max_id peercolor color peercolor profile_color int bot_active_users long bot_verification_icon long send_paid_messages_stars
 * @return User
 */

final class User extends Instance {
	public function request(int $id,null | bool $self = null,null | bool $contact = null,null | bool $mutual_contact = null,null | bool $deleted = null,null | bool $bot = null,null | bool $bot_chat_history = null,null | bool $bot_nochats = null,null | bool $verified = null,null | bool $restricted = null,null | bool $min = null,null | bool $bot_inline_geo = null,null | bool $support = null,null | bool $scam = null,null | bool $apply_min_photo = null,null | bool $fake = null,null | bool $bot_attach_menu = null,null | bool $premium = null,null | bool $attach_menu_enabled = null,null | bool $bot_can_edit = null,null | bool $close_friend = null,null | bool $stories_hidden = null,null | bool $stories_unavailable = null,null | bool $contact_require_premium = null,null | bool $bot_business = null,null | bool $bot_has_main_app = null,null | bool $bot_forum_view = null,null | bool $bot_forum_can_manage_topics = null,null | bool $bot_can_manage_bots = null,null | bool $bot_guestchat = null,null | bool $bot_guard = null,null | int $access_hash = null,null | string $first_name = null,null | string $last_name = null,null | string $username = null,null | string $phone = null,null | object $photo = null,null | object $status = null,null | int $bot_info_version = null,null | array $restriction_reason = null,null | string $bot_inline_placeholder = null,null | string $lang_code = null,null | object $emoji_status = null,null | array $usernames = null,null | object $stories_max_id = null,null | object $color = null,null | object $profile_color = null,null | int $bot_active_users = null,null | int $bot_verification_icon = null,null | int $send_paid_messages_stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31774388);
		$flags = 0;
		$flags |= $self ? (1 << 10) : 0;
		$flags |= $contact ? (1 << 11) : 0;
		$flags |= $mutual_contact ? (1 << 12) : 0;
		$flags |= $deleted ? (1 << 13) : 0;
		$flags |= $bot ? (1 << 14) : 0;
		$flags |= $bot_chat_history ? (1 << 15) : 0;
		$flags |= $bot_nochats ? (1 << 16) : 0;
		$flags |= $verified ? (1 << 17) : 0;
		$flags |= $restricted ? (1 << 18) : 0;
		$flags |= $min ? (1 << 20) : 0;
		$flags |= $bot_inline_geo ? (1 << 21) : 0;
		$flags |= $support ? (1 << 23) : 0;
		$flags |= $scam ? (1 << 24) : 0;
		$flags |= $apply_min_photo ? (1 << 25) : 0;
		$flags |= $fake ? (1 << 26) : 0;
		$flags |= $bot_attach_menu ? (1 << 27) : 0;
		$flags |= $premium ? (1 << 28) : 0;
		$flags |= $attach_menu_enabled ? (1 << 29) : 0;
		$flags |= is_null($access_hash) ? 0 : (1 << 0);
		$flags |= is_null($first_name) ? 0 : (1 << 1);
		$flags |= is_null($last_name) ? 0 : (1 << 2);
		$flags |= is_null($username) ? 0 : (1 << 3);
		$flags |= is_null($phone) ? 0 : (1 << 4);
		$flags |= is_null($photo) ? 0 : (1 << 5);
		$flags |= is_null($status) ? 0 : (1 << 6);
		$flags |= is_null($bot_info_version) ? 0 : (1 << 14);
		$flags |= is_null($restriction_reason) ? 0 : (1 << 18);
		$flags |= is_null($bot_inline_placeholder) ? 0 : (1 << 19);
		$flags |= is_null($lang_code) ? 0 : (1 << 22);
		$flags |= is_null($emoji_status) ? 0 : (1 << 30);
		$writer->writeInt($flags);
		$flags2 = 0;
		$flags2 |= $bot_can_edit ? (1 << 1) : 0;
		$flags2 |= $close_friend ? (1 << 2) : 0;
		$flags2 |= $stories_hidden ? (1 << 3) : 0;
		$flags2 |= $stories_unavailable ? (1 << 4) : 0;
		$flags2 |= $contact_require_premium ? (1 << 10) : 0;
		$flags2 |= $bot_business ? (1 << 11) : 0;
		$flags2 |= $bot_has_main_app ? (1 << 13) : 0;
		$flags2 |= $bot_forum_view ? (1 << 16) : 0;
		$flags2 |= $bot_forum_can_manage_topics ? (1 << 17) : 0;
		$flags2 |= $bot_can_manage_bots ? (1 << 18) : 0;
		$flags2 |= $bot_guestchat ? (1 << 19) : 0;
		$flags2 |= $bot_guard ? (1 << 20) : 0;
		$flags2 |= is_null($usernames) ? 0 : (1 << 0);
		$flags2 |= is_null($stories_max_id) ? 0 : (1 << 5);
		$flags2 |= is_null($color) ? 0 : (1 << 8);
		$flags2 |= is_null($profile_color) ? 0 : (1 << 9);
		$flags2 |= is_null($bot_active_users) ? 0 : (1 << 12);
		$flags2 |= is_null($bot_verification_icon) ? 0 : (1 << 14);
		$flags2 |= is_null($send_paid_messages_stars) ? 0 : (1 << 15);
		$writer->writeInt($flags2);
		$writer->writeLong($id);
		if(is_null($access_hash) === false):
			$writer->writeLong($access_hash);
		endif;
		if(is_null($first_name) === false):
			$writer->writeBytes($first_name);
		endif;
		if(is_null($last_name) === false):
			$writer->writeBytes($last_name);
		endif;
		if(is_null($username) === false):
			$writer->writeBytes($username);
		endif;
		if(is_null($phone) === false):
			$writer->writeBytes($phone);
		endif;
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		if(is_null($status) === false):
			$writer->writeObject($status);
		endif;
		if(is_null($bot_info_version) === false):
			$writer->writeInt($bot_info_version);
		endif;
		if(is_null($restriction_reason) === false):
			$writer->writeVector($restriction_reason,'restrictionreason');
		endif;
		if(is_null($bot_inline_placeholder) === false):
			$writer->writeBytes($bot_inline_placeholder);
		endif;
		if(is_null($lang_code) === false):
			$writer->writeBytes($lang_code);
		endif;
		if(is_null($emoji_status) === false):
			$writer->writeObject($emoji_status);
		endif;
		if(is_null($usernames) === false):
			$writer->writeVector($usernames,'username');
		endif;
		if(is_null($stories_max_id) === false):
			$writer->writeObject($stories_max_id);
		endif;
		if(is_null($color) === false):
			$writer->writeObject($color);
		endif;
		if(is_null($profile_color) === false):
			$writer->writeObject($profile_color);
		endif;
		if(is_null($bot_active_users) === false):
			$writer->writeInt($bot_active_users);
		endif;
		if(is_null($bot_verification_icon) === false):
			$writer->writeLong($bot_verification_icon);
		endif;
		if(is_null($send_paid_messages_stars) === false):
			$writer->writeLong($send_paid_messages_stars);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['self'] = boolval($flags & (1 << 10));
		$result['contact'] = boolval($flags & (1 << 11));
		$result['mutual_contact'] = boolval($flags & (1 << 12));
		$result['deleted'] = boolval($flags & (1 << 13));
		$result['bot'] = boolval($flags & (1 << 14));
		$result['bot_chat_history'] = boolval($flags & (1 << 15));
		$result['bot_nochats'] = boolval($flags & (1 << 16));
		$result['verified'] = boolval($flags & (1 << 17));
		$result['restricted'] = boolval($flags & (1 << 18));
		$result['min'] = boolval($flags & (1 << 20));
		$result['bot_inline_geo'] = boolval($flags & (1 << 21));
		$result['support'] = boolval($flags & (1 << 23));
		$result['scam'] = boolval($flags & (1 << 24));
		$result['apply_min_photo'] = boolval($flags & (1 << 25));
		$result['fake'] = boolval($flags & (1 << 26));
		$result['bot_attach_menu'] = boolval($flags & (1 << 27));
		$result['premium'] = boolval($flags & (1 << 28));
		$result['attach_menu_enabled'] = boolval($flags & (1 << 29));
		$flags2 = $reader->readInt();
		$result['bot_can_edit'] = boolval($flags2 & (1 << 1));
		$result['close_friend'] = boolval($flags2 & (1 << 2));
		$result['stories_hidden'] = boolval($flags2 & (1 << 3));
		$result['stories_unavailable'] = boolval($flags2 & (1 << 4));
		$result['contact_require_premium'] = boolval($flags2 & (1 << 10));
		$result['bot_business'] = boolval($flags2 & (1 << 11));
		$result['bot_has_main_app'] = boolval($flags2 & (1 << 13));
		$result['bot_forum_view'] = boolval($flags2 & (1 << 16));
		$result['bot_forum_can_manage_topics'] = boolval($flags2 & (1 << 17));
		$result['bot_can_manage_bots'] = boolval($flags2 & (1 << 18));
		$result['bot_guestchat'] = boolval($flags2 & (1 << 19));
		$result['bot_guard'] = boolval($flags2 & (1 << 20));
		$result['id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['access_hash'] = $reader->readLong();
		else:
			$result['access_hash'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['first_name'] = $reader->readBytes();
		else:
			$result['first_name'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['last_name'] = $reader->readBytes();
		else:
			$result['last_name'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['username'] = $reader->readBytes();
		else:
			$result['username'] = null;
		endif;
		if($flags & (1 << 4)):
			$result['phone'] = $reader->readBytes();
		else:
			$result['phone'] = null;
		endif;
		if($flags & (1 << 5)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['status'] = $reader->readObject();
		else:
			$result['status'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['bot_info_version'] = $reader->readInt();
		else:
			$result['bot_info_version'] = null;
		endif;
		if($flags & (1 << 18)):
			$result['restriction_reason'] = $reader->readVector('restrictionreason');
		else:
			$result['restriction_reason'] = null;
		endif;
		if($flags & (1 << 19)):
			$result['bot_inline_placeholder'] = $reader->readBytes();
		else:
			$result['bot_inline_placeholder'] = null;
		endif;
		if($flags & (1 << 22)):
			$result['lang_code'] = $reader->readBytes();
		else:
			$result['lang_code'] = null;
		endif;
		if($flags & (1 << 30)):
			$result['emoji_status'] = $reader->readObject();
		else:
			$result['emoji_status'] = null;
		endif;
		if($flags2 & (1 << 0)):
			$result['usernames'] = $reader->readVector('username');
		else:
			$result['usernames'] = null;
		endif;
		if($flags2 & (1 << 5)):
			$result['stories_max_id'] = $reader->readObject();
		else:
			$result['stories_max_id'] = null;
		endif;
		if($flags2 & (1 << 8)):
			$result['color'] = $reader->readObject();
		else:
			$result['color'] = null;
		endif;
		if($flags2 & (1 << 9)):
			$result['profile_color'] = $reader->readObject();
		else:
			$result['profile_color'] = null;
		endif;
		if($flags2 & (1 << 12)):
			$result['bot_active_users'] = $reader->readInt();
		else:
			$result['bot_active_users'] = null;
		endif;
		if($flags2 & (1 << 14)):
			$result['bot_verification_icon'] = $reader->readLong();
		else:
			$result['bot_verification_icon'] = null;
		endif;
		if($flags2 & (1 << 15)):
			$result['send_paid_messages_stars'] = $reader->readLong();
		else:
			$result['send_paid_messages_stars'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long stars int quantity int boosts int date
 * @return PrepaidGiveaway
 */

final class PrepaidStarsGiveaway extends Instance {
	public function request(int $id,int $stars,int $quantity,int $boosts,int $date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9a9d77e0);
		$writer->writeLong($id);
		$writer->writeLong($stars);
		$writer->writeInt($quantity);
		$writer->writeInt($boosts);
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['stars'] = $reader->readLong();
		$result['quantity'] = $reader->readInt();
		$result['boosts'] = $reader->readInt();
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true bot_managed string suggested_name string suggested_username
 * @return RequestPeerType
 */

final class RequestPeerTypeCreateBot extends Instance {
	public function request(null | bool $bot_managed = null,null | string $suggested_name = null,null | string $suggested_username = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e81e078);
		$flags = 0;
		$flags |= $bot_managed ? (1 << 0) : 0;
		$flags |= is_null($suggested_name) ? 0 : (1 << 1);
		$flags |= is_null($suggested_username) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($suggested_name) === false):
			$writer->writeBytes($suggested_name);
		endif;
		if(is_null($suggested_username) === false):
			$writer->writeBytes($suggested_username);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['bot_managed'] = boolval($flags & (1 << 0));
		if($flags & (1 << 1)):
			$result['suggested_name'] = $reader->readBytes();
		else:
			$result['suggested_name'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['suggested_username'] = $reader->readBytes();
		else:
			$result['suggested_username'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Reaction
 */

final class ReactionPaid extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x523da4eb);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text string url keyboardbuttonstyle style
 * @return KeyboardButton
 */

final class KeyboardButtonWebView extends Instance {
	public function request(string $text,string $url,null | object $style = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe846b1a0);
		$flags = 0;
		$flags |= is_null($style) ? 0 : (1 << 10);
		$writer->writeInt($flags);
		if(is_null($style) === false):
			$writer->writeObject($style);
		endif;
		$writer->writeBytes($text);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 10)):
			$result['style'] = $reader->readObject();
		else:
			$result['style'] = null;
		endif;
		$result['text'] = $reader->readBytes();
		$result['url'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param chat chat int expires
 * @return ChatInvite
 */

final class ChatInvitePeek extends Instance {
	public function request(object $chat,int $expires) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x61695cb0);
		$writer->writeObject($chat);
		$writer->writeInt($expires);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['chat'] = $reader->readObject();
		$result['expires'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash
 * @return InputSecureFile
 */

final class InputSecureFile extends Instance {
	public function request(int $id,int $access_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5367e5be);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReactionNotificationsFrom
 */

final class ReactionNotificationsFromAll extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4b9e22a0);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ProfileTab
 */

final class ProfileTabFiles extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xab339c00);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param geopoint geo int period int heading int proximity_notification_radius
 * @return MessageMedia
 */

final class MessageMediaGeoLive extends Instance {
	public function request(object $geo,int $period,null | int $heading = null,null | int $proximity_notification_radius = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb940c666);
		$flags = 0;
		$flags |= is_null($heading) ? 0 : (1 << 0);
		$flags |= is_null($proximity_notification_radius) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($geo);
		if(is_null($heading) === false):
			$writer->writeInt($heading);
		endif;
		$writer->writeInt($period);
		if(is_null($proximity_notification_radius) === false):
			$writer->writeInt($proximity_notification_radius);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['geo'] = $reader->readObject();
		if($flags & (1 << 0)):
			$result['heading'] = $reader->readInt();
		else:
			$result['heading'] = null;
		endif;
		$result['period'] = $reader->readInt();
		if($flags & (1 << 1)):
			$result['proximity_notification_radius'] = $reader->readInt();
		else:
			$result['proximity_notification_radius'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message true invert_media Vector<messageentity> entities replymarkup reply_markup
 * @return BotInlineMessage
 */

final class BotInlineMessageMediaAuto extends Instance {
	public function request(string $message,null | bool $invert_media = null,null | array $entities = null,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x764cf810);
		$flags = 0;
		$flags |= $invert_media ? (1 << 3) : 0;
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['invert_media'] = boolval($flags & (1 << 3));
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes option true optional
 * @return ReportResult
 */

final class ReportResultAddComment extends Instance {
	public function request(string $option,null | bool $optional = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6f09ac31);
		$flags = 0;
		$flags |= $optional ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($option);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['optional'] = boolval($flags & (1 << 0));
		$result['option'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> msg_ids
 * @return MsgsAck
 */

final class MsgsAck extends Instance {
	public function request(array $msg_ids) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x62d6b459);
		$writer->writeVector($msg_ids,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['msg_ids'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id int date string url
 * @return WebPage
 */

final class WebPagePending extends Instance {
	public function request(int $id,int $date,null | string $url = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb0d13e47);
		$flags = 0;
		$flags |= is_null($url) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		$writer->writeInt($date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['url'] = $reader->readBytes();
		else:
			$result['url'] = null;
		endif;
		$result['date'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash int date long admin_id long participant_id bytes g_b phonecallprotocol protocol true video
 * @return PhoneCall
 */

final class PhoneCallAccepted extends Instance {
	public function request(int $id,int $access_hash,int $date,int $admin_id,int $participant_id,string $g_b,object $protocol,null | bool $video = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3660c311);
		$flags = 0;
		$flags |= $video ? (1 << 6) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeInt($date);
		$writer->writeLong($admin_id);
		$writer->writeLong($participant_id);
		$writer->writeBytes($g_b);
		$writer->writeObject($protocol);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['video'] = boolval($flags & (1 << 6));
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['date'] = $reader->readInt();
		$result['admin_id'] = $reader->readLong();
		$result['participant_id'] = $reader->readLong();
		$result['g_b'] = $reader->readBytes();
		$result['protocol'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarsTransactionPeer
 */

final class StarsTransactionPeerPremiumBot extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x250dbaf8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param double time string type long peer jsonvalue data
 * @return InputAppEvent
 */

final class InputAppEvent extends Instance {
	public function request(float $time,string $type,int $peer,object $data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1d1b1245);
		$writer->writeDouble($time);
		$writer->writeBytes($type);
		$writer->writeLong($peer);
		$writer->writeObject($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['time'] = $reader->readDouble();
		$result['type'] = $reader->readBytes();
		$result['peer'] = $reader->readLong();
		$result['data'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputStickerSet
 */

final class InputStickerSetPremiumGifts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc88b3b02);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call long time_ms int scale int video_channel int video_quality
 * @return InputFileLocation
 */

final class InputGroupCallStream extends Instance {
	public function request(object $call,int $time_ms,int $scale,null | int $video_channel = null,null | int $video_quality = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x598a92a);
		$flags = 0;
		$flags |= is_null($video_channel) ? 0 : (1 << 0);
		$flags |= is_null($video_quality) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($call);
		$writer->writeLong($time_ms);
		$writer->writeInt($scale);
		if(is_null($video_channel) === false):
			$writer->writeInt($video_channel);
		endif;
		if(is_null($video_quality) === false):
			$writer->writeInt($video_quality);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['call'] = $reader->readObject();
		$result['time_ms'] = $reader->readLong();
		$result['scale'] = $reader->readInt();
		if($flags & (1 << 0)):
			$result['video_channel'] = $reader->readInt();
		else:
			$result['video_channel'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['video_quality'] = $reader->readInt();
		else:
			$result['video_quality'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return UrlAuthResult
 */

final class UrlAuthResultDefault extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa9d6db1f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextBotCommand extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2ff29d3);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param message message int pts int pts_count
 * @return Update
 */

final class UpdateNewChannelMessage extends Instance {
	public function request(object $message,int $pts,int $pts_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x62ba04d9);
		$writer->writeObject($message);
		$writer->writeInt($pts);
		$writer->writeInt($pts_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['message'] = $reader->readObject();
		$result['pts'] = $reader->readInt();
		$result['pts_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id
 * @return ForumTopic
 */

final class ForumTopicDeleted extends Instance {
	public function request(int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x23f109b);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id long user_id
 * @return InputPeer
 */

final class InputPeerUserFromMessage extends Instance {
	public function request(object $peer,int $msg_id,int $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa87b0a1c);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeLong($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['msg_id'] = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputbotinlinemessageid msg_id
 * @return WebViewMessageSent
 */

final class WebViewMessageSent extends Instance {
	public function request(null | object $msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc94511c);
		$flags = 0;
		$flags |= is_null($msg_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($msg_id) === false):
			$writer->writeObject($msg_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['msg_id'] = $reader->readObject();
		else:
			$result['msg_id'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id int parts string name
 * @return InputFile
 */

final class InputFileBig extends Instance {
	public function request(int $id,int $parts,string $name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfa4f0bb5);
		$writer->writeLong($id);
		$writer->writeInt($parts);
		$writer->writeBytes($name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['parts'] = $reader->readInt();
		$result['name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message string url true invert_media true force_large_media true force_small_media true optional Vector<messageentity> entities replymarkup reply_markup
 * @return InputBotInlineMessage
 */

final class InputBotInlineMessageMediaWebPage extends Instance {
	public function request(string $message,string $url,null | bool $invert_media = null,null | bool $force_large_media = null,null | bool $force_small_media = null,null | bool $optional = null,null | array $entities = null,null | object $reply_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbddcc510);
		$flags = 0;
		$flags |= $invert_media ? (1 << 3) : 0;
		$flags |= $force_large_media ? (1 << 4) : 0;
		$flags |= $force_small_media ? (1 << 5) : 0;
		$flags |= $optional ? (1 << 6) : 0;
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		$writer->writeBytes($url);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['invert_media'] = boolval($flags & (1 << 3));
		$result['force_large_media'] = boolval($flags & (1 << 4));
		$result['force_small_media'] = boolval($flags & (1 << 5));
		$result['optional'] = boolval($flags & (1 << 6));
		$result['message'] = $reader->readBytes();
		if($flags & (1 << 1)):
			$result['entities'] = $reader->readVector('messageentity');
		else:
			$result['entities'] = null;
		endif;
		$result['url'] = $reader->readBytes();
		if($flags & (1 << 2)):
			$result['reply_markup'] = $reader->readObject();
		else:
			$result['reply_markup'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return InputNotifyPeer
 */

final class InputNotifyChats extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4a95e84e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int folder_id
 * @return InputFolderPeer
 */

final class InputFolderPeer extends Instance {
	public function request(object $peer,int $folder_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfbd2c296);
		$writer->writeObject($peer);
		$writer->writeInt($folder_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['folder_id'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string semantics Vector<int> sources
 * @return GroupCallParticipantVideoSourceGroup
 */

final class GroupCallParticipantVideoSourceGroup extends Instance {
	public function request(string $semantics,array $sources) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdcb118b7);
		$writer->writeBytes($semantics);
		$writer->writeVector($sources,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['semantics'] = $reader->readBytes();
		$result['sources'] = $reader->readVector('int');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return AttachMenuBots
 */

final class AttachMenuBotsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf1d88a5c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson payment_data
 * @return InputPaymentCredentials
 */

final class InputPaymentCredentialsApplePay extends Instance {
	public function request(object $payment_data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaa1c39f);
		$writer->writeObject($payment_data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['payment_data'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id string url
 * @return WebPage
 */

final class WebPageEmpty extends Instance {
	public function request(int $id,null | string $url = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x211a1788);
		$flags = 0;
		$flags |= is_null($url) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($id);
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['url'] = $reader->readBytes();
		else:
			$result['url'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer storyitem story
 * @return FoundStory
 */

final class FoundStory extends Instance {
	public function request(object $peer,object $story) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe87acbc0);
		$writer->writeObject($peer);
		$writer->writeObject($story);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['peer'] = $reader->readObject();
		$result['story'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return EncryptedFile
 */

final class EncryptedFileEmpty extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc21f497e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string type int w int h int size
 * @return PhotoSize
 */

final class PhotoSize extends Instance {
	public function request(string $type,int $w,int $h,int $size) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x75c78e60);
		$writer->writeBytes($type);
		$writer->writeInt($w);
		$writer->writeInt($h);
		$writer->writeInt($size);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['type'] = $reader->readBytes();
		$result['w'] = $reader->readInt();
		$result['h'] = $reader->readInt();
		$result['size'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ProfileTab
 */

final class ProfileTabMedia extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x72c64955);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text Vector<messageentity> entities
 * @return TextWithEntities
 */

final class TextWithEntities extends Instance {
	public function request(string $text,array $entities) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x751f3146);
		$writer->writeBytes($text);
		$writer->writeVector($entities,'messageentity');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readBytes();
		$result['entities'] = $reader->readVector('messageentity');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer from_id peer to_id int distance
 * @return MessageAction
 */

final class MessageActionGeoProximityReached extends Instance {
	public function request(object $from_id,object $to_id,int $distance) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x98e0d697);
		$writer->writeObject($from_id);
		$writer->writeObject($to_id);
		$writer->writeInt($distance);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['from_id'] = $reader->readObject();
		$result['to_id'] = $reader->readObject();
		$result['distance'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarGiftAttributeRarity
 */

final class StarGiftAttributeRarityUncommon extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdbce6389);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> users
 * @return PrivacyRule
 */

final class PrivacyValueAllowUsers extends Instance {
	public function request(array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb8905fb2);
		$writer->writeVector($users,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['users'] = $reader->readVector('long');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string text string data
 * @return MessageAction
 */

final class MessageActionWebViewDataSentMe extends Instance {
	public function request(string $text,string $data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x47dd8079);
		$writer->writeBytes($text);
		$writer->writeBytes($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readBytes();
		$result['data'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id long access_hash bytes file_reference
 * @return InputDocument
 */

final class InputDocument extends Instance {
	public function request(int $id,int $access_hash,string $file_reference) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1abfb575);
		$writer->writeLong($id);
		$writer->writeLong($access_hash);
		$writer->writeBytes($file_reference);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['id'] = $reader->readLong();
		$result['access_hash'] = $reader->readLong();
		$result['file_reference'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true bg_primary true bg_danger true bg_success long icon
 * @return KeyboardButtonStyle
 */

final class KeyboardButtonStyle extends Instance {
	public function request(null | bool $bg_primary = null,null | bool $bg_danger = null,null | bool $bg_success = null,null | int $icon = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4fdd3430);
		$flags = 0;
		$flags |= $bg_primary ? (1 << 0) : 0;
		$flags |= $bg_danger ? (1 << 1) : 0;
		$flags |= $bg_success ? (1 << 2) : 0;
		$flags |= is_null($icon) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($icon) === false):
			$writer->writeLong($icon);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['bg_primary'] = boolval($flags & (1 << 0));
		$result['bg_danger'] = boolval($flags & (1 << 1));
		$result['bg_success'] = boolval($flags & (1 << 2));
		if($flags & (1 << 3)):
			$result['icon'] = $reader->readLong();
		else:
			$result['icon'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return TopPeerCategory
 */

final class TopPeerCategoryBotsInline extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x148677e2);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param richtext text
 * @return RichText
 */

final class TextSuperscript extends Instance {
	public function request(object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc7fb5e01);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['text'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long user_id string first_name string last_name string username photo photo
 * @return RequestedPeer
 */

final class RequestedPeerUser extends Instance {
	public function request(int $user_id,null | string $first_name = null,null | string $last_name = null,null | string $username = null,null | object $photo = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd62ff46a);
		$flags = 0;
		$flags |= is_null($first_name) ? 0 : (1 << 0);
		$flags |= is_null($last_name) ? 0 : (1 << 0);
		$flags |= is_null($username) ? 0 : (1 << 1);
		$flags |= is_null($photo) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($user_id);
		if(is_null($first_name) === false):
			$writer->writeBytes($first_name);
		endif;
		if(is_null($last_name) === false):
			$writer->writeBytes($last_name);
		endif;
		if(is_null($username) === false):
			$writer->writeBytes($username);
		endif;
		if(is_null($photo) === false):
			$writer->writeObject($photo);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['user_id'] = $reader->readLong();
		if($flags & (1 << 0)):
			$result['first_name'] = $reader->readBytes();
		else:
			$result['first_name'] = null;
		endif;
		if($flags & (1 << 0)):
			$result['last_name'] = $reader->readBytes();
		else:
			$result['last_name'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['username'] = $reader->readBytes();
		else:
			$result['username'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['photo'] = $reader->readObject();
		else:
			$result['photo'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url stickersetcovered set
 * @return RecentMeUrl
 */

final class RecentMeUrlStickerSet extends Instance {
	public function request(string $url,object $set) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbc0a57dc);
		$writer->writeBytes($url);
		$writer->writeObject($set);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['url'] = $reader->readBytes();
		$result['set'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return StarsTransactionPeer
 */

final class StarsTransactionPeerAds extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x60682812);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return PhoneCallDiscardReason
 */

final class PhoneCallDiscardReasonMigrateConferenceCall extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9fbbf1f7);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['slug'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call Vector<groupcallparticipant> participants int version
 * @return Update
 */

final class UpdateGroupCallParticipants extends Instance {
	public function request(object $call,array $participants,int $version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf2ebdb4e);
		$writer->writeObject($call);
		$writer->writeVector($participants,'groupcallparticipant');
		$writer->writeInt($version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['call'] = $reader->readObject();
		$result['participants'] = $reader->readVector('groupcallparticipant');
		$result['version'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title long icon_emoji_id bool closed bool hidden
 * @return MessageAction
 */

final class MessageActionTopicEdit extends Instance {
	public function request(null | string $title = null,null | int $icon_emoji_id = null,null | bool $closed = null,null | bool $hidden = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc0944820);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$flags |= is_null($icon_emoji_id) ? 0 : (1 << 1);
		$flags |= is_null($closed) ? 0 : (1 << 2);
		$flags |= is_null($hidden) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($icon_emoji_id) === false):
			$writer->writeLong($icon_emoji_id);
		endif;
		if(is_null($closed) === false):
			$writer->writeBool($closed);
		endif;
		if(is_null($hidden) === false):
			$writer->writeBool($hidden);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		if($flags & (1 << 0)):
			$result['title'] = $reader->readBytes();
		else:
			$result['title'] = null;
		endif;
		if($flags & (1 << 1)):
			$result['icon_emoji_id'] = $reader->readLong();
		else:
			$result['icon_emoji_id'] = null;
		endif;
		if($flags & (1 << 2)):
			$result['closed'] = $reader->readBool();
		else:
			$result['closed'] = null;
		endif;
		if($flags & (1 << 3)):
			$result['hidden'] = $reader->readBool();
		else:
			$result['hidden'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peer peer int date int source true muted true left true can_self_unmute true just_joined true versioned true min true muted_by_you true volume_by_admin true self true video_joined int active_date int volume string about long raise_hand_rating groupcallparticipantvideo video groupcallparticipantvideo presentation long paid_stars_total
 * @return GroupCallParticipant
 */

final class GroupCallParticipant extends Instance {
	public function request(object $peer,int $date,int $source,null | bool $muted = null,null | bool $left = null,null | bool $can_self_unmute = null,null | bool $just_joined = null,null | bool $versioned = null,null | bool $min = null,null | bool $muted_by_you = null,null | bool $volume_by_admin = null,null | bool $self = null,null | bool $video_joined = null,null | int $active_date = null,null | int $volume = null,null | string $about = null,null | int $raise_hand_rating = null,null | object $video = null,null | object $presentation = null,null | int $paid_stars_total = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2a3dc7ac);
		$flags = 0;
		$flags |= $muted ? (1 << 0) : 0;
		$flags |= $left ? (1 << 1) : 0;
		$flags |= $can_self_unmute ? (1 << 2) : 0;
		$flags |= $just_joined ? (1 << 4) : 0;
		$flags |= $versioned ? (1 << 5) : 0;
		$flags |= $min ? (1 << 8) : 0;
		$flags |= $muted_by_you ? (1 << 9) : 0;
		$flags |= $volume_by_admin ? (1 << 10) : 0;
		$flags |= $self ? (1 << 12) : 0;
		$flags |= $video_joined ? (1 << 15) : 0;
		$flags |= is_null($active_date) ? 0 : (1 << 3);
		$flags |= is_null($volume) ? 0 : (1 << 7);
		$flags |= is_null($about) ? 0 : (1 << 11);
		$flags |= is_null($raise_hand_rating) ? 0 : (1 << 13);
		$flags |= is_null($video) ? 0 : (1 << 6);
		$flags |= is_null($presentation) ? 0 : (1 << 14);
		$flags |= is_null($paid_stars_total) ? 0 : (1 << 16);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($date);
		if(is_null($active_date) === false):
			$writer->writeInt($active_date);
		endif;
		$writer->writeInt($source);
		if(is_null($volume) === false):
			$writer->writeInt($volume);
		endif;
		if(is_null($about) === false):
			$writer->writeBytes($about);
		endif;
		if(is_null($raise_hand_rating) === false):
			$writer->writeLong($raise_hand_rating);
		endif;
		if(is_null($video) === false):
			$writer->writeObject($video);
		endif;
		if(is_null($presentation) === false):
			$writer->writeObject($presentation);
		endif;
		if(is_null($paid_stars_total) === false):
			$writer->writeLong($paid_stars_total);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['muted'] = boolval($flags & (1 << 0));
		$result['left'] = boolval($flags & (1 << 1));
		$result['can_self_unmute'] = boolval($flags & (1 << 2));
		$result['just_joined'] = boolval($flags & (1 << 4));
		$result['versioned'] = boolval($flags & (1 << 5));
		$result['min'] = boolval($flags & (1 << 8));
		$result['muted_by_you'] = boolval($flags & (1 << 9));
		$result['volume_by_admin'] = boolval($flags & (1 << 10));
		$result['self'] = boolval($flags & (1 << 12));
		$result['video_joined'] = boolval($flags & (1 << 15));
		$result['peer'] = $reader->readObject();
		$result['date'] = $reader->readInt();
		if($flags & (1 << 3)):
			$result['active_date'] = $reader->readInt();
		else:
			$result['active_date'] = null;
		endif;
		$result['source'] = $reader->readInt();
		if($flags & (1 << 7)):
			$result['volume'] = $reader->readInt();
		else:
			$result['volume'] = null;
		endif;
		if($flags & (1 << 11)):
			$result['about'] = $reader->readBytes();
		else:
			$result['about'] = null;
		endif;
		if($flags & (1 << 13)):
			$result['raise_hand_rating'] = $reader->readLong();
		else:
			$result['raise_hand_rating'] = null;
		endif;
		if($flags & (1 << 6)):
			$result['video'] = $reader->readObject();
		else:
			$result['video'] = null;
		endif;
		if($flags & (1 << 14)):
			$result['presentation'] = $reader->readObject();
		else:
			$result['presentation'] = null;
		endif;
		if($flags & (1 << 16)):
			$result['paid_stars_total'] = $reader->readLong();
		else:
			$result['paid_stars_total'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int winners_count int unclaimed_count true stars
 * @return MessageAction
 */

final class MessageActionGiveawayResults extends Instance {
	public function request(int $winners_count,int $unclaimed_count,null | bool $stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x87e2f155);
		$flags = 0;
		$flags |= $stars ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($winners_count);
		$writer->writeInt($unclaimed_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['stars'] = boolval($flags & (1 << 0));
		$result['winners_count'] = $reader->readInt();
		$result['unclaimed_count'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param groupcall call true live_story peer peer
 * @return Update
 */

final class UpdateGroupCall extends Instance {
	public function request(object $call,null | bool $live_story = null,null | object $peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9d2216e0);
		$flags = 0;
		$flags |= $live_story ? (1 << 2) : 0;
		$flags |= is_null($peer) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		$writer->writeObject($call);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['live_story'] = boolval($flags & (1 << 2));
		if($flags & (1 << 1)):
			$result['peer'] = $reader->readObject();
		else:
			$result['peer'] = null;
		endif;
		$result['call'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string short_name
 * @return stickers.SuggestedShortName
 */

final class SuggestedShortName extends Instance {
	public function request(string $short_name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x85fea03f);
		$writer->writeBytes($short_name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['short_name'] = $reader->readBytes();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<storyviews> views Vector<user> users
 * @return stories.StoryViews
 */

final class StoryViews extends Instance {
	public function request(array $views,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xde9eed1d);
		$writer->writeVector($views,'storyviews');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['views'] = $reader->readVector('storyviews');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string state storiesstealthmode stealth_mode
 * @return stories.AllStories
 */

final class AllStoriesNotModified extends Instance {
	public function request(string $state,object $stealth_mode) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1158fe3e);
		$flags = 0;
		$writer->writeInt($flags);
		$writer->writeBytes($state);
		$writer->writeObject($stealth_mode);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['state'] = $reader->readBytes();
		$result['stealth_mode'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<storyreaction> reactions Vector<chat> chats Vector<user> users string next_offset
 * @return stories.StoryReactionsList
 */

final class StoryReactionsList extends Instance {
	public function request(int $count,array $reactions,array $chats,array $users,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaa5f789c);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeVector($reactions,'storyreaction');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['count'] = $reader->readInt();
		$result['reactions'] = $reader->readVector('storyreaction');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count int views_count int forwards_count int reactions_count Vector<storyview> views Vector<chat> chats Vector<user> users string next_offset
 * @return stories.StoryViewsList
 */

final class StoryViewsList extends Instance {
	public function request(int $count,int $views_count,int $forwards_count,int $reactions_count,array $views,array $chats,array $users,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x59d78fc5);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeInt($views_count);
		$writer->writeInt($forwards_count);
		$writer->writeInt($reactions_count);
		$writer->writeVector($views,'storyview');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['count'] = $reader->readInt();
		$result['views_count'] = $reader->readInt();
		$result['forwards_count'] = $reader->readInt();
		$result['reactions_count'] = $reader->readInt();
		$result['views'] = $reader->readVector('storyview');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash Vector<storyalbum> albums
 * @return stories.Albums
 */

final class Albums extends Instance {
	public function request(int $hash,array $albums) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc3987a3a);
		$writer->writeLong($hash);
		$writer->writeVector($albums,'storyalbum');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['hash'] = $reader->readLong();
		$result['albums'] = $reader->readVector('storyalbum');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param peerstories stories Vector<chat> chats Vector<user> users
 * @return stories.PeerStories
 */

final class PeerStories extends Instance {
	public function request(object $stories,array $chats,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcae68768);
		$writer->writeObject($stories);
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['stories'] = $reader->readObject();
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return stories.Albums
 */

final class AlbumsNotModified extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x564edaeb);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count_remains
 * @return stories.CanSendStoryCount
 */

final class CanSendStoryCount extends Instance {
	public function request(int $count_remains) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc387c04e);
		$writer->writeInt($count_remains);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['count_remains'] = $reader->readInt();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<foundstory> stories Vector<chat> chats Vector<user> users string next_offset
 * @return stories.FoundStories
 */

final class FoundStories extends Instance {
	public function request(int $count,array $stories,array $chats,array $users,null | string $next_offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe2de7737);
		$flags = 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeVector($stories,'foundstory');
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['count'] = $reader->readInt();
		$result['stories'] = $reader->readVector('foundstory');
		if($flags & (1 << 0)):
			$result['next_offset'] = $reader->readBytes();
		else:
			$result['next_offset'] = null;
		endif;
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count Vector<storyitem> stories Vector<chat> chats Vector<user> users Vector<int> pinned_to_top
 * @return stories.Stories
 */

final class Stories extends Instance {
	public function request(int $count,array $stories,array $chats,array $users,null | array $pinned_to_top = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x63c3dd0a);
		$flags = 0;
		$flags |= is_null($pinned_to_top) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeVector($stories,'storyitem');
		if(is_null($pinned_to_top) === false):
			$writer->writeVector($pinned_to_top,'int');
		endif;
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['count'] = $reader->readInt();
		$result['stories'] = $reader->readVector('storyitem');
		if($flags & (1 << 0)):
			$result['pinned_to_top'] = $reader->readVector('int');
		else:
			$result['pinned_to_top'] = null;
		endif;
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Types\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int count string state Vector<peerstories> peer_stories Vector<chat> chats Vector<user> users storiesstealthmode stealth_mode true has_more
 * @return stories.AllStories
 */

final class AllStories extends Instance {
	public function request(int $count,string $state,array $peer_stories,array $chats,array $users,object $stealth_mode,null | bool $has_more = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6efc5e81);
		$flags = 0;
		$flags |= $has_more ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($count);
		$writer->writeBytes($state);
		$writer->writeVector($peer_stories,'peerstories');
		$writer->writeVector($chats,'chat');
		$writer->writeVector($users,'user');
		$writer->writeObject($stealth_mode);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$flags = $reader->readInt();
		$result['has_more'] = boolval($flags & (1 << 0));
		$result['count'] = $reader->readInt();
		$result['state'] = $reader->readBytes();
		$result['peer_stories'] = $reader->readVector('peerstories');
		$result['chats'] = $reader->readVector('chat');
		$result['users'] = $reader->readVector('user');
		$result['stealth_mode'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string token long x
 * @return StatsGraph
 */

final class LoadAsyncGraph extends Instance {
	public function request(string $token,null | int $x = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x621d5fa0);
		$flags = 0;
		$flags |= is_null($x) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($token);
		if(is_null($x) === false):
			$writer->writeLong($x);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel true dark
 * @return stats.BroadcastStats
 */

final class GetBroadcastStats extends Instance {
	public function request(object $channel,null | bool $dark = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xab42441a);
		$flags = 0;
		$flags |= $dark ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel int msg_id true dark
 * @return stats.MessageStats
 */

final class GetMessageStats extends Instance {
	public function request(object $channel,int $msg_id,null | bool $dark = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb6e0a3f5);
		$flags = 0;
		$flags |= $dark ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel int msg_id string offset int limit
 * @return stats.PublicForwards
 */

final class GetMessagePublicForwards extends Instance {
	public function request(object $channel,int $msg_id,string $offset,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5f150144);
		$writer->writeObject($channel);
		$writer->writeInt($msg_id);
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel true dark
 * @return stats.MegagroupStats
 */

final class GetMegagroupStats extends Instance {
	public function request(object $channel,null | bool $dark = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdcdf8607);
		$flags = 0;
		$flags |= $dark ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id string offset int limit
 * @return stats.PublicForwards
 */

final class GetStoryPublicForwards extends Instance {
	public function request(object $peer,int $id,string $offset,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa6437ef6);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id true dark
 * @return stats.PollStats
 */

final class GetPollStats extends Instance {
	public function request(object $peer,int $msg_id,null | bool $dark = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc27dfa68);
		$flags = 0;
		$flags |= $dark ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stats;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id true dark
 * @return stats.StoryStats
 */

final class GetStoryStats extends Instance {
	public function request(object $peer,int $id,null | bool $dark = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x374fef40);
		$flags = 0;
		$flags |= $dark ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel int boosts
 * @return Updates
 */

final class SetBoostsToUnblockRestrictions extends Instance {
	public function request(object $channel,int $boosts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xad399cee);
		$writer->writeObject($channel);
		$writer->writeInt($boosts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset_rate inputpeer offset_peer int offset_id int limit string hashtag string query long allow_paid_stars
 * @return messages.Messages
 */

final class SearchPosts extends Instance {
	public function request(int $offset_rate,object $offset_peer,int $offset_id,int $limit,null | string $hashtag = null,null | string $query = null,null | int $allow_paid_stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf2c4f24d);
		$flags = 0;
		$flags |= is_null($hashtag) ? 0 : (1 << 0);
		$flags |= is_null($query) ? 0 : (1 << 1);
		$flags |= is_null($allow_paid_stars) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($hashtag) === false):
			$writer->writeBytes($hashtag);
		endif;
		if(is_null($query) === false):
			$writer->writeBytes($query);
		endif;
		$writer->writeInt($offset_rate);
		$writer->writeObject($offset_peer);
		$writer->writeInt($offset_id);
		$writer->writeInt($limit);
		if(is_null($allow_paid_stars) === false):
			$writer->writeLong($allow_paid_stars);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer true for_paid_reactions true for_live_stories
 * @return channels.SendAsPeers
 */

final class GetSendAs extends Instance {
	public function request(object $peer,null | bool $for_paid_reactions = null,null | bool $for_live_stories = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe785a43f);
		$flags = 0;
		$flags |= $for_paid_reactions ? (1 << 0) : 0;
		$flags |= $for_live_stories ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel bool enabled
 * @return Updates
 */

final class ToggleAutotranslation extends Instance {
	public function request(object $channel,bool $enabled) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x167fc0a1);
		$writer->writeObject($channel);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel bool enabled
 * @return Updates
 */

final class TogglePreHistoryHidden extends Instance {
	public function request(object $channel,bool $enabled) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeabbb94c);
		$writer->writeObject($channel);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel string title
 * @return Updates
 */

final class EditTitle extends Instance {
	public function request(object $channel,string $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x566decd0);
		$writer->writeObject($channel);
		$writer->writeBytes($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true by_location true check_limit true for_personal
 * @return messages.Chats
 */

final class GetAdminedPublicChannels extends Instance {
	public function request(null | bool $by_location = null,null | bool $check_limit = null,null | bool $for_personal = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf8b036af);
		$flags = 0;
		$flags |= $by_location ? (1 << 0) : 0;
		$flags |= $check_limit ? (1 << 1) : 0;
		$flags |= $for_personal ? (1 << 2) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel int max_id
 * @return Bool
 */

final class ReadHistory extends Instance {
	public function request(object $channel,int $max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcc104937);
		$writer->writeObject($channel);
		$writer->writeInt($max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel string username
 * @return Bool
 */

final class UpdateUsername extends Instance {
	public function request(object $channel,string $username) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3514b3de);
		$writer->writeObject($channel);
		$writer->writeBytes($username);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel string username
 * @return Bool
 */

final class CheckUsername extends Instance {
	public function request(object $channel,string $username) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x10e6bd2c);
		$writer->writeObject($channel);
		$writer->writeBytes($username);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel int id true grouped true thread
 * @return ExportedMessageLink
 */

final class ExportMessageLink extends Instance {
	public function request(object $channel,int $id,null | bool $grouped = null,null | bool $thread = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe63fadeb);
		$flags = 0;
		$flags |= $grouped ? (1 << 0) : 0;
		$flags |= $thread ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel bool enabled
 * @return Updates
 */

final class ToggleParticipantsHidden extends Instance {
	public function request(object $channel,bool $enabled) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6a6e7854);
		$writer->writeObject($channel);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel string username bool active
 * @return Bool
 */

final class ToggleUsername extends Instance {
	public function request(object $channel,string $username,bool $active) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x50f24105);
		$writer->writeObject($channel);
		$writer->writeBytes($username);
		$writer->writeBool($active);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel Vector<string> order
 * @return Bool
 */

final class ReorderUsernames extends Instance {
	public function request(object $channel,array $order) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb45ced1d);
		$writer->writeObject($channel);
		$writer->writeVector($order,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel channelparticipantsfilter filter int offset int limit long hash
 * @return channels.ChannelParticipants
 */

final class GetParticipants extends Instance {
	public function request(object $channel,object $filter,int $offset,int $limit,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x77ced9d0);
		$writer->writeObject($channel);
		$writer->writeObject($filter);
		$writer->writeInt($offset);
		$writer->writeInt($limit);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel bool enabled true apply_to_invites inputuser guard_bot
 * @return Updates
 */

final class ToggleJoinRequest extends Instance {
	public function request(object $channel,bool $enabled,null | bool $apply_to_invites = null,null | object $guard_bot = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xecc2618);
		$flags = 0;
		$flags |= $apply_to_invites ? (1 << 1) : 0;
		$flags |= is_null($guard_bot) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		$writer->writeBool($enabled);
		if(is_null($guard_bot) === false):
			$writer->writeObject($guard_bot);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel inputgeopoint geo_point string address
 * @return Bool
 */

final class EditLocation extends Instance {
	public function request(object $channel,object $geo_point,string $address) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x58e63f6d);
		$writer->writeObject($channel);
		$writer->writeObject($geo_point);
		$writer->writeBytes($address);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel inputstickerset stickerset
 * @return Bool
 */

final class SetEmojiStickers extends Instance {
	public function request(object $channel,object $stickerset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3cd930b7);
		$writer->writeObject($channel);
		$writer->writeObject($stickerset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputchannel> id
 * @return messages.Chats
 */

final class GetChannels extends Instance {
	public function request(array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa7f6bbb);
		$writer->writeVector($id,'inputchannel');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel inputpeer participant
 * @return messages.AffectedHistory
 */

final class DeleteParticipantHistory extends Instance {
	public function request(object $channel,object $participant) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x367544db);
		$writer->writeObject($channel);
		$writer->writeObject($participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel inputpeer participant chatbannedrights banned_rights
 * @return Updates
 */

final class EditBanned extends Instance {
	public function request(object $channel,object $participant,object $banned_rights) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x96e6cd81);
		$writer->writeObject($channel);
		$writer->writeObject($participant);
		$writer->writeObject($banned_rights);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel
 * @return Bool
 */

final class DeactivateAllUsernames extends Instance {
	public function request(object $channel) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa245dd3);
		$writer->writeObject($channel);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel inputuser user_id chatadminrights admin_rights string rank
 * @return Updates
 */

final class EditAdmin extends Instance {
	public function request(object $channel,object $user_id,object $admin_rights,null | string $rank = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9a98ad68);
		$flags = 0;
		$flags |= is_null($rank) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		$writer->writeObject($user_id);
		$writer->writeObject($admin_rights);
		if(is_null($rank) === false):
			$writer->writeBytes($rank);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel int seconds
 * @return Updates
 */

final class ToggleSlowMode extends Instance {
	public function request(object $channel,int $seconds) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xedd49ef0);
		$writer->writeObject($channel);
		$writer->writeInt($seconds);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel inputstickerset stickerset
 * @return Bool
 */

final class SetStickers extends Instance {
	public function request(object $channel,object $stickerset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xea8ca4f9);
		$writer->writeObject($channel);
		$writer->writeObject($stickerset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel int msg_id
 * @return Bool
 */

final class ReportAntiSpamFalsePositive extends Instance {
	public function request(object $channel,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa850a693);
		$writer->writeObject($channel);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title string about true broadcast true megagroup true for_import true forum inputgeopoint geo_point string address int ttl_period
 * @return Updates
 */

final class CreateChannel extends Instance {
	public function request(string $title,string $about,null | bool $broadcast = null,null | bool $megagroup = null,null | bool $for_import = null,null | bool $forum = null,null | object $geo_point = null,null | string $address = null,null | int $ttl_period = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x91006707);
		$flags = 0;
		$flags |= $broadcast ? (1 << 0) : 0;
		$flags |= $megagroup ? (1 << 1) : 0;
		$flags |= $for_import ? (1 << 3) : 0;
		$flags |= $forum ? (1 << 5) : 0;
		$flags |= is_null($geo_point) ? 0 : (1 << 2);
		$flags |= is_null($address) ? 0 : (1 << 2);
		$flags |= is_null($ttl_period) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeBytes($title);
		$writer->writeBytes($about);
		if(is_null($geo_point) === false):
			$writer->writeObject($geo_point);
		endif;
		if(is_null($address) === false):
			$writer->writeBytes($address);
		endif;
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel Vector<inputmessage> id
 * @return messages.Messages
 */

final class GetMessages extends Instance {
	public function request(object $channel,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xad8c9a23);
		$writer->writeObject($channel);
		$writer->writeVector($id,'inputmessage');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel bool enabled
 * @return Updates
 */

final class ToggleAntiSpam extends Instance {
	public function request(object $channel,bool $enabled) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x68f3e4eb);
		$writer->writeObject($channel);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel int id
 * @return User
 */

final class GetMessageAuthor extends Instance {
	public function request(object $channel,int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xece2a0e6);
		$writer->writeObject($channel);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.InactiveChats
 */

final class GetInactiveChannels extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x11e831ee);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel long send_paid_messages_stars true broadcast_messages_allowed
 * @return Updates
 */

final class UpdatePaidMessagesPrice extends Instance {
	public function request(object $channel,int $send_paid_messages_stars,null | bool $broadcast_messages_allowed = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4b12327b);
		$flags = 0;
		$flags |= $broadcast_messages_allowed ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		$writer->writeLong($send_paid_messages_stars);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel bool enabled bool tabs
 * @return Updates
 */

final class ToggleForum extends Instance {
	public function request(object $channel,bool $enabled,bool $tabs) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3ff75734);
		$writer->writeObject($channel);
		$writer->writeBool($enabled);
		$writer->writeBool($tabs);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel Vector<int> id
 * @return Bool
 */

final class ReadMessageContents extends Instance {
	public function request(object $channel,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeab5dc38);
		$writer->writeObject($channel);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel
 * @return Updates
 */

final class ConvertToGigagroup extends Instance {
	public function request(object $channel) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb290c69);
		$writer->writeObject($channel);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel broadcast inputchannel group
 * @return Bool
 */

final class SetDiscussionGroup extends Instance {
	public function request(object $broadcast,object $group) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x40582bb2);
		$writer->writeObject($broadcast);
		$writer->writeObject($group);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel int max_id true for_everyone
 * @return Updates
 */

final class DeleteHistory extends Instance {
	public function request(object $channel,int $max_id,null | bool $for_everyone = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9baa9647);
		$flags = 0;
		$flags |= $for_everyone ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		$writer->writeInt($max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel inputpeer participant
 * @return channels.ChannelParticipant
 */

final class GetParticipant extends Instance {
	public function request(object $channel,object $participant) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa0ab6cc6);
		$writer->writeObject($channel);
		$writer->writeObject($participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel profiletab tab
 * @return Bool
 */

final class SetMainProfileTab extends Instance {
	public function request(object $channel,object $tab) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3583fcb1);
		$writer->writeObject($channel);
		$writer->writeObject($tab);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel emojistatus emoji_status
 * @return Updates
 */

final class UpdateEmojiStatus extends Instance {
	public function request(object $channel,object $emoji_status) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf0d3e6a8);
		$writer->writeObject($channel);
		$writer->writeObject($emoji_status);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel
 * @return messages.Chats
 */

final class GetChannelRecommendations extends Instance {
	public function request(null | object $channel = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x25a71742);
		$flags = 0;
		$flags |= is_null($channel) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($channel) === false):
			$writer->writeObject($channel);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel
 * @return Updates
 */

final class DeleteChannel extends Instance {
	public function request(object $channel) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc0111fe3);
		$writer->writeObject($channel);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel
 * @return messages.ChatFull
 */

final class GetFullChannel extends Instance {
	public function request(object $channel) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8736a09);
		$writer->writeObject($channel);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel string q long max_id long min_id int limit channeladminlogeventsfilter events_filter Vector<inputuser> admins
 * @return channels.AdminLogResults
 */

final class GetAdminLog extends Instance {
	public function request(object $channel,string $q,int $max_id,int $min_id,int $limit,null | object $events_filter = null,null | array $admins = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x33ddf480);
		$flags = 0;
		$flags |= is_null($events_filter) ? 0 : (1 << 0);
		$flags |= is_null($admins) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		$writer->writeBytes($q);
		if(is_null($events_filter) === false):
			$writer->writeObject($events_filter);
		endif;
		if(is_null($admins) === false):
			$writer->writeVector($admins,'inputuser');
		endif;
		$writer->writeLong($max_id);
		$writer->writeLong($min_id);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel Vector<inputuser> users
 * @return messages.InvitedUsers
 */

final class InviteToChannel extends Instance {
	public function request(object $channel,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc9e33d54);
		$writer->writeObject($channel);
		$writer->writeVector($users,'inputuser');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel bool enabled
 * @return Updates
 */

final class ToggleJoinToSend extends Instance {
	public function request(object $channel,bool $enabled) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe4cb9580);
		$writer->writeObject($channel);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel inputchatphoto photo
 * @return Updates
 */

final class EditPhoto extends Instance {
	public function request(object $channel,object $photo) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf12e57c9);
		$writer->writeObject($channel);
		$writer->writeObject($photo);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel Vector<int> id
 * @return messages.AffectedMessages
 */

final class DeleteMessages extends Instance {
	public function request(object $channel,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x84c1fd4e);
		$writer->writeObject($channel);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel bool restricted
 * @return Updates
 */

final class RestrictSponsoredMessages extends Instance {
	public function request(object $channel,bool $restricted) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9ae91519);
		$writer->writeObject($channel);
		$writer->writeBool($restricted);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string query
 * @return SearchPostsFlood
 */

final class CheckSearchPostsFlood extends Instance {
	public function request(null | string $query = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x22567115);
		$flags = 0;
		$flags |= is_null($query) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($query) === false):
			$writer->writeBytes($query);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel bool enabled
 * @return Updates
 */

final class ToggleViewForumAsMessages extends Instance {
	public function request(object $channel,bool $enabled) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9738bb15);
		$writer->writeObject($channel);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.Chats
 */

final class GetGroupsForDiscussion extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf5dad378);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel true for_profile int color long background_emoji_id
 * @return Updates
 */

final class UpdateColor extends Instance {
	public function request(object $channel,null | bool $for_profile = null,null | int $color = null,null | int $background_emoji_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd8aa3671);
		$flags = 0;
		$flags |= $for_profile ? (1 << 1) : 0;
		$flags |= is_null($color) ? 0 : (1 << 2);
		$flags |= is_null($background_emoji_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		if(is_null($color) === false):
			$writer->writeInt($color);
		endif;
		if(is_null($background_emoji_id) === false):
			$writer->writeLong($background_emoji_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset
 * @return messages.Chats
 */

final class GetLeftChannels extends Instance {
	public function request(int $offset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8341ecc0);
		$writer->writeInt($offset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel
 * @return messages.ChatInviteJoinResult
 */

final class JoinChannel extends Instance {
	public function request(object $channel) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7f6a1e22);
		$writer->writeObject($channel);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel true signatures_enabled true profiles_enabled
 * @return Updates
 */

final class ToggleSignatures extends Instance {
	public function request(object $channel,null | bool $signatures_enabled = null,null | bool $profiles_enabled = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x418d549c);
		$flags = 0;
		$flags |= $signatures_enabled ? (1 << 0) : 0;
		$flags |= $profiles_enabled ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel inputpeer participant Vector<int> id
 * @return Bool
 */

final class ReportSpam extends Instance {
	public function request(object $channel,object $participant,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf44a8315);
		$writer->writeObject($channel);
		$writer->writeObject($participant);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Channels;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel
 * @return Updates
 */

final class LeaveChannel extends Instance {
	public function request(object $channel) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf836aa95);
		$writer->writeObject($channel);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id string title
 * @return Updates
 */

final class EditChatTitle extends Instance {
	public function request(int $chat_id,string $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x73783ffd);
		$writer->writeLong($chat_id);
		$writer->writeBytes($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string bot_query_id inputbotinlineresult result
 * @return WebViewMessageSent
 */

final class SendWebViewResultMessage extends Instance {
	public function request(string $bot_query_id,object $result) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa4314f5);
		$writer->writeBytes($bot_query_id);
		$writer->writeObject($result);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id bytes option
 * @return Updates
 */

final class DeletePollAnswer extends Instance {
	public function request(object $peer,int $msg_id,string $option) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xac8505a5);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeBytes($option);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string to_lang inputpeer peer Vector<int> id Vector<textwithentities> text string tone
 * @return messages.TranslatedText
 */

final class TranslateText extends Instance {
	public function request(string $to_lang,null | object $peer = null,null | array $id = null,null | array $text = null,null | string $tone = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa5eec345);
		$flags = 0;
		$flags |= is_null($peer) ? 0 : (1 << 0);
		$flags |= is_null($id) ? 0 : (1 << 0);
		$flags |= is_null($text) ? 0 : (1 << 1);
		$flags |= is_null($tone) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		if(is_null($id) === false):
			$writer->writeVector($id,'int');
		endif;
		if(is_null($text) === false):
			$writer->writeVector($text,'textwithentities');
		endif;
		$writer->writeBytes($to_lang);
		if(is_null($tone) === false):
			$writer->writeBytes($tone);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputreplyto reply_to long random_id
 * @return Updates
 */

final class SendScreenshotNotification extends Instance {
	public function request(object $peer,object $reply_to,int $random_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa1405817);
		$writer->writeObject($peer);
		$writer->writeObject($reply_to);
		$writer->writeLong($random_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string title long random_id true title_missing int icon_color long icon_emoji_id inputpeer send_as
 * @return Updates
 */

final class CreateForumTopic extends Instance {
	public function request(object $peer,string $title,int $random_id,null | bool $title_missing = null,null | int $icon_color = null,null | int $icon_emoji_id = null,null | object $send_as = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2f98c3d5);
		$flags = 0;
		$flags |= $title_missing ? (1 << 4) : 0;
		$flags |= is_null($icon_color) ? 0 : (1 << 0);
		$flags |= is_null($icon_emoji_id) ? 0 : (1 << 3);
		$flags |= is_null($send_as) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBytes($title);
		if(is_null($icon_color) === false):
			$writer->writeInt($icon_color);
		endif;
		if(is_null($icon_emoji_id) === false):
			$writer->writeLong($icon_emoji_id);
		endif;
		$writer->writeLong($random_id);
		if(is_null($send_as) === false):
			$writer->writeObject($send_as);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id
 * @return Updates
 */

final class SendScheduledMessages extends Instance {
	public function request(object $peer,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd38850a);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> order true masks true emojis
 * @return Bool
 */

final class ReorderStickerSets extends Instance {
	public function request(array $order,null | bool $masks = null,null | bool $emojis = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x78337739);
		$flags = 0;
		$flags |= $masks ? (1 << 0) : 0;
		$flags |= $emojis ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($order,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Updates
 */

final class GetAllDrafts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6a3f8d65);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.DialogFilters
 */

final class GetDialogFilters extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xefd48c89);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return ChatOnlines
 */

final class GetOnlines extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6e2be050);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return messages.QuickReplies
 */

final class GetQuickReplies extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd483f2a8);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot
 * @return AttachMenuBotsBot
 */

final class GetAttachMenuBot extends Instance {
	public function request(object $bot) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x77216192);
		$writer->writeObject($bot);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q long hash true exclude_featured
 * @return messages.FoundStickerSets
 */

final class SearchEmojiStickerSets extends Instance {
	public function request(string $q,int $hash,null | bool $exclude_featured = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x92b4494c);
		$flags = 0;
		$flags |= $exclude_featured ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($q);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id true game bytes data inputcheckpasswordsrp password
 * @return messages.BotCallbackAnswer
 */

final class GetBotCallbackAnswer extends Instance {
	public function request(object $peer,int $msg_id,null | bool $game = null,null | string $data = null,null | object $password = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9342ca07);
		$flags = 0;
		$flags |= $game ? (1 << 1) : 0;
		$flags |= is_null($data) ? 0 : (1 << 0);
		$flags |= is_null($password) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		if(is_null($data) === false):
			$writer->writeBytes($data);
		endif;
		if(is_null($password) === false):
			$writer->writeObject($password);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int topic_id bool pinned
 * @return Updates
 */

final class UpdatePinnedForumTopic extends Instance {
	public function request(object $peer,int $topic_id,bool $pinned) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x175df251);
		$writer->writeObject($peer);
		$writer->writeInt($topic_id);
		$writer->writeBool($pinned);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id long poll_hash
 * @return Updates
 */

final class GetPollResults extends Instance {
	public function request(object $peer,int $msg_id,int $poll_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeda3e33b);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeLong($poll_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer true legacy_revoke_permanent true request_needed int expire_date int usage_limit string title starssubscriptionpricing subscription_pricing
 * @return ExportedChatInvite
 */

final class ExportChatInvite extends Instance {
	public function request(object $peer,null | bool $legacy_revoke_permanent = null,null | bool $request_needed = null,null | int $expire_date = null,null | int $usage_limit = null,null | string $title = null,null | object $subscription_pricing = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa455de90);
		$flags = 0;
		$flags |= $legacy_revoke_permanent ? (1 << 2) : 0;
		$flags |= $request_needed ? (1 << 3) : 0;
		$flags |= is_null($expire_date) ? 0 : (1 << 0);
		$flags |= is_null($usage_limit) ? 0 : (1 << 1);
		$flags |= is_null($title) ? 0 : (1 << 4);
		$flags |= is_null($subscription_pricing) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($expire_date) === false):
			$writer->writeInt($expire_date);
		endif;
		if(is_null($usage_limit) === false):
			$writer->writeInt($usage_limit);
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($subscription_pricing) === false):
			$writer->writeObject($subscription_pricing);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputuser admin_id
 * @return Bool
 */

final class DeleteRevokedExportedChatInvites extends Instance {
	public function request(object $peer,object $admin_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x56987bd5);
		$writer->writeObject($peer);
		$writer->writeObject($admin_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int max_id
 * @return messages.AffectedMessages
 */

final class ReadHistory extends Instance {
	public function request(object $peer,int $max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe306d3a);
		$writer->writeObject($peer);
		$writer->writeInt($max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id inputuser user_id int fwd_limit
 * @return messages.InvitedUsers
 */

final class AddChatUser extends Instance {
	public function request(int $chat_id,object $user_id,int $fwd_limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcbc6d107);
		$writer->writeLong($chat_id);
		$writer->writeObject($user_id);
		$writer->writeInt($fwd_limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int max_id
 * @return Vector<ReceivedNotifyMessage>
 */

final class ReceivedMessages extends Instance {
	public function request(int $max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5a954c0);
		$writer->writeInt($max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return messages.AvailableEffects
 */

final class GetAvailableEffects extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdea20a39);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputdialogpeer> order true force
 * @return Bool
 */

final class ReorderPinnedSavedDialogs extends Instance {
	public function request(array $order,null | bool $force = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8b716587);
		$flags = 0;
		$flags |= $force ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($order,'inputdialogpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer bool enabled int request_msg_id
 * @return Updates
 */

final class ToggleNoForwards extends Instance {
	public function request(object $peer,bool $enabled,null | int $request_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb2081a35);
		$flags = 0;
		$flags |= is_null($request_msg_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBool($enabled);
		if(is_null($request_msg_id) === false):
			$writer->writeInt($request_msg_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id
 * @return Bool
 */

final class DeleteQuickReplyShortcut extends Instance {
	public function request(int $shortcut_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3cc04740);
		$writer->writeInt($shortcut_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.EmojiGameInfo
 */

final class GetEmojiGameInfo extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfb7e8ca7);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument id bool unfave
 * @return Bool
 */

final class FaveSticker extends Instance {
	public function request(object $id,bool $unfave) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb9ffc55b);
		$writer->writeObject($id);
		$writer->writeBool($unfave);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputuser> users string title int ttl_period
 * @return messages.InvitedUsers
 */

final class CreateChat extends Instance {
	public function request(array $users,string $title,null | int $ttl_period = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x92ceddd4);
		$flags = 0;
		$flags |= is_null($ttl_period) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeVector($users,'inputuser');
		$writer->writeBytes($title);
		if(is_null($ttl_period) === false):
			$writer->writeInt($ttl_period);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer messagesfilter filter int offset_id int limit inputpeer saved_peer_id
 * @return messages.SearchResultsPositions
 */

final class GetSearchResultsPositions extends Instance {
	public function request(object $peer,object $filter,int $offset_id,int $limit,null | object $saved_peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9c7f2f10);
		$flags = 0;
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		$writer->writeObject($filter);
		$writer->writeInt($offset_id);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return messages.EmojiGroups
 */

final class GetEmojiStatusGroups extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2ecd56cd);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int version int random_length
 * @return messages.DhConfig
 */

final class GetDhConfig extends Instance {
	public function request(int $version,int $random_length) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x26cf8950);
		$writer->writeInt($version);
		$writer->writeInt($random_length);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int period
 * @return Bool
 */

final class SetDefaultHistoryTTL extends Instance {
	public function request(int $period) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9eb51445);
		$writer->writeInt($period);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long offset_id int limit
 * @return messages.MyStickers
 */

final class GetMyStickers extends Instance {
	public function request(int $offset_id,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd0b5e1fc);
		$writer->writeLong($offset_id);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string q messagesfilter filter int min_date int max_date int offset_id int add_offset int limit int max_id int min_id long hash inputpeer from_id inputpeer saved_peer_id Vector<reaction> saved_reaction int top_msg_id
 * @return messages.Messages
 */

final class Search extends Instance {
	public function request(object $peer,string $q,object $filter,int $min_date,int $max_date,int $offset_id,int $add_offset,int $limit,int $max_id,int $min_id,int $hash,null | object $from_id = null,null | object $saved_peer_id = null,null | array $saved_reaction = null,null | int $top_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x29ee847a);
		$flags = 0;
		$flags |= is_null($from_id) ? 0 : (1 << 0);
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 2);
		$flags |= is_null($saved_reaction) ? 0 : (1 << 3);
		$flags |= is_null($top_msg_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBytes($q);
		if(is_null($from_id) === false):
			$writer->writeObject($from_id);
		endif;
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		if(is_null($saved_reaction) === false):
			$writer->writeVector($saved_reaction,'reaction');
		endif;
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		$writer->writeObject($filter);
		$writer->writeInt($min_date);
		$writer->writeInt($max_date);
		$writer->writeInt($offset_id);
		$writer->writeInt($add_offset);
		$writer->writeInt($limit);
		$writer->writeInt($max_id);
		$writer->writeInt($min_id);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputencryptedchat peer long random_id bytes data true silent
 * @return messages.SentEncryptedMessage
 */

final class SendEncrypted extends Instance {
	public function request(object $peer,int $random_id,string $data,null | bool $silent = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x44fa7a15);
		$flags = 0;
		$flags |= $silent ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeLong($random_id);
		$writer->writeBytes($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer long import_id
 * @return Bool
 */

final class StartHistoryImport extends Instance {
	public function request(object $peer,int $import_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb43df344);
		$writer->writeObject($peer);
		$writer->writeLong($import_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id textwithentities text
 * @return Updates
 */

final class EditFactCheck extends Instance {
	public function request(object $peer,int $msg_id,object $text) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x589ee75);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeObject($text);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return messages.AllStickers
 */

final class GetMaskStickers extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x640f82b8);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id int read_max_id
 * @return Bool
 */

final class ReadDiscussion extends Instance {
	public function request(object $peer,int $msg_id,int $read_max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf731a9f4);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeInt($read_max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int top_msg_id inputpeer saved_peer_id
 * @return messages.AffectedHistory
 */

final class ReadReactions extends Instance {
	public function request(object $peer,null | int $top_msg_id = null,null | object $saved_peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9ec44f93);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int max_qts
 * @return Vector<long>
 */

final class ReceivedQueue extends Instance {
	public function request(int $max_qts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x55a5bb66);
		$writer->writeInt($max_qts);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer long hash
 * @return messages.Messages
 */

final class GetScheduledHistory extends Instance {
	public function request(object $peer,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf516760b);
		$writer->writeObject($peer);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id true silent true unpin true pm_oneside
 * @return Updates
 */

final class UpdatePinnedMessage extends Instance {
	public function request(object $peer,int $id,null | bool $silent = null,null | bool $unpin = null,null | bool $pm_oneside = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd2aaf7ec);
		$flags = 0;
		$flags |= $silent ? (1 << 0) : 0;
		$flags |= $unpin ? (1 << 1) : 0;
		$flags |= $pm_oneside ? (1 << 2) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string hash
 * @return messages.ChatInviteJoinResult
 */

final class ImportChatInvite extends Instance {
	public function request(string $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xde91436e);
		$writer->writeBytes($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int folder_id Vector<inputdialogpeer> order true force
 * @return Bool
 */

final class ReorderPinnedDialogs extends Instance {
	public function request(int $folder_id,array $order,null | bool $force = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3b1adf37);
		$flags = 0;
		$flags |= $force ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($folder_id);
		$writer->writeVector($order,'inputdialogpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id
 * @return messages.TranscribedAudio
 */

final class TranscribeAudio extends Instance {
	public function request(object $peer,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x269e9a49);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id true push
 * @return Bool
 */

final class ReportMessagesDelivery extends Instance {
	public function request(object $peer,array $id,null | bool $push = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5a6d7395);
		$flags = 0;
		$flags |= $push ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return messages.FeaturedStickers
 */

final class GetFeaturedStickers extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x64780b14);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id
 * @return Updates
 */

final class GetExtendedMedia extends Instance {
	public function request(object $peer,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x84f80814);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickerset stickerset
 * @return Bool
 */

final class UninstallStickerSet extends Instance {
	public function request(object $stickerset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf96e55de);
		$writer->writeObject($stickerset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id inputchatphoto photo
 * @return Updates
 */

final class EditChatPhoto extends Instance {
	public function request(int $chat_id,object $photo) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x35ddd674);
		$writer->writeLong($chat_id);
		$writer->writeObject($photo);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id long transcription_id bool good
 * @return Bool
 */

final class RateTranscribedAudio extends Instance {
	public function request(object $peer,int $msg_id,int $transcription_id,bool $good) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7f1d072f);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeLong($transcription_id);
		$writer->writeBool($good);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<int> order
 * @return Bool
 */

final class UpdateDialogFiltersOrder extends Instance {
	public function request(array $order) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc563c1e4);
		$writer->writeVector($order,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string message true no_webpage true invert_media inputreplyto reply_to Vector<messageentity> entities inputmedia media long effect suggestedpost suggested_post inputrichmessage rich_message
 * @return Bool
 */

final class SaveDraft extends Instance {
	public function request(object $peer,string $message,null | bool $no_webpage = null,null | bool $invert_media = null,null | object $reply_to = null,null | array $entities = null,null | object $media = null,null | int $effect = null,null | object $suggested_post = null,null | object $rich_message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xad0fa15c);
		$flags = 0;
		$flags |= $no_webpage ? (1 << 1) : 0;
		$flags |= $invert_media ? (1 << 6) : 0;
		$flags |= is_null($reply_to) ? 0 : (1 << 4);
		$flags |= is_null($entities) ? 0 : (1 << 3);
		$flags |= is_null($media) ? 0 : (1 << 5);
		$flags |= is_null($effect) ? 0 : (1 << 7);
		$flags |= is_null($suggested_post) ? 0 : (1 << 8);
		$flags |= is_null($rich_message) ? 0 : (1 << 9);
		$writer->writeInt($flags);
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		$writer->writeObject($peer);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($media) === false):
			$writer->writeObject($media);
		endif;
		if(is_null($effect) === false):
			$writer->writeLong($effect);
		endif;
		if(is_null($suggested_post) === false):
			$writer->writeObject($suggested_post);
		endif;
		if(is_null($rich_message) === false):
			$writer->writeObject($rich_message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer true for_both true revert inputwallpaper wallpaper wallpapersettings settings int id
 * @return Updates
 */

final class SetChatWallPaper extends Instance {
	public function request(object $peer,null | bool $for_both = null,null | bool $revert = null,null | object $wallpaper = null,null | object $settings = null,null | int $id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ffacae1);
		$flags = 0;
		$flags |= $for_both ? (1 << 3) : 0;
		$flags |= $revert ? (1 << 4) : 0;
		$flags |= is_null($wallpaper) ? 0 : (1 << 0);
		$flags |= is_null($settings) ? 0 : (1 << 2);
		$flags |= is_null($id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($wallpaper) === false):
			$writer->writeObject($wallpaper);
		endif;
		if(is_null($settings) === false):
			$writer->writeObject($settings);
		endif;
		if(is_null($id) === false):
			$writer->writeInt($id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputuser admin_id int limit true revoked int offset_date string offset_link
 * @return messages.ExportedChatInvites
 */

final class GetExportedChatInvites extends Instance {
	public function request(object $peer,object $admin_id,int $limit,null | bool $revoked = null,null | int $offset_date = null,null | string $offset_link = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa2b5a3f6);
		$flags = 0;
		$flags |= $revoked ? (1 << 3) : 0;
		$flags |= is_null($offset_date) ? 0 : (1 << 2);
		$flags |= is_null($offset_link) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeObject($admin_id);
		if(is_null($offset_date) === false):
			$writer->writeInt($offset_date);
		endif;
		if(is_null($offset_link) === false):
			$writer->writeBytes($offset_link);
		endif;
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument id int listened_duration
 * @return Bool
 */

final class ReportMusicListen extends Instance {
	public function request(object $id,int $listened_duration) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xddbcd819);
		$writer->writeObject($id);
		$writer->writeInt($listened_duration);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int offset_id int offset_date int add_offset int limit int max_id int min_id long hash
 * @return messages.Messages
 */

final class GetHistory extends Instance {
	public function request(object $peer,int $offset_id,int $offset_date,int $add_offset,int $limit,int $max_id,int $min_id,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4423e6c5);
		$writer->writeObject($peer);
		$writer->writeInt($offset_id);
		$writer->writeInt($offset_date);
		$writer->writeInt($add_offset);
		$writer->writeInt($limit);
		$writer->writeInt($max_id);
		$writer->writeInt($min_id);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return User
 */

final class GetFutureChatCreatorAfterLeave extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3b7d0ea6);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id
 * @return messages.Messages
 */

final class GetRichMessage extends Instance {
	public function request(object $peer,int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x501569cf);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer messagesfilter filter int offset_id int offset_date inputpeer saved_peer_id
 * @return messages.SearchResultsCalendar
 */

final class GetSearchResultsCalendar extends Instance {
	public function request(object $peer,object $filter,int $offset_id,int $offset_date,null | object $saved_peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6aa3f6bd);
		$flags = 0;
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		$writer->writeObject($filter);
		$writer->writeInt($offset_id);
		$writer->writeInt($offset_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputuser user_id inputcheckpasswordsrp password
 * @return Updates
 */

final class EditChatCreator extends Instance {
	public function request(object $peer,object $user_id,object $password) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf743b857);
		$writer->writeObject($peer);
		$writer->writeObject($user_id);
		$writer->writeObject($password);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string emoticon long hash
 * @return EmojiList
 */

final class SearchCustomEmoji extends Instance {
	public function request(string $emoticon,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2c11c0d7);
		$writer->writeBytes($emoticon);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id
 * @return messages.ChatFull
 */

final class GetFullChat extends Instance {
	public function request(int $chat_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaeb00b34);
		$writer->writeLong($chat_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string link
 * @return Bool
 */

final class DeleteExportedChatInvite extends Instance {
	public function request(object $peer,string $link) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd464a42b);
		$writer->writeObject($peer);
		$writer->writeBytes($link);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id Vector<todoitem> list
 * @return Updates
 */

final class AppendTodoList extends Instance {
	public function request(object $peer,int $msg_id,array $list) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x21a61057);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeVector($list,'todoitem');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return messages.FeaturedStickers
 */

final class GetFeaturedEmojiStickers extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xecf6736);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id long hash Vector<int> id
 * @return messages.Messages
 */

final class GetQuickReplyMessages extends Instance {
	public function request(int $shortcut_id,int $hash,null | array $id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x94a495c3);
		$flags = 0;
		$flags |= is_null($id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($shortcut_id);
		if(is_null($id) === false):
			$writer->writeVector($id,'int');
		endif;
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> msg_id
 * @return Vector<FactCheck>
 */

final class GetFactCheck extends Instance {
	public function request(object $peer,array $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb9cdc5ee);
		$writer->writeObject($peer);
		$writer->writeVector($msg_id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer true approved string link
 * @return Updates
 */

final class HideAllChatJoinRequests extends Instance {
	public function request(object $peer,null | bool $approved = null,null | string $link = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe085f4ea);
		$flags = 0;
		$flags |= $approved ? (1 << 0) : 0;
		$flags |= is_null($link) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($link) === false):
			$writer->writeBytes($link);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int offset_date int offset_id int offset_topic int limit string q
 * @return messages.ForumTopics
 */

final class GetForumTopics extends Instance {
	public function request(object $peer,int $offset_date,int $offset_id,int $offset_topic,int $limit,null | string $q = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3ba47bff);
		$flags = 0;
		$flags |= is_null($q) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($q) === false):
			$writer->writeBytes($q);
		endif;
		$writer->writeInt($offset_date);
		$writer->writeInt($offset_id);
		$writer->writeInt($offset_topic);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot inputpeer peer string query string offset inputgeopoint geo_point
 * @return messages.BotResults
 */

final class GetInlineBotResults extends Instance {
	public function request(object $bot,object $peer,string $query,string $offset,null | object $geo_point = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x514e999d);
		$flags = 0;
		$flags |= is_null($geo_point) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($bot);
		$writer->writeObject($peer);
		if(is_null($geo_point) === false):
			$writer->writeObject($geo_point);
		endif;
		$writer->writeBytes($query);
		$writer->writeBytes($offset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> id
 * @return messages.Chats
 */

final class GetChats extends Instance {
	public function request(array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x49e9528f);
		$writer->writeVector($id,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<inputmessagereadmetric> metrics
 * @return Bool
 */

final class ReportReadMetrics extends Instance {
	public function request(object $peer,array $metrics) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4067c5e6);
		$writer->writeObject($peer);
		$writer->writeVector($metrics,'inputmessagereadmetric');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int top_msg_id inputpeer saved_peer_id
 * @return messages.AffectedHistory
 */

final class UnpinAllMessages extends Instance {
	public function request(object $peer,null | int $top_msg_id = null,null | object $saved_peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x62dd747);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickerset stickerset int hash
 * @return messages.StickerSet
 */

final class GetStickerSet extends Instance {
	public function request(object $stickerset,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc8a0ec74);
		$writer->writeObject($stickerset);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset_date int offset_id inputpeer offset_peer int limit long hash true exclude_pinned int folder_id
 * @return messages.Dialogs
 */

final class GetDialogs extends Instance {
	public function request(int $offset_date,int $offset_id,object $offset_peer,int $limit,int $hash,null | bool $exclude_pinned = null,null | int $folder_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa0f4cb4f);
		$flags = 0;
		$flags |= $exclude_pinned ? (1 << 0) : 0;
		$flags |= is_null($folder_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($folder_id) === false):
			$writer->writeInt($folder_id);
		endif;
		$writer->writeInt($offset_date);
		$writer->writeInt($offset_id);
		$writer->writeObject($offset_peer);
		$writer->writeInt($limit);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int offset_id int add_offset int limit int max_id int min_id int top_msg_id
 * @return messages.Messages
 */

final class GetUnreadMentions extends Instance {
	public function request(object $peer,int $offset_id,int $add_offset,int $limit,int $max_id,int $min_id,null | int $top_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf107e790);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		$writer->writeInt($offset_id);
		$writer->writeInt($add_offset);
		$writer->writeInt($limit);
		$writer->writeInt($max_id);
		$writer->writeInt($min_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Vector<MessageRange>
 */

final class GetSplitRanges extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1cff7e08);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int period
 * @return Updates
 */

final class SetHistoryTTL extends Instance {
	public function request(object $peer,int $period) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb80e5fe4);
		$writer->writeObject($peer);
		$writer->writeInt($period);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return messages.AllStickers
 */

final class GetEmojiStickers extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfbfca18f);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int top_msg_id
 * @return messages.AffectedHistory
 */

final class ReadMentions extends Instance {
	public function request(object $peer,null | int $top_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x36e5bf4d);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id
 * @return messages.DiscussionMessage
 */

final class GetDiscussionMessage extends Instance {
	public function request(object $peer,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x446972fd);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputfile file int media_count
 * @return messages.HistoryImport
 */

final class InitHistoryImport extends Instance {
	public function request(object $peer,object $file,int $media_count) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x34090c3b);
		$writer->writeObject($peer);
		$writer->writeObject($file);
		$writer->writeInt($media_count);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class ClearAllDrafts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7e58ee9c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool enabled
 * @return Bool
 */

final class ToggleDialogFilterTags extends Instance {
	public function request(bool $enabled) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfd2dda49);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param reaction reaction
 * @return Bool
 */

final class SetDefaultReaction extends Instance {
	public function request(object $reaction) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4f47a016);
		$writer->writeObject($reaction);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return Bool
 */

final class HidePeerSettingsBar extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4facb138);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickeredmedia media
 * @return Vector<StickerSetCovered>
 */

final class GetAttachedStickers extends Instance {
	public function request(object $media) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcc5b67cc);
		$writer->writeObject($media);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url string match_code
 * @return Bool
 */

final class CheckUrlAuthMatchCode extends Instance {
	public function request(string $url,string $match_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc9a47b0b);
		$writer->writeBytes($url);
		$writer->writeBytes($match_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Vector<DialogFilterSuggested>
 */

final class GetSuggestedDialogFilters extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa29cd42c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id inputuser user_id int score true edit_message true force
 * @return Updates
 */

final class SetGameScore extends Instance {
	public function request(object $peer,int $id,object $user_id,int $score,null | bool $edit_message = null,null | bool $force = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ef8ecc0);
		$flags = 0;
		$flags |= $edit_message ? (1 << 0) : 0;
		$flags |= $force ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		$writer->writeObject($user_id);
		$writer->writeInt($score);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer parent_peer inputpeer peer int max_id
 * @return Bool
 */

final class ReadSavedHistory extends Instance {
	public function request(object $parent_peer,object $peer,int $max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xba4a3b5b);
		$writer->writeObject($parent_peer);
		$writer->writeObject($peer);
		$writer->writeInt($max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int offset_date inputuser offset_user int limit true requested true subscription_expired string link string q
 * @return messages.ChatInviteImporters
 */

final class GetChatInviteImporters extends Instance {
	public function request(object $peer,int $offset_date,object $offset_user,int $limit,null | bool $requested = null,null | bool $subscription_expired = null,null | string $link = null,null | string $q = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdf04dd4e);
		$flags = 0;
		$flags |= $requested ? (1 << 0) : 0;
		$flags |= $subscription_expired ? (1 << 3) : 0;
		$flags |= is_null($link) ? 0 : (1 << 1);
		$flags |= is_null($q) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($link) === false):
			$writer->writeBytes($link);
		endif;
		if(is_null($q) === false):
			$writer->writeBytes($q);
		endif;
		$writer->writeInt($offset_date);
		$writer->writeObject($offset_user);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id string error Vector<shippingoption> shipping_options
 * @return Bool
 */

final class SetBotShippingResults extends Instance {
	public function request(int $query_id,null | string $error = null,null | array $shipping_options = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe5f672fa);
		$flags = 0;
		$flags |= is_null($error) ? 0 : (1 << 0);
		$flags |= is_null($shipping_options) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($query_id);
		if(is_null($error) === false):
			$writer->writeBytes($error);
		endif;
		if(is_null($shipping_options) === false):
			$writer->writeVector($shipping_options,'shippingoption');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputchattheme theme
 * @return Updates
 */

final class SetChatTheme extends Instance {
	public function request(object $peer,object $theme) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x81202c9);
		$writer->writeObject($peer);
		$writer->writeObject($theme);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputuser user_id true approved
 * @return Updates
 */

final class HideChatJoinRequest extends Instance {
	public function request(object $peer,object $user_id,null | bool $approved = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7fe7e815);
		$flags = 0;
		$flags |= $approved ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id
 * @return messages.SponsoredMessages
 */

final class GetSponsoredMessages extends Instance {
	public function request(object $peer,null | int $msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3d6ce850);
		$flags = 0;
		$flags |= is_null($msg_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($msg_id) === false):
			$writer->writeInt($msg_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true attached
 * @return Bool
 */

final class ClearRecentStickers extends Instance {
	public function request(null | bool $attached = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8999602d);
		$flags = 0;
		$flags |= $attached ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id int limit bytes option string offset
 * @return messages.VotesList
 */

final class GetPollVotes extends Instance {
	public function request(object $peer,int $id,int $limit,null | string $option = null,null | string $offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb86e380e);
		$flags = 0;
		$flags |= is_null($option) ? 0 : (1 << 0);
		$flags |= is_null($offset) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		if(is_null($option) === false):
			$writer->writeBytes($option);
		endif;
		if(is_null($offset) === false):
			$writer->writeBytes($offset);
		endif;
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int limit long hash
 * @return messages.FeaturedStickers
 */

final class GetOldFeaturedStickers extends Instance {
	public function request(int $offset,int $limit,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7ed094a1);
		$writer->writeInt($offset);
		$writer->writeInt($limit);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q messagesfilter filter int limit
 * @return messages.Messages
 */

final class SearchSentMedia extends Instance {
	public function request(string $q,object $filter,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x107e31a0);
		$writer->writeBytes($q);
		$writer->writeObject($filter);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_code
 * @return EmojiURL
 */

final class GetEmojiURL extends Instance {
	public function request(string $lang_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd5b10c26);
		$writer->writeBytes($lang_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id
 * @return Updates
 */

final class DeleteFactCheck extends Instance {
	public function request(object $peer,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd1da940c);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset_date int offset_id inputpeer offset_peer int limit long hash true exclude_pinned inputpeer parent_peer
 * @return messages.SavedDialogs
 */

final class GetSavedDialogs extends Instance {
	public function request(int $offset_date,int $offset_id,object $offset_peer,int $limit,int $hash,null | bool $exclude_pinned = null,null | object $parent_peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1e91fc99);
		$flags = 0;
		$flags |= $exclude_pinned ? (1 << 0) : 0;
		$flags |= is_null($parent_peer) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($parent_peer) === false):
			$writer->writeObject($parent_peer);
		endif;
		$writer->writeInt($offset_date);
		$writer->writeInt($offset_id);
		$writer->writeObject($offset_peer);
		$writer->writeInt($limit);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputmedia media string business_connection_id
 * @return MessageMedia
 */

final class UploadMedia extends Instance {
	public function request(object $peer,object $media,null | string $business_connection_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x14967978);
		$flags = 0;
		$flags |= is_null($business_connection_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($business_connection_id) === false):
			$writer->writeBytes($business_connection_id);
		endif;
		$writer->writeObject($peer);
		$writer->writeObject($media);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return messages.FavedStickers
 */

final class GetFavedStickers extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4f1aaa9);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputbotinlinemessageid id true no_webpage true invert_media string message inputmedia media replymarkup reply_markup Vector<messageentity> entities inputrichmessage rich_message
 * @return Bool
 */

final class EditInlineBotMessage extends Instance {
	public function request(object $id,null | bool $no_webpage = null,null | bool $invert_media = null,null | string $message = null,null | object $media = null,null | object $reply_markup = null,null | array $entities = null,null | object $rich_message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa423bb51);
		$flags = 0;
		$flags |= $no_webpage ? (1 << 1) : 0;
		$flags |= $invert_media ? (1 << 16) : 0;
		$flags |= is_null($message) ? 0 : (1 << 11);
		$flags |= is_null($media) ? 0 : (1 << 14);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$flags |= is_null($entities) ? 0 : (1 << 3);
		$flags |= is_null($rich_message) ? 0 : (1 << 23);
		$writer->writeInt($flags);
		$writer->writeObject($id);
		if(is_null($message) === false):
			$writer->writeBytes($message);
		endif;
		if(is_null($media) === false):
			$writer->writeObject($media);
		endif;
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($rich_message) === false):
			$writer->writeObject($rich_message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes random_id true media true fullscreen
 * @return Bool
 */

final class ClickSponsoredMessage extends Instance {
	public function request(string $random_id,null | bool $media = null,null | bool $fullscreen = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8235057e);
		$flags = 0;
		$flags |= $media ? (1 << 0) : 0;
		$flags |= $fullscreen ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($random_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id int count long random_id paidreactionprivacy private
 * @return Updates
 */

final class SendPaidReaction extends Instance {
	public function request(object $peer,int $msg_id,int $count,int $random_id,null | object $private = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x58bbcb50);
		$flags = 0;
		$flags |= is_null($private) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeInt($count);
		$writer->writeLong($random_id);
		if(is_null($private) === false):
			$writer->writeObject($private);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id
 * @return Bool
 */

final class DeleteChat extends Instance {
	public function request(int $chat_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5bd0ee50);
		$writer->writeLong($chat_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id bytes option string message
 * @return ReportResult
 */

final class Report extends Instance {
	public function request(object $peer,array $id,string $option,string $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfc78af9b);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		$writer->writeBytes($option);
		$writer->writeBytes($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer parent_peer
 * @return Vector<DialogPeer>
 */

final class GetDialogUnreadMarks extends Instance {
	public function request(null | object $parent_peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x21202222);
		$flags = 0;
		$flags |= is_null($parent_peer) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($parent_peer) === false):
			$writer->writeObject($parent_peer);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputencryptedchat peer bytes g_b long key_fingerprint
 * @return EncryptedChat
 */

final class AcceptEncryption extends Instance {
	public function request(object $peer,string $g_b,int $key_fingerprint) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3dbc0415);
		$writer->writeObject($peer);
		$writer->writeBytes($g_b);
		$writer->writeLong($key_fingerprint);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputbotinlinemessageid id inputuser user_id int score true edit_message true force
 * @return Bool
 */

final class SetInlineGameScore extends Instance {
	public function request(object $id,object $user_id,int $score,null | bool $edit_message = null,null | bool $force = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x15ad9f64);
		$flags = 0;
		$flags |= $edit_message ? (1 << 0) : 0;
		$flags |= $force ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($id);
		$writer->writeObject($user_id);
		$writer->writeInt($score);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes sha256 long size string mime_type
 * @return Document
 */

final class GetDocumentByHash extends Instance {
	public function request(string $sha256,int $size,string $mime_type) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb1f2061f);
		$writer->writeBytes($sha256);
		$writer->writeLong($size);
		$writer->writeBytes($mime_type);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return messages.AllStickers
 */

final class GetAllStickers extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb8a0a1a8);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param textwithentities text true proofread true emojify string translate_to_lang inputaicomposetone tone
 * @return messages.ComposedMessageWithAI
 */

final class ComposeMessageWithAI extends Instance {
	public function request(object $text,null | bool $proofread = null,null | bool $emojify = null,null | string $translate_to_lang = null,null | object $tone = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdaecc589);
		$flags = 0;
		$flags |= $proofread ? (1 << 0) : 0;
		$flags |= $emojify ? (1 << 3) : 0;
		$flags |= is_null($translate_to_lang) ? 0 : (1 << 1);
		$flags |= is_null($tone) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($text);
		if(is_null($translate_to_lang) === false):
			$writer->writeBytes($translate_to_lang);
		endif;
		if(is_null($tone) === false):
			$writer->writeObject($tone);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id true big true add_to_recent Vector<reaction> reaction
 * @return Updates
 */

final class SendReaction extends Instance {
	public function request(object $peer,int $msg_id,null | bool $big = null,null | bool $add_to_recent = null,null | array $reaction = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd30d78d4);
		$flags = 0;
		$flags |= $big ? (1 << 1) : 0;
		$flags |= $add_to_recent ? (1 << 2) : 0;
		$flags |= is_null($reaction) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		if(is_null($reaction) === false):
			$writer->writeVector($reaction,'reaction');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id inputpeer participant
 * @return Updates
 */

final class DeleteParticipantReaction extends Instance {
	public function request(object $peer,int $msg_id,object $participant) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe3b7f82c);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeObject($participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return messages.CheckedHistoryImportPeer
 */

final class CheckHistoryImportPeer extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5dc60f03);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id pollanswer answer
 * @return Updates
 */

final class AddPollAnswer extends Instance {
	public function request(object $peer,int $msg_id,object $answer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x19bc4b6d);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeObject($answer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputmessage> id
 * @return messages.Messages
 */

final class GetMessages extends Instance {
	public function request(array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x63c66506);
		$writer->writeVector($id,'inputmessage');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int limit long hash
 * @return messages.Reactions
 */

final class GetRecentReactions extends Instance {
	public function request(int $limit,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x39461db2);
		$writer->writeInt($limit);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return DefaultHistoryTTL
 */

final class GetDefaultHistoryTTL extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x658b7188);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputuser bot string platform true from_bot_menu true silent true compact true fullscreen string url string start_param datajson theme_params inputreplyto reply_to inputpeer send_as
 * @return WebViewResult
 */

final class RequestWebView extends Instance {
	public function request(object $peer,object $bot,string $platform,null | bool $from_bot_menu = null,null | bool $silent = null,null | bool $compact = null,null | bool $fullscreen = null,null | string $url = null,null | string $start_param = null,null | object $theme_params = null,null | object $reply_to = null,null | object $send_as = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x269dc2c1);
		$flags = 0;
		$flags |= $from_bot_menu ? (1 << 4) : 0;
		$flags |= $silent ? (1 << 5) : 0;
		$flags |= $compact ? (1 << 7) : 0;
		$flags |= $fullscreen ? (1 << 8) : 0;
		$flags |= is_null($url) ? 0 : (1 << 1);
		$flags |= is_null($start_param) ? 0 : (1 << 3);
		$flags |= is_null($theme_params) ? 0 : (1 << 2);
		$flags |= is_null($reply_to) ? 0 : (1 << 0);
		$flags |= is_null($send_as) ? 0 : (1 << 13);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeObject($bot);
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		if(is_null($start_param) === false):
			$writer->writeBytes($start_param);
		endif;
		if(is_null($theme_params) === false):
			$writer->writeObject($theme_params);
		endif;
		$writer->writeBytes($platform);
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		if(is_null($send_as) === false):
			$writer->writeObject($send_as);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputmedia media string message long random_id true silent true background true clear_draft true noforwards true update_stickersets_order true invert_media true allow_paid_floodskip inputreplyto reply_to replymarkup reply_markup Vector<messageentity> entities int schedule_date int schedule_repeat_period inputpeer send_as inputquickreplyshortcut quick_reply_shortcut long effect long allow_paid_stars suggestedpost suggested_post
 * @return Updates
 */

final class SendMedia extends Instance {
	public function request(object $peer,object $media,string $message,int $random_id,null | bool $silent = null,null | bool $background = null,null | bool $clear_draft = null,null | bool $noforwards = null,null | bool $update_stickersets_order = null,null | bool $invert_media = null,null | bool $allow_paid_floodskip = null,null | object $reply_to = null,null | object $reply_markup = null,null | array $entities = null,null | int $schedule_date = null,null | int $schedule_repeat_period = null,null | object $send_as = null,null | object $quick_reply_shortcut = null,null | int $effect = null,null | int $allow_paid_stars = null,null | object $suggested_post = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x330e77f);
		$flags = 0;
		$flags |= $silent ? (1 << 5) : 0;
		$flags |= $background ? (1 << 6) : 0;
		$flags |= $clear_draft ? (1 << 7) : 0;
		$flags |= $noforwards ? (1 << 14) : 0;
		$flags |= $update_stickersets_order ? (1 << 15) : 0;
		$flags |= $invert_media ? (1 << 16) : 0;
		$flags |= $allow_paid_floodskip ? (1 << 19) : 0;
		$flags |= is_null($reply_to) ? 0 : (1 << 0);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$flags |= is_null($entities) ? 0 : (1 << 3);
		$flags |= is_null($schedule_date) ? 0 : (1 << 10);
		$flags |= is_null($schedule_repeat_period) ? 0 : (1 << 24);
		$flags |= is_null($send_as) ? 0 : (1 << 13);
		$flags |= is_null($quick_reply_shortcut) ? 0 : (1 << 17);
		$flags |= is_null($effect) ? 0 : (1 << 18);
		$flags |= is_null($allow_paid_stars) ? 0 : (1 << 21);
		$flags |= is_null($suggested_post) ? 0 : (1 << 22);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		$writer->writeObject($media);
		$writer->writeBytes($message);
		$writer->writeLong($random_id);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($schedule_date) === false):
			$writer->writeInt($schedule_date);
		endif;
		if(is_null($schedule_repeat_period) === false):
			$writer->writeInt($schedule_repeat_period);
		endif;
		if(is_null($send_as) === false):
			$writer->writeObject($send_as);
		endif;
		if(is_null($quick_reply_shortcut) === false):
			$writer->writeObject($quick_reply_shortcut);
		endif;
		if(is_null($effect) === false):
			$writer->writeLong($effect);
		endif;
		if(is_null($allow_paid_stars) === false):
			$writer->writeLong($allow_paid_stars);
		endif;
		if(is_null($suggested_post) === false):
			$writer->writeObject($suggested_post);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int max_id inputpeer parent_peer int min_date int max_date
 * @return messages.AffectedHistory
 */

final class DeleteSavedHistory extends Instance {
	public function request(object $peer,int $max_id,null | object $parent_peer = null,null | int $min_date = null,null | int $max_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4dc5085f);
		$flags = 0;
		$flags |= is_null($parent_peer) ? 0 : (1 << 0);
		$flags |= is_null($min_date) ? 0 : (1 << 2);
		$flags |= is_null($max_date) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($parent_peer) === false):
			$writer->writeObject($parent_peer);
		endif;
		$writer->writeObject($peer);
		$writer->writeInt($max_id);
		if(is_null($min_date) === false):
			$writer->writeInt($min_date);
		endif;
		if(is_null($max_date) === false):
			$writer->writeInt($max_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return messages.SavedGifs
 */

final class GetSavedGifs extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5cf09635);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id inputbotinlineresult result
 * @return InputBotInlineMessageID
 */

final class SetBotGuestChatResult extends Instance {
	public function request(int $query_id,object $result) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb8f106e3);
		$writer->writeLong($query_id);
		$writer->writeObject($result);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot string platform true from_switch_webview true from_side_menu true compact true fullscreen string url string start_param datajson theme_params
 * @return WebViewResult
 */

final class RequestSimpleWebView extends Instance {
	public function request(object $bot,string $platform,null | bool $from_switch_webview = null,null | bool $from_side_menu = null,null | bool $compact = null,null | bool $fullscreen = null,null | string $url = null,null | string $start_param = null,null | object $theme_params = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x413a3e73);
		$flags = 0;
		$flags |= $from_switch_webview ? (1 << 1) : 0;
		$flags |= $from_side_menu ? (1 << 2) : 0;
		$flags |= $compact ? (1 << 7) : 0;
		$flags |= $fullscreen ? (1 << 8) : 0;
		$flags |= is_null($url) ? 0 : (1 << 3);
		$flags |= is_null($start_param) ? 0 : (1 << 4);
		$flags |= is_null($theme_params) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($bot);
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		if(is_null($start_param) === false):
			$writer->writeBytes($start_param);
		endif;
		if(is_null($theme_params) === false):
			$writer->writeObject($theme_params);
		endif;
		$writer->writeBytes($platform);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument id bool unsave
 * @return Bool
 */

final class SaveGif extends Instance {
	public function request(object $id,bool $unsave) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x327a30cb);
		$writer->writeObject($id);
		$writer->writeBool($unsave);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id long max_id int limit
 * @return messages.Chats
 */

final class GetCommonChats extends Instance {
	public function request(object $user_id,int $max_id,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe40ca104);
		$writer->writeObject($user_id);
		$writer->writeLong($max_id);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputencryptedchat peer long random_id bytes data
 * @return messages.SentEncryptedMessage
 */

final class SendEncryptedService extends Instance {
	public function request(object $peer,int $random_id,string $data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x32d439a4);
		$writer->writeObject($peer);
		$writer->writeLong($random_id);
		$writer->writeBytes($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash true attached
 * @return messages.RecentStickers
 */

final class GetRecentStickers extends Instance {
	public function request(int $hash,null | bool $attached = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9da9403b);
		$flags = 0;
		$flags |= $attached ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id
 * @return Updates
 */

final class GetMessagesReactions extends Instance {
	public function request(object $peer,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8bba90e6);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string message Vector<messageentity> entities
 * @return messages.WebPagePreview
 */

final class GetWebPagePreview extends Instance {
	public function request(string $message,null | array $entities = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x570d6f6f);
		$flags = 0;
		$flags |= is_null($entities) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeBytes($message);
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id
 * @return messages.MessageEditData
 */

final class GetMessageEditData extends Instance {
	public function request(object $peer,int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfda68d36);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id Vector<int> completed Vector<int> incompleted
 * @return Updates
 */

final class ToggleTodoCompleted extends Instance {
	public function request(object $peer,int $msg_id,array $completed,array $incompleted) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd3e03124);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeVector($completed,'int');
		$writer->writeVector($incompleted,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int folder_id
 * @return messages.PeerDialogs
 */

final class GetPinnedDialogs extends Instance {
	public function request(int $folder_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd6b94df2);
		$writer->writeInt($folder_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer sendmessageaction action int top_msg_id
 * @return Bool
 */

final class SetTyping extends Instance {
	public function request(object $peer,object $action,null | int $top_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x58943ee2);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		$writer->writeObject($action);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id int button_id string url string in_app_origin
 * @return UrlAuthResult
 */

final class RequestUrlAuth extends Instance {
	public function request(null | object $peer = null,null | int $msg_id = null,null | int $button_id = null,null | string $url = null,null | string $in_app_origin = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x894cc99c);
		$flags = 0;
		$flags |= is_null($peer) ? 0 : (1 << 1);
		$flags |= is_null($msg_id) ? 0 : (1 << 1);
		$flags |= is_null($button_id) ? 0 : (1 << 1);
		$flags |= is_null($url) ? 0 : (1 << 2);
		$flags |= is_null($in_app_origin) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		if(is_null($msg_id) === false):
			$writer->writeInt($msg_id);
		endif;
		if(is_null($button_id) === false):
			$writer->writeInt($button_id);
		endif;
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		if(is_null($in_app_origin) === false):
			$writer->writeBytes($in_app_origin);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot bool enabled true write_allowed
 * @return Bool
 */

final class ToggleBotInAttachMenu extends Instance {
	public function request(object $bot,bool $enabled,null | bool $write_allowed = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x69f59d69);
		$flags = 0;
		$flags |= $write_allowed ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($bot);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string message long random_id true no_webpage true silent true background true clear_draft true noforwards true update_stickersets_order true invert_media true allow_paid_floodskip inputreplyto reply_to replymarkup reply_markup Vector<messageentity> entities int schedule_date int schedule_repeat_period inputpeer send_as inputquickreplyshortcut quick_reply_shortcut long effect long allow_paid_stars suggestedpost suggested_post inputrichmessage rich_message
 * @return Updates
 */

final class SendMessage extends Instance {
	public function request(object $peer,string $message,int $random_id,null | bool $no_webpage = null,null | bool $silent = null,null | bool $background = null,null | bool $clear_draft = null,null | bool $noforwards = null,null | bool $update_stickersets_order = null,null | bool $invert_media = null,null | bool $allow_paid_floodskip = null,null | object $reply_to = null,null | object $reply_markup = null,null | array $entities = null,null | int $schedule_date = null,null | int $schedule_repeat_period = null,null | object $send_as = null,null | object $quick_reply_shortcut = null,null | int $effect = null,null | int $allow_paid_stars = null,null | object $suggested_post = null,null | object $rich_message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfef48f62);
		$flags = 0;
		$flags |= $no_webpage ? (1 << 1) : 0;
		$flags |= $silent ? (1 << 5) : 0;
		$flags |= $background ? (1 << 6) : 0;
		$flags |= $clear_draft ? (1 << 7) : 0;
		$flags |= $noforwards ? (1 << 14) : 0;
		$flags |= $update_stickersets_order ? (1 << 15) : 0;
		$flags |= $invert_media ? (1 << 16) : 0;
		$flags |= $allow_paid_floodskip ? (1 << 19) : 0;
		$flags |= is_null($reply_to) ? 0 : (1 << 0);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$flags |= is_null($entities) ? 0 : (1 << 3);
		$flags |= is_null($schedule_date) ? 0 : (1 << 10);
		$flags |= is_null($schedule_repeat_period) ? 0 : (1 << 24);
		$flags |= is_null($send_as) ? 0 : (1 << 13);
		$flags |= is_null($quick_reply_shortcut) ? 0 : (1 << 17);
		$flags |= is_null($effect) ? 0 : (1 << 18);
		$flags |= is_null($allow_paid_stars) ? 0 : (1 << 21);
		$flags |= is_null($suggested_post) ? 0 : (1 << 22);
		$flags |= is_null($rich_message) ? 0 : (1 << 23);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		$writer->writeBytes($message);
		$writer->writeLong($random_id);
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($schedule_date) === false):
			$writer->writeInt($schedule_date);
		endif;
		if(is_null($schedule_repeat_period) === false):
			$writer->writeInt($schedule_repeat_period);
		endif;
		if(is_null($send_as) === false):
			$writer->writeObject($send_as);
		endif;
		if(is_null($quick_reply_shortcut) === false):
			$writer->writeObject($quick_reply_shortcut);
		endif;
		if(is_null($effect) === false):
			$writer->writeLong($effect);
		endif;
		if(is_null($allow_paid_stars) === false):
			$writer->writeLong($allow_paid_stars);
		endif;
		if(is_null($suggested_post) === false):
			$writer->writeObject($suggested_post);
		endif;
		if(is_null($rich_message) === false):
			$writer->writeObject($rich_message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputdialogpeer> peers
 * @return messages.PeerDialogs
 */

final class GetPeerDialogs extends Instance {
	public function request(array $peers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe470bcfd);
		$writer->writeVector($peers,'inputdialogpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url int hash
 * @return messages.WebPage
 */

final class GetWebPage extends Instance {
	public function request(string $url,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8d9692a3);
		$writer->writeBytes($url);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputbotapp app string platform true write_allowed true compact true fullscreen string start_param datajson theme_params
 * @return WebViewResult
 */

final class RequestAppWebView extends Instance {
	public function request(object $peer,object $app,string $platform,null | bool $write_allowed = null,null | bool $compact = null,null | bool $fullscreen = null,null | string $start_param = null,null | object $theme_params = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x53618bce);
		$flags = 0;
		$flags |= $write_allowed ? (1 << 0) : 0;
		$flags |= $compact ? (1 << 7) : 0;
		$flags |= $fullscreen ? (1 << 8) : 0;
		$flags |= is_null($start_param) ? 0 : (1 << 1);
		$flags |= is_null($theme_params) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeObject($app);
		if(is_null($start_param) === false):
			$writer->writeBytes($start_param);
		endif;
		if(is_null($theme_params) === false):
			$writer->writeObject($theme_params);
		endif;
		$writer->writeBytes($platform);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<int> id
 * @return messages.AffectedMessages
 */

final class ReadMessageContents extends Instance {
	public function request(array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x36a73f77);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int limit long hash
 * @return messages.Reactions
 */

final class GetTopReactions extends Instance {
	public function request(int $limit,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbb8125ba);
		$writer->writeInt($limit);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id string to_lang string tone
 * @return TextWithEntities
 */

final class SummarizeText extends Instance {
	public function request(object $peer,int $id,null | string $to_lang = null,null | string $tone = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xabbbd346);
		$flags = 0;
		$flags |= is_null($to_lang) ? 0 : (1 << 0);
		$flags |= is_null($tone) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		if(is_null($to_lang) === false):
			$writer->writeBytes($to_lang);
		endif;
		if(is_null($tone) === false):
			$writer->writeBytes($tone);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id Vector<int> id
 * @return Updates
 */

final class DeleteQuickReplyMessages extends Instance {
	public function request(int $shortcut_id,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe105e910);
		$writer->writeInt($shortcut_id);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer chatreactions available_reactions int reactions_limit bool paid_enabled
 * @return Updates
 */

final class SetChatAvailableReactions extends Instance {
	public function request(object $peer,object $available_reactions,null | int $reactions_limit = null,null | bool $paid_enabled = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x864b2581);
		$flags = 0;
		$flags |= is_null($reactions_limit) ? 0 : (1 << 0);
		$flags |= is_null($paid_enabled) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeObject($available_reactions);
		if(is_null($reactions_limit) === false):
			$writer->writeInt($reactions_limit);
		endif;
		if(is_null($paid_enabled) === false):
			$writer->writeBool($paid_enabled);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputuser bot string platform true compact true fullscreen string start_param datajson theme_params
 * @return WebViewResult
 */

final class RequestMainWebView extends Instance {
	public function request(object $peer,object $bot,string $platform,null | bool $compact = null,null | bool $fullscreen = null,null | string $start_param = null,null | object $theme_params = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc9e01e7b);
		$flags = 0;
		$flags |= $compact ? (1 << 7) : 0;
		$flags |= $fullscreen ? (1 << 8) : 0;
		$flags |= is_null($start_param) ? 0 : (1 << 1);
		$flags |= is_null($theme_params) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeObject($bot);
		if(is_null($start_param) === false):
			$writer->writeBytes($start_param);
		endif;
		if(is_null($theme_params) === false):
			$writer->writeObject($theme_params);
		endif;
		$writer->writeBytes($platform);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int id dialogfilter filter
 * @return Bool
 */

final class UpdateDialogFilter extends Instance {
	public function request(int $id,null | object $filter = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1ad4a04a);
		$flags = 0;
		$flags |= is_null($filter) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeInt($id);
		if(is_null($filter) === false):
			$writer->writeObject($filter);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id true reject int schedule_date string reject_comment
 * @return Updates
 */

final class ToggleSuggestedPostApproval extends Instance {
	public function request(object $peer,int $msg_id,null | bool $reject = null,null | int $schedule_date = null,null | string $reject_comment = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8107455c);
		$flags = 0;
		$flags |= $reject ? (1 << 1) : 0;
		$flags |= is_null($schedule_date) ? 0 : (1 << 0);
		$flags |= is_null($reject_comment) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		if(is_null($schedule_date) === false):
			$writer->writeInt($schedule_date);
		endif;
		if(is_null($reject_comment) === false):
			$writer->writeBytes($reject_comment);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return messages.EmojiGroups
 */

final class GetEmojiProfilePhotoGroups extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x21a548f3);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputbotinlineresult result inputuser user_id Vector<inlinequerypeertype> peer_types
 * @return messages.BotPreparedInlineMessage
 */

final class SavePreparedInlineMessage extends Instance {
	public function request(object $result,object $user_id,null | array $peer_types = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf21f7f2f);
		$flags = 0;
		$flags |= is_null($peer_types) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($result);
		$writer->writeObject($user_id);
		if(is_null($peer_types) === false):
			$writer->writeVector($peer_types,'inlinequerypeertype');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id
 * @return Updates
 */

final class MigrateChat extends Instance {
	public function request(int $chat_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa2875319);
		$writer->writeLong($chat_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot string id
 * @return messages.PreparedInlineMessage
 */

final class GetPreparedInlineMessage extends Instance {
	public function request(object $bot,string $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x857ebdb8);
		$writer->writeObject($bot);
		$writer->writeBytes($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer chatbannedrights banned_rights
 * @return Updates
 */

final class EditChatDefaultBannedRights extends Instance {
	public function request(object $peer,object $banned_rights) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa5866b41);
		$writer->writeObject($peer);
		$writer->writeObject($banned_rights);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputstickerset> stickersets true uninstall true archive true unarchive
 * @return Bool
 */

final class ToggleStickerSets extends Instance {
	public function request(array $stickersets,null | bool $uninstall = null,null | bool $archive = null,null | bool $unarchive = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb5052fea);
		$flags = 0;
		$flags |= $uninstall ? (1 << 0) : 0;
		$flags |= $archive ? (1 << 1) : 0;
		$flags |= $unarchive ? (1 << 2) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($stickersets,'inputstickerset');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Updates
 */

final class GetPaidReactionPrivacy extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x472455aa);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class ClearRecentReactions extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9dfeefb4);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string shortcut
 * @return Bool
 */

final class CheckQuickReplyShortcut extends Instance {
	public function request(string $shortcut) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf1d0fbd3);
		$writer->writeBytes($shortcut);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.SavedDialogs
 */

final class GetPinnedSavedDialogs extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd63d94e0);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int max_id true just_clear true revoke int min_date int max_date
 * @return messages.AffectedHistory
 */

final class DeleteHistory extends Instance {
	public function request(object $peer,int $max_id,null | bool $just_clear = null,null | bool $revoke = null,null | int $min_date = null,null | int $max_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb08f922a);
		$flags = 0;
		$flags |= $just_clear ? (1 << 0) : 0;
		$flags |= $revoke ? (1 << 1) : 0;
		$flags |= is_null($min_date) ? 0 : (1 << 2);
		$flags |= is_null($max_date) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($max_id);
		if(is_null($min_date) === false):
			$writer->writeInt($min_date);
		endif;
		if(is_null($max_date) === false):
			$writer->writeInt($max_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdialogpeer peer true pinned
 * @return Bool
 */

final class ToggleDialogPin extends Instance {
	public function request(object $peer,null | bool $pinned = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa731e257);
		$flags = 0;
		$flags |= $pinned ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return messages.EmojiGroups
 */

final class GetEmojiGroups extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7488ce5b);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id inputuser user_id bool is_admin
 * @return Bool
 */

final class EditChatAdmin extends Instance {
	public function request(int $chat_id,object $user_id,bool $is_admin) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa85bd1c2);
		$writer->writeLong($chat_id);
		$writer->writeObject($user_id);
		$writer->writeBool($is_admin);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id
 * @return Updates
 */

final class DeleteScheduledMessages extends Instance {
	public function request(object $peer,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x59ae2b16);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputencryptedchat peer
 * @return Bool
 */

final class ReportEncryptedSpam extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4b0c8c0f);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputuser bot long query_id true silent inputreplyto reply_to inputpeer send_as
 * @return Bool
 */

final class ProlongWebView extends Instance {
	public function request(object $peer,object $bot,int $query_id,null | bool $silent = null,null | object $reply_to = null,null | object $send_as = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb0d81a83);
		$flags = 0;
		$flags |= $silent ? (1 << 5) : 0;
		$flags |= is_null($reply_to) ? 0 : (1 << 0);
		$flags |= is_null($send_as) ? 0 : (1 << 13);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeObject($bot);
		$writer->writeLong($query_id);
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		if(is_null($send_as) === false):
			$writer->writeObject($send_as);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> id
 * @return Bool
 */

final class ReadFeaturedStickers extends Instance {
	public function request(array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5b118126);
		$writer->writeVector($id,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot long random_id string button_text string data
 * @return Updates
 */

final class SendWebViewData extends Instance {
	public function request(object $bot,int $random_id,string $button_text,string $data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdc0242c8);
		$writer->writeObject($bot);
		$writer->writeLong($random_id);
		$writer->writeBytes($button_text);
		$writer->writeBytes($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickerset stickerset bool archived
 * @return messages.StickerSetInstallResult
 */

final class InstallStickerSet extends Instance {
	public function request(object $stickerset,bool $archived) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc78fe460);
		$writer->writeObject($stickerset);
		$writer->writeBool($archived);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id true no_webpage true invert_media string message inputmedia media replymarkup reply_markup Vector<messageentity> entities int schedule_date int schedule_repeat_period int quick_reply_shortcut_id inputrichmessage rich_message
 * @return Updates
 */

final class EditMessage extends Instance {
	public function request(object $peer,int $id,null | bool $no_webpage = null,null | bool $invert_media = null,null | string $message = null,null | object $media = null,null | object $reply_markup = null,null | array $entities = null,null | int $schedule_date = null,null | int $schedule_repeat_period = null,null | int $quick_reply_shortcut_id = null,null | object $rich_message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb106e66c);
		$flags = 0;
		$flags |= $no_webpage ? (1 << 1) : 0;
		$flags |= $invert_media ? (1 << 16) : 0;
		$flags |= is_null($message) ? 0 : (1 << 11);
		$flags |= is_null($media) ? 0 : (1 << 14);
		$flags |= is_null($reply_markup) ? 0 : (1 << 2);
		$flags |= is_null($entities) ? 0 : (1 << 3);
		$flags |= is_null($schedule_date) ? 0 : (1 << 15);
		$flags |= is_null($schedule_repeat_period) ? 0 : (1 << 18);
		$flags |= is_null($quick_reply_shortcut_id) ? 0 : (1 << 17);
		$flags |= is_null($rich_message) ? 0 : (1 << 23);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		if(is_null($message) === false):
			$writer->writeBytes($message);
		endif;
		if(is_null($media) === false):
			$writer->writeObject($media);
		endif;
		if(is_null($reply_markup) === false):
			$writer->writeObject($reply_markup);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($schedule_date) === false):
			$writer->writeInt($schedule_date);
		endif;
		if(is_null($schedule_repeat_period) === false):
			$writer->writeInt($schedule_repeat_period);
		endif;
		if(is_null($quick_reply_shortcut_id) === false):
			$writer->writeInt($quick_reply_shortcut_id);
		endif;
		if(is_null($rich_message) === false):
			$writer->writeObject($rich_message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument id bool unsave true attached
 * @return Bool
 */

final class SaveRecentSticker extends Instance {
	public function request(object $id,bool $unsave,null | bool $attached = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x392718f8);
		$flags = 0;
		$flags |= $attached ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($id);
		$writer->writeBool($unsave);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash inputpeer peer
 * @return messages.SavedReactionTags
 */

final class GetSavedReactionTags extends Instance {
	public function request(int $hash,null | object $peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3637e05b);
		$flags = 0;
		$flags |= is_null($peer) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> document_id
 * @return Vector<Document>
 */

final class GetCustomEmojiDocuments extends Instance {
	public function request(array $document_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd9ab0f54);
		$writer->writeVector($document_id,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string import_head
 * @return messages.HistoryImportParsed
 */

final class CheckHistoryImport extends Instance {
	public function request(string $import_head) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x43fe19f3);
		$writer->writeBytes($import_head);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int shortcut_id Vector<int> id Vector<long> random_id
 * @return Updates
 */

final class SendQuickReplyMessages extends Instance {
	public function request(object $peer,int $shortcut_id,array $id,array $random_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c750de1);
		$writer->writeObject($peer);
		$writer->writeInt($shortcut_id);
		$writer->writeVector($id,'int');
		$writer->writeVector($random_id,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputbotinlinemessageid id inputuser user_id
 * @return messages.HighScores
 */

final class GetInlineGameHighScores extends Instance {
	public function request(object $id,object $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf635e1b);
		$writer->writeObject($id);
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputpeer participant
 * @return Bool
 */

final class DeleteParticipantReactions extends Instance {
	public function request(object $peer,object $participant) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa0b80cf8);
		$writer->writeObject($peer);
		$writer->writeObject($participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long offset_id int limit true masks true emojis
 * @return messages.ArchivedStickers
 */

final class GetArchivedStickers extends Instance {
	public function request(int $offset_id,int $limit,null | bool $masks = null,null | bool $emojis = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x57f17692);
		$flags = 0;
		$flags |= $masks ? (1 << 0) : 0;
		$flags |= $emojis ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($offset_id);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return messages.EmojiGroups
 */

final class GetEmojiStickerGroups extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1dd840f5);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id int limit reaction reaction string offset
 * @return messages.MessageReactionsList
 */

final class GetMessageReactionsList extends Instance {
	public function request(object $peer,int $id,int $limit,null | object $reaction = null,null | string $offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x461b3f48);
		$flags = 0;
		$flags |= is_null($reaction) ? 0 : (1 << 0);
		$flags |= is_null($offset) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		if(is_null($reaction) === false):
			$writer->writeObject($reaction);
		endif;
		if(is_null($offset) === false):
			$writer->writeBytes($offset);
		endif;
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdialogpeer peer true unread inputpeer parent_peer
 * @return Bool
 */

final class MarkDialogUnread extends Instance {
	public function request(object $peer,null | bool $unread = null,null | object $parent_peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c5006f8);
		$flags = 0;
		$flags |= $unread ? (1 << 0) : 0;
		$flags |= is_null($parent_peer) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($parent_peer) === false):
			$writer->writeObject($parent_peer);
		endif;
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id int random_id bytes g_a
 * @return EncryptedChat
 */

final class RequestEncryption extends Instance {
	public function request(object $user_id,int $random_id,string $g_a) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf64daf43);
		$writer->writeObject($user_id);
		$writer->writeInt($random_id);
		$writer->writeBytes($g_a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param reaction reaction string title
 * @return Bool
 */

final class UpdateSavedReactionTag extends Instance {
	public function request(object $reaction,null | string $title = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x60297dec);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($reaction);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id bool increment
 * @return messages.MessageViews
 */

final class GetMessagesViews extends Instance {
	public function request(object $peer,array $id,bool $increment) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5784d3e1);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		$writer->writeBool($increment);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<messagesfilter> filters inputpeer saved_peer_id int top_msg_id
 * @return Vector<messages.SearchCounter>
 */

final class GetSearchCounters extends Instance {
	public function request(object $peer,array $filters,null | object $saved_peer_id = null,null | int $top_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1bbcf300);
		$flags = 0;
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 2);
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		$writer->writeVector($filters,'messagesfilter');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputencryptedchat peer inputencryptedfile file
 * @return EncryptedFile
 */

final class UploadEncryptedFile extends Instance {
	public function request(object $peer,object $file) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5057c497);
		$writer->writeObject($peer);
		$writer->writeObject($file);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int offset_id int add_offset int limit int max_id int min_id int top_msg_id inputpeer saved_peer_id
 * @return messages.Messages
 */

final class GetUnreadReactions extends Instance {
	public function request(object $peer,int $offset_id,int $add_offset,int $limit,int $max_id,int $min_id,null | int $top_msg_id = null,null | object $saved_peer_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd7f90ac);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$flags |= is_null($saved_peer_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		if(is_null($saved_peer_id) === false):
			$writer->writeObject($saved_peer_id);
		endif;
		$writer->writeInt($offset_id);
		$writer->writeInt($add_offset);
		$writer->writeInt($limit);
		$writer->writeInt($max_id);
		$writer->writeInt($min_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id
 * @return messages.Messages
 */

final class GetScheduledMessages extends Instance {
	public function request(object $peer,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbdbb0464);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true write_allowed true share_phone_number inputpeer peer int msg_id int button_id string url string match_code
 * @return UrlAuthResult
 */

final class AcceptUrlAuth extends Instance {
	public function request(null | bool $write_allowed = null,null | bool $share_phone_number = null,null | object $peer = null,null | int $msg_id = null,null | int $button_id = null,null | string $url = null,null | string $match_code = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x67a3f0de);
		$flags = 0;
		$flags |= $write_allowed ? (1 << 0) : 0;
		$flags |= $share_phone_number ? (1 << 3) : 0;
		$flags |= is_null($peer) ? 0 : (1 << 1);
		$flags |= is_null($msg_id) ? 0 : (1 << 1);
		$flags |= is_null($button_id) ? 0 : (1 << 1);
		$flags |= is_null($url) ? 0 : (1 << 2);
		$flags |= is_null($match_code) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		if(is_null($msg_id) === false):
			$writer->writeInt($msg_id);
		endif;
		if(is_null($button_id) === false):
			$writer->writeInt($button_id);
		endif;
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		if(is_null($match_code) === false):
			$writer->writeBytes($match_code);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> order true force
 * @return Updates
 */

final class ReorderPinnedForumTopics extends Instance {
	public function request(object $peer,array $order,null | bool $force = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe7841f0);
		$flags = 0;
		$flags |= $force ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeVector($order,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return messages.Reactions
 */

final class GetDefaultTagReactions extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbdf93428);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int offset_id int add_offset int limit int max_id int min_id int top_msg_id
 * @return messages.Messages
 */

final class GetUnreadPollVotes extends Instance {
	public function request(object $peer,int $offset_id,int $add_offset,int $limit,int $max_id,int $min_id,null | int $top_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x43286cf2);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		$writer->writeInt($offset_id);
		$writer->writeInt($add_offset);
		$writer->writeInt($limit);
		$writer->writeInt($max_id);
		$writer->writeInt($min_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes random_id
 * @return Bool
 */

final class ViewSponsoredMessage extends Instance {
	public function request(string $random_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x269e3643);
		$writer->writeBytes($random_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputencryptedchat peer bool typing
 * @return Bool
 */

final class SetEncryptedTyping extends Instance {
	public function request(object $peer,bool $typing) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x791451ed);
		$writer->writeObject($peer);
		$writer->writeBool($typing);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer true disabled
 * @return Bool
 */

final class TogglePeerTranslations extends Instance {
	public function request(object $peer,null | bool $disabled = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe47cb579);
		$flags = 0;
		$flags |= $disabled ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int top_msg_id
 * @return messages.AffectedHistory
 */

final class DeleteTopicHistory extends Instance {
	public function request(object $peer,int $top_msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd2816f10);
		$writer->writeObject($peer);
		$writer->writeInt($top_msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string about
 * @return Bool
 */

final class EditChatAbout extends Instance {
	public function request(object $peer,string $about) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdef60797);
		$writer->writeObject($peer);
		$writer->writeBytes($about);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id inputpeer reaction_peer
 * @return Bool
 */

final class ReportReaction extends Instance {
	public function request(object $peer,int $id,object $reaction_peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3f64c076);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		$writer->writeObject($reaction_peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int shortcut_id string shortcut
 * @return Bool
 */

final class EditQuickReplyShortcut extends Instance {
	public function request(int $shortcut_id,string $shortcut) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5c003cef);
		$writer->writeInt($shortcut_id);
		$writer->writeBytes($shortcut);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputencryptedchat peer long random_id bytes data inputencryptedfile file true silent
 * @return messages.SentEncryptedMessage
 */

final class SendEncryptedFile extends Instance {
	public function request(object $peer,int $random_id,string $data,object $file,null | bool $silent = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5559481d);
		$flags = 0;
		$flags |= $silent ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeLong($random_id);
		$writer->writeBytes($data);
		$writer->writeObject($file);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_code
 * @return EmojiKeywordsDifference
 */

final class GetEmojiKeywords extends Instance {
	public function request(string $lang_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x35a0e062);
		$writer->writeBytes($lang_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputpeer send_as
 * @return Bool
 */

final class SaveDefaultSendAs extends Instance {
	public function request(object $peer,object $send_as) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xccfddf96);
		$writer->writeObject($peer);
		$writer->writeObject($send_as);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_code int from_version
 * @return EmojiKeywordsDifference
 */

final class GetEmojiKeywordsDifference extends Instance {
	public function request(string $lang_code,int $from_version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1508b6af);
		$writer->writeBytes($lang_code);
		$writer->writeInt($from_version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<int> id true revoke
 * @return messages.AffectedMessages
 */

final class DeleteMessages extends Instance {
	public function request(array $id,null | bool $revoke = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe58e95d2);
		$flags = 0;
		$flags |= $revoke ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<inputsinglemedia> multi_media true silent true background true clear_draft true noforwards true update_stickersets_order true invert_media true allow_paid_floodskip inputreplyto reply_to int schedule_date inputpeer send_as inputquickreplyshortcut quick_reply_shortcut long effect long allow_paid_stars
 * @return Updates
 */

final class SendMultiMedia extends Instance {
	public function request(object $peer,array $multi_media,null | bool $silent = null,null | bool $background = null,null | bool $clear_draft = null,null | bool $noforwards = null,null | bool $update_stickersets_order = null,null | bool $invert_media = null,null | bool $allow_paid_floodskip = null,null | object $reply_to = null,null | int $schedule_date = null,null | object $send_as = null,null | object $quick_reply_shortcut = null,null | int $effect = null,null | int $allow_paid_stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1bf89d74);
		$flags = 0;
		$flags |= $silent ? (1 << 5) : 0;
		$flags |= $background ? (1 << 6) : 0;
		$flags |= $clear_draft ? (1 << 7) : 0;
		$flags |= $noforwards ? (1 << 14) : 0;
		$flags |= $update_stickersets_order ? (1 << 15) : 0;
		$flags |= $invert_media ? (1 << 16) : 0;
		$flags |= $allow_paid_floodskip ? (1 << 19) : 0;
		$flags |= is_null($reply_to) ? 0 : (1 << 0);
		$flags |= is_null($schedule_date) ? 0 : (1 << 10);
		$flags |= is_null($send_as) ? 0 : (1 << 13);
		$flags |= is_null($quick_reply_shortcut) ? 0 : (1 << 17);
		$flags |= is_null($effect) ? 0 : (1 << 18);
		$flags |= is_null($allow_paid_stars) ? 0 : (1 << 21);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		$writer->writeVector($multi_media,'inputsinglemedia');
		if(is_null($schedule_date) === false):
			$writer->writeInt($schedule_date);
		endif;
		if(is_null($send_as) === false):
			$writer->writeObject($send_as);
		endif;
		if(is_null($quick_reply_shortcut) === false):
			$writer->writeObject($quick_reply_shortcut);
		endif;
		if(is_null($effect) === false):
			$writer->writeLong($effect);
		endif;
		if(is_null($allow_paid_stars) === false):
			$writer->writeLong($allow_paid_stars);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string link
 * @return messages.ExportedChatInvite
 */

final class GetExportedChatInvite extends Instance {
	public function request(object $peer,string $link) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x73746f5c);
		$writer->writeObject($peer);
		$writer->writeBytes($link);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer long import_id string file_name inputmedia media
 * @return MessageMedia
 */

final class UploadImportedMedia extends Instance {
	public function request(object $peer,int $import_id,string $file_name,object $media) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2a862092);
		$writer->writeObject($peer);
		$writer->writeLong($import_id);
		$writer->writeBytes($file_name);
		$writer->writeObject($media);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url
 * @return Bool
 */

final class DeclineUrlAuth extends Instance {
	public function request(string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x35436bbc);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q long hash true exclude_featured
 * @return messages.FoundStickerSets
 */

final class SearchStickerSets extends Instance {
	public function request(string $q,int $hash,null | bool $exclude_featured = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x35705b8a);
		$flags = 0;
		$flags |= $exclude_featured ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($q);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int top_msg_id
 * @return messages.AffectedHistory
 */

final class ReadPollVotes extends Instance {
	public function request(object $peer,null | int $top_msg_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1720b4d8);
		$flags = 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputencryptedchat peer int max_date
 * @return Bool
 */

final class ReadEncryptedHistory extends Instance {
	public function request(object $peer,int $max_date) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7f4b690a);
		$writer->writeObject($peer);
		$writer->writeInt($max_date);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer from_peer Vector<int> id Vector<long> random_id inputpeer to_peer true silent true background true with_my_score true drop_author true drop_media_captions true noforwards true allow_paid_floodskip int top_msg_id inputreplyto reply_to int schedule_date int schedule_repeat_period inputpeer send_as inputquickreplyshortcut quick_reply_shortcut long effect int video_timestamp long allow_paid_stars suggestedpost suggested_post
 * @return Updates
 */

final class ForwardMessages extends Instance {
	public function request(object $from_peer,array $id,array $random_id,object $to_peer,null | bool $silent = null,null | bool $background = null,null | bool $with_my_score = null,null | bool $drop_author = null,null | bool $drop_media_captions = null,null | bool $noforwards = null,null | bool $allow_paid_floodskip = null,null | int $top_msg_id = null,null | object $reply_to = null,null | int $schedule_date = null,null | int $schedule_repeat_period = null,null | object $send_as = null,null | object $quick_reply_shortcut = null,null | int $effect = null,null | int $video_timestamp = null,null | int $allow_paid_stars = null,null | object $suggested_post = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x13704a7c);
		$flags = 0;
		$flags |= $silent ? (1 << 5) : 0;
		$flags |= $background ? (1 << 6) : 0;
		$flags |= $with_my_score ? (1 << 8) : 0;
		$flags |= $drop_author ? (1 << 11) : 0;
		$flags |= $drop_media_captions ? (1 << 12) : 0;
		$flags |= $noforwards ? (1 << 14) : 0;
		$flags |= $allow_paid_floodskip ? (1 << 19) : 0;
		$flags |= is_null($top_msg_id) ? 0 : (1 << 9);
		$flags |= is_null($reply_to) ? 0 : (1 << 22);
		$flags |= is_null($schedule_date) ? 0 : (1 << 10);
		$flags |= is_null($schedule_repeat_period) ? 0 : (1 << 24);
		$flags |= is_null($send_as) ? 0 : (1 << 13);
		$flags |= is_null($quick_reply_shortcut) ? 0 : (1 << 17);
		$flags |= is_null($effect) ? 0 : (1 << 18);
		$flags |= is_null($video_timestamp) ? 0 : (1 << 20);
		$flags |= is_null($allow_paid_stars) ? 0 : (1 << 21);
		$flags |= is_null($suggested_post) ? 0 : (1 << 23);
		$writer->writeInt($flags);
		$writer->writeObject($from_peer);
		$writer->writeVector($id,'int');
		$writer->writeVector($random_id,'long');
		$writer->writeObject($to_peer);
		if(is_null($top_msg_id) === false):
			$writer->writeInt($top_msg_id);
		endif;
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		if(is_null($schedule_date) === false):
			$writer->writeInt($schedule_date);
		endif;
		if(is_null($schedule_repeat_period) === false):
			$writer->writeInt($schedule_repeat_period);
		endif;
		if(is_null($send_as) === false):
			$writer->writeObject($send_as);
		endif;
		if(is_null($quick_reply_shortcut) === false):
			$writer->writeObject($quick_reply_shortcut);
		endif;
		if(is_null($effect) === false):
			$writer->writeLong($effect);
		endif;
		if(is_null($video_timestamp) === false):
			$writer->writeInt($video_timestamp);
		endif;
		if(is_null($allow_paid_stars) === false):
			$writer->writeLong($allow_paid_stars);
		endif;
		if(is_null($suggested_post) === false):
			$writer->writeObject($suggested_post);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q messagesfilter filter int min_date int max_date int offset_rate inputpeer offset_peer int offset_id int limit true broadcasts_only true groups_only true users_only int folder_id
 * @return messages.Messages
 */

final class SearchGlobal extends Instance {
	public function request(string $q,object $filter,int $min_date,int $max_date,int $offset_rate,object $offset_peer,int $offset_id,int $limit,null | bool $broadcasts_only = null,null | bool $groups_only = null,null | bool $users_only = null,null | int $folder_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4bc6589a);
		$flags = 0;
		$flags |= $broadcasts_only ? (1 << 1) : 0;
		$flags |= $groups_only ? (1 << 2) : 0;
		$flags |= $users_only ? (1 << 3) : 0;
		$flags |= is_null($folder_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($folder_id) === false):
			$writer->writeInt($folder_id);
		endif;
		$writer->writeBytes($q);
		$writer->writeObject($filter);
		$writer->writeInt($min_date);
		$writer->writeInt($max_date);
		$writer->writeInt($offset_rate);
		$writer->writeObject($offset_peer);
		$writer->writeInt($offset_id);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id int cache_time true alert string message string url
 * @return Bool
 */

final class SetBotCallbackAnswer extends Instance {
	public function request(int $query_id,int $cache_time,null | bool $alert = null,null | string $message = null,null | string $url = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd58f130a);
		$flags = 0;
		$flags |= $alert ? (1 << 1) : 0;
		$flags |= is_null($message) ? 0 : (1 << 0);
		$flags |= is_null($url) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($query_id);
		if(is_null($message) === false):
			$writer->writeBytes($message);
		endif;
		if(is_null($url) === false):
			$writer->writeBytes($url);
		endif;
		$writer->writeInt($cache_time);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer long random_id long query_id string id true silent true background true clear_draft true hide_via inputreplyto reply_to int schedule_date inputpeer send_as inputquickreplyshortcut quick_reply_shortcut long allow_paid_stars
 * @return Updates
 */

final class SendInlineBotResult extends Instance {
	public function request(object $peer,int $random_id,int $query_id,string $id,null | bool $silent = null,null | bool $background = null,null | bool $clear_draft = null,null | bool $hide_via = null,null | object $reply_to = null,null | int $schedule_date = null,null | object $send_as = null,null | object $quick_reply_shortcut = null,null | int $allow_paid_stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc0cf7646);
		$flags = 0;
		$flags |= $silent ? (1 << 5) : 0;
		$flags |= $background ? (1 << 6) : 0;
		$flags |= $clear_draft ? (1 << 7) : 0;
		$flags |= $hide_via ? (1 << 11) : 0;
		$flags |= is_null($reply_to) ? 0 : (1 << 0);
		$flags |= is_null($schedule_date) ? 0 : (1 << 10);
		$flags |= is_null($send_as) ? 0 : (1 << 13);
		$flags |= is_null($quick_reply_shortcut) ? 0 : (1 << 17);
		$flags |= is_null($allow_paid_stars) ? 0 : (1 << 21);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($reply_to) === false):
			$writer->writeObject($reply_to);
		endif;
		$writer->writeLong($random_id);
		$writer->writeLong($query_id);
		$writer->writeBytes($id);
		if(is_null($schedule_date) === false):
			$writer->writeInt($schedule_date);
		endif;
		if(is_null($send_as) === false):
			$writer->writeObject($send_as);
		endif;
		if(is_null($quick_reply_shortcut) === false):
			$writer->writeObject($quick_reply_shortcut);
		endif;
		if(is_null($allow_paid_stars) === false):
			$writer->writeLong($allow_paid_stars);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id
 * @return OutboxReadDate
 */

final class GetOutboxReadDate extends Instance {
	public function request(object $peer,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c4bfe5d);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return messages.PeerSettings
 */

final class GetPeerSettings extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xefd9a6a2);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return messages.AvailableReactions
 */

final class GetAvailableReactions extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x18dea0ac);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<string> lang_codes
 * @return Vector<EmojiLanguage>
 */

final class GetEmojiKeywordsLanguages extends Instance {
	public function request(array $lang_codes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4e9963b2);
		$writer->writeVector($lang_codes,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long chat_id inputuser user_id true revoke_history
 * @return Updates
 */

final class DeleteChatUser extends Instance {
	public function request(int $chat_id,object $user_id,null | bool $revoke_history = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa2185cab);
		$flags = 0;
		$flags |= $revoke_history ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($chat_id);
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id int limit int max_id int min_id long hash
 * @return messages.Messages
 */

final class GetPersonalChannelHistory extends Instance {
	public function request(object $user_id,int $limit,int $max_id,int $min_id,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x55fb0996);
		$writer->writeObject($user_id);
		$writer->writeInt($limit);
		$writer->writeInt($max_id);
		$writer->writeInt($min_id);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputpeer> ids inputpeer parent_peer
 * @return messages.SavedDialogs
 */

final class GetSavedDialogsByID extends Instance {
	public function request(array $ids,null | object $parent_peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6f6f9c96);
		$flags = 0;
		$flags |= is_null($parent_peer) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($parent_peer) === false):
			$writer->writeObject($parent_peer);
		endif;
		$writer->writeVector($ids,'inputpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id paidreactionprivacy private
 * @return Bool
 */

final class TogglePaidReactionPrivacy extends Instance {
	public function request(object $peer,int $msg_id,object $private) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x435885b5);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeObject($private);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id Vector<bytes> options
 * @return Updates
 */

final class SendVote extends Instance {
	public function request(object $peer,int $msg_id,array $options) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x10ea6184);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeVector($options,'bytes');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes random_id bytes option
 * @return channels.SponsoredMessageReportResult
 */

final class ReportSponsoredMessage extends Instance {
	public function request(string $random_id,string $option) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x12cbf0c4);
		$writer->writeBytes($random_id);
		$writer->writeBytes($option);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return messages.ChatAdminsWithInvites
 */

final class GetAdminsWithInvites extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3920e6ef);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id true success string error
 * @return Bool
 */

final class SetBotPrecheckoutResults extends Instance {
	public function request(int $query_id,null | bool $success = null,null | string $error = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9c2dd95);
		$flags = 0;
		$flags |= $success ? (1 << 1) : 0;
		$flags |= is_null($error) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeLong($query_id);
		if(is_null($error) === false):
			$writer->writeBytes($error);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int chat_id true delete_history
 * @return Bool
 */

final class DiscardEncryption extends Instance {
	public function request(int $chat_id,null | bool $delete_history = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf393aea0);
		$flags = 0;
		$flags |= $delete_history ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($chat_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id
 * @return Vector<ReadParticipantDate>
 */

final class GetMessageReadParticipants extends Instance {
	public function request(object $peer,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31c1c44f);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputbotapp app long hash
 * @return messages.BotApp
 */

final class GetBotApp extends Instance {
	public function request(object $app,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x34fdc5c3);
		$writer->writeObject($app);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id inputuser user_id
 * @return messages.HighScores
 */

final class GetGameHighScores extends Instance {
	public function request(object $peer,int $id,object $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe822649d);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot inputpeer peer long random_id string start_param
 * @return Updates
 */

final class StartBot extends Instance {
	public function request(object $bot,object $peer,int $random_id,string $start_param) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe6df7378);
		$writer->writeObject($bot);
		$writer->writeObject($peer);
		$writer->writeLong($random_id);
		$writer->writeBytes($start_param);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string link true revoked int expire_date int usage_limit bool request_needed string title
 * @return messages.ExportedChatInvite
 */

final class EditExportedChatInvite extends Instance {
	public function request(object $peer,string $link,null | bool $revoked = null,null | int $expire_date = null,null | int $usage_limit = null,null | bool $request_needed = null,null | string $title = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbdca2f75);
		$flags = 0;
		$flags |= $revoked ? (1 << 2) : 0;
		$flags |= is_null($expire_date) ? 0 : (1 << 0);
		$flags |= is_null($usage_limit) ? 0 : (1 << 1);
		$flags |= is_null($request_needed) ? 0 : (1 << 3);
		$flags |= is_null($title) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBytes($link);
		if(is_null($expire_date) === false):
			$writer->writeInt($expire_date);
		endif;
		if(is_null($usage_limit) === false):
			$writer->writeInt($usage_limit);
		endif;
		if(is_null($request_needed) === false):
			$writer->writeBool($request_needed);
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id Vector<inputbotinlineresult> results int cache_time true gallery true private string next_offset inlinebotswitchpm switch_pm inlinebotwebview switch_webview
 * @return Bool
 */

final class SetInlineBotResults extends Instance {
	public function request(int $query_id,array $results,int $cache_time,null | bool $gallery = null,null | bool $private = null,null | string $next_offset = null,null | object $switch_pm = null,null | object $switch_webview = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbb12a419);
		$flags = 0;
		$flags |= $gallery ? (1 << 0) : 0;
		$flags |= $private ? (1 << 1) : 0;
		$flags |= is_null($next_offset) ? 0 : (1 << 2);
		$flags |= is_null($switch_pm) ? 0 : (1 << 3);
		$flags |= is_null($switch_webview) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeLong($query_id);
		$writer->writeVector($results,'inputbotinlineresult');
		$writer->writeInt($cache_time);
		if(is_null($next_offset) === false):
			$writer->writeBytes($next_offset);
		endif;
		if(is_null($switch_pm) === false):
			$writer->writeObject($switch_pm);
		endif;
		if(is_null($switch_webview) === false):
			$writer->writeObject($switch_webview);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true revoke
 * @return messages.AffectedFoundMessages
 */

final class DeletePhoneCallHistory extends Instance {
	public function request(null | bool $revoke = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf9cbe409);
		$flags = 0;
		$flags |= $revoke ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q string emoticon Vector<string> lang_code int offset int limit long hash true emojis
 * @return messages.FoundStickers
 */

final class SearchStickers extends Instance {
	public function request(string $q,string $emoticon,array $lang_code,int $offset,int $limit,int $hash,null | bool $emojis = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x29b1c66a);
		$flags = 0;
		$flags |= $emojis ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($q);
		$writer->writeBytes($emoticon);
		$writer->writeVector($lang_code,'string');
		$writer->writeInt($offset);
		$writer->writeInt($limit);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int topic_id string title long icon_emoji_id bool closed bool hidden
 * @return Updates
 */

final class EditForumTopic extends Instance {
	public function request(object $peer,int $topic_id,null | string $title = null,null | int $icon_emoji_id = null,null | bool $closed = null,null | bool $hidden = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcecc1134);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$flags |= is_null($icon_emoji_id) ? 0 : (1 << 1);
		$flags |= is_null($closed) ? 0 : (1 << 2);
		$flags |= is_null($hidden) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($topic_id);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($icon_emoji_id) === false):
			$writer->writeLong($icon_emoji_id);
		endif;
		if(is_null($closed) === false):
			$writer->writeBool($closed);
		endif;
		if(is_null($hidden) === false):
			$writer->writeBool($hidden);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<int> order
 * @return Bool
 */

final class ReorderQuickReplies extends Instance {
	public function request(array $order) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x60331907);
		$writer->writeVector($order,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return AttachMenuBots
 */

final class GetAttachMenuBots extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x16fcc2cb);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int button_id Vector<inputpeer> requested_peers int msg_id string webapp_req_id
 * @return Updates
 */

final class SendBotRequestedPeer extends Instance {
	public function request(object $peer,int $button_id,array $requested_peers,null | int $msg_id = null,null | string $webapp_req_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c5cf2a7);
		$flags = 0;
		$flags |= is_null($msg_id) ? 0 : (1 << 0);
		$flags |= is_null($webapp_req_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($msg_id) === false):
			$writer->writeInt($msg_id);
		endif;
		if(is_null($webapp_req_id) === false):
			$writer->writeBytes($webapp_req_id);
		endif;
		$writer->writeInt($button_id);
		$writer->writeVector($requested_peers,'inputpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int limit long hash
 * @return messages.Messages
 */

final class GetRecentLocations extends Instance {
	public function request(object $peer,int $limit,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x702a40e0);
		$writer->writeObject($peer);
		$writer->writeInt($limit);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string hash
 * @return ChatInvite
 */

final class CheckChatInvite extends Instance {
	public function request(string $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3eadb1bb);
		$writer->writeBytes($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputpeer participant string rank
 * @return Updates
 */

final class EditChatParticipantRank extends Instance {
	public function request(object $peer,object $participant,string $rank) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa00f32b0);
		$writer->writeObject($peer);
		$writer->writeObject($participant);
		$writer->writeBytes($rank);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int offset_id int offset_date int add_offset int limit int max_id int min_id long hash inputpeer parent_peer
 * @return messages.Messages
 */

final class GetSavedHistory extends Instance {
	public function request(object $peer,int $offset_id,int $offset_date,int $add_offset,int $limit,int $max_id,int $min_id,int $hash,null | object $parent_peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x998ab009);
		$flags = 0;
		$flags |= is_null($parent_peer) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($parent_peer) === false):
			$writer->writeObject($parent_peer);
		endif;
		$writer->writeObject($peer);
		$writer->writeInt($offset_id);
		$writer->writeInt($offset_date);
		$writer->writeInt($add_offset);
		$writer->writeInt($limit);
		$writer->writeInt($max_id);
		$writer->writeInt($min_id);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return Bool
 */

final class ReportSpam extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcf1592db);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> topics
 * @return messages.ForumTopics
 */

final class GetForumTopicsByID extends Instance {
	public function request(object $peer,array $topics) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaf0a4a08);
		$writer->writeObject($peer);
		$writer->writeVector($topics,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id int offset_id int offset_date int add_offset int limit int max_id int min_id long hash
 * @return messages.Messages
 */

final class GetReplies extends Instance {
	public function request(object $peer,int $msg_id,int $offset_id,int $offset_date,int $add_offset,int $limit,int $max_id,int $min_id,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x22ddd30c);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		$writer->writeInt($offset_id);
		$writer->writeInt($offset_date);
		$writer->writeInt($add_offset);
		$writer->writeInt($limit);
		$writer->writeInt($max_id);
		$writer->writeInt($min_id);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string emoticon long hash
 * @return messages.Stickers
 */

final class GetStickers extends Instance {
	public function request(string $emoticon,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd5a5d3a1);
		$writer->writeBytes($emoticon);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Messages;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdialogpeer peer true pinned
 * @return Bool
 */

final class ToggleSavedDialogPin extends Instance {
	public function request(object $peer,null | bool $pinned = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xac81bbde);
		$flags = 0;
		$flags |= $pinned ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash
 * @return auth.SentCode
 */

final class ResetLoginEmail extends Instance {
	public function request(string $phone_number,string $phone_code_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7e960193);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int api_id string api_hash Vector<long> except_ids
 * @return auth.LoginToken
 */

final class ExportLoginToken extends Instance {
	public function request(int $api_id,string $api_hash,array $except_ids) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb7e085fe);
		$writer->writeInt($api_id);
		$writer->writeBytes($api_hash);
		$writer->writeVector($except_ids,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long perm_auth_key_id long nonce int expires_at bytes encrypted_message
 * @return Bool
 */

final class BindTempAuthKey extends Instance {
	public function request(int $perm_auth_key_id,int $nonce,int $expires_at,string $encrypted_message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcdd42a05);
		$writer->writeLong($perm_auth_key_id);
		$writer->writeLong($nonce);
		$writer->writeInt($expires_at);
		$writer->writeBytes($encrypted_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes token
 * @return auth.LoginToken
 */

final class ImportLoginToken extends Instance {
	public function request(string $token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x95ac5ce4);
		$writer->writeBytes($token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long id bytes bytes
 * @return auth.Authorization
 */

final class ImportAuthorization extends Instance {
	public function request(int $id,string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa57a7dad);
		$writer->writeLong($id);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash
 * @return Bool
 */

final class CancelCode extends Instance {
	public function request(string $phone_number,string $phone_code_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1f040578);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class ResetAuthorizations extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9fab0d1a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash string first_name string last_name true no_joined_notifications
 * @return auth.Authorization
 */

final class SignUp extends Instance {
	public function request(string $phone_number,string $phone_code_hash,string $first_name,string $last_name,null | bool $no_joined_notifications = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaac7b717);
		$flags = 0;
		$flags |= $no_joined_notifications ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		$writer->writeBytes($first_name);
		$writer->writeBytes($last_name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string code
 * @return Bool
 */

final class CheckRecoveryPassword extends Instance {
	public function request(string $code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd36bf79);
		$writer->writeBytes($code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash string mnc
 * @return Bool
 */

final class ReportMissingCode extends Instance {
	public function request(string $phone_number,string $phone_code_hash,string $mnc) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcb9deff6);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		$writer->writeBytes($mnc);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return auth.LoggedOut
 */

final class LogOut extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e72ba19);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int dc_id
 * @return auth.ExportedAuthorization
 */

final class ExportAuthorization extends Instance {
	public function request(int $dc_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe5bfffcd);
		$writer->writeInt($dc_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number int api_id string api_hash codesettings settings
 * @return auth.SentCode
 */

final class SendCode extends Instance {
	public function request(string $phone_number,int $api_id,string $api_hash,object $settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa677244f);
		$writer->writeBytes($phone_number);
		$writer->writeInt($api_id);
		$writer->writeBytes($api_hash);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash long form_id
 * @return auth.SentCode
 */

final class CheckPaidAuth extends Instance {
	public function request(string $phone_number,string $phone_code_hash,int $form_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x56e59f9c);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		$writer->writeLong($form_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes token
 * @return Authorization
 */

final class AcceptLoginToken extends Instance {
	public function request(string $token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe894ad4d);
		$writer->writeBytes($token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int api_id string api_hash
 * @return auth.PasskeyLoginOptions
 */

final class InitPasskeyLogin extends Instance {
	public function request(int $api_id,string $api_hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x518ad0b7);
		$writer->writeInt($api_id);
		$writer->writeBytes($api_hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string code account.passwordinputsettings new_settings
 * @return auth.Authorization
 */

final class RecoverPassword extends Instance {
	public function request(string $code,null | object $new_settings = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x37096c70);
		$flags = 0;
		$flags |= is_null($new_settings) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($code);
		if(is_null($new_settings) === false):
			$writer->writeObject($new_settings);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> except_auth_keys
 * @return Bool
 */

final class DropTempAuthKeys extends Instance {
	public function request(array $except_auth_keys) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8e48a188);
		$writer->writeVector($except_auth_keys,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpasskeycredential credential int from_dc_id long from_auth_key_id
 * @return auth.Authorization
 */

final class FinishPasskeyLogin extends Instance {
	public function request(object $credential,null | int $from_dc_id = null,null | int $from_auth_key_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9857ad07);
		$flags = 0;
		$flags |= is_null($from_dc_id) ? 0 : (1 << 0);
		$flags |= is_null($from_auth_key_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($credential);
		if(is_null($from_dc_id) === false):
			$writer->writeInt($from_dc_id);
		endif;
		if(is_null($from_auth_key_id) === false):
			$writer->writeLong($from_auth_key_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputcheckpasswordsrp password
 * @return auth.Authorization
 */

final class CheckPassword extends Instance {
	public function request(object $password) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd18b4d16);
		$writer->writeObject($password);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash string safety_net_token string play_integrity_token string ios_push_secret
 * @return Bool
 */

final class RequestFirebaseSms extends Instance {
	public function request(string $phone_number,string $phone_code_hash,null | string $safety_net_token = null,null | string $play_integrity_token = null,null | string $ios_push_secret = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8e39261e);
		$flags = 0;
		$flags |= is_null($safety_net_token) ? 0 : (1 << 0);
		$flags |= is_null($play_integrity_token) ? 0 : (1 << 2);
		$flags |= is_null($ios_push_secret) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		if(is_null($safety_net_token) === false):
			$writer->writeBytes($safety_net_token);
		endif;
		if(is_null($play_integrity_token) === false):
			$writer->writeBytes($play_integrity_token);
		endif;
		if(is_null($ios_push_secret) === false):
			$writer->writeBytes($ios_push_secret);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash string phone_code emailverification email_verification
 * @return auth.Authorization
 */

final class SignIn extends Instance {
	public function request(string $phone_number,string $phone_code_hash,null | string $phone_code = null,null | object $email_verification = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8d52a951);
		$flags = 0;
		$flags |= is_null($phone_code) ? 0 : (1 << 0);
		$flags |= is_null($email_verification) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		if(is_null($phone_code) === false):
			$writer->writeBytes($phone_code);
		endif;
		if(is_null($email_verification) === false):
			$writer->writeObject($email_verification);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash string reason
 * @return auth.SentCode
 */

final class ResendCode extends Instance {
	public function request(string $phone_number,string $phone_code_hash,null | string $reason = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcae47523);
		$flags = 0;
		$flags |= is_null($reason) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		if(is_null($reason) === false):
			$writer->writeBytes($reason);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int api_id string api_hash string web_auth_token
 * @return auth.Authorization
 */

final class ImportWebTokenAuthorization extends Instance {
	public function request(int $api_id,string $api_hash,string $web_auth_token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2db873a9);
		$writer->writeInt($api_id);
		$writer->writeBytes($api_hash);
		$writer->writeBytes($web_auth_token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return auth.PasswordRecovery
 */

final class RequestPasswordRecovery extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd897bc66);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Auth;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int flags int api_id string api_hash string bot_auth_token
 * @return auth.Authorization
 */

final class ImportBotAuthorization extends Instance {
	public function request(int $flags,int $api_id,string $api_hash,string $bot_auth_token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x67a3ff2c);
		$writer->writeInt($flags);
		$writer->writeInt($api_id);
		$writer->writeBytes($api_hash);
		$writer->writeBytes($bot_auth_token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchatlist chatlist
 * @return Bool
 */

final class HideChatlistUpdates extends Instance {
	public function request(object $chatlist) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x66e486fb);
		$writer->writeObject($chatlist);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return chatlists.ChatlistInvite
 */

final class CheckChatlistInvite extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x41c10fff);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchatlist chatlist
 * @return chatlists.ExportedInvites
 */

final class GetExportedInvites extends Instance {
	public function request(object $chatlist) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xce03da83);
		$writer->writeObject($chatlist);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchatlist chatlist Vector<inputpeer> peers
 * @return Updates
 */

final class LeaveChatlist extends Instance {
	public function request(object $chatlist,array $peers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x74fae13a);
		$writer->writeObject($chatlist);
		$writer->writeVector($peers,'inputpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchatlist chatlist string slug string title Vector<inputpeer> peers
 * @return ExportedChatlistInvite
 */

final class EditExportedInvite extends Instance {
	public function request(object $chatlist,string $slug,null | string $title = null,null | array $peers = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x653db63d);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 1);
		$flags |= is_null($peers) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($chatlist);
		$writer->writeBytes($slug);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($peers) === false):
			$writer->writeVector($peers,'inputpeer');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchatlist chatlist Vector<inputpeer> peers
 * @return Updates
 */

final class JoinChatlistUpdates extends Instance {
	public function request(object $chatlist,array $peers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe089f8f5);
		$writer->writeObject($chatlist);
		$writer->writeVector($peers,'inputpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchatlist chatlist string title Vector<inputpeer> peers
 * @return chatlists.ExportedChatlistInvite
 */

final class ExportChatlistInvite extends Instance {
	public function request(object $chatlist,string $title,array $peers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8472478e);
		$writer->writeObject($chatlist);
		$writer->writeBytes($title);
		$writer->writeVector($peers,'inputpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug Vector<inputpeer> peers
 * @return Updates
 */

final class JoinChatlistInvite extends Instance {
	public function request(string $slug,array $peers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa6b1e39a);
		$writer->writeBytes($slug);
		$writer->writeVector($peers,'inputpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchatlist chatlist
 * @return Vector<Peer>
 */

final class GetLeaveChatlistSuggestions extends Instance {
	public function request(object $chatlist) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfdbcd714);
		$writer->writeObject($chatlist);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchatlist chatlist string slug
 * @return Bool
 */

final class DeleteExportedInvite extends Instance {
	public function request(object $chatlist,string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x719c5c5e);
		$writer->writeObject($chatlist);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Chatlists;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchatlist chatlist
 * @return chatlists.ChatlistUpdates
 */

final class GetChatlistUpdates extends Instance {
	public function request(object $chatlist) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x89419521);
		$writer->writeObject($chatlist);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.Support
 */

final class GetSupport extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9cdf08cd);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.InviteText
 */

final class GetInviteText extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4d392343);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return CdnConfig
 */

final class GetCdnConfig extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x52029342);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.TermsOfServiceUpdate
 */

final class GetTermsOfServiceUpdate extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2ca51fd1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pending_updates_count string message
 * @return Bool
 */

final class SetBotUpdatesStatus extends Instance {
	public function request(int $pending_updates_count,string $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xec22cfcd);
		$writer->writeInt($pending_updates_count);
		$writer->writeBytes($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return help.PeerColors
 */

final class GetPeerProfileColors extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xabcfa9fd);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id
 * @return help.UserInfo
 */

final class GetUserInfo extends Instance {
	public function request(object $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x38a08d3);
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Config
 */

final class GetConfig extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc4f9186b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.PremiumPromo
 */

final class GetPremiumPromo extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb81b93d4);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string referer
 * @return help.RecentMeUrls
 */

final class GetRecentMeUrls extends Instance {
	public function request(string $referer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3dc0f114);
		$writer->writeBytes($referer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_code int hash
 * @return help.CountriesList
 */

final class GetCountriesList extends Instance {
	public function request(string $lang_code,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x735787a8);
		$writer->writeBytes($lang_code);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return help.AppConfig
 */

final class GetAppConfig extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x61e3f854);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string suggestion
 * @return Bool
 */

final class DismissSuggestion extends Instance {
	public function request(object $peer,string $suggestion) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf50dbaa1);
		$writer->writeObject($peer);
		$writer->writeBytes($suggestion);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return help.PeerColors
 */

final class GetPeerColors extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xda80f42f);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson id
 * @return Bool
 */

final class AcceptTermsOfService extends Instance {
	public function request(object $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xee72f79a);
		$writer->writeObject($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return NearestDc
 */

final class GetNearestDc extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1fb33026);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id string message Vector<messageentity> entities
 * @return help.UserInfo
 */

final class EditUserInfo extends Instance {
	public function request(object $user_id,string $message,array $entities) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x66b91b70);
		$writer->writeObject($user_id);
		$writer->writeBytes($message);
		$writer->writeVector($entities,'messageentity');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return help.TimezonesList
 */

final class GetTimezonesList extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x49b30240);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.SupportName
 */

final class GetSupportName extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd360e72c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return help.PromoData
 */

final class GetPromoData extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc0977421);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return help.PassportConfig
 */

final class GetPassportConfig extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc661ad08);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputappevent> events
 * @return Bool
 */

final class SaveAppLog extends Instance {
	public function request(array $events) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6f02f748);
		$writer->writeVector($events,'inputappevent');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string source
 * @return help.AppUpdate
 */

final class GetAppUpdate extends Instance {
	public function request(string $source) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x522d5a7d);
		$writer->writeBytes($source);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string path
 * @return help.DeepLinkInfo
 */

final class GetDeepLinkInfo extends Instance {
	public function request(string $path) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3fedc75f);
		$writer->writeBytes($path);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Help;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return Bool
 */

final class HidePromoData extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1e251c95);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Photos;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id true suggest true save inputfile file inputfile video double video_start_ts videosize video_emoji_markup
 * @return photos.Photo
 */

final class UploadContactProfilePhoto extends Instance {
	public function request(object $user_id,null | bool $suggest = null,null | bool $save = null,null | object $file = null,null | object $video = null,null | float $video_start_ts = null,null | object $video_emoji_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe14c4a71);
		$flags = 0;
		$flags |= $suggest ? (1 << 3) : 0;
		$flags |= $save ? (1 << 4) : 0;
		$flags |= is_null($file) ? 0 : (1 << 0);
		$flags |= is_null($video) ? 0 : (1 << 1);
		$flags |= is_null($video_start_ts) ? 0 : (1 << 2);
		$flags |= is_null($video_emoji_markup) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeObject($user_id);
		if(is_null($file) === false):
			$writer->writeObject($file);
		endif;
		if(is_null($video) === false):
			$writer->writeObject($video);
		endif;
		if(is_null($video_start_ts) === false):
			$writer->writeDouble($video_start_ts);
		endif;
		if(is_null($video_emoji_markup) === false):
			$writer->writeObject($video_emoji_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Photos;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputphoto> id
 * @return Vector<long>
 */

final class DeletePhotos extends Instance {
	public function request(array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x87cf7f2f);
		$writer->writeVector($id,'inputphoto');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Photos;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphoto id true fallback inputuser bot
 * @return photos.Photo
 */

final class UpdateProfilePhoto extends Instance {
	public function request(object $id,null | bool $fallback = null,null | object $bot = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9e82039);
		$flags = 0;
		$flags |= $fallback ? (1 << 0) : 0;
		$flags |= is_null($bot) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($bot) === false):
			$writer->writeObject($bot);
		endif;
		$writer->writeObject($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Photos;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id int offset long max_id int limit
 * @return photos.Photos
 */

final class GetUserPhotos extends Instance {
	public function request(object $user_id,int $offset,int $max_id,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x91cd32a8);
		$writer->writeObject($user_id);
		$writer->writeInt($offset);
		$writer->writeLong($max_id);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Photos;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true fallback inputuser bot inputfile file inputfile video double video_start_ts videosize video_emoji_markup
 * @return photos.Photo
 */

final class UploadProfilePhoto extends Instance {
	public function request(null | bool $fallback = null,null | object $bot = null,null | object $file = null,null | object $video = null,null | float $video_start_ts = null,null | object $video_emoji_markup = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x388a3b5);
		$flags = 0;
		$flags |= $fallback ? (1 << 3) : 0;
		$flags |= is_null($bot) ? 0 : (1 << 5);
		$flags |= is_null($file) ? 0 : (1 << 0);
		$flags |= is_null($video) ? 0 : (1 << 1);
		$flags |= is_null($video_start_ts) ? 0 : (1 << 2);
		$flags |= is_null($video_emoji_markup) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		if(is_null($bot) === false):
			$writer->writeObject($bot);
		endif;
		if(is_null($file) === false):
			$writer->writeObject($file);
		endif;
		if(is_null($video) === false):
			$writer->writeObject($video);
		endif;
		if(is_null($video_start_ts) === false):
			$writer->writeDouble($video_start_ts);
		endif;
		if(is_null($video_emoji_markup) === false):
			$writer->writeObject($video_emoji_markup);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Fragment;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputcollectible collectible
 * @return fragment.CollectibleInfo
 */

final class GetCollectibleInfo extends Instance {
	public function request(object $collectible) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbe1e85ba);
		$writer->writeObject($collectible);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param botcommandscope scope string lang_code
 * @return Bool
 */

final class ResetBotCommands extends Instance {
	public function request(object $scope,string $lang_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3d8de0f9);
		$writer->writeObject($scope);
		$writer->writeBytes($lang_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot int commission_permille int duration_months
 * @return StarRefProgram
 */

final class UpdateStarRefProgram extends Instance {
	public function request(object $bot,int $commission_permille,null | int $duration_months = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x778b5ab3);
		$flags = 0;
		$flags |= is_null($duration_months) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($bot);
		$writer->writeInt($commission_permille);
		if(is_null($duration_months) === false):
			$writer->writeInt($duration_months);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot bool enabled
 * @return Bool
 */

final class ToggleUserEmojiStatusPermission extends Instance {
	public function request(object $bot,bool $enabled) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6de6392);
		$writer->writeObject($bot);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string username
 * @return Bool
 */

final class CheckUsername extends Instance {
	public function request(string $username) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x87f2219b);
		$writer->writeBytes($username);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot string lang_code Vector<inputmedia> order
 * @return Bool
 */

final class ReorderPreviewMedias extends Instance {
	public function request(object $bot,string $lang_code,array $order) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb627f3aa);
		$writer->writeObject($bot);
		$writer->writeBytes($lang_code);
		$writer->writeVector($order,'inputmedia');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id botmenubutton button
 * @return Bool
 */

final class SetBotMenuButton extends Instance {
	public function request(object $user_id,object $button) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4504d54f);
		$writer->writeObject($user_id);
		$writer->writeObject($button);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Vector<User>
 */

final class GetAdminedBots extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb0711d83);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot string webapp_req_id
 * @return KeyboardButton
 */

final class GetRequestedWebViewButton extends Instance {
	public function request(object $bot,string $webapp_req_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbf25b7f3);
		$writer->writeObject($bot);
		$writer->writeBytes($webapp_req_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string offset int limit
 * @return bots.PopularAppBots
 */

final class GetPopularAppBots extends Instance {
	public function request(string $offset,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc2510192);
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id joinchatbotresult result
 * @return Bool
 */

final class SetJoinChatResults extends Instance {
	public function request(int $query_id,object $result) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe71a4810);
		$writer->writeLong($query_id);
		$writer->writeObject($result);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot string username bool active
 * @return Bool
 */

final class ToggleUsername extends Instance {
	public function request(object $bot,string $username,bool $active) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x53ca973);
		$writer->writeObject($bot);
		$writer->writeBytes($username);
		$writer->writeBool($active);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param botcommandscope scope string lang_code
 * @return Vector<BotCommand>
 */

final class GetBotCommands extends Instance {
	public function request(object $scope,string $lang_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe34c0dd6);
		$writer->writeObject($scope);
		$writer->writeBytes($lang_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot Vector<string> order
 * @return Bool
 */

final class ReorderUsernames extends Instance {
	public function request(object $bot,array $order) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9709b1c2);
		$writer->writeObject($bot);
		$writer->writeVector($order,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long query_id datajson data
 * @return Bool
 */

final class AnswerWebhookJSONQuery extends Instance {
	public function request(int $query_id,object $data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe6213f4d);
		$writer->writeLong($query_id);
		$writer->writeObject($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot
 * @return Bool
 */

final class CanSendMessage extends Instance {
	public function request(object $bot) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1359f4e6);
		$writer->writeObject($bot);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string name string username inputuser manager_id true via_deeplink
 * @return User
 */

final class CreateBot extends Instance {
	public function request(string $name,string $username,object $manager_id,null | bool $via_deeplink = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe5b17f2b);
		$flags = 0;
		$flags |= $via_deeplink ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($name);
		$writer->writeBytes($username);
		$writer->writeObject($manager_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param botcommandscope scope string lang_code Vector<botcommand> commands
 * @return Bool
 */

final class SetBotCommands extends Instance {
	public function request(object $scope,string $lang_code,array $commands) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x517165a);
		$writer->writeObject($scope);
		$writer->writeBytes($lang_code);
		$writer->writeVector($commands,'botcommand');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot
 * @return bots.AccessSettings
 */

final class GetAccessSettings extends Instance {
	public function request(object $bot) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x213853a3);
		$writer->writeObject($bot);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id
 * @return BotMenuButton
 */

final class GetBotMenuButton extends Instance {
	public function request(object $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9c60eb28);
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string custom_method datajson params
 * @return DataJSON
 */

final class SendCustomRequest extends Instance {
	public function request(string $custom_method,object $params) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaa2769ed);
		$writer->writeBytes($custom_method);
		$writer->writeObject($params);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot
 * @return users.Users
 */

final class GetBotRecommendations extends Instance {
	public function request(object $bot) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa1b70815);
		$writer->writeObject($bot);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot string custom_method datajson params
 * @return DataJSON
 */

final class InvokeWebViewCustomMethod extends Instance {
	public function request(object $bot,string $custom_method,object $params) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x87fc5e7);
		$writer->writeObject($bot);
		$writer->writeBytes($custom_method);
		$writer->writeObject($params);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot string lang_code inputmedia media
 * @return BotPreviewMedia
 */

final class AddPreviewMedia extends Instance {
	public function request(object $bot,string $lang_code,object $media) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x17aeb75a);
		$writer->writeObject($bot);
		$writer->writeBytes($lang_code);
		$writer->writeObject($media);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param chatadminrights admin_rights
 * @return Bool
 */

final class SetBotGroupDefaultAdminRights extends Instance {
	public function request(object $admin_rights) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x925ec9ea);
		$writer->writeObject($admin_rights);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot string lang_code Vector<inputmedia> media
 * @return Bool
 */

final class DeletePreviewMedia extends Instance {
	public function request(object $bot,string $lang_code,array $media) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2d0135b3);
		$writer->writeObject($bot);
		$writer->writeBytes($lang_code);
		$writer->writeVector($media,'inputmedia');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot string file_name string url
 * @return Bool
 */

final class CheckDownloadFileParams extends Instance {
	public function request(object $bot,string $file_name,string $url) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x50077589);
		$writer->writeObject($bot);
		$writer->writeBytes($file_name);
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot
 * @return Updates
 */

final class AllowSendMessage extends Instance {
	public function request(object $bot) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf132e3ef);
		$writer->writeObject($bot);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param chatadminrights admin_rights
 * @return Bool
 */

final class SetBotBroadcastDefaultAdminRights extends Instance {
	public function request(object $admin_rights) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x788464e1);
		$writer->writeObject($admin_rights);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer true enabled inputuser bot string custom_description
 * @return Bool
 */

final class SetCustomVerification extends Instance {
	public function request(object $peer,null | bool $enabled = null,null | object $bot = null,null | string $custom_description = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8b89dfbd);
		$flags = 0;
		$flags |= $enabled ? (1 << 1) : 0;
		$flags |= is_null($bot) ? 0 : (1 << 0);
		$flags |= is_null($custom_description) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($bot) === false):
			$writer->writeObject($bot);
		endif;
		$writer->writeObject($peer);
		if(is_null($custom_description) === false):
			$writer->writeBytes($custom_description);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_code inputuser bot string name string about string description
 * @return Bool
 */

final class SetBotInfo extends Instance {
	public function request(string $lang_code,null | object $bot = null,null | string $name = null,null | string $about = null,null | string $description = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x10cf3123);
		$flags = 0;
		$flags |= is_null($bot) ? 0 : (1 << 2);
		$flags |= is_null($name) ? 0 : (1 << 3);
		$flags |= is_null($about) ? 0 : (1 << 0);
		$flags |= is_null($description) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($bot) === false):
			$writer->writeObject($bot);
		endif;
		$writer->writeBytes($lang_code);
		if(is_null($name) === false):
			$writer->writeBytes($name);
		endif;
		if(is_null($about) === false):
			$writer->writeBytes($about);
		endif;
		if(is_null($description) === false):
			$writer->writeBytes($description);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id keyboardbutton button
 * @return bots.RequestedButton
 */

final class RequestWebViewButton extends Instance {
	public function request(object $user_id,object $button) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31a2a35e);
		$writer->writeObject($user_id);
		$writer->writeObject($button);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot
 * @return Vector<BotPreviewMedia>
 */

final class GetPreviewMedias extends Instance {
	public function request(object $bot) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa2a5594d);
		$writer->writeObject($bot);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot true restricted Vector<inputuser> add_users
 * @return Bool
 */

final class EditAccessSettings extends Instance {
	public function request(object $bot,null | bool $restricted = null,null | array $add_users = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x31813cd8);
		$flags = 0;
		$flags |= $restricted ? (1 << 0) : 0;
		$flags |= is_null($add_users) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($bot);
		if(is_null($add_users) === false):
			$writer->writeVector($add_users,'inputuser');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot string lang_code inputmedia media inputmedia new_media
 * @return BotPreviewMedia
 */

final class EditPreviewMedia extends Instance {
	public function request(object $bot,string $lang_code,object $media,object $new_media) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8525606f);
		$writer->writeObject($bot);
		$writer->writeBytes($lang_code);
		$writer->writeObject($media);
		$writer->writeObject($new_media);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id emojistatus emoji_status
 * @return Bool
 */

final class UpdateUserEmojiStatus extends Instance {
	public function request(object $user_id,object $emoji_status) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xed9f30c5);
		$writer->writeObject($user_id);
		$writer->writeObject($emoji_status);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot string lang_code
 * @return bots.PreviewInfo
 */

final class GetPreviewInfo extends Instance {
	public function request(object $bot,string $lang_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x423ab3ad);
		$writer->writeObject($bot);
		$writer->writeBytes($lang_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_code inputuser bot
 * @return bots.BotInfo
 */

final class GetBotInfo extends Instance {
	public function request(string $lang_code,null | object $bot = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdcd914fd);
		$flags = 0;
		$flags |= is_null($bot) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($bot) === false):
			$writer->writeObject($bot);
		endif;
		$writer->writeBytes($lang_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Bots;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot bool revoke
 * @return bots.ExportedBotToken
 */

final class ExportBotToken extends Instance {
	public function request(object $bot,bool $revoke) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd0d99eb);
		$writer->writeObject($bot);
		$writer->writeBool($revoke);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> id
 * @return Bool
 */

final class EditCloseFriends extends Instance {
	public function request(array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xba6705f0);
		$writer->writeVector($id,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q int limit true broadcasts true bots
 * @return contacts.Found
 */

final class Search extends Instance {
	public function request(string $q,int $limit,null | bool $broadcasts = null,null | bool $bots = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5f58d0f);
		$flags = 0;
		$flags |= $broadcasts ? (1 << 0) : 0;
		$flags |= $bots ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeBytes($q);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string q
 * @return contacts.SponsoredPeers
 */

final class GetSponsoredPeers extends Instance {
	public function request(string $q) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb6c8c393);
		$writer->writeBytes($q);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Vector<SavedContact>
 */

final class GetSaved extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x82f1e39f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class ResetSaved extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x879537f1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputcontact> contacts
 * @return contacts.ImportedContacts
 */

final class ImportContacts extends Instance {
	public function request(array $contacts) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2c800be5);
		$writer->writeVector($contacts,'inputcontact');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return contacts.Contacts
 */

final class GetContacts extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5dd69e12);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return Vector<int>
 */

final class GetContactIDs extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7adc669d);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<string> phones
 * @return Bool
 */

final class DeleteByPhones extends Instance {
	public function request(array $phones) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1013fd9e);
		$writer->writeVector($phones,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string token
 * @return User
 */

final class ImportContactToken extends Instance {
	public function request(string $token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x13005788);
		$writer->writeBytes($token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int limit long hash true correspondents true bots_pm true bots_inline true phone_calls true forward_users true forward_chats true groups true channels true bots_app true bots_guestchat
 * @return contacts.TopPeers
 */

final class GetTopPeers extends Instance {
	public function request(int $offset,int $limit,int $hash,null | bool $correspondents = null,null | bool $bots_pm = null,null | bool $bots_inline = null,null | bool $phone_calls = null,null | bool $forward_users = null,null | bool $forward_chats = null,null | bool $groups = null,null | bool $channels = null,null | bool $bots_app = null,null | bool $bots_guestchat = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x973478b6);
		$flags = 0;
		$flags |= $correspondents ? (1 << 0) : 0;
		$flags |= $bots_pm ? (1 << 1) : 0;
		$flags |= $bots_inline ? (1 << 2) : 0;
		$flags |= $phone_calls ? (1 << 3) : 0;
		$flags |= $forward_users ? (1 << 4) : 0;
		$flags |= $forward_chats ? (1 << 5) : 0;
		$flags |= $groups ? (1 << 10) : 0;
		$flags |= $channels ? (1 << 15) : 0;
		$flags |= $bots_app ? (1 << 16) : 0;
		$flags |= $bots_guestchat ? (1 << 17) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($offset);
		$writer->writeInt($limit);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer id true my_stories_from
 * @return Bool
 */

final class Block extends Instance {
	public function request(object $id,null | bool $my_stories_from = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2e2e8734);
		$flags = 0;
		$flags |= $my_stories_from ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputuser> id
 * @return Updates
 */

final class DeleteContacts extends Instance {
	public function request(array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x96a0e00);
		$writer->writeVector($id,'inputuser');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool enabled
 * @return Bool
 */

final class ToggleTopPeers extends Instance {
	public function request(bool $enabled) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8514bdda);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgeopoint geo_point true background int self_expires
 * @return Updates
 */

final class GetLocated extends Instance {
	public function request(object $geo_point,null | bool $background = null,null | int $self_expires = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd348bc44);
		$flags = 0;
		$flags |= $background ? (1 << 1) : 0;
		$flags |= is_null($self_expires) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($geo_point);
		if(is_null($self_expires) === false):
			$writer->writeInt($self_expires);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ExportedContactToken
 */

final class ExportContactToken extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf8654027);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string username string referer
 * @return contacts.ResolvedPeer
 */

final class ResolveUsername extends Instance {
	public function request(string $username,null | string $referer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x725afbbc);
		$flags = 0;
		$flags |= is_null($referer) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($username);
		if(is_null($referer) === false):
			$writer->writeBytes($referer);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputpeer> id int limit true my_stories_from
 * @return Bool
 */

final class SetBlocked extends Instance {
	public function request(array $id,int $limit,null | bool $my_stories_from = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x94c65c76);
		$flags = 0;
		$flags |= $my_stories_from ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeVector($id,'inputpeer');
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int msg_id true delete_message true delete_history true report_spam
 * @return Updates
 */

final class BlockFromReplies extends Instance {
	public function request(int $msg_id,null | bool $delete_message = null,null | bool $delete_history = null,null | bool $report_spam = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x29a8962c);
		$flags = 0;
		$flags |= $delete_message ? (1 << 0) : 0;
		$flags |= $delete_history ? (1 << 1) : 0;
		$flags |= $report_spam ? (1 << 2) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser id textwithentities note
 * @return Bool
 */

final class UpdateContactNote extends Instance {
	public function request(object $id,object $note) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x139f63fb);
		$writer->writeObject($id);
		$writer->writeObject($note);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer id true my_stories_from
 * @return Bool
 */

final class Unblock extends Instance {
	public function request(object $id,null | bool $my_stories_from = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb550d328);
		$flags = 0;
		$flags |= $my_stories_from ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone
 * @return contacts.ResolvedPeer
 */

final class ResolvePhone extends Instance {
	public function request(string $phone) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8af94344);
		$writer->writeBytes($phone);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param toppeercategory category inputpeer peer
 * @return Bool
 */

final class ResetTopPeerRating extends Instance {
	public function request(object $category,object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1ae373ac);
		$writer->writeObject($category);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offset int limit true my_stories_from
 * @return contacts.Blocked
 */

final class GetBlocked extends Instance {
	public function request(int $offset,int $limit,null | bool $my_stories_from = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9a868f80);
		$flags = 0;
		$flags |= $my_stories_from ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser id
 * @return Updates
 */

final class AcceptContact extends Instance {
	public function request(object $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf831a20f);
		$writer->writeObject($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return contacts.ContactBirthdays
 */

final class GetBirthdays extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdaeda864);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Vector<ContactStatus>
 */

final class GetStatuses extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc4a353ee);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Contacts;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser id string first_name string last_name string phone true add_phone_privacy_exception textwithentities note
 * @return Updates
 */

final class AddContact extends Instance {
	public function request(object $id,string $first_name,string $last_name,string $phone,null | bool $add_phone_privacy_exception = null,null | object $note = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd9ba2e54);
		$flags = 0;
		$flags |= $add_phone_privacy_exception ? (1 << 0) : 0;
		$flags |= is_null($note) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($id);
		$writer->writeBytes($first_name);
		$writer->writeBytes($last_name);
		$writer->writeBytes($phone);
		if(is_null($note) === false):
			$writer->writeObject($note);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Folders;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputfolderpeer> folder_peers
 * @return Updates
 */

final class EditPeerFolders extends Instance {
	public function request(array $folder_peers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6847d0ab);
		$writer->writeVector($folder_peers,'inputfolderpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser id birthday birthday
 * @return Updates
 */

final class SuggestBirthday extends Instance {
	public function request(object $id,object $birthday) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfc533372);
		$writer->writeObject($id);
		$writer->writeObject($birthday);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser id int offset int limit long hash
 * @return users.SavedMusic
 */

final class GetSavedMusic extends Instance {
	public function request(object $id,int $offset,int $limit,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x788d7fe3);
		$writer->writeObject($id);
		$writer->writeInt($offset);
		$writer->writeInt($limit);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser id
 * @return users.UserFull
 */

final class GetFullUser extends Instance {
	public function request(object $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb60f5918);
		$writer->writeObject($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser id Vector<inputdocument> documents
 * @return users.SavedMusic
 */

final class GetSavedMusicByID extends Instance {
	public function request(object $id,array $documents) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7573a4e9);
		$writer->writeObject($id);
		$writer->writeVector($documents,'inputdocument');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputuser> id
 * @return Vector<User>
 */

final class GetUsers extends Instance {
	public function request(array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd91a548);
		$writer->writeVector($id,'inputuser');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputuser> id
 * @return Vector<RequirementToContact>
 */

final class GetRequirementsToContact extends Instance {
	public function request(array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd89a83a3);
		$writer->writeVector($id,'inputuser');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Users;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser id Vector<securevalueerror> errors
 * @return Bool
 */

final class SetSecureValueErrors extends Instance {
	public function request(object $id,array $errors) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x90c894b5);
		$writer->writeObject($id);
		$writer->writeVector($errors,'securevalueerror');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer true ton
 * @return payments.StarsStatus
 */

final class GetStarsStatus extends Instance {
	public function request(object $peer,null | bool $ton = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4ea9b3bf);
		$flags = 0;
		$flags |= $ton ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<inputstarstransaction> id true ton
 * @return payments.StarsStatus
 */

final class GetStarsTransactionsByID extends Instance {
	public function request(object $peer,array $id,null | bool $ton = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2dca16b8);
		$flags = 0;
		$flags |= $ton ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeVector($id,'inputstarstransaction');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string link true revoked
 * @return payments.ConnectedStarRefBots
 */

final class EditConnectedStarRefBot extends Instance {
	public function request(object $peer,string $link,null | bool $revoked = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe4fca4a3);
		$flags = 0;
		$flags |= $revoked ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBytes($link);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return payments.SavedInfo
 */

final class GetSavedInfo extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x227d824b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstargiftauction auction int version
 * @return payments.StarGiftAuctionState
 */

final class GetStarGiftAuctionState extends Instance {
	public function request(object $auction,int $version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5c9ff4d6);
		$writer->writeObject($auction);
		$writer->writeInt($version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputsavedstargift> stargift
 * @return Updates
 */

final class CraftStarGift extends Instance {
	public function request(array $stargift) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb0f9684f);
		$writer->writeVector($stargift,'inputsavedstargift');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int limit int offset_date string offset_link
 * @return payments.ConnectedStarRefBots
 */

final class GetConnectedStarRefBots extends Instance {
	public function request(object $peer,int $limit,null | int $offset_date = null,null | string $offset_link = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5869a553);
		$flags = 0;
		$flags |= is_null($offset_date) ? 0 : (1 << 2);
		$flags |= is_null($offset_link) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($offset_date) === false):
			$writer->writeInt($offset_date);
		endif;
		if(is_null($offset_link) === false):
			$writer->writeBytes($offset_link);
		endif;
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long gift_id
 * @return payments.StarGiftAuctionAcquiredGifts
 */

final class GetStarGiftAuctionAcquiredGifts extends Instance {
	public function request(int $gift_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6ba2cbec);
		$writer->writeLong($gift_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id string charge_id true restore
 * @return Bool
 */

final class BotCancelStarsSubscription extends Instance {
	public function request(object $user_id,string $charge_id,null | bool $restore = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6dfa0622);
		$flags = 0;
		$flags |= $restore ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($user_id);
		$writer->writeBytes($charge_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputsavedstargift> stargift
 * @return payments.SavedStarGifts
 */

final class GetSavedStarGift extends Instance {
	public function request(array $stargift) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb455a106);
		$writer->writeVector($stargift,'inputsavedstargift');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Vector<StarsTopupOption>
 */

final class GetStarsTopupOptions extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc00ec7d3);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id
 * @return Vector<StarsGiftOption>
 */

final class GetStarsGiftOptions extends Instance {
	public function request(null | object $user_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd3c96bc8);
		$flags = 0;
		$flags |= is_null($user_id) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($user_id) === false):
			$writer->writeObject($user_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer true enabled
 * @return Bool
 */

final class ToggleChatStarGiftNotifications extends Instance {
	public function request(object $peer,null | bool $enabled = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x60eaefa1);
		$flags = 0;
		$flags |= $enabled ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long gift_id
 * @return payments.StarGiftUpgradePreview
 */

final class GetStarGiftUpgradePreview extends Instance {
	public function request(int $gift_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9c9abcb1);
		$writer->writeLong($gift_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int collection_id
 * @return Bool
 */

final class DeleteStarGiftCollection extends Instance {
	public function request(object $peer,int $collection_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xad5648e8);
		$writer->writeObject($peer);
		$writer->writeInt($collection_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputsavedstargift stargift true keep_original_details
 * @return Updates
 */

final class UpgradeStarGift extends Instance {
	public function request(object $stargift,null | bool $keep_original_details = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaed6e4f5);
		$flags = 0;
		$flags |= $keep_original_details ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($stargift);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputsavedstargift stargift inputpeer to_id
 * @return Updates
 */

final class TransferStarGift extends Instance {
	public function request(object $stargift,object $to_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7f18176a);
		$writer->writeObject($stargift);
		$writer->writeObject($to_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param datajson receipt inputstorepaymentpurpose purpose
 * @return Updates
 */

final class AssignPlayMarketTransaction extends Instance {
	public function request(object $receipt,object $purpose) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdffd50d3);
		$writer->writeObject($receipt);
		$writer->writeObject($purpose);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string number
 * @return payments.BankCardData
 */

final class GetBankCardData extends Instance {
	public function request(string $number) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2e79d779);
		$writer->writeBytes($number);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long form_id inputinvoice invoice inputpaymentcredentials credentials string requested_info_id string shipping_option_id long tip_amount
 * @return payments.PaymentResult
 */

final class SendPaymentForm extends Instance {
	public function request(int $form_id,object $invoice,object $credentials,null | string $requested_info_id = null,null | string $shipping_option_id = null,null | int $tip_amount = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2d03522f);
		$flags = 0;
		$flags |= is_null($requested_info_id) ? 0 : (1 << 0);
		$flags |= is_null($shipping_option_id) ? 0 : (1 << 1);
		$flags |= is_null($tip_amount) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeLong($form_id);
		$writer->writeObject($invoice);
		if(is_null($requested_info_id) === false):
			$writer->writeBytes($requested_info_id);
		endif;
		if(is_null($shipping_option_id) === false):
			$writer->writeBytes($shipping_option_id);
		endif;
		$writer->writeObject($credentials);
		if(is_null($tip_amount) === false):
			$writer->writeLong($tip_amount);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string title Vector<inputsavedstargift> stargift
 * @return StarGiftCollection
 */

final class CreateStarGiftCollection extends Instance {
	public function request(object $peer,string $title,array $stargift) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1f4a0e87);
		$writer->writeObject($peer);
		$writer->writeBytes($title);
		$writer->writeVector($stargift,'inputsavedstargift');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer long giveaway_id inputstorepaymentpurpose purpose
 * @return Updates
 */

final class LaunchPrepaidGiveaway extends Instance {
	public function request(object $peer,int $giveaway_id,object $purpose) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5ff58f20);
		$writer->writeObject($peer);
		$writer->writeLong($giveaway_id);
		$writer->writeObject($purpose);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Vector<StarsGiveawayOption>
 */

final class GetStarsGiveawayOptions extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd1efd3e);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id
 * @return payments.GiveawayInfo
 */

final class GetGiveawayInfo extends Instance {
	public function request(object $peer,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf4239425);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputuser bot
 * @return payments.ConnectedStarRefBots
 */

final class ConnectStarRefBot extends Instance {
	public function request(object $peer,object $bot) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7ed5348a);
		$writer->writeObject($peer);
		$writer->writeObject($bot);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputcheckpasswordsrp password true ton long amount
 * @return payments.StarsRevenueWithdrawalUrl
 */

final class GetStarsRevenueWithdrawalUrl extends Instance {
	public function request(object $peer,object $password,null | bool $ton = null,null | int $amount = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2433dc92);
		$flags = 0;
		$flags |= $ton ? (1 << 0) : 0;
		$flags |= is_null($amount) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($amount) === false):
			$writer->writeLong($amount);
		endif;
		$writer->writeObject($password);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string subscription_id bool canceled
 * @return Bool
 */

final class ChangeStarsSubscription extends Instance {
	public function request(object $peer,string $subscription_id,null | bool $canceled = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc7770878);
		$flags = 0;
		$flags |= is_null($canceled) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBytes($subscription_id);
		if(is_null($canceled) === false):
			$writer->writeBool($canceled);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string offset true missing_balance
 * @return payments.StarsStatus
 */

final class GetStarsSubscriptions extends Instance {
	public function request(object $peer,string $offset,null | bool $missing_balance = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x32512c5);
		$flags = 0;
		$flags |= $missing_balance ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBytes($offset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int hash
 * @return payments.StarGifts
 */

final class GetStarGifts extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc4563590);
		$writer->writeInt($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return payments.UniqueStarGiftValueInfo
 */

final class GetUniqueStarGiftValueInfo extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4365af6b);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputmedia invoice_media
 * @return payments.ExportedInvoice
 */

final class ExportInvoice extends Instance {
	public function request(object $invoice_media) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf91b065);
		$writer->writeObject($invoice_media);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return Updates
 */

final class ApplyGiftCode extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf6e26854);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputsavedstargift stargift true unsave
 * @return Bool
 */

final class SaveStarGift extends Instance {
	public function request(object $stargift,null | bool $unsave = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2a2a697c);
		$flags = 0;
		$flags |= $unsave ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($stargift);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string offset int limit true order_by_revenue true order_by_date
 * @return payments.SuggestedStarRefBots
 */

final class GetSuggestedStarRefBots extends Instance {
	public function request(object $peer,string $offset,int $limit,null | bool $order_by_revenue = null,null | bool $order_by_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd6b48f7);
		$flags = 0;
		$flags |= $order_by_revenue ? (1 << 0) : 0;
		$flags |= $order_by_date ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputsavedstargift stargift
 * @return Bool
 */

final class ConvertStarGift extends Instance {
	public function request(object $stargift) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x74bf076b);
		$writer->writeObject($stargift);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return payments.UniqueStarGift
 */

final class GetUniqueStarGift extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa1974d72);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer true dark true ton
 * @return payments.StarsRevenueStats
 */

final class GetStarsRevenueStats extends Instance {
	public function request(object $peer,null | bool $dark = null,null | bool $ton = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd91ffad6);
		$flags = 0;
		$flags |= $dark ? (1 << 0) : 0;
		$flags |= $ton ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long gift_id string offset int limit true sort_by_price true sort_by_num true for_craft true stars_only long attributes_hash Vector<stargiftattributeid> attributes
 * @return payments.ResaleStarGifts
 */

final class GetResaleStarGifts extends Instance {
	public function request(int $gift_id,string $offset,int $limit,null | bool $sort_by_price = null,null | bool $sort_by_num = null,null | bool $for_craft = null,null | bool $stars_only = null,null | int $attributes_hash = null,null | array $attributes = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7a5fa236);
		$flags = 0;
		$flags |= $sort_by_price ? (1 << 1) : 0;
		$flags |= $sort_by_num ? (1 << 2) : 0;
		$flags |= $for_craft ? (1 << 4) : 0;
		$flags |= $stars_only ? (1 << 5) : 0;
		$flags |= is_null($attributes_hash) ? 0 : (1 << 0);
		$flags |= is_null($attributes) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($attributes_hash) === false):
			$writer->writeLong($attributes_hash);
		endif;
		$writer->writeLong($gift_id);
		if(is_null($attributes) === false):
			$writer->writeVector($attributes,'stargiftattributeid');
		endif;
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long gift_id
 * @return payments.CheckCanSendGiftResult
 */

final class CheckCanSendGift extends Instance {
	public function request(int $gift_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc0c4edc9);
		$writer->writeLong($gift_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputuser bot
 * @return payments.ConnectedStarRefBots
 */

final class GetConnectedStarRefBot extends Instance {
	public function request(object $peer,object $bot) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb7d998f0);
		$writer->writeObject($peer);
		$writer->writeObject($bot);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return payments.CheckedGiftCode
 */

final class CheckGiftCode extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8e51b4c1);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int msg_id
 * @return payments.PaymentReceipt
 */

final class GetPaymentReceipt extends Instance {
	public function request(object $peer,int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2478d1cc);
		$writer->writeObject($peer);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return payments.StarGiftActiveAuctions
 */

final class GetStarGiftActiveAuctions extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa5d0514d);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer long hash
 * @return payments.StarGiftCollections
 */

final class GetStarGiftCollections extends Instance {
	public function request(object $peer,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x981b91dd);
		$writer->writeObject($peer);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return payments.StarsRevenueAdsAccountUrl
 */

final class GetStarsRevenueAdsAccountUrl extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd1d7efc5);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string slug starsamount price int duration long random_id long allow_paid_stars
 * @return Updates
 */

final class SendStarGiftOffer extends Instance {
	public function request(object $peer,string $slug,object $price,int $duration,int $random_id,null | int $allow_paid_stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8fb86b41);
		$flags = 0;
		$flags |= is_null($allow_paid_stars) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBytes($slug);
		$writer->writeObject($price);
		$writer->writeInt($duration);
		$writer->writeLong($random_id);
		if(is_null($allow_paid_stars) === false):
			$writer->writeLong($allow_paid_stars);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<inputsavedstargift> stargift
 * @return Bool
 */

final class ToggleStarGiftsPinnedToTop extends Instance {
	public function request(object $peer,array $stargift) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1513e7b0);
		$writer->writeObject($peer);
		$writer->writeVector($stargift,'inputsavedstargift');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long gift_id
 * @return payments.StarGiftUpgradeAttributes
 */

final class GetStarGiftUpgradeAttributes extends Instance {
	public function request(int $gift_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6d038b58);
		$writer->writeLong($gift_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long form_id inputinvoice invoice
 * @return payments.PaymentResult
 */

final class SendStarsForm extends Instance {
	public function request(int $form_id,object $invoice) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7998c914);
		$writer->writeLong($form_id);
		$writer->writeObject($invoice);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> order
 * @return Bool
 */

final class ReorderStarGiftCollections extends Instance {
	public function request(object $peer,array $order) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc32af4cc);
		$writer->writeObject($peer);
		$writer->writeVector($order,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int offer_msg_id true decline
 * @return Updates
 */

final class ResolveStarGiftOffer extends Instance {
	public function request(int $offer_msg_id,null | bool $decline = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe9ce781c);
		$flags = 0;
		$flags |= $decline ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($offer_msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes receipt inputstorepaymentpurpose purpose
 * @return Updates
 */

final class AssignAppStoreTransaction extends Instance {
	public function request(string $receipt,object $purpose) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x80ed747d);
		$writer->writeBytes($receipt);
		$writer->writeObject($purpose);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstorepaymentpurpose purpose
 * @return Bool
 */

final class CanPurchaseStore extends Instance {
	public function request(object $purpose) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4fdc5ea7);
		$writer->writeObject($purpose);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id string charge_id
 * @return Updates
 */

final class RefundStarsCharge extends Instance {
	public function request(object $user_id,string $charge_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x25ae8f4a);
		$writer->writeObject($user_id);
		$writer->writeBytes($charge_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true credentials true info
 * @return Bool
 */

final class ClearSavedInfo extends Instance {
	public function request(null | bool $credentials = null,null | bool $info = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd83d70c1);
		$flags = 0;
		$flags |= $credentials ? (1 << 0) : 0;
		$flags |= $info ? (1 << 1) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string offset int limit true exclude_unsaved true exclude_saved true exclude_unlimited true exclude_unique true sort_by_value true exclude_upgradable true exclude_unupgradable true peer_color_available true exclude_hosted int collection_id
 * @return payments.SavedStarGifts
 */

final class GetSavedStarGifts extends Instance {
	public function request(object $peer,string $offset,int $limit,null | bool $exclude_unsaved = null,null | bool $exclude_saved = null,null | bool $exclude_unlimited = null,null | bool $exclude_unique = null,null | bool $sort_by_value = null,null | bool $exclude_upgradable = null,null | bool $exclude_unupgradable = null,null | bool $peer_color_available = null,null | bool $exclude_hosted = null,null | int $collection_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa319e569);
		$flags = 0;
		$flags |= $exclude_unsaved ? (1 << 0) : 0;
		$flags |= $exclude_saved ? (1 << 1) : 0;
		$flags |= $exclude_unlimited ? (1 << 2) : 0;
		$flags |= $exclude_unique ? (1 << 4) : 0;
		$flags |= $sort_by_value ? (1 << 5) : 0;
		$flags |= $exclude_upgradable ? (1 << 7) : 0;
		$flags |= $exclude_unupgradable ? (1 << 8) : 0;
		$flags |= $peer_color_available ? (1 << 9) : 0;
		$flags |= $exclude_hosted ? (1 << 10) : 0;
		$flags |= is_null($collection_id) ? 0 : (1 << 6);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($collection_id) === false):
			$writer->writeInt($collection_id);
		endif;
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputinvoice invoice datajson theme_params
 * @return payments.PaymentForm
 */

final class GetPaymentForm extends Instance {
	public function request(object $invoice,null | object $theme_params = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x37148dbb);
		$flags = 0;
		$flags |= is_null($theme_params) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($invoice);
		if(is_null($theme_params) === false):
			$writer->writeObject($theme_params);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long gift_id string offset int limit
 * @return payments.SavedStarGifts
 */

final class GetCraftStarGifts extends Instance {
	public function request(int $gift_id,string $offset,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfd05dd00);
		$writer->writeLong($gift_id);
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int collection_id string title Vector<inputsavedstargift> delete_stargift Vector<inputsavedstargift> add_stargift Vector<inputsavedstargift> order
 * @return StarGiftCollection
 */

final class UpdateStarGiftCollection extends Instance {
	public function request(object $peer,int $collection_id,null | string $title = null,null | array $delete_stargift = null,null | array $add_stargift = null,null | array $order = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4fddbee7);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$flags |= is_null($delete_stargift) ? 0 : (1 << 1);
		$flags |= is_null($add_stargift) ? 0 : (1 << 2);
		$flags |= is_null($order) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($collection_id);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($delete_stargift) === false):
			$writer->writeVector($delete_stargift,'inputsavedstargift');
		endif;
		if(is_null($add_stargift) === false):
			$writer->writeVector($add_stargift,'inputsavedstargift');
		endif;
		if(is_null($order) === false):
			$writer->writeVector($order,'inputsavedstargift');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputsavedstargift stargift starsamount resell_amount
 * @return Updates
 */

final class UpdateStarGiftPrice extends Instance {
	public function request(object $stargift,object $resell_amount) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xedbe6ccb);
		$writer->writeObject($stargift);
		$writer->writeObject($resell_amount);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer boost_peer
 * @return Vector<PremiumGiftCodeOption>
 */

final class GetPremiumGiftCodeOptions extends Instance {
	public function request(null | object $boost_peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2757ba54);
		$flags = 0;
		$flags |= is_null($boost_peer) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($boost_peer) === false):
			$writer->writeObject($boost_peer);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string subscription_id
 * @return Bool
 */

final class FulfillStarsSubscription extends Instance {
	public function request(object $peer,string $subscription_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcc5bebb3);
		$writer->writeObject($peer);
		$writer->writeBytes($subscription_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputinvoice invoice paymentrequestedinfo info true save
 * @return payments.ValidatedRequestedInfo
 */

final class ValidateRequestedInfo extends Instance {
	public function request(object $invoice,object $info,null | bool $save = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb6c8f12b);
		$flags = 0;
		$flags |= $save ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($invoice);
		$writer->writeObject($info);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string offset int limit true inbound true outbound true ascending true ton string subscription_id
 * @return payments.StarsStatus
 */

final class GetStarsTransactions extends Instance {
	public function request(object $peer,string $offset,int $limit,null | bool $inbound = null,null | bool $outbound = null,null | bool $ascending = null,null | bool $ton = null,null | string $subscription_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x69da4557);
		$flags = 0;
		$flags |= $inbound ? (1 << 0) : 0;
		$flags |= $outbound ? (1 << 1) : 0;
		$flags |= $ascending ? (1 << 2) : 0;
		$flags |= $ton ? (1 << 4) : 0;
		$flags |= is_null($subscription_id) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($subscription_id) === false):
			$writer->writeBytes($subscription_id);
		endif;
		$writer->writeObject($peer);
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Payments;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputsavedstargift stargift inputcheckpasswordsrp password
 * @return payments.StarGiftWithdrawalUrl
 */

final class GetStarGiftWithdrawalUrl extends Instance {
	public function request(object $stargift,object $password) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd06e93a8);
		$writer->writeObject($stargift);
		$writer->writeObject($password);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param accountdaysttl ttl
 * @return Bool
 */

final class SetAccountTTL extends Instance {
	public function request(object $ttl) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2442485e);
		$writer->writeObject($ttl);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number codesettings settings
 * @return auth.SentCode
 */

final class SendVerifyPhoneCode extends Instance {
	public function request(string $phone_number,object $settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa5a356f9);
		$writer->writeBytes($phone_number);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.AutoDownloadSettings
 */

final class GetAutoDownloadSettings extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x56da0b3f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return account.SavedRingtones
 */

final class GetSavedRingtones extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe1902288);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash true confirmed bool encrypted_requests_disabled bool call_requests_disabled
 * @return Bool
 */

final class ChangeAuthorizationSettings extends Instance {
	public function request(int $hash,null | bool $confirmed = null,null | bool $encrypted_requests_disabled = null,null | bool $call_requests_disabled = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x40f48462);
		$flags = 0;
		$flags |= $confirmed ? (1 << 3) : 0;
		$flags |= is_null($encrypted_requests_disabled) ? 0 : (1 << 0);
		$flags |= is_null($call_requests_disabled) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeLong($hash);
		if(is_null($encrypted_requests_disabled) === false):
			$writer->writeBool($encrypted_requests_disabled);
		endif;
		if(is_null($call_requests_disabled) === false):
			$writer->writeBool($call_requests_disabled);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument id bool unsave
 * @return account.SavedRingtone
 */

final class SaveRingtone extends Instance {
	public function request(object $id,bool $unsave) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3dea5b03);
		$writer->writeObject($id);
		$writer->writeBool($unsave);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool enabled
 * @return Bool
 */

final class ToggleSponsoredMessages extends Instance {
	public function request(bool $enabled) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb9d9a38d);
		$writer->writeBool($enabled);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputfile file string file_name string mime_type
 * @return Document
 */

final class UploadRingtone extends Instance {
	public function request(object $file,string $file_name,string $mime_type) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x831a83a2);
		$writer->writeObject($file);
		$writer->writeBytes($file_name);
		$writer->writeBytes($mime_type);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int period
 * @return Bool
 */

final class UpdateDeviceLocked extends Instance {
	public function request(int $period) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x38df3532);
		$writer->writeInt($period);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true sensitive_enabled
 * @return Bool
 */

final class SetContentSettings extends Instance {
	public function request(null | bool $sensitive_enabled = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb574b16b);
		$flags = 0;
		$flags |= $sensitive_enabled ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true contacts true message_users true message_chats true message_megagroups true message_channels true files long file_max_size
 * @return account.Takeout
 */

final class InitTakeoutSession extends Instance {
	public function request(null | bool $contacts = null,null | bool $message_users = null,null | bool $message_chats = null,null | bool $message_megagroups = null,null | bool $message_channels = null,null | bool $files = null,null | int $file_max_size = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ef3eab0);
		$flags = 0;
		$flags |= $contacts ? (1 << 0) : 0;
		$flags |= $message_users ? (1 << 1) : 0;
		$flags |= $message_chats ? (1 << 2) : 0;
		$flags |= $message_megagroups ? (1 << 3) : 0;
		$flags |= $message_channels ? (1 << 4) : 0;
		$flags |= $files ? (1 << 5) : 0;
		$flags |= is_null($file_max_size) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		if(is_null($file_max_size) === false):
			$writer->writeLong($file_max_size);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param emailverifypurpose purpose emailverification verification
 * @return account.EmailVerified
 */

final class VerifyEmail extends Instance {
	public function request(object $purpose,object $verification) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x32da4cf);
		$writer->writeObject($purpose);
		$writer->writeObject($verification);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id inputpeer parent_peer
 * @return account.PaidMessagesRevenue
 */

final class GetPaidMessagesRevenue extends Instance {
	public function request(object $user_id,null | object $parent_peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x19ba4a67);
		$flags = 0;
		$flags |= is_null($parent_peer) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($parent_peer) === false):
			$writer->writeObject($parent_peer);
		endif;
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class ClearRecentEmojiStatuses extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x18201aae);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param globalprivacysettings settings
 * @return GlobalPrivacySettings
 */

final class SetGlobalPrivacySettings extends Instance {
	public function request(object $settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1edaaac2);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param emailverifypurpose purpose string email
 * @return account.SentEmailCode
 */

final class SendVerifyEmailCode extends Instance {
	public function request(object $purpose,string $email) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x98e037bb);
		$writer->writeObject($purpose);
		$writer->writeBytes($email);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string username
 * @return User
 */

final class UpdateUsername extends Instance {
	public function request(string $username) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3e0bdd7c);
		$writer->writeBytes($username);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string username
 * @return Bool
 */

final class CheckUsername extends Instance {
	public function request(string $username) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2714d86c);
		$writer->writeBytes($username);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputfile file string file_name string mime_type inputfile thumb
 * @return Document
 */

final class UploadTheme extends Instance {
	public function request(object $file,string $file_name,string $mime_type,null | object $thumb = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1c3db333);
		$flags = 0;
		$flags |= is_null($thumb) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeObject($file);
		if(is_null($thumb) === false):
			$writer->writeObject($thumb);
		endif;
		$writer->writeBytes($file_name);
		$writer->writeBytes($mime_type);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<securevaluetype> types
 * @return Bool
 */

final class DeleteSecureValue extends Instance {
	public function request(array $types) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb880bc4b);
		$writer->writeVector($types,'securevaluetype');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return GlobalPrivacySettings
 */

final class GetGlobalPrivacySettings extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeb2b4cf6);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputfile file string mime_type wallpapersettings settings true for_chat
 * @return WallPaper
 */

final class UploadWallPaper extends Instance {
	public function request(object $file,string $mime_type,object $settings,null | bool $for_chat = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe39a8f03);
		$flags = 0;
		$flags |= $for_chat ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($file);
		$writer->writeBytes($mime_type);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.WebBrowserSettings
 */

final class DeleteWebBrowserSettingsExceptions extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x86a0765d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class ResetWebAuthorizations extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x682d2594);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string format inputtheme theme
 * @return Theme
 */

final class GetTheme extends Instance {
	public function request(string $format,object $theme) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3a5869ec);
		$writer->writeBytes($format);
		$writer->writeObject($theme);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.ContentSettings
 */

final class GetContentSettings extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8b9b4dae);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Vector<SecureValue>
 */

final class GetAllSecureValues extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb288bc7d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class DeclinePasswordReset extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4c9409f6);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<string> codes
 * @return Bool
 */

final class InvalidateSignInCodes extends Instance {
	public function request(array $codes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xca8ae8ba);
		$writer->writeVector($codes,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param autosavesettings settings true users true chats true broadcasts inputpeer peer
 * @return Bool
 */

final class SaveAutoSaveSettings extends Instance {
	public function request(object $settings,null | bool $users = null,null | bool $chats = null,null | bool $broadcasts = null,null | object $peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd69b8361);
		$flags = 0;
		$flags |= $users ? (1 << 0) : 0;
		$flags |= $chats ? (1 << 1) : 0;
		$flags |= $broadcasts ? (1 << 2) : 0;
		$flags |= is_null($peer) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return account.EmojiStatuses
 */

final class GetChannelDefaultEmojiStatuses extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7727a7d5);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return account.Themes
 */

final class GetChatThemes extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd638de89);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return account.ResolvedBusinessChatLinks
 */

final class ResolveBusinessChatLink extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5492e5ee);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash string phone_code
 * @return Bool
 */

final class VerifyPhone extends Instance {
	public function request(string $phone_number,string $phone_code_hash,string $phone_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4dd3a7f6);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		$writer->writeBytes($phone_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputbusinesschatlink link
 * @return BusinessChatLink
 */

final class CreateBusinessChatLink extends Instance {
	public function request(object $link) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8851e68e);
		$writer->writeObject($link);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.WebAuthorizations
 */

final class GetWebAuthorizations extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x182e6d6f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgeopoint geo_point string address
 * @return Bool
 */

final class UpdateBusinessLocation extends Instance {
	public function request(null | object $geo_point = null,null | string $address = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9e6b131a);
		$flags = 0;
		$flags |= is_null($geo_point) ? 0 : (1 << 1);
		$flags |= is_null($address) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($geo_point) === false):
			$writer->writeObject($geo_point);
		endif;
		if(is_null($address) === false):
			$writer->writeBytes($address);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return account.EmojiStatuses
 */

final class GetDefaultEmojiStatuses extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd6753386);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number string phone_code_hash string phone_code
 * @return User
 */

final class ChangePhone extends Instance {
	public function request(string $phone_number,string $phone_code_hash,string $phone_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x70c32edb);
		$writer->writeBytes($phone_number);
		$writer->writeBytes($phone_code_hash);
		$writer->writeBytes($phone_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string username bool active
 * @return Bool
 */

final class ToggleUsername extends Instance {
	public function request(string $username,bool $active) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x58d6b376);
		$writer->writeBytes($username);
		$writer->writeBool($active);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param businessworkhours business_work_hours
 * @return Bool
 */

final class UpdateBusinessWorkHours extends Instance {
	public function request(null | object $business_work_hours = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4b00e066);
		$flags = 0;
		$flags |= is_null($business_work_hours) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($business_work_hours) === false):
			$writer->writeObject($business_work_hours);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class DeleteAutoSaveExceptions extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x53bc0020);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug
 * @return Bool
 */

final class DeleteBusinessChatLink extends Instance {
	public function request(string $slug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x60073674);
		$writer->writeBytes($slug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class ResendPasswordEmail extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7a7f2a15);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<string> order
 * @return Bool
 */

final class ReorderUsernames extends Instance {
	public function request(array $order) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xef500eab);
		$writer->writeVector($order,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug string title inputdocument document Vector<inputthemesettings> settings
 * @return Theme
 */

final class CreateTheme extends Instance {
	public function request(string $slug,string $title,null | object $document = null,null | array $settings = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x652e4400);
		$flags = 0;
		$flags |= is_null($document) ? 0 : (1 << 2);
		$flags |= is_null($settings) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeBytes($slug);
		$writer->writeBytes($title);
		if(is_null($document) === false):
			$writer->writeObject($document);
		endif;
		if(is_null($settings) === false):
			$writer->writeVector($settings,'inputthemesettings');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string slug inputbusinesschatlink link
 * @return BusinessChatLink
 */

final class EditBusinessChatLink extends Instance {
	public function request(string $slug,object $link) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8c3410af);
		$writer->writeBytes($slug);
		$writer->writeObject($link);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument id true unsave inputdocument after_id
 * @return Bool
 */

final class SaveMusic extends Instance {
	public function request(object $id,null | bool $unsave = null,null | object $after_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb26732a9);
		$flags = 0;
		$flags |= $unsave ? (1 << 0) : 0;
		$flags |= is_null($after_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($id);
		if(is_null($after_id) === false):
			$writer->writeObject($after_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot inputbusinessbotrecipients recipients true deleted businessbotrights rights
 * @return Updates
 */

final class UpdateConnectedBot extends Instance {
	public function request(object $bot,object $recipients,null | bool $deleted = null,null | object $rights = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x66a08c7e);
		$flags = 0;
		$flags |= $deleted ? (1 << 1) : 0;
		$flags |= is_null($rights) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($rights) === false):
			$writer->writeObject($rights);
		endif;
		$writer->writeObject($bot);
		$writer->writeObject($recipients);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return Bool
 */

final class DisablePeerConnectedBot extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5e437ed9);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class ResetWallPapers extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbb3b9804);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param birthday birthday
 * @return Bool
 */

final class UpdateBirthday extends Instance {
	public function request(null | object $birthday = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcc6e0c11);
		$flags = 0;
		$flags |= is_null($birthday) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($birthday) === false):
			$writer->writeObject($birthday);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool offline
 * @return Bool
 */

final class UpdateStatus extends Instance {
	public function request(bool $offline) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6628562c);
		$writer->writeBool($offline);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true compare_sound true compare_stories inputnotifypeer peer
 * @return Updates
 */

final class GetNotifyExceptions extends Instance {
	public function request(null | bool $compare_sound = null,null | bool $compare_stories = null,null | object $peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x53577479);
		$flags = 0;
		$flags |= $compare_sound ? (1 << 1) : 0;
		$flags |= $compare_stories ? (1 << 2) : 0;
		$flags |= is_null($peer) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string reason inputcheckpasswordsrp password
 * @return Bool
 */

final class DeleteAccount extends Instance {
	public function request(string $reason,null | object $password = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa2c0cf74);
		$flags = 0;
		$flags |= is_null($password) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($reason);
		if(is_null($password) === false):
			$writer->writeObject($password);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel
 * @return Bool
 */

final class UpdatePersonalChannel extends Instance {
	public function request(object $channel) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd94305e0);
		$writer->writeObject($channel);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string hash codesettings settings
 * @return auth.SentCode
 */

final class SendConfirmPhoneCode extends Instance {
	public function request(string $hash,object $settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1b3faa88);
		$writer->writeBytes($hash);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.AutoSaveSettings
 */

final class GetAutoSaveSettings extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xadcbbcda);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param reactionsnotifysettings settings
 * @return ReactionsNotifySettings
 */

final class SetReactionsNotifySettings extends Instance {
	public function request(object $settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x316ce548);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputwallpaper wallpaper bool unsave wallpapersettings settings
 * @return Bool
 */

final class SaveWallPaper extends Instance {
	public function request(object $wallpaper,bool $unsave,object $settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6c5a5b37);
		$writer->writeObject($wallpaper);
		$writer->writeBool($unsave);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputsecurevalue value long secure_secret_id
 * @return SecureValue
 */

final class SaveSecureValue extends Instance {
	public function request(object $value,int $secure_secret_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x899fe31d);
		$writer->writeObject($value);
		$writer->writeLong($secure_secret_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputwallpaper wallpaper wallpapersettings settings
 * @return Bool
 */

final class InstallWallPaper extends Instance {
	public function request(object $wallpaper,object $settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfeed5769);
		$writer->writeObject($wallpaper);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int token_type string token Vector<long> other_uids
 * @return Bool
 */

final class UnregisterDevice extends Instance {
	public function request(int $token_type,string $token,array $other_uids) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6a0d3206);
		$writer->writeInt($token_type);
		$writer->writeBytes($token);
		$writer->writeVector($other_uids,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string code
 * @return Bool
 */

final class ConfirmPasswordEmail extends Instance {
	public function request(string $code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8fdf1920);
		$writer->writeBytes($code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int authorization_ttl_days
 * @return Bool
 */

final class SetAuthorizationTTL extends Instance {
	public function request(int $authorization_ttl_days) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbf899aa0);
		$writer->writeInt($authorization_ttl_days);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer reportreason reason string message
 * @return Bool
 */

final class ReportPeer extends Instance {
	public function request(object $peer,object $reason,string $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc5ba3d86);
		$writer->writeObject($peer);
		$writer->writeObject($reason);
		$writer->writeBytes($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputcheckpasswordsrp password account.passwordinputsettings new_settings
 * @return Bool
 */

final class UpdatePasswordSettings extends Instance {
	public function request(object $password,object $new_settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa59b102f);
		$writer->writeObject($password);
		$writer->writeObject($new_settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string id
 * @return Bool
 */

final class DeletePasskey extends Instance {
	public function request(string $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf5b5563f);
		$writer->writeBytes($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputnotifypeer peer inputpeernotifysettings settings
 * @return Bool
 */

final class UpdateNotifySettings extends Instance {
	public function request(object $peer,object $settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x84be5b93);
		$writer->writeObject($peer);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputnotifypeer peer
 * @return PeerNotifySettings
 */

final class GetNotifySettings extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x12b3ad31);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string format inputtheme theme string slug string title inputdocument document Vector<inputthemesettings> settings
 * @return Theme
 */

final class UpdateTheme extends Instance {
	public function request(string $format,object $theme,null | string $slug = null,null | string $title = null,null | object $document = null,null | array $settings = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2bf40ccc);
		$flags = 0;
		$flags |= is_null($slug) ? 0 : (1 << 0);
		$flags |= is_null($title) ? 0 : (1 << 1);
		$flags |= is_null($document) ? 0 : (1 << 2);
		$flags |= is_null($settings) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeBytes($format);
		$writer->writeObject($theme);
		if(is_null($slug) === false):
			$writer->writeBytes($slug);
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($document) === false):
			$writer->writeObject($document);
		endif;
		if(is_null($settings) === false):
			$writer->writeVector($settings,'inputthemesettings');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputprivacykey key Vector<inputprivacyrule> rules
 * @return account.PrivacyRules
 */

final class SetPrivacy extends Instance {
	public function request(object $key,array $rules) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc9f81ce8);
		$writer->writeObject($key);
		$writer->writeVector($rules,'inputprivacyrule');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer bool paused
 * @return Bool
 */

final class ToggleConnectedBotPaused extends Instance {
	public function request(object $peer,bool $paused) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x646e1097);
		$writer->writeObject($peer);
		$writer->writeBool($paused);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string first_name string last_name string about
 * @return User
 */

final class UpdateProfile extends Instance {
	public function request(null | string $first_name = null,null | string $last_name = null,null | string $about = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x78515775);
		$flags = 0;
		$flags |= is_null($first_name) ? 0 : (1 << 0);
		$flags |= is_null($last_name) ? 0 : (1 << 1);
		$flags |= is_null($about) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($first_name) === false):
			$writer->writeBytes($first_name);
		endif;
		if(is_null($last_name) === false):
			$writer->writeBytes($last_name);
		endif;
		if(is_null($about) === false):
			$writer->writeBytes($about);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class ResetNotifySettings extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdb7e1747);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return AccountDaysTTL
 */

final class GetAccountTTL extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8fc711d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int token_type string token bool app_sandbox bytes secret Vector<long> other_uids true no_muted
 * @return Bool
 */

final class RegisterDevice extends Instance {
	public function request(int $token_type,string $token,bool $app_sandbox,string $secret,array $other_uids,null | bool $no_muted = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xec86017a);
		$flags = 0;
		$flags |= $no_muted ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeInt($token_type);
		$writer->writeBytes($token);
		$writer->writeBool($app_sandbox);
		$writer->writeBytes($secret);
		$writer->writeVector($other_uids,'long');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class GetContactSignUpNotification extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9f07c728);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.BusinessChatLinks
 */

final class GetBusinessChatLinks extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6f70dde1);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputwallpaper> wallpapers
 * @return Vector<WallPaper>
 */

final class GetMultiWallPapers extends Instance {
	public function request(array $wallpapers) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x65ad71dc);
		$writer->writeVector($wallpapers,'inputwallpaper');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id true refund_charged true require_payment inputpeer parent_peer
 * @return Bool
 */

final class ToggleNoPaidMessagesException extends Instance {
	public function request(object $user_id,null | bool $refund_charged = null,null | bool $require_payment = null,null | object $parent_peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfe2eda76);
		$flags = 0;
		$flags |= $refund_charged ? (1 << 0) : 0;
		$flags |= $require_payment ? (1 << 2) : 0;
		$flags |= is_null($parent_peer) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		if(is_null($parent_peer) === false):
			$writer->writeObject($parent_peer);
		endif;
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return account.EmojiStatuses
 */

final class GetRecentEmojiStatuses extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf578105);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser bot_id
 * @return Bool
 */

final class ConfirmBotConnection extends Instance {
	public function request(object $bot_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x67ed1f68);
		$writer->writeObject($bot_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_number codesettings settings
 * @return auth.SentCode
 */

final class SendChangePhoneCode extends Instance {
	public function request(string $phone_number,object $settings) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x82574ae5);
		$writer->writeBytes($phone_number);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return EmojiList
 */

final class GetDefaultProfilePhotoEmojis extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe2750328);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bot_id string scope string public_key Vector<securevaluehash> value_hashes securecredentialsencrypted credentials
 * @return Bool
 */

final class AcceptAuthorization extends Instance {
	public function request(int $bot_id,string $scope,string $public_key,array $value_hashes,object $credentials) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf3ed4c73);
		$writer->writeLong($bot_id);
		$writer->writeBytes($scope);
		$writer->writeBytes($public_key);
		$writer->writeVector($value_hashes,'securevaluehash');
		$writer->writeObject($credentials);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string phone_code_hash string phone_code
 * @return Bool
 */

final class ConfirmPhone extends Instance {
	public function request(string $phone_code_hash,string $phone_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5f2178c3);
		$writer->writeBytes($phone_code_hash);
		$writer->writeBytes($phone_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return Bool
 */

final class ResetAuthorization extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdf77f3bc);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true dark inputtheme theme string format basetheme base_theme
 * @return Bool
 */

final class InstallTheme extends Instance {
	public function request(null | bool $dark = null,null | object $theme = null,null | string $format = null,null | object $base_theme = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc727bb3b);
		$flags = 0;
		$flags |= $dark ? (1 << 0) : 0;
		$flags |= is_null($theme) ? 0 : (1 << 1);
		$flags |= is_null($format) ? 0 : (1 << 2);
		$flags |= is_null($base_theme) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		if(is_null($theme) === false):
			$writer->writeObject($theme);
		endif;
		if(is_null($format) === false):
			$writer->writeBytes($format);
		endif;
		if(is_null($base_theme) === false):
			$writer->writeObject($base_theme);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return account.EmojiStatuses
 */

final class GetCollectibleEmojiStatuses extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2e7b4543);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param profiletab tab
 * @return Bool
 */

final class SetMainProfileTab extends Instance {
	public function request(object $tab) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5dee78b0);
		$writer->writeObject($tab);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.ConnectedBots
 */

final class GetConnectedBots extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4ea4c80f);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param emojistatus emoji_status
 * @return Bool
 */

final class UpdateEmojiStatus extends Instance {
	public function request(object $emoji_status) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfbd3de6b);
		$writer->writeObject($emoji_status);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputbusinessintro intro
 * @return Bool
 */

final class UpdateBusinessIntro extends Instance {
	public function request(null | object $intro = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa614d034);
		$flags = 0;
		$flags |= is_null($intro) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($intro) === false):
			$writer->writeObject($intro);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return Bool
 */

final class ResetWebAuthorization extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2d01b9ef);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return EmojiList
 */

final class GetDefaultGroupPhotoEmojis extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x915860ae);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string format long hash
 * @return account.Themes
 */

final class GetThemes extends Instance {
	public function request(string $format,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7206e458);
		$writer->writeBytes($format);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputprivacykey key
 * @return account.PrivacyRules
 */

final class GetPrivacy extends Instance {
	public function request(object $key) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdadbc950);
		$writer->writeObject($key);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<securevaluetype> types
 * @return Vector<SecureValue>
 */

final class GetSecureValue extends Instance {
	public function request(array $types) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x73665bc2);
		$writer->writeVector($types,'securevaluetype');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputbusinessgreetingmessage message
 * @return Bool
 */

final class UpdateBusinessGreetingMessage extends Instance {
	public function request(null | object $message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x66cdafc4);
		$flags = 0;
		$flags |= is_null($message) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return account.SavedMusicIds
 */

final class GetSavedMusicIds extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe09d5faf);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true success
 * @return Bool
 */

final class FinishTakeoutSession extends Instance {
	public function request(null | bool $success = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1d2652ee);
		$flags = 0;
		$flags |= $success ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputbusinessawaymessage message
 * @return Bool
 */

final class UpdateBusinessAwayMessage extends Instance {
	public function request(null | object $message = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa26a7fa5);
		$flags = 0;
		$flags |= is_null($message) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($message) === false):
			$writer->writeObject($message);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.PasskeyRegistrationOptions
 */

final class InitPasskeyRegistration extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x429547e8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpasskeycredential credential
 * @return Passkey
 */

final class RegisterPasskey extends Instance {
	public function request(object $credential) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x55b41fd6);
		$writer->writeObject($credential);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return EmojiList
 */

final class GetChannelRestrictedStatusEmojis extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x35a9e0d5);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param autodownloadsettings settings true low true high
 * @return Bool
 */

final class SaveAutoDownloadSettings extends Instance {
	public function request(object $settings,null | bool $low = null,null | bool $high = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x76f36233);
		$flags = 0;
		$flags |= $low ? (1 << 0) : 0;
		$flags |= $high ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($settings);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputphoto photo_id reportreason reason string message
 * @return Bool
 */

final class ReportProfilePhoto extends Instance {
	public function request(object $peer,object $photo_id,object $reason,string $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfa8cc6f5);
		$writer->writeObject($peer);
		$writer->writeObject($photo_id);
		$writer->writeObject($reason);
		$writer->writeBytes($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true open_external_browser true display_close_button
 * @return account.WebBrowserSettings
 */

final class UpdateWebBrowserSettings extends Instance {
	public function request(null | bool $open_external_browser = null,null | bool $display_close_button = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9adf82fe);
		$flags = 0;
		$flags |= $open_external_browser ? (1 << 0) : 0;
		$flags |= $display_close_button ? (1 << 1) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool silent
 * @return Bool
 */

final class SetContactSignUpNotification extends Instance {
	public function request(bool $silent) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcff43f61);
		$writer->writeBool($silent);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true for_profile peercolor color
 * @return Bool
 */

final class UpdateColor extends Instance {
	public function request(null | bool $for_profile = null,null | object $color = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x684d214e);
		$flags = 0;
		$flags |= $for_profile ? (1 << 1) : 0;
		$flags |= is_null($color) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($color) === false):
			$writer->writeObject($color);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.Passkeys
 */

final class GetPasskeys extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xea1f0c52);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.Password
 */

final class GetPassword extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x548a30f5);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputtheme theme bool unsave
 * @return Bool
 */

final class SaveTheme extends Instance {
	public function request(object $theme,bool $unsave) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf257106c);
		$writer->writeObject($theme);
		$writer->writeBool($unsave);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long bot_id string scope string public_key
 * @return account.AuthorizationForm
 */

final class GetAuthorizationForm extends Instance {
	public function request(int $bot_id,string $scope,string $public_key) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa929597a);
		$writer->writeLong($bot_id);
		$writer->writeBytes($scope);
		$writer->writeBytes($public_key);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputcheckpasswordsrp password
 * @return account.PasswordSettings
 */

final class GetPasswordSettings extends Instance {
	public function request(object $password) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9cd4eaf9);
		$writer->writeObject($password);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return EmojiList
 */

final class GetDefaultBackgroundEmojis extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa60ab9ce);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class CancelPasswordEmail extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc1cbd5b6);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return ReactionsNotifySettings
 */

final class GetReactionsNotifySettings extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6dd654c);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string connection_id
 * @return Updates
 */

final class GetBotBusinessConnection extends Instance {
	public function request(string $connection_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x76a86270);
		$writer->writeBytes($connection_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string offset int limit long hash
 * @return account.ChatThemes
 */

final class GetUniqueGiftChatThemes extends Instance {
	public function request(string $offset,int $limit,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe42ce9c9);
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string url true delete bool open_external_browser
 * @return Updates
 */

final class ToggleWebBrowserSettingsException extends Instance {
	public function request(string $url,null | bool $delete = null,null | bool $open_external_browser = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x60ed4229);
		$flags = 0;
		$flags |= $delete ? (1 << 1) : 0;
		$flags |= is_null($open_external_browser) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($open_external_browser) === false):
			$writer->writeBool($open_external_browser);
		endif;
		$writer->writeBytes($url);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.ResetPasswordResult
 */

final class ResetPassword extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9308ce1b);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputwallpaper wallpaper
 * @return WallPaper
 */

final class GetWallPaper extends Instance {
	public function request(object $wallpaper) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xfc8ddbea);
		$writer->writeObject($wallpaper);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return account.WallPapers
 */

final class GetWallPapers extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7967d36);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return account.Authorizations
 */

final class GetAuthorizations extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe320c158);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return account.WebBrowserSettings
 */

final class GetWebBrowserSettings extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x56655768);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Account;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputcheckpasswordsrp password int period
 * @return account.TmpPassword
 */

final class GetTmpPassword extends Instance {
	public function request(object $password,int $period) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x449e0b51);
		$writer->writeObject($password);
		$writer->writeInt($period);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Updates;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int pts int date int qts int pts_limit int pts_total_limit int qts_limit
 * @return updates.Difference
 */

final class GetDifference extends Instance {
	public function request(int $pts,int $date,int $qts,null | int $pts_limit = null,null | int $pts_total_limit = null,null | int $qts_limit = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x19c2f763);
		$flags = 0;
		$flags |= is_null($pts_limit) ? 0 : (1 << 1);
		$flags |= is_null($pts_total_limit) ? 0 : (1 << 0);
		$flags |= is_null($qts_limit) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeInt($pts);
		if(is_null($pts_limit) === false):
			$writer->writeInt($pts_limit);
		endif;
		if(is_null($pts_total_limit) === false):
			$writer->writeInt($pts_total_limit);
		endif;
		$writer->writeInt($date);
		$writer->writeInt($qts);
		if(is_null($qts_limit) === false):
			$writer->writeInt($qts_limit);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Updates;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return updates.State
 */

final class GetState extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xedd4882a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Updates;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputchannel channel channelmessagesfilter filter int pts int limit true force
 * @return updates.ChannelDifference
 */

final class GetChannelDifference extends Instance {
	public function request(object $channel,object $filter,int $pts,int $limit,null | bool $force = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3173d78);
		$flags = 0;
		$flags |= $force ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($channel);
		$writer->writeObject($filter);
		$writer->writeInt($pts);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Smsjobs;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return smsjobs.EligibilityToJoin
 */

final class IsEligibleToJoin extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xedc39d0);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Smsjobs;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string job_id
 * @return SmsJob
 */

final class GetSmsJob extends Instance {
	public function request(string $job_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x778d902f);
		$writer->writeBytes($job_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Smsjobs;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return smsjobs.Status
 */

final class GetStatus extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x10a698e8);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Smsjobs;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class Leave extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9898ad73);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Smsjobs;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Bool
 */

final class Join extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa74ece2d);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Smsjobs;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string job_id string error
 * @return Bool
 */

final class FinishJob extends Instance {
	public function request(string $job_id,null | string $error = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4f1ebf24);
		$flags = 0;
		$flags |= is_null($error) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		$writer->writeBytes($job_id);
		if(is_null($error) === false):
			$writer->writeBytes($error);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Smsjobs;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true allow_international
 * @return Bool
 */

final class UpdateSettings extends Instance {
	public function request(null | bool $allow_international = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x93fa0bf);
		$flags = 0;
		$flags |= $allow_international ? (1 << 0) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Premium;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> slots
 * @return premium.MyBoosts
 */

final class ApplyBoost extends Instance {
	public function request(object $peer,null | array $slots = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6b7da746);
		$flags = 0;
		$flags |= is_null($slots) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($slots) === false):
			$writer->writeVector($slots,'int');
		endif;
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Premium;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return premium.BoostsStatus
 */

final class GetBoostsStatus extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x42f1f61);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Premium;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string offset int limit true gifts
 * @return premium.BoostsList
 */

final class GetBoostsList extends Instance {
	public function request(object $peer,string $offset,int $limit,null | bool $gifts = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x60f67660);
		$flags = 0;
		$flags |= $gifts ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Premium;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputuser user_id
 * @return premium.BoostsList
 */

final class GetUserBoosts extends Instance {
	public function request(object $peer,object $user_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x39854d1f);
		$writer->writeObject($peer);
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Premium;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return premium.MyBoosts
 */

final class GetMyBoosts extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbe77b4a);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call inputpeer join_as datajson params true muted true video_stopped string invite_hash int256 public_key bytes block
 * @return Updates
 */

final class JoinGroupCall extends Instance {
	public function request(object $call,object $join_as,object $params,null | bool $muted = null,null | bool $video_stopped = null,null | string $invite_hash = null,null | int | string $public_key = null,null | string $block = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8fb53057);
		$flags = 0;
		$flags |= $muted ? (1 << 0) : 0;
		$flags |= $video_stopped ? (1 << 2) : 0;
		$flags |= is_null($invite_hash) ? 0 : (1 << 1);
		$flags |= is_null($public_key) ? 0 : (1 << 3);
		$flags |= is_null($block) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeObject($call);
		$writer->writeObject($join_as);
		if(is_null($invite_hash) === false):
			$writer->writeBytes($invite_hash);
		endif;
		if(is_null($public_key) === false):
			$writer->writeLargeInt($public_key,256);
		endif;
		if(is_null($block) === false):
			$writer->writeBytes($block);
		endif;
		$writer->writeObject($params);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call int source
 * @return Updates
 */

final class LeaveGroupCall extends Instance {
	public function request(object $call,int $source) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x500377f9);
		$writer->writeObject($call);
		$writer->writeInt($source);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call inputpeer participant true report_spam
 * @return Updates
 */

final class DeleteGroupCallParticipantMessages extends Instance {
	public function request(object $call,object $participant,null | bool $report_spam = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1dbfeca0);
		$flags = 0;
		$flags |= $report_spam ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($call);
		$writer->writeObject($participant);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputpeer join_as
 * @return Bool
 */

final class SaveDefaultGroupCallJoinAs extends Instance {
	public function request(object $peer,object $join_as) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x575e1f8c);
		$writer->writeObject($peer);
		$writer->writeObject($join_as);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call inputuser user_id true video
 * @return Updates
 */

final class InviteConferenceCallParticipant extends Instance {
	public function request(object $call,object $user_id,null | bool $video = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbcf22685);
		$flags = 0;
		$flags |= $video ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($call);
		$writer->writeObject($user_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphonecall peer datajson debug
 * @return Bool
 */

final class SaveCallDebug extends Instance {
	public function request(object $peer,object $debug) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x277add7e);
		$writer->writeObject($peer);
		$writer->writeObject($debug);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int random_id true muted true video_stopped true join int256 public_key bytes block datajson params
 * @return Updates
 */

final class CreateConferenceCall extends Instance {
	public function request(int $random_id,null | bool $muted = null,null | bool $video_stopped = null,null | bool $join = null,null | int | string $public_key = null,null | string $block = null,null | object $params = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7d0444bb);
		$flags = 0;
		$flags |= $muted ? (1 << 0) : 0;
		$flags |= $video_stopped ? (1 << 2) : 0;
		$flags |= $join ? (1 << 3) : 0;
		$flags |= is_null($public_key) ? 0 : (1 << 3);
		$flags |= is_null($block) ? 0 : (1 << 3);
		$flags |= is_null($params) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeInt($random_id);
		if(is_null($public_key) === false):
			$writer->writeLargeInt($public_key,256);
		endif;
		if(is_null($block) === false):
			$writer->writeBytes($block);
		endif;
		if(is_null($params) === false):
			$writer->writeObject($params);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphonecall peer int duration phonecalldiscardreason reason long connection_id true video
 * @return Updates
 */

final class DiscardCall extends Instance {
	public function request(object $peer,int $duration,object $reason,int $connection_id,null | bool $video = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb2cbc1c0);
		$flags = 0;
		$flags |= $video ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($duration);
		$writer->writeObject($reason);
		$writer->writeLong($connection_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call true reset_invite_hash bool join_muted bool messages_enabled long send_paid_messages_stars
 * @return Updates
 */

final class ToggleGroupCallSettings extends Instance {
	public function request(object $call,null | bool $reset_invite_hash = null,null | bool $join_muted = null,null | bool $messages_enabled = null,null | int $send_paid_messages_stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x974392f2);
		$flags = 0;
		$flags |= $reset_invite_hash ? (1 << 1) : 0;
		$flags |= is_null($join_muted) ? 0 : (1 << 0);
		$flags |= is_null($messages_enabled) ? 0 : (1 << 2);
		$flags |= is_null($send_paid_messages_stars) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeObject($call);
		if(is_null($join_muted) === false):
			$writer->writeBool($join_muted);
		endif;
		if(is_null($messages_enabled) === false):
			$writer->writeBool($messages_enabled);
		endif;
		if(is_null($send_paid_messages_stars) === false):
			$writer->writeLong($send_paid_messages_stars);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int msg_id
 * @return Updates
 */

final class DeclineConferenceCallInvite extends Instance {
	public function request(int $msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3c479971);
		$writer->writeInt($msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphonecall peer
 * @return Bool
 */

final class ReceivedCall extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x17d54f61);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call bool subscribed
 * @return Updates
 */

final class ToggleGroupCallStartSubscription extends Instance {
	public function request(object $call,bool $subscribed) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x219c34e6);
		$writer->writeObject($call);
		$writer->writeBool($subscribed);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return DataJSON
 */

final class GetCallConfig extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x55451fa9);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call long random_id textwithentities message long allow_paid_stars inputpeer send_as
 * @return Updates
 */

final class SendGroupCallMessage extends Instance {
	public function request(object $call,int $random_id,object $message,null | int $allow_paid_stars = null,null | object $send_as = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb1d11410);
		$flags = 0;
		$flags |= is_null($allow_paid_stars) ? 0 : (1 << 0);
		$flags |= is_null($send_as) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($call);
		$writer->writeLong($random_id);
		$writer->writeObject($message);
		if(is_null($allow_paid_stars) === false):
			$writer->writeLong($allow_paid_stars);
		endif;
		if(is_null($send_as) === false):
			$writer->writeObject($send_as);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call
 * @return Updates
 */

final class StartScheduledGroupCall extends Instance {
	public function request(object $call) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5680e342);
		$writer->writeObject($call);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call
 * @return Updates
 */

final class LeaveGroupCallPresentation extends Instance {
	public function request(object $call) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1c50d144);
		$writer->writeObject($call);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphonecall peer bytes g_b phonecallprotocol protocol
 * @return phone.PhoneCall
 */

final class AcceptCall extends Instance {
	public function request(object $peer,string $g_b,object $protocol) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3bd2b4a0);
		$writer->writeObject($peer);
		$writer->writeBytes($g_b);
		$writer->writeObject($protocol);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call bytes block
 * @return Updates
 */

final class SendConferenceCallBroadcast extends Instance {
	public function request(object $call,string $block) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc6701900);
		$writer->writeObject($call);
		$writer->writeBytes($block);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call Vector<inputpeer> ids Vector<int> sources string offset int limit
 * @return phone.GroupParticipants
 */

final class GetGroupParticipants extends Instance {
	public function request(object $call,array $ids,array $sources,string $offset,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc558d8ab);
		$writer->writeObject($call);
		$writer->writeVector($ids,'inputpeer');
		$writer->writeVector($sources,'int');
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call Vector<int> messages true report_spam
 * @return Updates
 */

final class DeleteGroupCallMessages extends Instance {
	public function request(object $call,array $messages,null | bool $report_spam = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf64f54f7);
		$flags = 0;
		$flags |= $report_spam ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($call);
		$writer->writeVector($messages,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call bytes encrypted_message
 * @return Bool
 */

final class SendGroupCallEncryptedMessage extends Instance {
	public function request(object $call,string $encrypted_message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe5afa56d);
		$writer->writeObject($call);
		$writer->writeBytes($encrypted_message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphonecall peer inputfile file
 * @return Bool
 */

final class SaveCallLog extends Instance {
	public function request(object $peer,object $file) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x41248786);
		$writer->writeObject($peer);
		$writer->writeObject($file);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call
 * @return phone.GroupCallStreamChannels
 */

final class GetGroupCallStreamChannels extends Instance {
	public function request(object $call) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1ab21940);
		$writer->writeObject($call);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call Vector<long> ids bytes block true only_left true kick
 * @return Updates
 */

final class DeleteConferenceCallParticipants extends Instance {
	public function request(object $call,array $ids,string $block,null | bool $only_left = null,null | bool $kick = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8ca60525);
		$flags = 0;
		$flags |= $only_left ? (1 << 0) : 0;
		$flags |= $kick ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($call);
		$writer->writeVector($ids,'long');
		$writer->writeBytes($block);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call Vector<int> sources
 * @return Vector<int>
 */

final class CheckGroupCall extends Instance {
	public function request(object $call,array $sources) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb59cf977);
		$writer->writeObject($call);
		$writer->writeVector($sources,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call datajson params
 * @return Updates
 */

final class JoinGroupCallPresentation extends Instance {
	public function request(object $call,object $params) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcbea6bc4);
		$writer->writeObject($call);
		$writer->writeObject($params);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call int sub_chain_id int offset int limit
 * @return Updates
 */

final class GetGroupCallChainBlocks extends Instance {
	public function request(object $call,int $sub_chain_id,int $offset,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xee9f88a6);
		$writer->writeObject($call);
		$writer->writeInt($sub_chain_id);
		$writer->writeInt($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call
 * @return Updates
 */

final class DiscardGroupCall extends Instance {
	public function request(object $call) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7a777135);
		$writer->writeObject($call);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphonecall peer bytes data
 * @return Bool
 */

final class SendSignalingData extends Instance {
	public function request(object $peer,string $data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xff7a9383);
		$writer->writeObject($peer);
		$writer->writeBytes($data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call string title
 * @return Updates
 */

final class EditGroupCallTitle extends Instance {
	public function request(object $call,string $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1ca6ac0a);
		$writer->writeObject($call);
		$writer->writeBytes($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int random_id true rtmp_stream string title int schedule_date
 * @return Updates
 */

final class CreateGroupCall extends Instance {
	public function request(object $peer,int $random_id,null | bool $rtmp_stream = null,null | string $title = null,null | int $schedule_date = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x48cdc6d8);
		$flags = 0;
		$flags |= $rtmp_stream ? (1 << 2) : 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$flags |= is_null($schedule_date) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($random_id);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($schedule_date) === false):
			$writer->writeInt($schedule_date);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call
 * @return phone.GroupCallStars
 */

final class GetGroupCallStars extends Instance {
	public function request(object $call) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6f636302);
		$writer->writeObject($call);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphonecall peer int rating string comment true user_initiative
 * @return Updates
 */

final class SetCallRating extends Instance {
	public function request(object $peer,int $rating,string $comment,null | bool $user_initiative = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x59ead627);
		$flags = 0;
		$flags |= $user_initiative ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($rating);
		$writer->writeBytes($comment);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call inputpeer send_as
 * @return Bool
 */

final class SaveDefaultSendAs extends Instance {
	public function request(object $call,object $send_as) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4167add1);
		$writer->writeObject($call);
		$writer->writeObject($send_as);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call int limit
 * @return phone.GroupCall
 */

final class GetGroupCall extends Instance {
	public function request(object $call,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x41845db);
		$writer->writeObject($call);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputphonecall peer bytes g_a long key_fingerprint phonecallprotocol protocol
 * @return phone.PhoneCall
 */

final class ConfirmCall extends Instance {
	public function request(object $peer,string $g_a,int $key_fingerprint,object $protocol) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2efe1722);
		$writer->writeObject($peer);
		$writer->writeBytes($g_a);
		$writer->writeLong($key_fingerprint);
		$writer->writeObject($protocol);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call Vector<inputuser> users
 * @return Updates
 */

final class InviteToGroupCall extends Instance {
	public function request(object $call,array $users) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7b393160);
		$writer->writeObject($call);
		$writer->writeVector($users,'inputuser');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer bool revoke true live_story
 * @return phone.GroupCallStreamRtmpUrl
 */

final class GetGroupCallStreamRtmpUrl extends Instance {
	public function request(object $peer,bool $revoke,null | bool $live_story = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5af4c73a);
		$flags = 0;
		$flags |= $live_story ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeBool($revoke);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return phone.JoinAsPeers
 */

final class GetGroupCallJoinAs extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xef7c213a);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call true start true video string title bool video_portrait
 * @return Updates
 */

final class ToggleGroupCallRecord extends Instance {
	public function request(object $call,null | bool $start = null,null | bool $video = null,null | string $title = null,null | bool $video_portrait = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf128c708);
		$flags = 0;
		$flags |= $start ? (1 << 0) : 0;
		$flags |= $video ? (1 << 2) : 0;
		$flags |= is_null($title) ? 0 : (1 << 1);
		$flags |= is_null($video_portrait) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($call);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($video_portrait) === false):
			$writer->writeBool($video_portrait);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id int random_id bytes g_a_hash phonecallprotocol protocol true video
 * @return phone.PhoneCall
 */

final class RequestCall extends Instance {
	public function request(object $user_id,int $random_id,string $g_a_hash,object $protocol,null | bool $video = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x42ff96ed);
		$flags = 0;
		$flags |= $video ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($user_id);
		$writer->writeInt($random_id);
		$writer->writeBytes($g_a_hash);
		$writer->writeObject($protocol);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call inputpeer participant bool muted int volume bool raise_hand bool video_stopped bool video_paused bool presentation_paused
 * @return Updates
 */

final class EditGroupCallParticipant extends Instance {
	public function request(object $call,object $participant,null | bool $muted = null,null | int $volume = null,null | bool $raise_hand = null,null | bool $video_stopped = null,null | bool $video_paused = null,null | bool $presentation_paused = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa5273abf);
		$flags = 0;
		$flags |= is_null($muted) ? 0 : (1 << 0);
		$flags |= is_null($volume) ? 0 : (1 << 1);
		$flags |= is_null($raise_hand) ? 0 : (1 << 2);
		$flags |= is_null($video_stopped) ? 0 : (1 << 3);
		$flags |= is_null($video_paused) ? 0 : (1 << 4);
		$flags |= is_null($presentation_paused) ? 0 : (1 << 5);
		$writer->writeInt($flags);
		$writer->writeObject($call);
		$writer->writeObject($participant);
		if(is_null($muted) === false):
			$writer->writeBool($muted);
		endif;
		if(is_null($volume) === false):
			$writer->writeInt($volume);
		endif;
		if(is_null($raise_hand) === false):
			$writer->writeBool($raise_hand);
		endif;
		if(is_null($video_stopped) === false):
			$writer->writeBool($video_stopped);
		endif;
		if(is_null($video_paused) === false):
			$writer->writeBool($video_paused);
		endif;
		if(is_null($presentation_paused) === false):
			$writer->writeBool($presentation_paused);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Phone;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputgroupcall call true can_self_unmute
 * @return phone.ExportedGroupCallInvite
 */

final class ExportGroupCallInvite extends Instance {
	public function request(object $call,null | bool $can_self_unmute = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe6aa647f);
		$flags = 0;
		$flags |= $can_self_unmute ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($call);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Aicompose;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long emoji_id string title string prompt true display_author
 * @return AiComposeTone
 */

final class CreateTone extends Instance {
	public function request(int $emoji_id,string $title,string $prompt,null | bool $display_author = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4aa83913);
		$flags = 0;
		$flags |= $display_author ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeLong($emoji_id);
		$writer->writeBytes($title);
		$writer->writeBytes($prompt);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Aicompose;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputaicomposetone tone
 * @return aicompose.Tones
 */

final class GetTone extends Instance {
	public function request(object $tone) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb2e8ba03);
		$writer->writeObject($tone);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Aicompose;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputaicomposetone tone bool unsave
 * @return Bool
 */

final class SaveTone extends Instance {
	public function request(object $tone,bool $unsave) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1782cbb1);
		$writer->writeObject($tone);
		$writer->writeBool($unsave);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Aicompose;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputaicomposetone tone int num
 * @return AiComposeToneExample
 */

final class GetToneExample extends Instance {
	public function request(object $tone,int $num) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd1b4ab14);
		$writer->writeObject($tone);
		$writer->writeInt($num);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Aicompose;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputaicomposetone tone bool display_author long emoji_id string title string prompt
 * @return AiComposeTone
 */

final class UpdateTone extends Instance {
	public function request(object $tone,null | bool $display_author = null,null | int $emoji_id = null,null | string $title = null,null | string $prompt = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x903bcf59);
		$flags = 0;
		$flags |= is_null($display_author) ? 0 : (1 << 0);
		$flags |= is_null($emoji_id) ? 0 : (1 << 1);
		$flags |= is_null($title) ? 0 : (1 << 2);
		$flags |= is_null($prompt) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeObject($tone);
		if(is_null($display_author) === false):
			$writer->writeBool($display_author);
		endif;
		if(is_null($emoji_id) === false):
			$writer->writeLong($emoji_id);
		endif;
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($prompt) === false):
			$writer->writeBytes($prompt);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Aicompose;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputaicomposetone tone
 * @return Bool
 */

final class DeleteTone extends Instance {
	public function request(object $tone) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdd39316a);
		$writer->writeObject($tone);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Aicompose;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long hash
 * @return aicompose.Tones
 */

final class GetTones extends Instance {
	public function request(int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xabd59201);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputwebfilelocation location int offset int limit
 * @return upload.WebFile
 */

final class GetWebFile extends Instance {
	public function request(object $location,int $offset,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x24e6818d);
		$writer->writeObject($location);
		$writer->writeInt($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long file_id int file_part int file_total_parts bytes bytes
 * @return Bool
 */

final class SaveBigFilePart extends Instance {
	public function request(int $file_id,int $file_part,int $file_total_parts,string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xde7b673d);
		$writer->writeLong($file_id);
		$writer->writeInt($file_part);
		$writer->writeInt($file_total_parts);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputfilelocation location long offset
 * @return Vector<FileHash>
 */

final class GetFileHashes extends Instance {
	public function request(object $location,int $offset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9156982a);
		$writer->writeObject($location);
		$writer->writeLong($offset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long file_id int file_part bytes bytes
 * @return Bool
 */

final class SaveFilePart extends Instance {
	public function request(int $file_id,int $file_part,string $bytes) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb304a621);
		$writer->writeLong($file_id);
		$writer->writeInt($file_part);
		$writer->writeBytes($bytes);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes file_token long offset
 * @return Vector<FileHash>
 */

final class GetCdnFileHashes extends Instance {
	public function request(string $file_token,int $offset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x91dc3f31);
		$writer->writeBytes($file_token);
		$writer->writeLong($offset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputfilelocation location long offset int limit true precise true cdn_supported
 * @return upload.File
 */

final class GetFile extends Instance {
	public function request(object $location,int $offset,int $limit,null | bool $precise = null,null | bool $cdn_supported = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbe5335be);
		$flags = 0;
		$flags |= $precise ? (1 << 0) : 0;
		$flags |= $cdn_supported ? (1 << 1) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($location);
		$writer->writeLong($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes file_token long offset int limit
 * @return upload.CdnFile
 */

final class GetCdnFile extends Instance {
	public function request(string $file_token,int $offset,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x395f69da);
		$writer->writeBytes($file_token);
		$writer->writeLong($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Upload;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bytes file_token bytes request_token
 * @return Vector<FileHash>
 */

final class ReuploadCdnFile extends Instance {
	public function request(string $file_token,string $request_token) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9b2754a8);
		$writer->writeBytes($file_token);
		$writer->writeBytes($request_token);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Langpack;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_pack string lang_code int from_version
 * @return LangPackDifference
 */

final class GetDifference extends Instance {
	public function request(string $lang_pack,string $lang_code,int $from_version) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcd984aa5);
		$writer->writeBytes($lang_pack);
		$writer->writeBytes($lang_code);
		$writer->writeInt($from_version);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Langpack;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_pack string lang_code
 * @return LangPackDifference
 */

final class GetLangPack extends Instance {
	public function request(string $lang_pack,string $lang_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf2f2330a);
		$writer->writeBytes($lang_pack);
		$writer->writeBytes($lang_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Langpack;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_pack string lang_code Vector<string> keys
 * @return Vector<LangPackString>
 */

final class GetStrings extends Instance {
	public function request(string $lang_pack,string $lang_code,array $keys) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xefea3803);
		$writer->writeBytes($lang_pack);
		$writer->writeBytes($lang_code);
		$writer->writeVector($keys,'string');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Langpack;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_pack
 * @return Vector<LangPackLanguage>
 */

final class GetLanguages extends Instance {
	public function request(string $lang_pack) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x42c6978f);
		$writer->writeBytes($lang_pack);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Langpack;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string lang_pack string lang_code
 * @return LangPackLanguage
 */

final class GetLanguage extends Instance {
	public function request(string $lang_pack,string $lang_code) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x6a596502);
		$writer->writeBytes($lang_pack);
		$writer->writeBytes($lang_code);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long takeout_id x query
 * @return X
 */

final class InvokeWithTakeout extends Instance {
	public function request(int $takeout_id,object $query) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xaca9fd2e);
		$writer->writeLong($takeout_id);
		$writer->writeObject($query);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param x query
 * @return X
 */

final class InvokeWithoutUpdates extends Instance {
	public function request(object $query) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbf9459b7);
		$writer->writeObject($query);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param messagerange range x query
 * @return X
 */

final class InvokeWithMessagesRange extends Instance {
	public function request(object $range,object $query) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x365275f2);
		$writer->writeObject($range);
		$writer->writeObject($query);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<long> msg_ids x query
 * @return X
 */

final class InvokeAfterMsgs extends Instance {
	public function request(array $msg_ids,object $query) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x3dc4b4f0);
		$writer->writeVector($msg_ids,'long');
		$writer->writeObject($query);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce int128 server_nonce string encrypted_data
 * @return Set_client_DH_params_answer
 */

final class SetClientDHParams extends Instance {
	public function request(int | string $nonce,int | string $server_nonce,string $encrypted_data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf5045f1f);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeBytes($encrypted_data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return DestroyAuthKeyRes
 */

final class DestroyAuthKey extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd1435160);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string token x query
 * @return X
 */

final class InvokeWithReCaptcha extends Instance {
	public function request(string $token,object $query) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xadbb0f94);
		$writer->writeBytes($token);
		$writer->writeObject($query);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string connection_id x query
 * @return X
 */

final class InvokeWithBusinessConnection extends Instance {
	public function request(string $connection_id,object $query) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdd289f8e);
		$writer->writeBytes($connection_id);
		$writer->writeObject($query);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string nonce string secret x query
 * @return X
 */

final class InvokeWithApnsSecret extends Instance {
	public function request(string $nonce,string $secret,object $query) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xdae54f8);
		$writer->writeBytes($nonce);
		$writer->writeBytes($secret);
		$writer->writeObject($query);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce
 * @return ResPQ
 */

final class ReqPq extends Instance {
	public function request(int | string $nonce) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x60469778);
		$writer->writeLargeInt($nonce,128);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long session_id
 * @return DestroySessionRes
 */

final class DestroySession extends Instance {
	public function request(int $session_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xe7512126);
		$writer->writeLong($session_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long req_msg_id
 * @return RpcDropAnswer
 */

final class RpcDropAnswer extends Instance {
	public function request(int $req_msg_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x58e4a740);
		$writer->writeLong($req_msg_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string nonce string token x query
 * @return X
 */

final class InvokeWithGooglePlayIntegrity extends Instance {
	public function request(string $nonce,string $token,object $query) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x1df92984);
		$writer->writeBytes($nonce);
		$writer->writeBytes($token);
		$writer->writeObject($query);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce
 * @return ResPQ
 */

final class ReqPqMulti extends Instance {
	public function request(int | string $nonce) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbe7e8ef1);
		$writer->writeLargeInt($nonce,128);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int128 nonce int128 server_nonce string p string q long public_key_fingerprint string encrypted_data
 * @return Server_DH_Params
 */

final class ReqDHParams extends Instance {
	public function request(int | string $nonce,int | string $server_nonce,string $p,string $q,int $public_key_fingerprint,string $encrypted_data) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd712e4be);
		$writer->writeLargeInt($nonce,128);
		$writer->writeLargeInt($server_nonce,128);
		$writer->writeBytes($p);
		$writer->writeBytes($q);
		$writer->writeLong($public_key_fingerprint);
		$writer->writeBytes($encrypted_data);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int layer x query
 * @return X
 */

final class InvokeWithLayer extends Instance {
	public function request(int $layer,object $query) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xda9b0d0d);
		$writer->writeInt($layer);
		$writer->writeObject($query);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long msg_id x query
 * @return X
 */

final class InvokeAfterMsg extends Instance {
	public function request(int $msg_id,object $query) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xcb9f372d);
		$writer->writeLong($msg_id);
		$writer->writeObject($query);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long ping_id int disconnect_delay
 * @return Pong
 */

final class PingDelayDisconnect extends Instance {
	public function request(int $ping_id,int $disconnect_delay) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf3427b8c);
		$writer->writeLong($ping_id);
		$writer->writeInt($disconnect_delay);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param long ping_id
 * @return Pong
 */

final class Ping extends Instance {
	public function request(int $ping_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7abe77ec);
		$writer->writeLong($ping_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int api_id string device_model string system_version string app_version string system_lang_code string lang_pack string lang_code x query inputclientproxy proxy jsonvalue params
 * @return X
 */

final class InitConnection extends Instance {
	public function request(int $api_id,string $device_model,string $system_version,string $app_version,string $system_lang_code,string $lang_pack,string $lang_code,object $query,null | object $proxy = null,null | object $params = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xc1cd5ea9);
		$flags = 0;
		$flags |= is_null($proxy) ? 0 : (1 << 0);
		$flags |= is_null($params) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeInt($api_id);
		$writer->writeBytes($device_model);
		$writer->writeBytes($system_version);
		$writer->writeBytes($app_version);
		$writer->writeBytes($system_lang_code);
		$writer->writeBytes($lang_pack);
		$writer->writeBytes($lang_code);
		if(is_null($proxy) === false):
			$writer->writeObject($proxy);
		endif;
		if(is_null($params) === false):
			$writer->writeObject($params);
		endif;
		$writer->writeObject($query);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Other;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param int num
 * @return FutureSalts
 */

final class GetFutureSalts extends Instance {
	public function request(int $num) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb921bd04);
		$writer->writeInt($num);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument sticker int position
 * @return messages.StickerSet
 */

final class ChangeStickerPosition extends Instance {
	public function request(object $sticker,int $position) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xffb6d4ca);
		$writer->writeObject($sticker);
		$writer->writeInt($position);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument sticker
 * @return messages.StickerSet
 */

final class RemoveStickerFromSet extends Instance {
	public function request(object $sticker) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf7760f51);
		$writer->writeObject($sticker);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument sticker inputstickersetitem new_sticker
 * @return messages.StickerSet
 */

final class ReplaceSticker extends Instance {
	public function request(object $sticker,object $new_sticker) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4696459a);
		$writer->writeObject($sticker);
		$writer->writeObject($new_sticker);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickerset stickerset
 * @return Bool
 */

final class DeleteStickerSet extends Instance {
	public function request(object $stickerset) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x87704394);
		$writer->writeObject($stickerset);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputuser user_id string title string short_name Vector<inputstickersetitem> stickers true masks true emojis true text_color inputdocument thumb string software
 * @return messages.StickerSet
 */

final class CreateStickerSet extends Instance {
	public function request(object $user_id,string $title,string $short_name,array $stickers,null | bool $masks = null,null | bool $emojis = null,null | bool $text_color = null,null | object $thumb = null,null | string $software = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9021ab67);
		$flags = 0;
		$flags |= $masks ? (1 << 0) : 0;
		$flags |= $emojis ? (1 << 5) : 0;
		$flags |= $text_color ? (1 << 6) : 0;
		$flags |= is_null($thumb) ? 0 : (1 << 2);
		$flags |= is_null($software) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeObject($user_id);
		$writer->writeBytes($title);
		$writer->writeBytes($short_name);
		if(is_null($thumb) === false):
			$writer->writeObject($thumb);
		endif;
		$writer->writeVector($stickers,'inputstickersetitem');
		if(is_null($software) === false):
			$writer->writeBytes($software);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickerset stickerset inputstickersetitem sticker
 * @return messages.StickerSet
 */

final class AddStickerToSet extends Instance {
	public function request(object $stickerset,object $sticker) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8653febe);
		$writer->writeObject($stickerset);
		$writer->writeObject($sticker);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickerset stickerset string title
 * @return messages.StickerSet
 */

final class RenameStickerSet extends Instance {
	public function request(object $stickerset,string $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x124b1c00);
		$writer->writeObject($stickerset);
		$writer->writeBytes($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputstickerset stickerset inputdocument thumb long thumb_document_id
 * @return messages.StickerSet
 */

final class SetStickerSetThumb extends Instance {
	public function request(object $stickerset,null | object $thumb = null,null | int $thumb_document_id = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa76a5392);
		$flags = 0;
		$flags |= is_null($thumb) ? 0 : (1 << 0);
		$flags |= is_null($thumb_document_id) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($stickerset);
		if(is_null($thumb) === false):
			$writer->writeObject($thumb);
		endif;
		if(is_null($thumb_document_id) === false):
			$writer->writeLong($thumb_document_id);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string title
 * @return stickers.SuggestedShortName
 */

final class SuggestShortName extends Instance {
	public function request(string $title) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x4dafc503);
		$writer->writeBytes($title);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string short_name
 * @return Bool
 */

final class CheckShortName extends Instance {
	public function request(string $short_name) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x284b3639);
		$writer->writeBytes($short_name);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stickers;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputdocument sticker string emoji maskcoords mask_coords string keywords
 * @return messages.StickerSet
 */

final class ChangeSticker extends Instance {
	public function request(object $sticker,null | string $emoji = null,null | object $mask_coords = null,null | string $keywords = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xf5537ebc);
		$flags = 0;
		$flags |= is_null($emoji) ? 0 : (1 << 0);
		$flags |= is_null($mask_coords) ? 0 : (1 << 1);
		$flags |= is_null($keywords) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		$writer->writeObject($sticker);
		if(is_null($emoji) === false):
			$writer->writeBytes($emoji);
		endif;
		if(is_null($mask_coords) === false):
			$writer->writeObject($mask_coords);
		endif;
		if(is_null($keywords) === false):
			$writer->writeBytes($keywords);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int offset_id int limit
 * @return stories.Stories
 */

final class GetPinnedStories extends Instance {
	public function request(object $peer,int $offset_id,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5821a5dc);
		$writer->writeObject($peer);
		$writer->writeInt($offset_id);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param string offset int limit string hashtag mediaarea area inputpeer peer
 * @return stories.FoundStories
 */

final class SearchPosts extends Instance {
	public function request(string $offset,int $limit,null | string $hashtag = null,null | object $area = null,null | object $peer = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd1810907);
		$flags = 0;
		$flags |= is_null($hashtag) ? 0 : (1 << 0);
		$flags |= is_null($area) ? 0 : (1 << 1);
		$flags |= is_null($peer) ? 0 : (1 << 2);
		$writer->writeInt($flags);
		if(is_null($hashtag) === false):
			$writer->writeBytes($hashtag);
		endif;
		if(is_null($area) === false):
			$writer->writeObject($area);
		endif;
		if(is_null($peer) === false):
			$writer->writeObject($peer);
		endif;
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<inputprivacyrule> privacy_rules long random_id true pinned true noforwards true rtmp_stream string caption Vector<messageentity> entities bool messages_enabled long send_paid_messages_stars
 * @return Updates
 */

final class StartLive extends Instance {
	public function request(object $peer,array $privacy_rules,int $random_id,null | bool $pinned = null,null | bool $noforwards = null,null | bool $rtmp_stream = null,null | string $caption = null,null | array $entities = null,null | bool $messages_enabled = null,null | int $send_paid_messages_stars = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xd069ccde);
		$flags = 0;
		$flags |= $pinned ? (1 << 2) : 0;
		$flags |= $noforwards ? (1 << 4) : 0;
		$flags |= $rtmp_stream ? (1 << 5) : 0;
		$flags |= is_null($caption) ? 0 : (1 << 0);
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$flags |= is_null($messages_enabled) ? 0 : (1 << 6);
		$flags |= is_null($send_paid_messages_stars) ? 0 : (1 << 7);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($caption) === false):
			$writer->writeBytes($caption);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		$writer->writeVector($privacy_rules,'inputprivacyrule');
		$writer->writeLong($random_id);
		if(is_null($messages_enabled) === false):
			$writer->writeBool($messages_enabled);
		endif;
		if(is_null($send_paid_messages_stars) === false):
			$writer->writeLong($send_paid_messages_stars);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id string offset int limit true just_contacts true reactions_first true forwards_first string q
 * @return stories.StoryViewsList
 */

final class GetStoryViewsList extends Instance {
	public function request(object $peer,int $id,string $offset,int $limit,null | bool $just_contacts = null,null | bool $reactions_first = null,null | bool $forwards_first = null,null | string $q = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7ed23c57);
		$flags = 0;
		$flags |= $just_contacts ? (1 << 0) : 0;
		$flags |= $reactions_first ? (1 << 2) : 0;
		$flags |= $forwards_first ? (1 << 3) : 0;
		$flags |= is_null($q) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		if(is_null($q) === false):
			$writer->writeBytes($q);
		endif;
		$writer->writeInt($id);
		$writer->writeBytes($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return messages.Chats
 */

final class GetChatsToSend extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa56a8b60);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id
 * @return Vector<int>
 */

final class DeleteStories extends Instance {
	public function request(object $peer,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xae59db5f);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int offset_id int limit
 * @return stories.Stories
 */

final class GetStoriesArchive extends Instance {
	public function request(object $peer,int $offset_id,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb4352016);
		$writer->writeObject($peer);
		$writer->writeInt($offset_id);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int album_id
 * @return Bool
 */

final class DeleteAlbum extends Instance {
	public function request(object $peer,int $album_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8d3456d0);
		$writer->writeObject($peer);
		$writer->writeInt($album_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true past true future
 * @return Updates
 */

final class ActivateStealthMode extends Instance {
	public function request(null | bool $past = null,null | bool $future = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x57bbd166);
		$flags = 0;
		$flags |= $past ? (1 << 0) : 0;
		$flags |= $future ? (1 << 1) : 0;
		$writer->writeInt($flags);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return stories.CanSendStoryCount
 */

final class CanSendStory extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x30eb63f0);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id
 * @return stories.StoryViews
 */

final class GetStoriesViews extends Instance {
	public function request(object $peer,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x28e16cc8);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id bytes option string message
 * @return ReportResult
 */

final class Report extends Instance {
	public function request(object $peer,array $id,string $option,string $message) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x19d8eb45);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		$writer->writeBytes($option);
		$writer->writeBytes($message);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id bool pinned
 * @return Vector<int>
 */

final class TogglePinned extends Instance {
	public function request(object $peer,array $id,bool $pinned) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9a75a1ef);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		$writer->writeBool($pinned);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int story_id reaction reaction true add_to_recent
 * @return Updates
 */

final class SendReaction extends Instance {
	public function request(object $peer,int $story_id,object $reaction,null | bool $add_to_recent = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7fd736b2);
		$flags = 0;
		$flags |= $add_to_recent ? (1 << 0) : 0;
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($story_id);
		$writer->writeObject($reaction);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id
 * @return Bool
 */

final class IncrementStoryViews extends Instance {
	public function request(object $peer,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb2028afb);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer bool hidden
 * @return Bool
 */

final class TogglePeerStoriesHidden extends Instance {
	public function request(object $peer,bool $hidden) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xbd0415c4);
		$writer->writeObject($peer);
		$writer->writeBool($hidden);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param true next true hidden string state
 * @return stories.AllStories
 */

final class GetAllStories extends Instance {
	public function request(null | bool $next = null,null | bool $hidden = null,null | string $state = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xeeb0d625);
		$flags = 0;
		$flags |= $next ? (1 << 1) : 0;
		$flags |= $hidden ? (1 << 2) : 0;
		$flags |= is_null($state) ? 0 : (1 << 0);
		$writer->writeInt($flags);
		if(is_null($state) === false):
			$writer->writeBytes($state);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id
 * @return ExportedStoryLink
 */

final class ExportStoryLink extends Instance {
	public function request(object $peer,int $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7b8def20);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param bool hidden
 * @return Bool
 */

final class ToggleAllStoriesHidden extends Instance {
	public function request(bool $hidden) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x7c2557c4);
		$writer->writeBool($hidden);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id inputmedia media Vector<mediaarea> media_areas string caption Vector<messageentity> entities Vector<inputprivacyrule> privacy_rules inputdocument music
 * @return Updates
 */

final class EditStory extends Instance {
	public function request(object $peer,int $id,null | object $media = null,null | array $media_areas = null,null | string $caption = null,null | array $entities = null,null | array $privacy_rules = null,null | object $music = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2c63a72b);
		$flags = 0;
		$flags |= is_null($media) ? 0 : (1 << 0);
		$flags |= is_null($media_areas) ? 0 : (1 << 3);
		$flags |= is_null($caption) ? 0 : (1 << 1);
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$flags |= is_null($privacy_rules) ? 0 : (1 << 2);
		$flags |= is_null($music) ? 0 : (1 << 4);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		if(is_null($media) === false):
			$writer->writeObject($media);
		endif;
		if(is_null($media_areas) === false):
			$writer->writeVector($media_areas,'mediaarea');
		endif;
		if(is_null($caption) === false):
			$writer->writeBytes($caption);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		if(is_null($privacy_rules) === false):
			$writer->writeVector($privacy_rules,'inputprivacyrule');
		endif;
		if(is_null($music) === false):
			$writer->writeObject($music);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer string title Vector<int> stories
 * @return StoryAlbum
 */

final class CreateAlbum extends Instance {
	public function request(object $peer,string $title,array $stories) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa36396e5);
		$writer->writeObject($peer);
		$writer->writeBytes($title);
		$writer->writeVector($stories,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param Vector<inputpeer> id
 * @return Vector<RecentStory>
 */

final class GetPeerMaxIDs extends Instance {
	public function request(array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x78499170);
		$writer->writeVector($id,'inputpeer');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer long hash
 * @return stories.Albums
 */

final class GetAlbums extends Instance {
	public function request(object $peer,int $hash) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x25b3eac7);
		$writer->writeObject($peer);
		$writer->writeLong($hash);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int album_id string title Vector<int> delete_stories Vector<int> add_stories Vector<int> order
 * @return StoryAlbum
 */

final class UpdateAlbum extends Instance {
	public function request(object $peer,int $album_id,null | string $title = null,null | array $delete_stories = null,null | array $add_stories = null,null | array $order = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5e5259b6);
		$flags = 0;
		$flags |= is_null($title) ? 0 : (1 << 0);
		$flags |= is_null($delete_stories) ? 0 : (1 << 1);
		$flags |= is_null($add_stories) ? 0 : (1 << 2);
		$flags |= is_null($order) ? 0 : (1 << 3);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($album_id);
		if(is_null($title) === false):
			$writer->writeBytes($title);
		endif;
		if(is_null($delete_stories) === false):
			$writer->writeVector($delete_stories,'int');
		endif;
		if(is_null($add_stories) === false):
			$writer->writeVector($add_stories,'int');
		endif;
		if(is_null($order) === false):
			$writer->writeVector($order,'int');
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param 
 * @return Updates
 */

final class GetAllReadPeerStories extends Instance {
	public function request() : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x9b5ae7f9);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> order
 * @return Bool
 */

final class ReorderAlbums extends Instance {
	public function request(object $peer,array $order) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8535fbd9);
		$writer->writeObject($peer);
		$writer->writeVector($order,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id
 * @return Bool
 */

final class TogglePinnedToTop extends Instance {
	public function request(object $peer,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb297e9b);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer
 * @return stories.PeerStories
 */

final class GetPeerStories extends Instance {
	public function request(object $peer) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x2c4ada50);
		$writer->writeObject($peer);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer Vector<int> id
 * @return stories.Stories
 */

final class GetStoriesByID extends Instance {
	public function request(object $peer,array $id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x5774ca74);
		$writer->writeObject($peer);
		$writer->writeVector($id,'int');
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int album_id int offset int limit
 * @return stories.Stories
 */

final class GetAlbumStories extends Instance {
	public function request(object $peer,int $album_id,int $offset,int $limit) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xac806d61);
		$writer->writeObject($peer);
		$writer->writeInt($album_id);
		$writer->writeInt($offset);
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer inputmedia media Vector<inputprivacyrule> privacy_rules long random_id true pinned true noforwards true fwd_modified Vector<mediaarea> media_areas string caption Vector<messageentity> entities int period inputpeer fwd_from_id int fwd_from_story Vector<int> albums inputdocument music
 * @return Updates
 */

final class SendStory extends Instance {
	public function request(object $peer,object $media,array $privacy_rules,int $random_id,null | bool $pinned = null,null | bool $noforwards = null,null | bool $fwd_modified = null,null | array $media_areas = null,null | string $caption = null,null | array $entities = null,null | int $period = null,null | object $fwd_from_id = null,null | int $fwd_from_story = null,null | array $albums = null,null | object $music = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0x8f9e6898);
		$flags = 0;
		$flags |= $pinned ? (1 << 2) : 0;
		$flags |= $noforwards ? (1 << 4) : 0;
		$flags |= $fwd_modified ? (1 << 7) : 0;
		$flags |= is_null($media_areas) ? 0 : (1 << 5);
		$flags |= is_null($caption) ? 0 : (1 << 0);
		$flags |= is_null($entities) ? 0 : (1 << 1);
		$flags |= is_null($period) ? 0 : (1 << 3);
		$flags |= is_null($fwd_from_id) ? 0 : (1 << 6);
		$flags |= is_null($fwd_from_story) ? 0 : (1 << 6);
		$flags |= is_null($albums) ? 0 : (1 << 8);
		$flags |= is_null($music) ? 0 : (1 << 9);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeObject($media);
		if(is_null($media_areas) === false):
			$writer->writeVector($media_areas,'mediaarea');
		endif;
		if(is_null($caption) === false):
			$writer->writeBytes($caption);
		endif;
		if(is_null($entities) === false):
			$writer->writeVector($entities,'messageentity');
		endif;
		$writer->writeVector($privacy_rules,'inputprivacyrule');
		$writer->writeLong($random_id);
		if(is_null($period) === false):
			$writer->writeInt($period);
		endif;
		if(is_null($fwd_from_id) === false):
			$writer->writeObject($fwd_from_id);
		endif;
		if(is_null($fwd_from_story) === false):
			$writer->writeInt($fwd_from_story);
		endif;
		if(is_null($albums) === false):
			$writer->writeVector($albums,'int');
		endif;
		if(is_null($music) === false):
			$writer->writeObject($music);
		endif;
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int max_id
 * @return Vector<int>
 */

final class ReadStories extends Instance {
	public function request(object $peer,int $max_id) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xa556dac8);
		$writer->writeObject($peer);
		$writer->writeInt($max_id);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Functions\Stories;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

/**
 * @param inputpeer peer int id int limit true forwards_first reaction reaction string offset
 * @return stories.StoryReactionsList
 */

final class GetStoryReactionsList extends Instance {
	public function request(object $peer,int $id,int $limit,null | bool $forwards_first = null,null | object $reaction = null,null | string $offset = null) : Binary {
		$writer = new Binary(true);
		$writer->writeInt(0xb9b2881f);
		$flags = 0;
		$flags |= $forwards_first ? (1 << 2) : 0;
		$flags |= is_null($reaction) ? 0 : (1 << 0);
		$flags |= is_null($offset) ? 0 : (1 << 1);
		$writer->writeInt($flags);
		$writer->writeObject($peer);
		$writer->writeInt($id);
		if(is_null($reaction) === false):
			$writer->writeObject($reaction);
		endif;
		if(is_null($offset) === false):
			$writer->writeBytes($offset);
		endif;
		$writer->writeInt($limit);
		return $writer;
	}
	public function response(Binary $reader) : object {
		$result = array();
		$result['result'] = $reader->readObject();
		return new self($result);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl;

final class All {
	static public function getConstructor(int $constructorId) : object {
		return match(intval($constructorId)){
			0xcb9f372d => new \Tak\Liveproto\Tl\Functions\Other\InvokeAfterMsg,
			0x3dc4b4f0 => new \Tak\Liveproto\Tl\Functions\Other\InvokeAfterMsgs,
			0xc1cd5ea9 => new \Tak\Liveproto\Tl\Functions\Other\InitConnection,
			0xda9b0d0d => new \Tak\Liveproto\Tl\Functions\Other\InvokeWithLayer,
			0xbf9459b7 => new \Tak\Liveproto\Tl\Functions\Other\InvokeWithoutUpdates,
			0x365275f2 => new \Tak\Liveproto\Tl\Functions\Other\InvokeWithMessagesRange,
			0xaca9fd2e => new \Tak\Liveproto\Tl\Functions\Other\InvokeWithTakeout,
			0xdd289f8e => new \Tak\Liveproto\Tl\Functions\Other\InvokeWithBusinessConnection,
			0x1df92984 => new \Tak\Liveproto\Tl\Functions\Other\InvokeWithGooglePlayIntegrity,
			0xdae54f8 => new \Tak\Liveproto\Tl\Functions\Other\InvokeWithApnsSecret,
			0xadbb0f94 => new \Tak\Liveproto\Tl\Functions\Other\InvokeWithReCaptcha,
			0x60469778 => new \Tak\Liveproto\Tl\Functions\Other\ReqPq,
			0xbe7e8ef1 => new \Tak\Liveproto\Tl\Functions\Other\ReqPqMulti,
			0xd712e4be => new \Tak\Liveproto\Tl\Functions\Other\ReqDHParams,
			0xf5045f1f => new \Tak\Liveproto\Tl\Functions\Other\SetClientDHParams,
			0x58e4a740 => new \Tak\Liveproto\Tl\Functions\Other\RpcDropAnswer,
			0xb921bd04 => new \Tak\Liveproto\Tl\Functions\Other\GetFutureSalts,
			0x7abe77ec => new \Tak\Liveproto\Tl\Functions\Other\Ping,
			0xf3427b8c => new \Tak\Liveproto\Tl\Functions\Other\PingDelayDisconnect,
			0xe7512126 => new \Tak\Liveproto\Tl\Functions\Other\DestroySession,
			0xd1435160 => new \Tak\Liveproto\Tl\Functions\Other\DestroyAuthKey,
			0xa677244f => new \Tak\Liveproto\Tl\Functions\Auth\SendCode,
			0xaac7b717 => new \Tak\Liveproto\Tl\Functions\Auth\SignUp,
			0x8d52a951 => new \Tak\Liveproto\Tl\Functions\Auth\SignIn,
			0x3e72ba19 => new \Tak\Liveproto\Tl\Functions\Auth\LogOut,
			0x9fab0d1a => new \Tak\Liveproto\Tl\Functions\Auth\ResetAuthorizations,
			0xe5bfffcd => new \Tak\Liveproto\Tl\Functions\Auth\ExportAuthorization,
			0xa57a7dad => new \Tak\Liveproto\Tl\Functions\Auth\ImportAuthorization,
			0xcdd42a05 => new \Tak\Liveproto\Tl\Functions\Auth\BindTempAuthKey,
			0x67a3ff2c => new \Tak\Liveproto\Tl\Functions\Auth\ImportBotAuthorization,
			0xd18b4d16 => new \Tak\Liveproto\Tl\Functions\Auth\CheckPassword,
			0xd897bc66 => new \Tak\Liveproto\Tl\Functions\Auth\RequestPasswordRecovery,
			0x37096c70 => new \Tak\Liveproto\Tl\Functions\Auth\RecoverPassword,
			0xcae47523 => new \Tak\Liveproto\Tl\Functions\Auth\ResendCode,
			0x1f040578 => new \Tak\Liveproto\Tl\Functions\Auth\CancelCode,
			0x8e48a188 => new \Tak\Liveproto\Tl\Functions\Auth\DropTempAuthKeys,
			0xb7e085fe => new \Tak\Liveproto\Tl\Functions\Auth\ExportLoginToken,
			0x95ac5ce4 => new \Tak\Liveproto\Tl\Functions\Auth\ImportLoginToken,
			0xe894ad4d => new \Tak\Liveproto\Tl\Functions\Auth\AcceptLoginToken,
			0xd36bf79 => new \Tak\Liveproto\Tl\Functions\Auth\CheckRecoveryPassword,
			0x2db873a9 => new \Tak\Liveproto\Tl\Functions\Auth\ImportWebTokenAuthorization,
			0x8e39261e => new \Tak\Liveproto\Tl\Functions\Auth\RequestFirebaseSms,
			0x7e960193 => new \Tak\Liveproto\Tl\Functions\Auth\ResetLoginEmail,
			0xcb9deff6 => new \Tak\Liveproto\Tl\Functions\Auth\ReportMissingCode,
			0x56e59f9c => new \Tak\Liveproto\Tl\Functions\Auth\CheckPaidAuth,
			0x518ad0b7 => new \Tak\Liveproto\Tl\Functions\Auth\InitPasskeyLogin,
			0x9857ad07 => new \Tak\Liveproto\Tl\Functions\Auth\FinishPasskeyLogin,
			0xec86017a => new \Tak\Liveproto\Tl\Functions\Account\RegisterDevice,
			0x6a0d3206 => new \Tak\Liveproto\Tl\Functions\Account\UnregisterDevice,
			0x84be5b93 => new \Tak\Liveproto\Tl\Functions\Account\UpdateNotifySettings,
			0x12b3ad31 => new \Tak\Liveproto\Tl\Functions\Account\GetNotifySettings,
			0xdb7e1747 => new \Tak\Liveproto\Tl\Functions\Account\ResetNotifySettings,
			0x78515775 => new \Tak\Liveproto\Tl\Functions\Account\UpdateProfile,
			0x6628562c => new \Tak\Liveproto\Tl\Functions\Account\UpdateStatus,
			0x7967d36 => new \Tak\Liveproto\Tl\Functions\Account\GetWallPapers,
			0xc5ba3d86 => new \Tak\Liveproto\Tl\Functions\Account\ReportPeer,
			0x2714d86c => new \Tak\Liveproto\Tl\Functions\Account\CheckUsername,
			0x3e0bdd7c => new \Tak\Liveproto\Tl\Functions\Account\UpdateUsername,
			0xdadbc950 => new \Tak\Liveproto\Tl\Functions\Account\GetPrivacy,
			0xc9f81ce8 => new \Tak\Liveproto\Tl\Functions\Account\SetPrivacy,
			0xa2c0cf74 => new \Tak\Liveproto\Tl\Functions\Account\DeleteAccount,
			0x8fc711d => new \Tak\Liveproto\Tl\Functions\Account\GetAccountTTL,
			0x2442485e => new \Tak\Liveproto\Tl\Functions\Account\SetAccountTTL,
			0x82574ae5 => new \Tak\Liveproto\Tl\Functions\Account\SendChangePhoneCode,
			0x70c32edb => new \Tak\Liveproto\Tl\Functions\Account\ChangePhone,
			0x38df3532 => new \Tak\Liveproto\Tl\Functions\Account\UpdateDeviceLocked,
			0xe320c158 => new \Tak\Liveproto\Tl\Functions\Account\GetAuthorizations,
			0xdf77f3bc => new \Tak\Liveproto\Tl\Functions\Account\ResetAuthorization,
			0x548a30f5 => new \Tak\Liveproto\Tl\Functions\Account\GetPassword,
			0x9cd4eaf9 => new \Tak\Liveproto\Tl\Functions\Account\GetPasswordSettings,
			0xa59b102f => new \Tak\Liveproto\Tl\Functions\Account\UpdatePasswordSettings,
			0x1b3faa88 => new \Tak\Liveproto\Tl\Functions\Account\SendConfirmPhoneCode,
			0x5f2178c3 => new \Tak\Liveproto\Tl\Functions\Account\ConfirmPhone,
			0x449e0b51 => new \Tak\Liveproto\Tl\Functions\Account\GetTmpPassword,
			0x182e6d6f => new \Tak\Liveproto\Tl\Functions\Account\GetWebAuthorizations,
			0x2d01b9ef => new \Tak\Liveproto\Tl\Functions\Account\ResetWebAuthorization,
			0x682d2594 => new \Tak\Liveproto\Tl\Functions\Account\ResetWebAuthorizations,
			0xb288bc7d => new \Tak\Liveproto\Tl\Functions\Account\GetAllSecureValues,
			0x73665bc2 => new \Tak\Liveproto\Tl\Functions\Account\GetSecureValue,
			0x899fe31d => new \Tak\Liveproto\Tl\Functions\Account\SaveSecureValue,
			0xb880bc4b => new \Tak\Liveproto\Tl\Functions\Account\DeleteSecureValue,
			0xa929597a => new \Tak\Liveproto\Tl\Functions\Account\GetAuthorizationForm,
			0xf3ed4c73 => new \Tak\Liveproto\Tl\Functions\Account\AcceptAuthorization,
			0xa5a356f9 => new \Tak\Liveproto\Tl\Functions\Account\SendVerifyPhoneCode,
			0x4dd3a7f6 => new \Tak\Liveproto\Tl\Functions\Account\VerifyPhone,
			0x98e037bb => new \Tak\Liveproto\Tl\Functions\Account\SendVerifyEmailCode,
			0x32da4cf => new \Tak\Liveproto\Tl\Functions\Account\VerifyEmail,
			0x8ef3eab0 => new \Tak\Liveproto\Tl\Functions\Account\InitTakeoutSession,
			0x1d2652ee => new \Tak\Liveproto\Tl\Functions\Account\FinishTakeoutSession,
			0x8fdf1920 => new \Tak\Liveproto\Tl\Functions\Account\ConfirmPasswordEmail,
			0x7a7f2a15 => new \Tak\Liveproto\Tl\Functions\Account\ResendPasswordEmail,
			0xc1cbd5b6 => new \Tak\Liveproto\Tl\Functions\Account\CancelPasswordEmail,
			0x9f07c728 => new \Tak\Liveproto\Tl\Functions\Account\GetContactSignUpNotification,
			0xcff43f61 => new \Tak\Liveproto\Tl\Functions\Account\SetContactSignUpNotification,
			0x53577479 => new \Tak\Liveproto\Tl\Functions\Account\GetNotifyExceptions,
			0xfc8ddbea => new \Tak\Liveproto\Tl\Functions\Account\GetWallPaper,
			0xe39a8f03 => new \Tak\Liveproto\Tl\Functions\Account\UploadWallPaper,
			0x6c5a5b37 => new \Tak\Liveproto\Tl\Functions\Account\SaveWallPaper,
			0xfeed5769 => new \Tak\Liveproto\Tl\Functions\Account\InstallWallPaper,
			0xbb3b9804 => new \Tak\Liveproto\Tl\Functions\Account\ResetWallPapers,
			0x56da0b3f => new \Tak\Liveproto\Tl\Functions\Account\GetAutoDownloadSettings,
			0x76f36233 => new \Tak\Liveproto\Tl\Functions\Account\SaveAutoDownloadSettings,
			0x1c3db333 => new \Tak\Liveproto\Tl\Functions\Account\UploadTheme,
			0x652e4400 => new \Tak\Liveproto\Tl\Functions\Account\CreateTheme,
			0x2bf40ccc => new \Tak\Liveproto\Tl\Functions\Account\UpdateTheme,
			0xf257106c => new \Tak\Liveproto\Tl\Functions\Account\SaveTheme,
			0xc727bb3b => new \Tak\Liveproto\Tl\Functions\Account\InstallTheme,
			0x3a5869ec => new \Tak\Liveproto\Tl\Functions\Account\GetTheme,
			0x7206e458 => new \Tak\Liveproto\Tl\Functions\Account\GetThemes,
			0xb574b16b => new \Tak\Liveproto\Tl\Functions\Account\SetContentSettings,
			0x8b9b4dae => new \Tak\Liveproto\Tl\Functions\Account\GetContentSettings,
			0x65ad71dc => new \Tak\Liveproto\Tl\Functions\Account\GetMultiWallPapers,
			0xeb2b4cf6 => new \Tak\Liveproto\Tl\Functions\Account\GetGlobalPrivacySettings,
			0x1edaaac2 => new \Tak\Liveproto\Tl\Functions\Account\SetGlobalPrivacySettings,
			0xfa8cc6f5 => new \Tak\Liveproto\Tl\Functions\Account\ReportProfilePhoto,
			0x9308ce1b => new \Tak\Liveproto\Tl\Functions\Account\ResetPassword,
			0x4c9409f6 => new \Tak\Liveproto\Tl\Functions\Account\DeclinePasswordReset,
			0xd638de89 => new \Tak\Liveproto\Tl\Functions\Account\GetChatThemes,
			0xbf899aa0 => new \Tak\Liveproto\Tl\Functions\Account\SetAuthorizationTTL,
			0x40f48462 => new \Tak\Liveproto\Tl\Functions\Account\ChangeAuthorizationSettings,
			0xe1902288 => new \Tak\Liveproto\Tl\Functions\Account\GetSavedRingtones,
			0x3dea5b03 => new \Tak\Liveproto\Tl\Functions\Account\SaveRingtone,
			0x831a83a2 => new \Tak\Liveproto\Tl\Functions\Account\UploadRingtone,
			0xfbd3de6b => new \Tak\Liveproto\Tl\Functions\Account\UpdateEmojiStatus,
			0xd6753386 => new \Tak\Liveproto\Tl\Functions\Account\GetDefaultEmojiStatuses,
			0xf578105 => new \Tak\Liveproto\Tl\Functions\Account\GetRecentEmojiStatuses,
			0x18201aae => new \Tak\Liveproto\Tl\Functions\Account\ClearRecentEmojiStatuses,
			0xef500eab => new \Tak\Liveproto\Tl\Functions\Account\ReorderUsernames,
			0x58d6b376 => new \Tak\Liveproto\Tl\Functions\Account\ToggleUsername,
			0xe2750328 => new \Tak\Liveproto\Tl\Functions\Account\GetDefaultProfilePhotoEmojis,
			0x915860ae => new \Tak\Liveproto\Tl\Functions\Account\GetDefaultGroupPhotoEmojis,
			0xadcbbcda => new \Tak\Liveproto\Tl\Functions\Account\GetAutoSaveSettings,
			0xd69b8361 => new \Tak\Liveproto\Tl\Functions\Account\SaveAutoSaveSettings,
			0x53bc0020 => new \Tak\Liveproto\Tl\Functions\Account\DeleteAutoSaveExceptions,
			0xca8ae8ba => new \Tak\Liveproto\Tl\Functions\Account\InvalidateSignInCodes,
			0x684d214e => new \Tak\Liveproto\Tl\Functions\Account\UpdateColor,
			0xa60ab9ce => new \Tak\Liveproto\Tl\Functions\Account\GetDefaultBackgroundEmojis,
			0x7727a7d5 => new \Tak\Liveproto\Tl\Functions\Account\GetChannelDefaultEmojiStatuses,
			0x35a9e0d5 => new \Tak\Liveproto\Tl\Functions\Account\GetChannelRestrictedStatusEmojis,
			0x4b00e066 => new \Tak\Liveproto\Tl\Functions\Account\UpdateBusinessWorkHours,
			0x9e6b131a => new \Tak\Liveproto\Tl\Functions\Account\UpdateBusinessLocation,
			0x66cdafc4 => new \Tak\Liveproto\Tl\Functions\Account\UpdateBusinessGreetingMessage,
			0xa26a7fa5 => new \Tak\Liveproto\Tl\Functions\Account\UpdateBusinessAwayMessage,
			0x66a08c7e => new \Tak\Liveproto\Tl\Functions\Account\UpdateConnectedBot,
			0x4ea4c80f => new \Tak\Liveproto\Tl\Functions\Account\GetConnectedBots,
			0x76a86270 => new \Tak\Liveproto\Tl\Functions\Account\GetBotBusinessConnection,
			0xa614d034 => new \Tak\Liveproto\Tl\Functions\Account\UpdateBusinessIntro,
			0x646e1097 => new \Tak\Liveproto\Tl\Functions\Account\ToggleConnectedBotPaused,
			0x5e437ed9 => new \Tak\Liveproto\Tl\Functions\Account\DisablePeerConnectedBot,
			0xcc6e0c11 => new \Tak\Liveproto\Tl\Functions\Account\UpdateBirthday,
			0x8851e68e => new \Tak\Liveproto\Tl\Functions\Account\CreateBusinessChatLink,
			0x8c3410af => new \Tak\Liveproto\Tl\Functions\Account\EditBusinessChatLink,
			0x60073674 => new \Tak\Liveproto\Tl\Functions\Account\DeleteBusinessChatLink,
			0x6f70dde1 => new \Tak\Liveproto\Tl\Functions\Account\GetBusinessChatLinks,
			0x5492e5ee => new \Tak\Liveproto\Tl\Functions\Account\ResolveBusinessChatLink,
			0xd94305e0 => new \Tak\Liveproto\Tl\Functions\Account\UpdatePersonalChannel,
			0xb9d9a38d => new \Tak\Liveproto\Tl\Functions\Account\ToggleSponsoredMessages,
			0x6dd654c => new \Tak\Liveproto\Tl\Functions\Account\GetReactionsNotifySettings,
			0x316ce548 => new \Tak\Liveproto\Tl\Functions\Account\SetReactionsNotifySettings,
			0x2e7b4543 => new \Tak\Liveproto\Tl\Functions\Account\GetCollectibleEmojiStatuses,
			0x19ba4a67 => new \Tak\Liveproto\Tl\Functions\Account\GetPaidMessagesRevenue,
			0xfe2eda76 => new \Tak\Liveproto\Tl\Functions\Account\ToggleNoPaidMessagesException,
			0x5dee78b0 => new \Tak\Liveproto\Tl\Functions\Account\SetMainProfileTab,
			0xb26732a9 => new \Tak\Liveproto\Tl\Functions\Account\SaveMusic,
			0xe09d5faf => new \Tak\Liveproto\Tl\Functions\Account\GetSavedMusicIds,
			0xe42ce9c9 => new \Tak\Liveproto\Tl\Functions\Account\GetUniqueGiftChatThemes,
			0x429547e8 => new \Tak\Liveproto\Tl\Functions\Account\InitPasskeyRegistration,
			0x55b41fd6 => new \Tak\Liveproto\Tl\Functions\Account\RegisterPasskey,
			0xea1f0c52 => new \Tak\Liveproto\Tl\Functions\Account\GetPasskeys,
			0xf5b5563f => new \Tak\Liveproto\Tl\Functions\Account\DeletePasskey,
			0x67ed1f68 => new \Tak\Liveproto\Tl\Functions\Account\ConfirmBotConnection,
			0x56655768 => new \Tak\Liveproto\Tl\Functions\Account\GetWebBrowserSettings,
			0x9adf82fe => new \Tak\Liveproto\Tl\Functions\Account\UpdateWebBrowserSettings,
			0x60ed4229 => new \Tak\Liveproto\Tl\Functions\Account\ToggleWebBrowserSettingsException,
			0x86a0765d => new \Tak\Liveproto\Tl\Functions\Account\DeleteWebBrowserSettingsExceptions,
			0xd91a548 => new \Tak\Liveproto\Tl\Functions\Users\GetUsers,
			0xb60f5918 => new \Tak\Liveproto\Tl\Functions\Users\GetFullUser,
			0x90c894b5 => new \Tak\Liveproto\Tl\Functions\Users\SetSecureValueErrors,
			0xd89a83a3 => new \Tak\Liveproto\Tl\Functions\Users\GetRequirementsToContact,
			0x788d7fe3 => new \Tak\Liveproto\Tl\Functions\Users\GetSavedMusic,
			0x7573a4e9 => new \Tak\Liveproto\Tl\Functions\Users\GetSavedMusicByID,
			0xfc533372 => new \Tak\Liveproto\Tl\Functions\Users\SuggestBirthday,
			0x7adc669d => new \Tak\Liveproto\Tl\Functions\Contacts\GetContactIDs,
			0xc4a353ee => new \Tak\Liveproto\Tl\Functions\Contacts\GetStatuses,
			0x5dd69e12 => new \Tak\Liveproto\Tl\Functions\Contacts\GetContacts,
			0x2c800be5 => new \Tak\Liveproto\Tl\Functions\Contacts\ImportContacts,
			0x96a0e00 => new \Tak\Liveproto\Tl\Functions\Contacts\DeleteContacts,
			0x1013fd9e => new \Tak\Liveproto\Tl\Functions\Contacts\DeleteByPhones,
			0x2e2e8734 => new \Tak\Liveproto\Tl\Functions\Contacts\Block,
			0xb550d328 => new \Tak\Liveproto\Tl\Functions\Contacts\Unblock,
			0x9a868f80 => new \Tak\Liveproto\Tl\Functions\Contacts\GetBlocked,
			0x5f58d0f => new \Tak\Liveproto\Tl\Functions\Contacts\Search,
			0x725afbbc => new \Tak\Liveproto\Tl\Functions\Contacts\ResolveUsername,
			0x973478b6 => new \Tak\Liveproto\Tl\Functions\Contacts\GetTopPeers,
			0x1ae373ac => new \Tak\Liveproto\Tl\Functions\Contacts\ResetTopPeerRating,
			0x879537f1 => new \Tak\Liveproto\Tl\Functions\Contacts\ResetSaved,
			0x82f1e39f => new \Tak\Liveproto\Tl\Functions\Contacts\GetSaved,
			0x8514bdda => new \Tak\Liveproto\Tl\Functions\Contacts\ToggleTopPeers,
			0xd9ba2e54 => new \Tak\Liveproto\Tl\Functions\Contacts\AddContact,
			0xf831a20f => new \Tak\Liveproto\Tl\Functions\Contacts\AcceptContact,
			0xd348bc44 => new \Tak\Liveproto\Tl\Functions\Contacts\GetLocated,
			0x29a8962c => new \Tak\Liveproto\Tl\Functions\Contacts\BlockFromReplies,
			0x8af94344 => new \Tak\Liveproto\Tl\Functions\Contacts\ResolvePhone,
			0xf8654027 => new \Tak\Liveproto\Tl\Functions\Contacts\ExportContactToken,
			0x13005788 => new \Tak\Liveproto\Tl\Functions\Contacts\ImportContactToken,
			0xba6705f0 => new \Tak\Liveproto\Tl\Functions\Contacts\EditCloseFriends,
			0x94c65c76 => new \Tak\Liveproto\Tl\Functions\Contacts\SetBlocked,
			0xdaeda864 => new \Tak\Liveproto\Tl\Functions\Contacts\GetBirthdays,
			0xb6c8c393 => new \Tak\Liveproto\Tl\Functions\Contacts\GetSponsoredPeers,
			0x139f63fb => new \Tak\Liveproto\Tl\Functions\Contacts\UpdateContactNote,
			0x63c66506 => new \Tak\Liveproto\Tl\Functions\Messages\GetMessages,
			0xa0f4cb4f => new \Tak\Liveproto\Tl\Functions\Messages\GetDialogs,
			0x4423e6c5 => new \Tak\Liveproto\Tl\Functions\Messages\GetHistory,
			0x29ee847a => new \Tak\Liveproto\Tl\Functions\Messages\Search,
			0xe306d3a => new \Tak\Liveproto\Tl\Functions\Messages\ReadHistory,
			0xb08f922a => new \Tak\Liveproto\Tl\Functions\Messages\DeleteHistory,
			0xe58e95d2 => new \Tak\Liveproto\Tl\Functions\Messages\DeleteMessages,
			0x5a954c0 => new \Tak\Liveproto\Tl\Functions\Messages\ReceivedMessages,
			0x58943ee2 => new \Tak\Liveproto\Tl\Functions\Messages\SetTyping,
			0xfef48f62 => new \Tak\Liveproto\Tl\Functions\Messages\SendMessage,
			0x330e77f => new \Tak\Liveproto\Tl\Functions\Messages\SendMedia,
			0x13704a7c => new \Tak\Liveproto\Tl\Functions\Messages\ForwardMessages,
			0xcf1592db => new \Tak\Liveproto\Tl\Functions\Messages\ReportSpam,
			0xefd9a6a2 => new \Tak\Liveproto\Tl\Functions\Messages\GetPeerSettings,
			0xfc78af9b => new \Tak\Liveproto\Tl\Functions\Messages\Report,
			0x49e9528f => new \Tak\Liveproto\Tl\Functions\Messages\GetChats,
			0xaeb00b34 => new \Tak\Liveproto\Tl\Functions\Messages\GetFullChat,
			0x73783ffd => new \Tak\Liveproto\Tl\Functions\Messages\EditChatTitle,
			0x35ddd674 => new \Tak\Liveproto\Tl\Functions\Messages\EditChatPhoto,
			0xcbc6d107 => new \Tak\Liveproto\Tl\Functions\Messages\AddChatUser,
			0xa2185cab => new \Tak\Liveproto\Tl\Functions\Messages\DeleteChatUser,
			0x92ceddd4 => new \Tak\Liveproto\Tl\Functions\Messages\CreateChat,
			0x26cf8950 => new \Tak\Liveproto\Tl\Functions\Messages\GetDhConfig,
			0xf64daf43 => new \Tak\Liveproto\Tl\Functions\Messages\RequestEncryption,
			0x3dbc0415 => new \Tak\Liveproto\Tl\Functions\Messages\AcceptEncryption,
			0xf393aea0 => new \Tak\Liveproto\Tl\Functions\Messages\DiscardEncryption,
			0x791451ed => new \Tak\Liveproto\Tl\Functions\Messages\SetEncryptedTyping,
			0x7f4b690a => new \Tak\Liveproto\Tl\Functions\Messages\ReadEncryptedHistory,
			0x44fa7a15 => new \Tak\Liveproto\Tl\Functions\Messages\SendEncrypted,
			0x5559481d => new \Tak\Liveproto\Tl\Functions\Messages\SendEncryptedFile,
			0x32d439a4 => new \Tak\Liveproto\Tl\Functions\Messages\SendEncryptedService,
			0x55a5bb66 => new \Tak\Liveproto\Tl\Functions\Messages\ReceivedQueue,
			0x4b0c8c0f => new \Tak\Liveproto\Tl\Functions\Messages\ReportEncryptedSpam,
			0x36a73f77 => new \Tak\Liveproto\Tl\Functions\Messages\ReadMessageContents,
			0xd5a5d3a1 => new \Tak\Liveproto\Tl\Functions\Messages\GetStickers,
			0xb8a0a1a8 => new \Tak\Liveproto\Tl\Functions\Messages\GetAllStickers,
			0x570d6f6f => new \Tak\Liveproto\Tl\Functions\Messages\GetWebPagePreview,
			0xa455de90 => new \Tak\Liveproto\Tl\Functions\Messages\ExportChatInvite,
			0x3eadb1bb => new \Tak\Liveproto\Tl\Functions\Messages\CheckChatInvite,
			0xde91436e => new \Tak\Liveproto\Tl\Functions\Messages\ImportChatInvite,
			0xc8a0ec74 => new \Tak\Liveproto\Tl\Functions\Messages\GetStickerSet,
			0xc78fe460 => new \Tak\Liveproto\Tl\Functions\Messages\InstallStickerSet,
			0xf96e55de => new \Tak\Liveproto\Tl\Functions\Messages\UninstallStickerSet,
			0xe6df7378 => new \Tak\Liveproto\Tl\Functions\Messages\StartBot,
			0x5784d3e1 => new \Tak\Liveproto\Tl\Functions\Messages\GetMessagesViews,
			0xa85bd1c2 => new \Tak\Liveproto\Tl\Functions\Messages\EditChatAdmin,
			0xa2875319 => new \Tak\Liveproto\Tl\Functions\Messages\MigrateChat,
			0x4bc6589a => new \Tak\Liveproto\Tl\Functions\Messages\SearchGlobal,
			0x78337739 => new \Tak\Liveproto\Tl\Functions\Messages\ReorderStickerSets,
			0xb1f2061f => new \Tak\Liveproto\Tl\Functions\Messages\GetDocumentByHash,
			0x5cf09635 => new \Tak\Liveproto\Tl\Functions\Messages\GetSavedGifs,
			0x327a30cb => new \Tak\Liveproto\Tl\Functions\Messages\SaveGif,
			0x514e999d => new \Tak\Liveproto\Tl\Functions\Messages\GetInlineBotResults,
			0xbb12a419 => new \Tak\Liveproto\Tl\Functions\Messages\SetInlineBotResults,
			0xc0cf7646 => new \Tak\Liveproto\Tl\Functions\Messages\SendInlineBotResult,
			0xfda68d36 => new \Tak\Liveproto\Tl\Functions\Messages\GetMessageEditData,
			0xb106e66c => new \Tak\Liveproto\Tl\Functions\Messages\EditMessage,
			0xa423bb51 => new \Tak\Liveproto\Tl\Functions\Messages\EditInlineBotMessage,
			0x9342ca07 => new \Tak\Liveproto\Tl\Functions\Messages\GetBotCallbackAnswer,
			0xd58f130a => new \Tak\Liveproto\Tl\Functions\Messages\SetBotCallbackAnswer,
			0xe470bcfd => new \Tak\Liveproto\Tl\Functions\Messages\GetPeerDialogs,
			0xad0fa15c => new \Tak\Liveproto\Tl\Functions\Messages\SaveDraft,
			0x6a3f8d65 => new \Tak\Liveproto\Tl\Functions\Messages\GetAllDrafts,
			0x64780b14 => new \Tak\Liveproto\Tl\Functions\Messages\GetFeaturedStickers,
			0x5b118126 => new \Tak\Liveproto\Tl\Functions\Messages\ReadFeaturedStickers,
			0x9da9403b => new \Tak\Liveproto\Tl\Functions\Messages\GetRecentStickers,
			0x392718f8 => new \Tak\Liveproto\Tl\Functions\Messages\SaveRecentSticker,
			0x8999602d => new \Tak\Liveproto\Tl\Functions\Messages\ClearRecentStickers,
			0x57f17692 => new \Tak\Liveproto\Tl\Functions\Messages\GetArchivedStickers,
			0x640f82b8 => new \Tak\Liveproto\Tl\Functions\Messages\GetMaskStickers,
			0xcc5b67cc => new \Tak\Liveproto\Tl\Functions\Messages\GetAttachedStickers,
			0x8ef8ecc0 => new \Tak\Liveproto\Tl\Functions\Messages\SetGameScore,
			0x15ad9f64 => new \Tak\Liveproto\Tl\Functions\Messages\SetInlineGameScore,
			0xe822649d => new \Tak\Liveproto\Tl\Functions\Messages\GetGameHighScores,
			0xf635e1b => new \Tak\Liveproto\Tl\Functions\Messages\GetInlineGameHighScores,
			0xe40ca104 => new \Tak\Liveproto\Tl\Functions\Messages\GetCommonChats,
			0x8d9692a3 => new \Tak\Liveproto\Tl\Functions\Messages\GetWebPage,
			0xa731e257 => new \Tak\Liveproto\Tl\Functions\Messages\ToggleDialogPin,
			0x3b1adf37 => new \Tak\Liveproto\Tl\Functions\Messages\ReorderPinnedDialogs,
			0xd6b94df2 => new \Tak\Liveproto\Tl\Functions\Messages\GetPinnedDialogs,
			0xe5f672fa => new \Tak\Liveproto\Tl\Functions\Messages\SetBotShippingResults,
			0x9c2dd95 => new \Tak\Liveproto\Tl\Functions\Messages\SetBotPrecheckoutResults,
			0x14967978 => new \Tak\Liveproto\Tl\Functions\Messages\UploadMedia,
			0xa1405817 => new \Tak\Liveproto\Tl\Functions\Messages\SendScreenshotNotification,
			0x4f1aaa9 => new \Tak\Liveproto\Tl\Functions\Messages\GetFavedStickers,
			0xb9ffc55b => new \Tak\Liveproto\Tl\Functions\Messages\FaveSticker,
			0xf107e790 => new \Tak\Liveproto\Tl\Functions\Messages\GetUnreadMentions,
			0x36e5bf4d => new \Tak\Liveproto\Tl\Functions\Messages\ReadMentions,
			0x702a40e0 => new \Tak\Liveproto\Tl\Functions\Messages\GetRecentLocations,
			0x1bf89d74 => new \Tak\Liveproto\Tl\Functions\Messages\SendMultiMedia,
			0x5057c497 => new \Tak\Liveproto\Tl\Functions\Messages\UploadEncryptedFile,
			0x35705b8a => new \Tak\Liveproto\Tl\Functions\Messages\SearchStickerSets,
			0x1cff7e08 => new \Tak\Liveproto\Tl\Functions\Messages\GetSplitRanges,
			0x8c5006f8 => new \Tak\Liveproto\Tl\Functions\Messages\MarkDialogUnread,
			0x21202222 => new \Tak\Liveproto\Tl\Functions\Messages\GetDialogUnreadMarks,
			0x7e58ee9c => new \Tak\Liveproto\Tl\Functions\Messages\ClearAllDrafts,
			0xd2aaf7ec => new \Tak\Liveproto\Tl\Functions\Messages\UpdatePinnedMessage,
			0x10ea6184 => new \Tak\Liveproto\Tl\Functions\Messages\SendVote,
			0xeda3e33b => new \Tak\Liveproto\Tl\Functions\Messages\GetPollResults,
			0x6e2be050 => new \Tak\Liveproto\Tl\Functions\Messages\GetOnlines,
			0xdef60797 => new \Tak\Liveproto\Tl\Functions\Messages\EditChatAbout,
			0xa5866b41 => new \Tak\Liveproto\Tl\Functions\Messages\EditChatDefaultBannedRights,
			0x35a0e062 => new \Tak\Liveproto\Tl\Functions\Messages\GetEmojiKeywords,
			0x1508b6af => new \Tak\Liveproto\Tl\Functions\Messages\GetEmojiKeywordsDifference,
			0x4e9963b2 => new \Tak\Liveproto\Tl\Functions\Messages\GetEmojiKeywordsLanguages,
			0xd5b10c26 => new \Tak\Liveproto\Tl\Functions\Messages\GetEmojiURL,
			0x1bbcf300 => new \Tak\Liveproto\Tl\Functions\Messages\GetSearchCounters,
			0x894cc99c => new \Tak\Liveproto\Tl\Functions\Messages\RequestUrlAuth,
			0x67a3f0de => new \Tak\Liveproto\Tl\Functions\Messages\AcceptUrlAuth,
			0x4facb138 => new \Tak\Liveproto\Tl\Functions\Messages\HidePeerSettingsBar,
			0xf516760b => new \Tak\Liveproto\Tl\Functions\Messages\GetScheduledHistory,
			0xbdbb0464 => new \Tak\Liveproto\Tl\Functions\Messages\GetScheduledMessages,
			0xbd38850a => new \Tak\Liveproto\Tl\Functions\Messages\SendScheduledMessages,
			0x59ae2b16 => new \Tak\Liveproto\Tl\Functions\Messages\DeleteScheduledMessages,
			0xb86e380e => new \Tak\Liveproto\Tl\Functions\Messages\GetPollVotes,
			0xb5052fea => new \Tak\Liveproto\Tl\Functions\Messages\ToggleStickerSets,
			0xefd48c89 => new \Tak\Liveproto\Tl\Functions\Messages\GetDialogFilters,
			0xa29cd42c => new \Tak\Liveproto\Tl\Functions\Messages\GetSuggestedDialogFilters,
			0x1ad4a04a => new \Tak\Liveproto\Tl\Functions\Messages\UpdateDialogFilter,
			0xc563c1e4 => new \Tak\Liveproto\Tl\Functions\Messages\UpdateDialogFiltersOrder,
			0x7ed094a1 => new \Tak\Liveproto\Tl\Functions\Messages\GetOldFeaturedStickers,
			0x22ddd30c => new \Tak\Liveproto\Tl\Functions\Messages\GetReplies,
			0x446972fd => new \Tak\Liveproto\Tl\Functions\Messages\GetDiscussionMessage,
			0xf731a9f4 => new \Tak\Liveproto\Tl\Functions\Messages\ReadDiscussion,
			0x62dd747 => new \Tak\Liveproto\Tl\Functions\Messages\UnpinAllMessages,
			0x5bd0ee50 => new \Tak\Liveproto\Tl\Functions\Messages\DeleteChat,
			0xf9cbe409 => new \Tak\Liveproto\Tl\Functions\Messages\DeletePhoneCallHistory,
			0x43fe19f3 => new \Tak\Liveproto\Tl\Functions\Messages\CheckHistoryImport,
			0x34090c3b => new \Tak\Liveproto\Tl\Functions\Messages\InitHistoryImport,
			0x2a862092 => new \Tak\Liveproto\Tl\Functions\Messages\UploadImportedMedia,
			0xb43df344 => new \Tak\Liveproto\Tl\Functions\Messages\StartHistoryImport,
			0xa2b5a3f6 => new \Tak\Liveproto\Tl\Functions\Messages\GetExportedChatInvites,
			0x73746f5c => new \Tak\Liveproto\Tl\Functions\Messages\GetExportedChatInvite,
			0xbdca2f75 => new \Tak\Liveproto\Tl\Functions\Messages\EditExportedChatInvite,
			0x56987bd5 => new \Tak\Liveproto\Tl\Functions\Messages\DeleteRevokedExportedChatInvites,
			0xd464a42b => new \Tak\Liveproto\Tl\Functions\Messages\DeleteExportedChatInvite,
			0x3920e6ef => new \Tak\Liveproto\Tl\Functions\Messages\GetAdminsWithInvites,
			0xdf04dd4e => new \Tak\Liveproto\Tl\Functions\Messages\GetChatInviteImporters,
			0xb80e5fe4 => new \Tak\Liveproto\Tl\Functions\Messages\SetHistoryTTL,
			0x5dc60f03 => new \Tak\Liveproto\Tl\Functions\Messages\CheckHistoryImportPeer,
			0x81202c9 => new \Tak\Liveproto\Tl\Functions\Messages\SetChatTheme,
			0x31c1c44f => new \Tak\Liveproto\Tl\Functions\Messages\GetMessageReadParticipants,
			0x6aa3f6bd => new \Tak\Liveproto\Tl\Functions\Messages\GetSearchResultsCalendar,
			0x9c7f2f10 => new \Tak\Liveproto\Tl\Functions\Messages\GetSearchResultsPositions,
			0x7fe7e815 => new \Tak\Liveproto\Tl\Functions\Messages\HideChatJoinRequest,
			0xe085f4ea => new \Tak\Liveproto\Tl\Functions\Messages\HideAllChatJoinRequests,
			0xb2081a35 => new \Tak\Liveproto\Tl\Functions\Messages\ToggleNoForwards,
			0xccfddf96 => new \Tak\Liveproto\Tl\Functions\Messages\SaveDefaultSendAs,
			0xd30d78d4 => new \Tak\Liveproto\Tl\Functions\Messages\SendReaction,
			0x8bba90e6 => new \Tak\Liveproto\Tl\Functions\Messages\GetMessagesReactions,
			0x461b3f48 => new \Tak\Liveproto\Tl\Functions\Messages\GetMessageReactionsList,
			0x864b2581 => new \Tak\Liveproto\Tl\Functions\Messages\SetChatAvailableReactions,
			0x18dea0ac => new \Tak\Liveproto\Tl\Functions\Messages\GetAvailableReactions,
			0x4f47a016 => new \Tak\Liveproto\Tl\Functions\Messages\SetDefaultReaction,
			0xa5eec345 => new \Tak\Liveproto\Tl\Functions\Messages\TranslateText,
			0xbd7f90ac => new \Tak\Liveproto\Tl\Functions\Messages\GetUnreadReactions,
			0x9ec44f93 => new \Tak\Liveproto\Tl\Functions\Messages\ReadReactions,
			0x107e31a0 => new \Tak\Liveproto\Tl\Functions\Messages\SearchSentMedia,
			0x16fcc2cb => new \Tak\Liveproto\Tl\Functions\Messages\GetAttachMenuBots,
			0x77216192 => new \Tak\Liveproto\Tl\Functions\Messages\GetAttachMenuBot,
			0x69f59d69 => new \Tak\Liveproto\Tl\Functions\Messages\ToggleBotInAttachMenu,
			0x269dc2c1 => new \Tak\Liveproto\Tl\Functions\Messages\RequestWebView,
			0xb0d81a83 => new \Tak\Liveproto\Tl\Functions\Messages\ProlongWebView,
			0x413a3e73 => new \Tak\Liveproto\Tl\Functions\Messages\RequestSimpleWebView,
			0xa4314f5 => new \Tak\Liveproto\Tl\Functions\Messages\SendWebViewResultMessage,
			0xdc0242c8 => new \Tak\Liveproto\Tl\Functions\Messages\SendWebViewData,
			0x269e9a49 => new \Tak\Liveproto\Tl\Functions\Messages\TranscribeAudio,
			0x7f1d072f => new \Tak\Liveproto\Tl\Functions\Messages\RateTranscribedAudio,
			0xd9ab0f54 => new \Tak\Liveproto\Tl\Functions\Messages\GetCustomEmojiDocuments,
			0xfbfca18f => new \Tak\Liveproto\Tl\Functions\Messages\GetEmojiStickers,
			0xecf6736 => new \Tak\Liveproto\Tl\Functions\Messages\GetFeaturedEmojiStickers,
			0x3f64c076 => new \Tak\Liveproto\Tl\Functions\Messages\ReportReaction,
			0xbb8125ba => new \Tak\Liveproto\Tl\Functions\Messages\GetTopReactions,
			0x39461db2 => new \Tak\Liveproto\Tl\Functions\Messages\GetRecentReactions,
			0x9dfeefb4 => new \Tak\Liveproto\Tl\Functions\Messages\ClearRecentReactions,
			0x84f80814 => new \Tak\Liveproto\Tl\Functions\Messages\GetExtendedMedia,
			0x9eb51445 => new \Tak\Liveproto\Tl\Functions\Messages\SetDefaultHistoryTTL,
			0x658b7188 => new \Tak\Liveproto\Tl\Functions\Messages\GetDefaultHistoryTTL,
			0x6c5cf2a7 => new \Tak\Liveproto\Tl\Functions\Messages\SendBotRequestedPeer,
			0x7488ce5b => new \Tak\Liveproto\Tl\Functions\Messages\GetEmojiGroups,
			0x2ecd56cd => new \Tak\Liveproto\Tl\Functions\Messages\GetEmojiStatusGroups,
			0x21a548f3 => new \Tak\Liveproto\Tl\Functions\Messages\GetEmojiProfilePhotoGroups,
			0x2c11c0d7 => new \Tak\Liveproto\Tl\Functions\Messages\SearchCustomEmoji,
			0xe47cb579 => new \Tak\Liveproto\Tl\Functions\Messages\TogglePeerTranslations,
			0x34fdc5c3 => new \Tak\Liveproto\Tl\Functions\Messages\GetBotApp,
			0x53618bce => new \Tak\Liveproto\Tl\Functions\Messages\RequestAppWebView,
			0x8ffacae1 => new \Tak\Liveproto\Tl\Functions\Messages\SetChatWallPaper,
			0x92b4494c => new \Tak\Liveproto\Tl\Functions\Messages\SearchEmojiStickerSets,
			0x1e91fc99 => new \Tak\Liveproto\Tl\Functions\Messages\GetSavedDialogs,
			0x998ab009 => new \Tak\Liveproto\Tl\Functions\Messages\GetSavedHistory,
			0x4dc5085f => new \Tak\Liveproto\Tl\Functions\Messages\DeleteSavedHistory,
			0xd63d94e0 => new \Tak\Liveproto\Tl\Functions\Messages\GetPinnedSavedDialogs,
			0xac81bbde => new \Tak\Liveproto\Tl\Functions\Messages\ToggleSavedDialogPin,
			0x8b716587 => new \Tak\Liveproto\Tl\Functions\Messages\ReorderPinnedSavedDialogs,
			0x3637e05b => new \Tak\Liveproto\Tl\Functions\Messages\GetSavedReactionTags,
			0x60297dec => new \Tak\Liveproto\Tl\Functions\Messages\UpdateSavedReactionTag,
			0xbdf93428 => new \Tak\Liveproto\Tl\Functions\Messages\GetDefaultTagReactions,
			0x8c4bfe5d => new \Tak\Liveproto\Tl\Functions\Messages\GetOutboxReadDate,
			0xd483f2a8 => new \Tak\Liveproto\Tl\Functions\Messages\GetQuickReplies,
			0x60331907 => new \Tak\Liveproto\Tl\Functions\Messages\ReorderQuickReplies,
			0xf1d0fbd3 => new \Tak\Liveproto\Tl\Functions\Messages\CheckQuickReplyShortcut,
			0x5c003cef => new \Tak\Liveproto\Tl\Functions\Messages\EditQuickReplyShortcut,
			0x3cc04740 => new \Tak\Liveproto\Tl\Functions\Messages\DeleteQuickReplyShortcut,
			0x94a495c3 => new \Tak\Liveproto\Tl\Functions\Messages\GetQuickReplyMessages,
			0x6c750de1 => new \Tak\Liveproto\Tl\Functions\Messages\SendQuickReplyMessages,
			0xe105e910 => new \Tak\Liveproto\Tl\Functions\Messages\DeleteQuickReplyMessages,
			0xfd2dda49 => new \Tak\Liveproto\Tl\Functions\Messages\ToggleDialogFilterTags,
			0xd0b5e1fc => new \Tak\Liveproto\Tl\Functions\Messages\GetMyStickers,
			0x1dd840f5 => new \Tak\Liveproto\Tl\Functions\Messages\GetEmojiStickerGroups,
			0xdea20a39 => new \Tak\Liveproto\Tl\Functions\Messages\GetAvailableEffects,
			0x589ee75 => new \Tak\Liveproto\Tl\Functions\Messages\EditFactCheck,
			0xd1da940c => new \Tak\Liveproto\Tl\Functions\Messages\DeleteFactCheck,
			0xb9cdc5ee => new \Tak\Liveproto\Tl\Functions\Messages\GetFactCheck,
			0xc9e01e7b => new \Tak\Liveproto\Tl\Functions\Messages\RequestMainWebView,
			0x58bbcb50 => new \Tak\Liveproto\Tl\Functions\Messages\SendPaidReaction,
			0x435885b5 => new \Tak\Liveproto\Tl\Functions\Messages\TogglePaidReactionPrivacy,
			0x472455aa => new \Tak\Liveproto\Tl\Functions\Messages\GetPaidReactionPrivacy,
			0x269e3643 => new \Tak\Liveproto\Tl\Functions\Messages\ViewSponsoredMessage,
			0x8235057e => new \Tak\Liveproto\Tl\Functions\Messages\ClickSponsoredMessage,
			0x12cbf0c4 => new \Tak\Liveproto\Tl\Functions\Messages\ReportSponsoredMessage,
			0x3d6ce850 => new \Tak\Liveproto\Tl\Functions\Messages\GetSponsoredMessages,
			0xf21f7f2f => new \Tak\Liveproto\Tl\Functions\Messages\SavePreparedInlineMessage,
			0x857ebdb8 => new \Tak\Liveproto\Tl\Functions\Messages\GetPreparedInlineMessage,
			0x29b1c66a => new \Tak\Liveproto\Tl\Functions\Messages\SearchStickers,
			0x5a6d7395 => new \Tak\Liveproto\Tl\Functions\Messages\ReportMessagesDelivery,
			0x6f6f9c96 => new \Tak\Liveproto\Tl\Functions\Messages\GetSavedDialogsByID,
			0xba4a3b5b => new \Tak\Liveproto\Tl\Functions\Messages\ReadSavedHistory,
			0xd3e03124 => new \Tak\Liveproto\Tl\Functions\Messages\ToggleTodoCompleted,
			0x21a61057 => new \Tak\Liveproto\Tl\Functions\Messages\AppendTodoList,
			0x8107455c => new \Tak\Liveproto\Tl\Functions\Messages\ToggleSuggestedPostApproval,
			0x3ba47bff => new \Tak\Liveproto\Tl\Functions\Messages\GetForumTopics,
			0xaf0a4a08 => new \Tak\Liveproto\Tl\Functions\Messages\GetForumTopicsByID,
			0xcecc1134 => new \Tak\Liveproto\Tl\Functions\Messages\EditForumTopic,
			0x175df251 => new \Tak\Liveproto\Tl\Functions\Messages\UpdatePinnedForumTopic,
			0xe7841f0 => new \Tak\Liveproto\Tl\Functions\Messages\ReorderPinnedForumTopics,
			0x2f98c3d5 => new \Tak\Liveproto\Tl\Functions\Messages\CreateForumTopic,
			0xd2816f10 => new \Tak\Liveproto\Tl\Functions\Messages\DeleteTopicHistory,
			0xfb7e8ca7 => new \Tak\Liveproto\Tl\Functions\Messages\GetEmojiGameInfo,
			0xabbbd346 => new \Tak\Liveproto\Tl\Functions\Messages\SummarizeText,
			0xf743b857 => new \Tak\Liveproto\Tl\Functions\Messages\EditChatCreator,
			0x3b7d0ea6 => new \Tak\Liveproto\Tl\Functions\Messages\GetFutureChatCreatorAfterLeave,
			0xa00f32b0 => new \Tak\Liveproto\Tl\Functions\Messages\EditChatParticipantRank,
			0x35436bbc => new \Tak\Liveproto\Tl\Functions\Messages\DeclineUrlAuth,
			0xc9a47b0b => new \Tak\Liveproto\Tl\Functions\Messages\CheckUrlAuthMatchCode,
			0xdaecc589 => new \Tak\Liveproto\Tl\Functions\Messages\ComposeMessageWithAI,
			0x4067c5e6 => new \Tak\Liveproto\Tl\Functions\Messages\ReportReadMetrics,
			0xddbcd819 => new \Tak\Liveproto\Tl\Functions\Messages\ReportMusicListen,
			0x19bc4b6d => new \Tak\Liveproto\Tl\Functions\Messages\AddPollAnswer,
			0xac8505a5 => new \Tak\Liveproto\Tl\Functions\Messages\DeletePollAnswer,
			0x43286cf2 => new \Tak\Liveproto\Tl\Functions\Messages\GetUnreadPollVotes,
			0x1720b4d8 => new \Tak\Liveproto\Tl\Functions\Messages\ReadPollVotes,
			0xb8f106e3 => new \Tak\Liveproto\Tl\Functions\Messages\SetBotGuestChatResult,
			0xa0b80cf8 => new \Tak\Liveproto\Tl\Functions\Messages\DeleteParticipantReactions,
			0xe3b7f82c => new \Tak\Liveproto\Tl\Functions\Messages\DeleteParticipantReaction,
			0x55fb0996 => new \Tak\Liveproto\Tl\Functions\Messages\GetPersonalChannelHistory,
			0x501569cf => new \Tak\Liveproto\Tl\Functions\Messages\GetRichMessage,
			0xedd4882a => new \Tak\Liveproto\Tl\Functions\Updates\GetState,
			0x19c2f763 => new \Tak\Liveproto\Tl\Functions\Updates\GetDifference,
			0x3173d78 => new \Tak\Liveproto\Tl\Functions\Updates\GetChannelDifference,
			0x9e82039 => new \Tak\Liveproto\Tl\Functions\Photos\UpdateProfilePhoto,
			0x388a3b5 => new \Tak\Liveproto\Tl\Functions\Photos\UploadProfilePhoto,
			0x87cf7f2f => new \Tak\Liveproto\Tl\Functions\Photos\DeletePhotos,
			0x91cd32a8 => new \Tak\Liveproto\Tl\Functions\Photos\GetUserPhotos,
			0xe14c4a71 => new \Tak\Liveproto\Tl\Functions\Photos\UploadContactProfilePhoto,
			0xb304a621 => new \Tak\Liveproto\Tl\Functions\Upload\SaveFilePart,
			0xbe5335be => new \Tak\Liveproto\Tl\Functions\Upload\GetFile,
			0xde7b673d => new \Tak\Liveproto\Tl\Functions\Upload\SaveBigFilePart,
			0x24e6818d => new \Tak\Liveproto\Tl\Functions\Upload\GetWebFile,
			0x395f69da => new \Tak\Liveproto\Tl\Functions\Upload\GetCdnFile,
			0x9b2754a8 => new \Tak\Liveproto\Tl\Functions\Upload\ReuploadCdnFile,
			0x91dc3f31 => new \Tak\Liveproto\Tl\Functions\Upload\GetCdnFileHashes,
			0x9156982a => new \Tak\Liveproto\Tl\Functions\Upload\GetFileHashes,
			0xc4f9186b => new \Tak\Liveproto\Tl\Functions\Help\GetConfig,
			0x1fb33026 => new \Tak\Liveproto\Tl\Functions\Help\GetNearestDc,
			0x522d5a7d => new \Tak\Liveproto\Tl\Functions\Help\GetAppUpdate,
			0x4d392343 => new \Tak\Liveproto\Tl\Functions\Help\GetInviteText,
			0x9cdf08cd => new \Tak\Liveproto\Tl\Functions\Help\GetSupport,
			0xec22cfcd => new \Tak\Liveproto\Tl\Functions\Help\SetBotUpdatesStatus,
			0x52029342 => new \Tak\Liveproto\Tl\Functions\Help\GetCdnConfig,
			0x3dc0f114 => new \Tak\Liveproto\Tl\Functions\Help\GetRecentMeUrls,
			0x2ca51fd1 => new \Tak\Liveproto\Tl\Functions\Help\GetTermsOfServiceUpdate,
			0xee72f79a => new \Tak\Liveproto\Tl\Functions\Help\AcceptTermsOfService,
			0x3fedc75f => new \Tak\Liveproto\Tl\Functions\Help\GetDeepLinkInfo,
			0x61e3f854 => new \Tak\Liveproto\Tl\Functions\Help\GetAppConfig,
			0x6f02f748 => new \Tak\Liveproto\Tl\Functions\Help\SaveAppLog,
			0xc661ad08 => new \Tak\Liveproto\Tl\Functions\Help\GetPassportConfig,
			0xd360e72c => new \Tak\Liveproto\Tl\Functions\Help\GetSupportName,
			0x38a08d3 => new \Tak\Liveproto\Tl\Functions\Help\GetUserInfo,
			0x66b91b70 => new \Tak\Liveproto\Tl\Functions\Help\EditUserInfo,
			0xc0977421 => new \Tak\Liveproto\Tl\Functions\Help\GetPromoData,
			0x1e251c95 => new \Tak\Liveproto\Tl\Functions\Help\HidePromoData,
			0xf50dbaa1 => new \Tak\Liveproto\Tl\Functions\Help\DismissSuggestion,
			0x735787a8 => new \Tak\Liveproto\Tl\Functions\Help\GetCountriesList,
			0xb81b93d4 => new \Tak\Liveproto\Tl\Functions\Help\GetPremiumPromo,
			0xda80f42f => new \Tak\Liveproto\Tl\Functions\Help\GetPeerColors,
			0xabcfa9fd => new \Tak\Liveproto\Tl\Functions\Help\GetPeerProfileColors,
			0x49b30240 => new \Tak\Liveproto\Tl\Functions\Help\GetTimezonesList,
			0xcc104937 => new \Tak\Liveproto\Tl\Functions\Channels\ReadHistory,
			0x84c1fd4e => new \Tak\Liveproto\Tl\Functions\Channels\DeleteMessages,
			0xf44a8315 => new \Tak\Liveproto\Tl\Functions\Channels\ReportSpam,
			0xad8c9a23 => new \Tak\Liveproto\Tl\Functions\Channels\GetMessages,
			0x77ced9d0 => new \Tak\Liveproto\Tl\Functions\Channels\GetParticipants,
			0xa0ab6cc6 => new \Tak\Liveproto\Tl\Functions\Channels\GetParticipant,
			0xa7f6bbb => new \Tak\Liveproto\Tl\Functions\Channels\GetChannels,
			0x8736a09 => new \Tak\Liveproto\Tl\Functions\Channels\GetFullChannel,
			0x91006707 => new \Tak\Liveproto\Tl\Functions\Channels\CreateChannel,
			0x9a98ad68 => new \Tak\Liveproto\Tl\Functions\Channels\EditAdmin,
			0x566decd0 => new \Tak\Liveproto\Tl\Functions\Channels\EditTitle,
			0xf12e57c9 => new \Tak\Liveproto\Tl\Functions\Channels\EditPhoto,
			0x10e6bd2c => new \Tak\Liveproto\Tl\Functions\Channels\CheckUsername,
			0x3514b3de => new \Tak\Liveproto\Tl\Functions\Channels\UpdateUsername,
			0x7f6a1e22 => new \Tak\Liveproto\Tl\Functions\Channels\JoinChannel,
			0xf836aa95 => new \Tak\Liveproto\Tl\Functions\Channels\LeaveChannel,
			0xc9e33d54 => new \Tak\Liveproto\Tl\Functions\Channels\InviteToChannel,
			0xc0111fe3 => new \Tak\Liveproto\Tl\Functions\Channels\DeleteChannel,
			0xe63fadeb => new \Tak\Liveproto\Tl\Functions\Channels\ExportMessageLink,
			0x418d549c => new \Tak\Liveproto\Tl\Functions\Channels\ToggleSignatures,
			0xf8b036af => new \Tak\Liveproto\Tl\Functions\Channels\GetAdminedPublicChannels,
			0x96e6cd81 => new \Tak\Liveproto\Tl\Functions\Channels\EditBanned,
			0x33ddf480 => new \Tak\Liveproto\Tl\Functions\Channels\GetAdminLog,
			0xea8ca4f9 => new \Tak\Liveproto\Tl\Functions\Channels\SetStickers,
			0xeab5dc38 => new \Tak\Liveproto\Tl\Functions\Channels\ReadMessageContents,
			0x9baa9647 => new \Tak\Liveproto\Tl\Functions\Channels\DeleteHistory,
			0xeabbb94c => new \Tak\Liveproto\Tl\Functions\Channels\TogglePreHistoryHidden,
			0x8341ecc0 => new \Tak\Liveproto\Tl\Functions\Channels\GetLeftChannels,
			0xf5dad378 => new \Tak\Liveproto\Tl\Functions\Channels\GetGroupsForDiscussion,
			0x40582bb2 => new \Tak\Liveproto\Tl\Functions\Channels\SetDiscussionGroup,
			0x58e63f6d => new \Tak\Liveproto\Tl\Functions\Channels\EditLocation,
			0xedd49ef0 => new \Tak\Liveproto\Tl\Functions\Channels\ToggleSlowMode,
			0x11e831ee => new \Tak\Liveproto\Tl\Functions\Channels\GetInactiveChannels,
			0xb290c69 => new \Tak\Liveproto\Tl\Functions\Channels\ConvertToGigagroup,
			0xe785a43f => new \Tak\Liveproto\Tl\Functions\Channels\GetSendAs,
			0x367544db => new \Tak\Liveproto\Tl\Functions\Channels\DeleteParticipantHistory,
			0xe4cb9580 => new \Tak\Liveproto\Tl\Functions\Channels\ToggleJoinToSend,
			0xecc2618 => new \Tak\Liveproto\Tl\Functions\Channels\ToggleJoinRequest,
			0xb45ced1d => new \Tak\Liveproto\Tl\Functions\Channels\ReorderUsernames,
			0x50f24105 => new \Tak\Liveproto\Tl\Functions\Channels\ToggleUsername,
			0xa245dd3 => new \Tak\Liveproto\Tl\Functions\Channels\DeactivateAllUsernames,
			0x3ff75734 => new \Tak\Liveproto\Tl\Functions\Channels\ToggleForum,
			0x68f3e4eb => new \Tak\Liveproto\Tl\Functions\Channels\ToggleAntiSpam,
			0xa850a693 => new \Tak\Liveproto\Tl\Functions\Channels\ReportAntiSpamFalsePositive,
			0x6a6e7854 => new \Tak\Liveproto\Tl\Functions\Channels\ToggleParticipantsHidden,
			0xd8aa3671 => new \Tak\Liveproto\Tl\Functions\Channels\UpdateColor,
			0x9738bb15 => new \Tak\Liveproto\Tl\Functions\Channels\ToggleViewForumAsMessages,
			0x25a71742 => new \Tak\Liveproto\Tl\Functions\Channels\GetChannelRecommendations,
			0xf0d3e6a8 => new \Tak\Liveproto\Tl\Functions\Channels\UpdateEmojiStatus,
			0xad399cee => new \Tak\Liveproto\Tl\Functions\Channels\SetBoostsToUnblockRestrictions,
			0x3cd930b7 => new \Tak\Liveproto\Tl\Functions\Channels\SetEmojiStickers,
			0x9ae91519 => new \Tak\Liveproto\Tl\Functions\Channels\RestrictSponsoredMessages,
			0xf2c4f24d => new \Tak\Liveproto\Tl\Functions\Channels\SearchPosts,
			0x4b12327b => new \Tak\Liveproto\Tl\Functions\Channels\UpdatePaidMessagesPrice,
			0x167fc0a1 => new \Tak\Liveproto\Tl\Functions\Channels\ToggleAutotranslation,
			0xece2a0e6 => new \Tak\Liveproto\Tl\Functions\Channels\GetMessageAuthor,
			0x22567115 => new \Tak\Liveproto\Tl\Functions\Channels\CheckSearchPostsFlood,
			0x3583fcb1 => new \Tak\Liveproto\Tl\Functions\Channels\SetMainProfileTab,
			0xaa2769ed => new \Tak\Liveproto\Tl\Functions\Bots\SendCustomRequest,
			0xe6213f4d => new \Tak\Liveproto\Tl\Functions\Bots\AnswerWebhookJSONQuery,
			0x517165a => new \Tak\Liveproto\Tl\Functions\Bots\SetBotCommands,
			0x3d8de0f9 => new \Tak\Liveproto\Tl\Functions\Bots\ResetBotCommands,
			0xe34c0dd6 => new \Tak\Liveproto\Tl\Functions\Bots\GetBotCommands,
			0x4504d54f => new \Tak\Liveproto\Tl\Functions\Bots\SetBotMenuButton,
			0x9c60eb28 => new \Tak\Liveproto\Tl\Functions\Bots\GetBotMenuButton,
			0x788464e1 => new \Tak\Liveproto\Tl\Functions\Bots\SetBotBroadcastDefaultAdminRights,
			0x925ec9ea => new \Tak\Liveproto\Tl\Functions\Bots\SetBotGroupDefaultAdminRights,
			0x10cf3123 => new \Tak\Liveproto\Tl\Functions\Bots\SetBotInfo,
			0xdcd914fd => new \Tak\Liveproto\Tl\Functions\Bots\GetBotInfo,
			0x9709b1c2 => new \Tak\Liveproto\Tl\Functions\Bots\ReorderUsernames,
			0x53ca973 => new \Tak\Liveproto\Tl\Functions\Bots\ToggleUsername,
			0x1359f4e6 => new \Tak\Liveproto\Tl\Functions\Bots\CanSendMessage,
			0xf132e3ef => new \Tak\Liveproto\Tl\Functions\Bots\AllowSendMessage,
			0x87fc5e7 => new \Tak\Liveproto\Tl\Functions\Bots\InvokeWebViewCustomMethod,
			0xc2510192 => new \Tak\Liveproto\Tl\Functions\Bots\GetPopularAppBots,
			0x17aeb75a => new \Tak\Liveproto\Tl\Functions\Bots\AddPreviewMedia,
			0x8525606f => new \Tak\Liveproto\Tl\Functions\Bots\EditPreviewMedia,
			0x2d0135b3 => new \Tak\Liveproto\Tl\Functions\Bots\DeletePreviewMedia,
			0xb627f3aa => new \Tak\Liveproto\Tl\Functions\Bots\ReorderPreviewMedias,
			0x423ab3ad => new \Tak\Liveproto\Tl\Functions\Bots\GetPreviewInfo,
			0xa2a5594d => new \Tak\Liveproto\Tl\Functions\Bots\GetPreviewMedias,
			0xed9f30c5 => new \Tak\Liveproto\Tl\Functions\Bots\UpdateUserEmojiStatus,
			0x6de6392 => new \Tak\Liveproto\Tl\Functions\Bots\ToggleUserEmojiStatusPermission,
			0x50077589 => new \Tak\Liveproto\Tl\Functions\Bots\CheckDownloadFileParams,
			0xb0711d83 => new \Tak\Liveproto\Tl\Functions\Bots\GetAdminedBots,
			0x778b5ab3 => new \Tak\Liveproto\Tl\Functions\Bots\UpdateStarRefProgram,
			0x8b89dfbd => new \Tak\Liveproto\Tl\Functions\Bots\SetCustomVerification,
			0xa1b70815 => new \Tak\Liveproto\Tl\Functions\Bots\GetBotRecommendations,
			0x87f2219b => new \Tak\Liveproto\Tl\Functions\Bots\CheckUsername,
			0xe5b17f2b => new \Tak\Liveproto\Tl\Functions\Bots\CreateBot,
			0xbd0d99eb => new \Tak\Liveproto\Tl\Functions\Bots\ExportBotToken,
			0x31a2a35e => new \Tak\Liveproto\Tl\Functions\Bots\RequestWebViewButton,
			0xbf25b7f3 => new \Tak\Liveproto\Tl\Functions\Bots\GetRequestedWebViewButton,
			0x213853a3 => new \Tak\Liveproto\Tl\Functions\Bots\GetAccessSettings,
			0x31813cd8 => new \Tak\Liveproto\Tl\Functions\Bots\EditAccessSettings,
			0xe71a4810 => new \Tak\Liveproto\Tl\Functions\Bots\SetJoinChatResults,
			0x37148dbb => new \Tak\Liveproto\Tl\Functions\Payments\GetPaymentForm,
			0x2478d1cc => new \Tak\Liveproto\Tl\Functions\Payments\GetPaymentReceipt,
			0xb6c8f12b => new \Tak\Liveproto\Tl\Functions\Payments\ValidateRequestedInfo,
			0x2d03522f => new \Tak\Liveproto\Tl\Functions\Payments\SendPaymentForm,
			0x227d824b => new \Tak\Liveproto\Tl\Functions\Payments\GetSavedInfo,
			0xd83d70c1 => new \Tak\Liveproto\Tl\Functions\Payments\ClearSavedInfo,
			0x2e79d779 => new \Tak\Liveproto\Tl\Functions\Payments\GetBankCardData,
			0xf91b065 => new \Tak\Liveproto\Tl\Functions\Payments\ExportInvoice,
			0x80ed747d => new \Tak\Liveproto\Tl\Functions\Payments\AssignAppStoreTransaction,
			0xdffd50d3 => new \Tak\Liveproto\Tl\Functions\Payments\AssignPlayMarketTransaction,
			0x2757ba54 => new \Tak\Liveproto\Tl\Functions\Payments\GetPremiumGiftCodeOptions,
			0x8e51b4c1 => new \Tak\Liveproto\Tl\Functions\Payments\CheckGiftCode,
			0xf6e26854 => new \Tak\Liveproto\Tl\Functions\Payments\ApplyGiftCode,
			0xf4239425 => new \Tak\Liveproto\Tl\Functions\Payments\GetGiveawayInfo,
			0x5ff58f20 => new \Tak\Liveproto\Tl\Functions\Payments\LaunchPrepaidGiveaway,
			0xc00ec7d3 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarsTopupOptions,
			0x4ea9b3bf => new \Tak\Liveproto\Tl\Functions\Payments\GetStarsStatus,
			0x69da4557 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarsTransactions,
			0x7998c914 => new \Tak\Liveproto\Tl\Functions\Payments\SendStarsForm,
			0x25ae8f4a => new \Tak\Liveproto\Tl\Functions\Payments\RefundStarsCharge,
			0xd91ffad6 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarsRevenueStats,
			0x2433dc92 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarsRevenueWithdrawalUrl,
			0xd1d7efc5 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarsRevenueAdsAccountUrl,
			0x2dca16b8 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarsTransactionsByID,
			0xd3c96bc8 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarsGiftOptions,
			0x32512c5 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarsSubscriptions,
			0xc7770878 => new \Tak\Liveproto\Tl\Functions\Payments\ChangeStarsSubscription,
			0xcc5bebb3 => new \Tak\Liveproto\Tl\Functions\Payments\FulfillStarsSubscription,
			0xbd1efd3e => new \Tak\Liveproto\Tl\Functions\Payments\GetStarsGiveawayOptions,
			0xc4563590 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarGifts,
			0x2a2a697c => new \Tak\Liveproto\Tl\Functions\Payments\SaveStarGift,
			0x74bf076b => new \Tak\Liveproto\Tl\Functions\Payments\ConvertStarGift,
			0x6dfa0622 => new \Tak\Liveproto\Tl\Functions\Payments\BotCancelStarsSubscription,
			0x5869a553 => new \Tak\Liveproto\Tl\Functions\Payments\GetConnectedStarRefBots,
			0xb7d998f0 => new \Tak\Liveproto\Tl\Functions\Payments\GetConnectedStarRefBot,
			0xd6b48f7 => new \Tak\Liveproto\Tl\Functions\Payments\GetSuggestedStarRefBots,
			0x7ed5348a => new \Tak\Liveproto\Tl\Functions\Payments\ConnectStarRefBot,
			0xe4fca4a3 => new \Tak\Liveproto\Tl\Functions\Payments\EditConnectedStarRefBot,
			0x9c9abcb1 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarGiftUpgradePreview,
			0xaed6e4f5 => new \Tak\Liveproto\Tl\Functions\Payments\UpgradeStarGift,
			0x7f18176a => new \Tak\Liveproto\Tl\Functions\Payments\TransferStarGift,
			0xa1974d72 => new \Tak\Liveproto\Tl\Functions\Payments\GetUniqueStarGift,
			0xa319e569 => new \Tak\Liveproto\Tl\Functions\Payments\GetSavedStarGifts,
			0xb455a106 => new \Tak\Liveproto\Tl\Functions\Payments\GetSavedStarGift,
			0xd06e93a8 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarGiftWithdrawalUrl,
			0x60eaefa1 => new \Tak\Liveproto\Tl\Functions\Payments\ToggleChatStarGiftNotifications,
			0x1513e7b0 => new \Tak\Liveproto\Tl\Functions\Payments\ToggleStarGiftsPinnedToTop,
			0x4fdc5ea7 => new \Tak\Liveproto\Tl\Functions\Payments\CanPurchaseStore,
			0x7a5fa236 => new \Tak\Liveproto\Tl\Functions\Payments\GetResaleStarGifts,
			0xedbe6ccb => new \Tak\Liveproto\Tl\Functions\Payments\UpdateStarGiftPrice,
			0x1f4a0e87 => new \Tak\Liveproto\Tl\Functions\Payments\CreateStarGiftCollection,
			0x4fddbee7 => new \Tak\Liveproto\Tl\Functions\Payments\UpdateStarGiftCollection,
			0xc32af4cc => new \Tak\Liveproto\Tl\Functions\Payments\ReorderStarGiftCollections,
			0xad5648e8 => new \Tak\Liveproto\Tl\Functions\Payments\DeleteStarGiftCollection,
			0x981b91dd => new \Tak\Liveproto\Tl\Functions\Payments\GetStarGiftCollections,
			0x4365af6b => new \Tak\Liveproto\Tl\Functions\Payments\GetUniqueStarGiftValueInfo,
			0xc0c4edc9 => new \Tak\Liveproto\Tl\Functions\Payments\CheckCanSendGift,
			0x5c9ff4d6 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarGiftAuctionState,
			0x6ba2cbec => new \Tak\Liveproto\Tl\Functions\Payments\GetStarGiftAuctionAcquiredGifts,
			0xa5d0514d => new \Tak\Liveproto\Tl\Functions\Payments\GetStarGiftActiveAuctions,
			0xe9ce781c => new \Tak\Liveproto\Tl\Functions\Payments\ResolveStarGiftOffer,
			0x8fb86b41 => new \Tak\Liveproto\Tl\Functions\Payments\SendStarGiftOffer,
			0x6d038b58 => new \Tak\Liveproto\Tl\Functions\Payments\GetStarGiftUpgradeAttributes,
			0xfd05dd00 => new \Tak\Liveproto\Tl\Functions\Payments\GetCraftStarGifts,
			0xb0f9684f => new \Tak\Liveproto\Tl\Functions\Payments\CraftStarGift,
			0x9021ab67 => new \Tak\Liveproto\Tl\Functions\Stickers\CreateStickerSet,
			0xf7760f51 => new \Tak\Liveproto\Tl\Functions\Stickers\RemoveStickerFromSet,
			0xffb6d4ca => new \Tak\Liveproto\Tl\Functions\Stickers\ChangeStickerPosition,
			0x8653febe => new \Tak\Liveproto\Tl\Functions\Stickers\AddStickerToSet,
			0xa76a5392 => new \Tak\Liveproto\Tl\Functions\Stickers\SetStickerSetThumb,
			0x284b3639 => new \Tak\Liveproto\Tl\Functions\Stickers\CheckShortName,
			0x4dafc503 => new \Tak\Liveproto\Tl\Functions\Stickers\SuggestShortName,
			0xf5537ebc => new \Tak\Liveproto\Tl\Functions\Stickers\ChangeSticker,
			0x124b1c00 => new \Tak\Liveproto\Tl\Functions\Stickers\RenameStickerSet,
			0x87704394 => new \Tak\Liveproto\Tl\Functions\Stickers\DeleteStickerSet,
			0x4696459a => new \Tak\Liveproto\Tl\Functions\Stickers\ReplaceSticker,
			0x55451fa9 => new \Tak\Liveproto\Tl\Functions\Phone\GetCallConfig,
			0x42ff96ed => new \Tak\Liveproto\Tl\Functions\Phone\RequestCall,
			0x3bd2b4a0 => new \Tak\Liveproto\Tl\Functions\Phone\AcceptCall,
			0x2efe1722 => new \Tak\Liveproto\Tl\Functions\Phone\ConfirmCall,
			0x17d54f61 => new \Tak\Liveproto\Tl\Functions\Phone\ReceivedCall,
			0xb2cbc1c0 => new \Tak\Liveproto\Tl\Functions\Phone\DiscardCall,
			0x59ead627 => new \Tak\Liveproto\Tl\Functions\Phone\SetCallRating,
			0x277add7e => new \Tak\Liveproto\Tl\Functions\Phone\SaveCallDebug,
			0xff7a9383 => new \Tak\Liveproto\Tl\Functions\Phone\SendSignalingData,
			0x48cdc6d8 => new \Tak\Liveproto\Tl\Functions\Phone\CreateGroupCall,
			0x8fb53057 => new \Tak\Liveproto\Tl\Functions\Phone\JoinGroupCall,
			0x500377f9 => new \Tak\Liveproto\Tl\Functions\Phone\LeaveGroupCall,
			0x7b393160 => new \Tak\Liveproto\Tl\Functions\Phone\InviteToGroupCall,
			0x7a777135 => new \Tak\Liveproto\Tl\Functions\Phone\DiscardGroupCall,
			0x974392f2 => new \Tak\Liveproto\Tl\Functions\Phone\ToggleGroupCallSettings,
			0x41845db => new \Tak\Liveproto\Tl\Functions\Phone\GetGroupCall,
			0xc558d8ab => new \Tak\Liveproto\Tl\Functions\Phone\GetGroupParticipants,
			0xb59cf977 => new \Tak\Liveproto\Tl\Functions\Phone\CheckGroupCall,
			0xf128c708 => new \Tak\Liveproto\Tl\Functions\Phone\ToggleGroupCallRecord,
			0xa5273abf => new \Tak\Liveproto\Tl\Functions\Phone\EditGroupCallParticipant,
			0x1ca6ac0a => new \Tak\Liveproto\Tl\Functions\Phone\EditGroupCallTitle,
			0xef7c213a => new \Tak\Liveproto\Tl\Functions\Phone\GetGroupCallJoinAs,
			0xe6aa647f => new \Tak\Liveproto\Tl\Functions\Phone\ExportGroupCallInvite,
			0x219c34e6 => new \Tak\Liveproto\Tl\Functions\Phone\ToggleGroupCallStartSubscription,
			0x5680e342 => new \Tak\Liveproto\Tl\Functions\Phone\StartScheduledGroupCall,
			0x575e1f8c => new \Tak\Liveproto\Tl\Functions\Phone\SaveDefaultGroupCallJoinAs,
			0xcbea6bc4 => new \Tak\Liveproto\Tl\Functions\Phone\JoinGroupCallPresentation,
			0x1c50d144 => new \Tak\Liveproto\Tl\Functions\Phone\LeaveGroupCallPresentation,
			0x1ab21940 => new \Tak\Liveproto\Tl\Functions\Phone\GetGroupCallStreamChannels,
			0x5af4c73a => new \Tak\Liveproto\Tl\Functions\Phone\GetGroupCallStreamRtmpUrl,
			0x41248786 => new \Tak\Liveproto\Tl\Functions\Phone\SaveCallLog,
			0x7d0444bb => new \Tak\Liveproto\Tl\Functions\Phone\CreateConferenceCall,
			0x8ca60525 => new \Tak\Liveproto\Tl\Functions\Phone\DeleteConferenceCallParticipants,
			0xc6701900 => new \Tak\Liveproto\Tl\Functions\Phone\SendConferenceCallBroadcast,
			0xbcf22685 => new \Tak\Liveproto\Tl\Functions\Phone\InviteConferenceCallParticipant,
			0x3c479971 => new \Tak\Liveproto\Tl\Functions\Phone\DeclineConferenceCallInvite,
			0xee9f88a6 => new \Tak\Liveproto\Tl\Functions\Phone\GetGroupCallChainBlocks,
			0xb1d11410 => new \Tak\Liveproto\Tl\Functions\Phone\SendGroupCallMessage,
			0xe5afa56d => new \Tak\Liveproto\Tl\Functions\Phone\SendGroupCallEncryptedMessage,
			0xf64f54f7 => new \Tak\Liveproto\Tl\Functions\Phone\DeleteGroupCallMessages,
			0x1dbfeca0 => new \Tak\Liveproto\Tl\Functions\Phone\DeleteGroupCallParticipantMessages,
			0x6f636302 => new \Tak\Liveproto\Tl\Functions\Phone\GetGroupCallStars,
			0x4167add1 => new \Tak\Liveproto\Tl\Functions\Phone\SaveDefaultSendAs,
			0xf2f2330a => new \Tak\Liveproto\Tl\Functions\Langpack\GetLangPack,
			0xefea3803 => new \Tak\Liveproto\Tl\Functions\Langpack\GetStrings,
			0xcd984aa5 => new \Tak\Liveproto\Tl\Functions\Langpack\GetDifference,
			0x42c6978f => new \Tak\Liveproto\Tl\Functions\Langpack\GetLanguages,
			0x6a596502 => new \Tak\Liveproto\Tl\Functions\Langpack\GetLanguage,
			0x6847d0ab => new \Tak\Liveproto\Tl\Functions\Folders\EditPeerFolders,
			0xab42441a => new \Tak\Liveproto\Tl\Functions\Stats\GetBroadcastStats,
			0x621d5fa0 => new \Tak\Liveproto\Tl\Functions\Stats\LoadAsyncGraph,
			0xdcdf8607 => new \Tak\Liveproto\Tl\Functions\Stats\GetMegagroupStats,
			0x5f150144 => new \Tak\Liveproto\Tl\Functions\Stats\GetMessagePublicForwards,
			0xb6e0a3f5 => new \Tak\Liveproto\Tl\Functions\Stats\GetMessageStats,
			0x374fef40 => new \Tak\Liveproto\Tl\Functions\Stats\GetStoryStats,
			0xa6437ef6 => new \Tak\Liveproto\Tl\Functions\Stats\GetStoryPublicForwards,
			0xc27dfa68 => new \Tak\Liveproto\Tl\Functions\Stats\GetPollStats,
			0x8472478e => new \Tak\Liveproto\Tl\Functions\Chatlists\ExportChatlistInvite,
			0x719c5c5e => new \Tak\Liveproto\Tl\Functions\Chatlists\DeleteExportedInvite,
			0x653db63d => new \Tak\Liveproto\Tl\Functions\Chatlists\EditExportedInvite,
			0xce03da83 => new \Tak\Liveproto\Tl\Functions\Chatlists\GetExportedInvites,
			0x41c10fff => new \Tak\Liveproto\Tl\Functions\Chatlists\CheckChatlistInvite,
			0xa6b1e39a => new \Tak\Liveproto\Tl\Functions\Chatlists\JoinChatlistInvite,
			0x89419521 => new \Tak\Liveproto\Tl\Functions\Chatlists\GetChatlistUpdates,
			0xe089f8f5 => new \Tak\Liveproto\Tl\Functions\Chatlists\JoinChatlistUpdates,
			0x66e486fb => new \Tak\Liveproto\Tl\Functions\Chatlists\HideChatlistUpdates,
			0xfdbcd714 => new \Tak\Liveproto\Tl\Functions\Chatlists\GetLeaveChatlistSuggestions,
			0x74fae13a => new \Tak\Liveproto\Tl\Functions\Chatlists\LeaveChatlist,
			0x30eb63f0 => new \Tak\Liveproto\Tl\Functions\Stories\CanSendStory,
			0x8f9e6898 => new \Tak\Liveproto\Tl\Functions\Stories\SendStory,
			0x2c63a72b => new \Tak\Liveproto\Tl\Functions\Stories\EditStory,
			0xae59db5f => new \Tak\Liveproto\Tl\Functions\Stories\DeleteStories,
			0x9a75a1ef => new \Tak\Liveproto\Tl\Functions\Stories\TogglePinned,
			0xeeb0d625 => new \Tak\Liveproto\Tl\Functions\Stories\GetAllStories,
			0x5821a5dc => new \Tak\Liveproto\Tl\Functions\Stories\GetPinnedStories,
			0xb4352016 => new \Tak\Liveproto\Tl\Functions\Stories\GetStoriesArchive,
			0x5774ca74 => new \Tak\Liveproto\Tl\Functions\Stories\GetStoriesByID,
			0x7c2557c4 => new \Tak\Liveproto\Tl\Functions\Stories\ToggleAllStoriesHidden,
			0xa556dac8 => new \Tak\Liveproto\Tl\Functions\Stories\ReadStories,
			0xb2028afb => new \Tak\Liveproto\Tl\Functions\Stories\IncrementStoryViews,
			0x7ed23c57 => new \Tak\Liveproto\Tl\Functions\Stories\GetStoryViewsList,
			0x28e16cc8 => new \Tak\Liveproto\Tl\Functions\Stories\GetStoriesViews,
			0x7b8def20 => new \Tak\Liveproto\Tl\Functions\Stories\ExportStoryLink,
			0x19d8eb45 => new \Tak\Liveproto\Tl\Functions\Stories\Report,
			0x57bbd166 => new \Tak\Liveproto\Tl\Functions\Stories\ActivateStealthMode,
			0x7fd736b2 => new \Tak\Liveproto\Tl\Functions\Stories\SendReaction,
			0x2c4ada50 => new \Tak\Liveproto\Tl\Functions\Stories\GetPeerStories,
			0x9b5ae7f9 => new \Tak\Liveproto\Tl\Functions\Stories\GetAllReadPeerStories,
			0x78499170 => new \Tak\Liveproto\Tl\Functions\Stories\GetPeerMaxIDs,
			0xa56a8b60 => new \Tak\Liveproto\Tl\Functions\Stories\GetChatsToSend,
			0xbd0415c4 => new \Tak\Liveproto\Tl\Functions\Stories\TogglePeerStoriesHidden,
			0xb9b2881f => new \Tak\Liveproto\Tl\Functions\Stories\GetStoryReactionsList,
			0xb297e9b => new \Tak\Liveproto\Tl\Functions\Stories\TogglePinnedToTop,
			0xd1810907 => new \Tak\Liveproto\Tl\Functions\Stories\SearchPosts,
			0xa36396e5 => new \Tak\Liveproto\Tl\Functions\Stories\CreateAlbum,
			0x5e5259b6 => new \Tak\Liveproto\Tl\Functions\Stories\UpdateAlbum,
			0x8535fbd9 => new \Tak\Liveproto\Tl\Functions\Stories\ReorderAlbums,
			0x8d3456d0 => new \Tak\Liveproto\Tl\Functions\Stories\DeleteAlbum,
			0x25b3eac7 => new \Tak\Liveproto\Tl\Functions\Stories\GetAlbums,
			0xac806d61 => new \Tak\Liveproto\Tl\Functions\Stories\GetAlbumStories,
			0xd069ccde => new \Tak\Liveproto\Tl\Functions\Stories\StartLive,
			0x60f67660 => new \Tak\Liveproto\Tl\Functions\Premium\GetBoostsList,
			0xbe77b4a => new \Tak\Liveproto\Tl\Functions\Premium\GetMyBoosts,
			0x6b7da746 => new \Tak\Liveproto\Tl\Functions\Premium\ApplyBoost,
			0x42f1f61 => new \Tak\Liveproto\Tl\Functions\Premium\GetBoostsStatus,
			0x39854d1f => new \Tak\Liveproto\Tl\Functions\Premium\GetUserBoosts,
			0xedc39d0 => new \Tak\Liveproto\Tl\Functions\Smsjobs\IsEligibleToJoin,
			0xa74ece2d => new \Tak\Liveproto\Tl\Functions\Smsjobs\Join,
			0x9898ad73 => new \Tak\Liveproto\Tl\Functions\Smsjobs\Leave,
			0x93fa0bf => new \Tak\Liveproto\Tl\Functions\Smsjobs\UpdateSettings,
			0x10a698e8 => new \Tak\Liveproto\Tl\Functions\Smsjobs\GetStatus,
			0x778d902f => new \Tak\Liveproto\Tl\Functions\Smsjobs\GetSmsJob,
			0x4f1ebf24 => new \Tak\Liveproto\Tl\Functions\Smsjobs\FinishJob,
			0xbe1e85ba => new \Tak\Liveproto\Tl\Functions\Fragment\GetCollectibleInfo,
			0x4aa83913 => new \Tak\Liveproto\Tl\Functions\Aicompose\CreateTone,
			0x903bcf59 => new \Tak\Liveproto\Tl\Functions\Aicompose\UpdateTone,
			0x1782cbb1 => new \Tak\Liveproto\Tl\Functions\Aicompose\SaveTone,
			0xdd39316a => new \Tak\Liveproto\Tl\Functions\Aicompose\DeleteTone,
			0xb2e8ba03 => new \Tak\Liveproto\Tl\Functions\Aicompose\GetTone,
			0xabd59201 => new \Tak\Liveproto\Tl\Functions\Aicompose\GetTones,
			0xd1b4ab14 => new \Tak\Liveproto\Tl\Functions\Aicompose\GetToneExample,
			0xbc799737 => new \Tak\Liveproto\Tl\Types\Other\BoolFalse,
			0x997275b5 => new \Tak\Liveproto\Tl\Types\Other\BoolTrue,
			0x3fedd339 => new \Tak\Liveproto\Tl\Types\Other\TrueObject,
			0xc4b9f9bb => new \Tak\Liveproto\Tl\Types\Other\ErrorObject,
			0x56730bcc => new \Tak\Liveproto\Tl\Types\Other\NullObject,
			0x7f3b18ea => new \Tak\Liveproto\Tl\Types\Other\InputPeerEmpty,
			0x7da07ec9 => new \Tak\Liveproto\Tl\Types\Other\InputPeerSelf,
			0x35a95cb9 => new \Tak\Liveproto\Tl\Types\Other\InputPeerChat,
			0xdde8a54c => new \Tak\Liveproto\Tl\Types\Other\InputPeerUser,
			0x27bcbbfc => new \Tak\Liveproto\Tl\Types\Other\InputPeerChannel,
			0xa87b0a1c => new \Tak\Liveproto\Tl\Types\Other\InputPeerUserFromMessage,
			0xbd2a0840 => new \Tak\Liveproto\Tl\Types\Other\InputPeerChannelFromMessage,
			0xb98886cf => new \Tak\Liveproto\Tl\Types\Other\InputUserEmpty,
			0xf7c1b13f => new \Tak\Liveproto\Tl\Types\Other\InputUserSelf,
			0xf21158c6 => new \Tak\Liveproto\Tl\Types\Other\InputUser,
			0x1da448e2 => new \Tak\Liveproto\Tl\Types\Other\InputUserFromMessage,
			0x6a1dc4be => new \Tak\Liveproto\Tl\Types\Other\InputPhoneContact,
			0xf52ff27f => new \Tak\Liveproto\Tl\Types\Other\InputFile,
			0xfa4f0bb5 => new \Tak\Liveproto\Tl\Types\Other\InputFileBig,
			0x62dc8b48 => new \Tak\Liveproto\Tl\Types\Other\InputFileStoryDocument,
			0x9664f57f => new \Tak\Liveproto\Tl\Types\Other\InputMediaEmpty,
			0x7d8375da => new \Tak\Liveproto\Tl\Types\Other\InputMediaUploadedPhoto,
			0xe3af4434 => new \Tak\Liveproto\Tl\Types\Other\InputMediaPhoto,
			0xf9c44144 => new \Tak\Liveproto\Tl\Types\Other\InputMediaGeoPoint,
			0xf8ab7dfb => new \Tak\Liveproto\Tl\Types\Other\InputMediaContact,
			0x37c9330 => new \Tak\Liveproto\Tl\Types\Other\InputMediaUploadedDocument,
			0xa8763ab5 => new \Tak\Liveproto\Tl\Types\Other\InputMediaDocument,
			0xc13d1c11 => new \Tak\Liveproto\Tl\Types\Other\InputMediaVenue,
			0xe5bbfe1a => new \Tak\Liveproto\Tl\Types\Other\InputMediaPhotoExternal,
			0x779600f9 => new \Tak\Liveproto\Tl\Types\Other\InputMediaDocumentExternal,
			0xd33f43f3 => new \Tak\Liveproto\Tl\Types\Other\InputMediaGame,
			0x405fef0d => new \Tak\Liveproto\Tl\Types\Other\InputMediaInvoice,
			0x971fa843 => new \Tak\Liveproto\Tl\Types\Other\InputMediaGeoLive,
			0x883a4108 => new \Tak\Liveproto\Tl\Types\Other\InputMediaPoll,
			0xe66fbf7b => new \Tak\Liveproto\Tl\Types\Other\InputMediaDice,
			0x89fdd778 => new \Tak\Liveproto\Tl\Types\Other\InputMediaStory,
			0xc21b8849 => new \Tak\Liveproto\Tl\Types\Other\InputMediaWebPage,
			0xc4103386 => new \Tak\Liveproto\Tl\Types\Other\InputMediaPaidMedia,
			0x9fc55fde => new \Tak\Liveproto\Tl\Types\Other\InputMediaTodo,
			0xf3a9244a => new \Tak\Liveproto\Tl\Types\Other\InputMediaStakeDice,
			0x1ca48f57 => new \Tak\Liveproto\Tl\Types\Other\InputChatPhotoEmpty,
			0xbdcdaec0 => new \Tak\Liveproto\Tl\Types\Other\InputChatUploadedPhoto,
			0x8953ad37 => new \Tak\Liveproto\Tl\Types\Other\InputChatPhoto,
			0xe4c123d6 => new \Tak\Liveproto\Tl\Types\Other\InputGeoPointEmpty,
			0x48222faf => new \Tak\Liveproto\Tl\Types\Other\InputGeoPoint,
			0x1cd7bf0d => new \Tak\Liveproto\Tl\Types\Other\InputPhotoEmpty,
			0x3bb3b94a => new \Tak\Liveproto\Tl\Types\Other\InputPhoto,
			0xdfdaabe1 => new \Tak\Liveproto\Tl\Types\Other\InputFileLocation,
			0xf5235d55 => new \Tak\Liveproto\Tl\Types\Other\InputEncryptedFileLocation,
			0xbad07584 => new \Tak\Liveproto\Tl\Types\Other\InputDocumentFileLocation,
			0xcbc7ee28 => new \Tak\Liveproto\Tl\Types\Other\InputSecureFileLocation,
			0x29be5899 => new \Tak\Liveproto\Tl\Types\Other\InputTakeoutFileLocation,
			0x40181ffe => new \Tak\Liveproto\Tl\Types\Other\InputPhotoFileLocation,
			0xd83466f3 => new \Tak\Liveproto\Tl\Types\Other\InputPhotoLegacyFileLocation,
			0x37257e99 => new \Tak\Liveproto\Tl\Types\Other\InputPeerPhotoFileLocation,
			0x9d84f3db => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetThumb,
			0x598a92a => new \Tak\Liveproto\Tl\Types\Other\InputGroupCallStream,
			0x59511722 => new \Tak\Liveproto\Tl\Types\Other\PeerUser,
			0x36c6019a => new \Tak\Liveproto\Tl\Types\Other\PeerChat,
			0xa2a5371e => new \Tak\Liveproto\Tl\Types\Other\PeerChannel,
			0xd3bc4b7a => new \Tak\Liveproto\Tl\Types\Other\UserEmpty,
			0x31774388 => new \Tak\Liveproto\Tl\Types\Other\User,
			0x4f11bae1 => new \Tak\Liveproto\Tl\Types\Other\UserProfilePhotoEmpty,
			0x82d1f706 => new \Tak\Liveproto\Tl\Types\Other\UserProfilePhoto,
			0x9d05049 => new \Tak\Liveproto\Tl\Types\Other\UserStatusEmpty,
			0xedb93949 => new \Tak\Liveproto\Tl\Types\Other\UserStatusOnline,
			0x8c703f => new \Tak\Liveproto\Tl\Types\Other\UserStatusOffline,
			0x7b197dc8 => new \Tak\Liveproto\Tl\Types\Other\UserStatusRecently,
			0x541a1d1a => new \Tak\Liveproto\Tl\Types\Other\UserStatusLastWeek,
			0x65899777 => new \Tak\Liveproto\Tl\Types\Other\UserStatusLastMonth,
			0x29562865 => new \Tak\Liveproto\Tl\Types\Other\ChatEmpty,
			0x41cbf256 => new \Tak\Liveproto\Tl\Types\Other\Chat,
			0x6592a1a7 => new \Tak\Liveproto\Tl\Types\Other\ChatForbidden,
			0x1c32b11c => new \Tak\Liveproto\Tl\Types\Other\Channel,
			0x17d493d5 => new \Tak\Liveproto\Tl\Types\Other\ChannelForbidden,
			0x2633421b => new \Tak\Liveproto\Tl\Types\Other\ChatFull,
			0xa04e8d3a => new \Tak\Liveproto\Tl\Types\Other\ChannelFull,
			0x38e79fde => new \Tak\Liveproto\Tl\Types\Other\ChatParticipant,
			0xe1f867b8 => new \Tak\Liveproto\Tl\Types\Other\ChatParticipantCreator,
			0x360d5d2 => new \Tak\Liveproto\Tl\Types\Other\ChatParticipantAdmin,
			0x8763d3e1 => new \Tak\Liveproto\Tl\Types\Other\ChatParticipantsForbidden,
			0x3cbc93f8 => new \Tak\Liveproto\Tl\Types\Other\ChatParticipants,
			0x37c1011c => new \Tak\Liveproto\Tl\Types\Other\ChatPhotoEmpty,
			0x1c6e1c11 => new \Tak\Liveproto\Tl\Types\Other\ChatPhoto,
			0x90a6ca84 => new \Tak\Liveproto\Tl\Types\Other\MessageEmpty,
			0x7600b9d3 => new \Tak\Liveproto\Tl\Types\Other\Message,
			0x7a800e0a => new \Tak\Liveproto\Tl\Types\Other\MessageService,
			0x3ded6320 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaEmpty,
			0xe216eb63 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaPhoto,
			0x56e0d474 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaGeo,
			0x70322949 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaContact,
			0x9f84f49e => new \Tak\Liveproto\Tl\Types\Other\MessageMediaUnsupported,
			0x52d8ccd9 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaDocument,
			0xddf10c3b => new \Tak\Liveproto\Tl\Types\Other\MessageMediaWebPage,
			0x2ec0533f => new \Tak\Liveproto\Tl\Types\Other\MessageMediaVenue,
			0xfdb19008 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaGame,
			0xf6a548d3 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaInvoice,
			0xb940c666 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaGeoLive,
			0x773f4e66 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaPoll,
			0x8cbec07 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaDice,
			0x68cb6283 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaStory,
			0xaa073beb => new \Tak\Liveproto\Tl\Types\Other\MessageMediaGiveaway,
			0xceaa3ea1 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaGiveawayResults,
			0xa8852491 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaPaidMedia,
			0x8a53b014 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaToDo,
			0xca5cab89 => new \Tak\Liveproto\Tl\Types\Other\MessageMediaVideoStream,
			0xb6aef7b0 => new \Tak\Liveproto\Tl\Types\Other\MessageActionEmpty,
			0xbd47cbad => new \Tak\Liveproto\Tl\Types\Other\MessageActionChatCreate,
			0xb5a1ce5a => new \Tak\Liveproto\Tl\Types\Other\MessageActionChatEditTitle,
			0x7fcb13a8 => new \Tak\Liveproto\Tl\Types\Other\MessageActionChatEditPhoto,
			0x95e3fbef => new \Tak\Liveproto\Tl\Types\Other\MessageActionChatDeletePhoto,
			0x15cefd00 => new \Tak\Liveproto\Tl\Types\Other\MessageActionChatAddUser,
			0xa43f30cc => new \Tak\Liveproto\Tl\Types\Other\MessageActionChatDeleteUser,
			0x31224c3 => new \Tak\Liveproto\Tl\Types\Other\MessageActionChatJoinedByLink,
			0x95d2ac92 => new \Tak\Liveproto\Tl\Types\Other\MessageActionChannelCreate,
			0xe1037f92 => new \Tak\Liveproto\Tl\Types\Other\MessageActionChatMigrateTo,
			0xea3948e9 => new \Tak\Liveproto\Tl\Types\Other\MessageActionChannelMigrateFrom,
			0x94bd38ed => new \Tak\Liveproto\Tl\Types\Other\MessageActionPinMessage,
			0x9fbab604 => new \Tak\Liveproto\Tl\Types\Other\MessageActionHistoryClear,
			0x92a72876 => new \Tak\Liveproto\Tl\Types\Other\MessageActionGameScore,
			0xffa00ccc => new \Tak\Liveproto\Tl\Types\Other\MessageActionPaymentSentMe,
			0xc624b16e => new \Tak\Liveproto\Tl\Types\Other\MessageActionPaymentSent,
			0x80e11a7f => new \Tak\Liveproto\Tl\Types\Other\MessageActionPhoneCall,
			0x4792929b => new \Tak\Liveproto\Tl\Types\Other\MessageActionScreenshotTaken,
			0xfae69f56 => new \Tak\Liveproto\Tl\Types\Other\MessageActionCustomAction,
			0xc516d679 => new \Tak\Liveproto\Tl\Types\Other\MessageActionBotAllowed,
			0x1b287353 => new \Tak\Liveproto\Tl\Types\Other\MessageActionSecureValuesSentMe,
			0xd95c6154 => new \Tak\Liveproto\Tl\Types\Other\MessageActionSecureValuesSent,
			0xf3f25f76 => new \Tak\Liveproto\Tl\Types\Other\MessageActionContactSignUp,
			0x98e0d697 => new \Tak\Liveproto\Tl\Types\Other\MessageActionGeoProximityReached,
			0x7a0d7f42 => new \Tak\Liveproto\Tl\Types\Other\MessageActionGroupCall,
			0x502f92f7 => new \Tak\Liveproto\Tl\Types\Other\MessageActionInviteToGroupCall,
			0x3c134d7b => new \Tak\Liveproto\Tl\Types\Other\MessageActionSetMessagesTTL,
			0xb3a07661 => new \Tak\Liveproto\Tl\Types\Other\MessageActionGroupCallScheduled,
			0xb91bbd3a => new \Tak\Liveproto\Tl\Types\Other\MessageActionSetChatTheme,
			0xebbca3cb => new \Tak\Liveproto\Tl\Types\Other\MessageActionChatJoinedByRequest,
			0x47dd8079 => new \Tak\Liveproto\Tl\Types\Other\MessageActionWebViewDataSentMe,
			0xb4c38cb5 => new \Tak\Liveproto\Tl\Types\Other\MessageActionWebViewDataSent,
			0x48e91302 => new \Tak\Liveproto\Tl\Types\Other\MessageActionGiftPremium,
			0xd999256 => new \Tak\Liveproto\Tl\Types\Other\MessageActionTopicCreate,
			0xc0944820 => new \Tak\Liveproto\Tl\Types\Other\MessageActionTopicEdit,
			0x57de635e => new \Tak\Liveproto\Tl\Types\Other\MessageActionSuggestProfilePhoto,
			0x31518e9b => new \Tak\Liveproto\Tl\Types\Other\MessageActionRequestedPeer,
			0x5060a3f4 => new \Tak\Liveproto\Tl\Types\Other\MessageActionSetChatWallPaper,
			0x31c48347 => new \Tak\Liveproto\Tl\Types\Other\MessageActionGiftCode,
			0xa80f51e4 => new \Tak\Liveproto\Tl\Types\Other\MessageActionGiveawayLaunch,
			0x87e2f155 => new \Tak\Liveproto\Tl\Types\Other\MessageActionGiveawayResults,
			0xcc02aa6d => new \Tak\Liveproto\Tl\Types\Other\MessageActionBoostApply,
			0x93b31848 => new \Tak\Liveproto\Tl\Types\Other\MessageActionRequestedPeerSentMe,
			0x41b3e202 => new \Tak\Liveproto\Tl\Types\Other\MessageActionPaymentRefunded,
			0x45d5b021 => new \Tak\Liveproto\Tl\Types\Other\MessageActionGiftStars,
			0xb00c47a2 => new \Tak\Liveproto\Tl\Types\Other\MessageActionPrizeStars,
			0xea2c31d3 => new \Tak\Liveproto\Tl\Types\Other\MessageActionStarGift,
			0xe6c31522 => new \Tak\Liveproto\Tl\Types\Other\MessageActionStarGiftUnique,
			0xac1f1fcd => new \Tak\Liveproto\Tl\Types\Other\MessageActionPaidMessagesRefunded,
			0x84b88578 => new \Tak\Liveproto\Tl\Types\Other\MessageActionPaidMessagesPrice,
			0x2ffe2f7a => new \Tak\Liveproto\Tl\Types\Other\MessageActionConferenceCall,
			0xcc7c5c89 => new \Tak\Liveproto\Tl\Types\Other\MessageActionTodoCompletions,
			0xc7edbc83 => new \Tak\Liveproto\Tl\Types\Other\MessageActionTodoAppendTasks,
			0xee7a1596 => new \Tak\Liveproto\Tl\Types\Other\MessageActionSuggestedPostApproval,
			0x95ddcf69 => new \Tak\Liveproto\Tl\Types\Other\MessageActionSuggestedPostSuccess,
			0x69f916f8 => new \Tak\Liveproto\Tl\Types\Other\MessageActionSuggestedPostRefund,
			0xa8a3c699 => new \Tak\Liveproto\Tl\Types\Other\MessageActionGiftTon,
			0x2c8f2a25 => new \Tak\Liveproto\Tl\Types\Other\MessageActionSuggestBirthday,
			0x774278d4 => new \Tak\Liveproto\Tl\Types\Other\MessageActionStarGiftPurchaseOffer,
			0x73ada76b => new \Tak\Liveproto\Tl\Types\Other\MessageActionStarGiftPurchaseOfferDeclined,
			0xb07ed085 => new \Tak\Liveproto\Tl\Types\Other\MessageActionNewCreatorPending,
			0xe188503b => new \Tak\Liveproto\Tl\Types\Other\MessageActionChangeCreator,
			0xbf7d6572 => new \Tak\Liveproto\Tl\Types\Other\MessageActionNoForwardsToggle,
			0x3e2793ba => new \Tak\Liveproto\Tl\Types\Other\MessageActionNoForwardsRequest,
			0x9da1cd6c => new \Tak\Liveproto\Tl\Types\Other\MessageActionPollAppendAnswer,
			0x399674dc => new \Tak\Liveproto\Tl\Types\Other\MessageActionPollDeleteAnswer,
			0x16605e3e => new \Tak\Liveproto\Tl\Types\Other\MessageActionManagedBotCreated,
			0xfc89f7f3 => new \Tak\Liveproto\Tl\Types\Other\Dialog,
			0x71bd134c => new \Tak\Liveproto\Tl\Types\Other\DialogFolder,
			0x2331b22d => new \Tak\Liveproto\Tl\Types\Other\PhotoEmpty,
			0xfb197a65 => new \Tak\Liveproto\Tl\Types\Other\Photo,
			0xe17e23c => new \Tak\Liveproto\Tl\Types\Other\PhotoSizeEmpty,
			0x75c78e60 => new \Tak\Liveproto\Tl\Types\Other\PhotoSize,
			0x21e1ad6 => new \Tak\Liveproto\Tl\Types\Other\PhotoCachedSize,
			0xe0b0bc2e => new \Tak\Liveproto\Tl\Types\Other\PhotoStrippedSize,
			0xfa3efb95 => new \Tak\Liveproto\Tl\Types\Other\PhotoSizeProgressive,
			0xd8214d41 => new \Tak\Liveproto\Tl\Types\Other\PhotoPathSize,
			0x1117dd5f => new \Tak\Liveproto\Tl\Types\Other\GeoPointEmpty,
			0xb2a2f663 => new \Tak\Liveproto\Tl\Types\Other\GeoPoint,
			0xb8bc5b0c => new \Tak\Liveproto\Tl\Types\Other\InputNotifyPeer,
			0x193b4417 => new \Tak\Liveproto\Tl\Types\Other\InputNotifyUsers,
			0x4a95e84e => new \Tak\Liveproto\Tl\Types\Other\InputNotifyChats,
			0xb1db7c7e => new \Tak\Liveproto\Tl\Types\Other\InputNotifyBroadcasts,
			0x5c467992 => new \Tak\Liveproto\Tl\Types\Other\InputNotifyForumTopic,
			0xcacb6ae2 => new \Tak\Liveproto\Tl\Types\Other\InputPeerNotifySettings,
			0x99622c0c => new \Tak\Liveproto\Tl\Types\Other\PeerNotifySettings,
			0xf47741f7 => new \Tak\Liveproto\Tl\Types\Other\PeerSettings,
			0xa437c3ed => new \Tak\Liveproto\Tl\Types\Other\WallPaper,
			0xe0804116 => new \Tak\Liveproto\Tl\Types\Other\WallPaperNoFile,
			0x58dbcab8 => new \Tak\Liveproto\Tl\Types\Other\InputReportReasonSpam,
			0x1e22c78d => new \Tak\Liveproto\Tl\Types\Other\InputReportReasonViolence,
			0x2e59d922 => new \Tak\Liveproto\Tl\Types\Other\InputReportReasonPornography,
			0xadf44ee3 => new \Tak\Liveproto\Tl\Types\Other\InputReportReasonChildAbuse,
			0xc1e4a2b1 => new \Tak\Liveproto\Tl\Types\Other\InputReportReasonOther,
			0x9b89f93a => new \Tak\Liveproto\Tl\Types\Other\InputReportReasonCopyright,
			0xdbd4feed => new \Tak\Liveproto\Tl\Types\Other\InputReportReasonGeoIrrelevant,
			0xf5ddd6e7 => new \Tak\Liveproto\Tl\Types\Other\InputReportReasonFake,
			0xa8eb2be => new \Tak\Liveproto\Tl\Types\Other\InputReportReasonIllegalDrugs,
			0x9ec7863d => new \Tak\Liveproto\Tl\Types\Other\InputReportReasonPersonalDetails,
			0x6cbe645 => new \Tak\Liveproto\Tl\Types\Other\UserFull,
			0x145ade0b => new \Tak\Liveproto\Tl\Types\Other\Contact,
			0xc13e3c50 => new \Tak\Liveproto\Tl\Types\Other\ImportedContact,
			0x16d9703b => new \Tak\Liveproto\Tl\Types\Other\ContactStatus,
			0x57e2f66c => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterEmpty,
			0x9609a51c => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterPhotos,
			0x9fc00e65 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterVideo,
			0x56e9f0e4 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterPhotoVideo,
			0x9eddf188 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterDocument,
			0x7ef0dd87 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterUrl,
			0xffc86587 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterGif,
			0x50f5c392 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterVoice,
			0x3751b49e => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterMusic,
			0x3a20ecb8 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterChatPhotos,
			0x80c99768 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterPhoneCalls,
			0x7a7c17a4 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterRoundVoice,
			0xb549da53 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterRoundVideo,
			0xc1f8e69a => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterMyMentions,
			0xe7026d0d => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterGeo,
			0xe062db83 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterContacts,
			0x1bb00451 => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterPinned,
			0xfa2bc90a => new \Tak\Liveproto\Tl\Types\Other\InputMessagesFilterPoll,
			0x1f2b0afd => new \Tak\Liveproto\Tl\Types\Other\UpdateNewMessage,
			0x4e90bfd6 => new \Tak\Liveproto\Tl\Types\Other\UpdateMessageID,
			0xa20db0e5 => new \Tak\Liveproto\Tl\Types\Other\UpdateDeleteMessages,
			0x2a17bf5c => new \Tak\Liveproto\Tl\Types\Other\UpdateUserTyping,
			0x83487af0 => new \Tak\Liveproto\Tl\Types\Other\UpdateChatUserTyping,
			0x7761198 => new \Tak\Liveproto\Tl\Types\Other\UpdateChatParticipants,
			0xe5bdf8de => new \Tak\Liveproto\Tl\Types\Other\UpdateUserStatus,
			0xa7848924 => new \Tak\Liveproto\Tl\Types\Other\UpdateUserName,
			0x8951abef => new \Tak\Liveproto\Tl\Types\Other\UpdateNewAuthorization,
			0x12bcbd9a => new \Tak\Liveproto\Tl\Types\Other\UpdateNewEncryptedMessage,
			0x1710f156 => new \Tak\Liveproto\Tl\Types\Other\UpdateEncryptedChatTyping,
			0xb4a2e88d => new \Tak\Liveproto\Tl\Types\Other\UpdateEncryption,
			0x38fe25b7 => new \Tak\Liveproto\Tl\Types\Other\UpdateEncryptedMessagesRead,
			0x3dda5451 => new \Tak\Liveproto\Tl\Types\Other\UpdateChatParticipantAdd,
			0xe32f3d77 => new \Tak\Liveproto\Tl\Types\Other\UpdateChatParticipantDelete,
			0x8e5e9873 => new \Tak\Liveproto\Tl\Types\Other\UpdateDcOptions,
			0xbec268ef => new \Tak\Liveproto\Tl\Types\Other\UpdateNotifySettings,
			0xebe46819 => new \Tak\Liveproto\Tl\Types\Other\UpdateServiceNotification,
			0xee3b272a => new \Tak\Liveproto\Tl\Types\Other\UpdatePrivacy,
			0x5492a13 => new \Tak\Liveproto\Tl\Types\Other\UpdateUserPhone,
			0x9e84bc99 => new \Tak\Liveproto\Tl\Types\Other\UpdateReadHistoryInbox,
			0x2f2f21bf => new \Tak\Liveproto\Tl\Types\Other\UpdateReadHistoryOutbox,
			0x7f891213 => new \Tak\Liveproto\Tl\Types\Other\UpdateWebPage,
			0xf8227181 => new \Tak\Liveproto\Tl\Types\Other\UpdateReadMessagesContents,
			0x108d941f => new \Tak\Liveproto\Tl\Types\Other\UpdateChannelTooLong,
			0x635b4c09 => new \Tak\Liveproto\Tl\Types\Other\UpdateChannel,
			0x62ba04d9 => new \Tak\Liveproto\Tl\Types\Other\UpdateNewChannelMessage,
			0x922e6e10 => new \Tak\Liveproto\Tl\Types\Other\UpdateReadChannelInbox,
			0xc32d5b12 => new \Tak\Liveproto\Tl\Types\Other\UpdateDeleteChannelMessages,
			0xf226ac08 => new \Tak\Liveproto\Tl\Types\Other\UpdateChannelMessageViews,
			0xd7ca61a2 => new \Tak\Liveproto\Tl\Types\Other\UpdateChatParticipantAdmin,
			0x688a30aa => new \Tak\Liveproto\Tl\Types\Other\UpdateNewStickerSet,
			0xbb2d201 => new \Tak\Liveproto\Tl\Types\Other\UpdateStickerSetsOrder,
			0x31c24808 => new \Tak\Liveproto\Tl\Types\Other\UpdateStickerSets,
			0x9375341e => new \Tak\Liveproto\Tl\Types\Other\UpdateSavedGifs,
			0x496f379c => new \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineQuery,
			0x12f12a07 => new \Tak\Liveproto\Tl\Types\Other\UpdateBotInlineSend,
			0x1b3f4df7 => new \Tak\Liveproto\Tl\Types\Other\UpdateEditChannelMessage,
			0xb9cfc48d => new \Tak\Liveproto\Tl\Types\Other\UpdateBotCallbackQuery,
			0xe40370a3 => new \Tak\Liveproto\Tl\Types\Other\UpdateEditMessage,
			0x691e9052 => new \Tak\Liveproto\Tl\Types\Other\UpdateInlineBotCallbackQuery,
			0xb75f99a9 => new \Tak\Liveproto\Tl\Types\Other\UpdateReadChannelOutbox,
			0xedfc111e => new \Tak\Liveproto\Tl\Types\Other\UpdateDraftMessage,
			0x571d2742 => new \Tak\Liveproto\Tl\Types\Other\UpdateReadFeaturedStickers,
			0x9a422c20 => new \Tak\Liveproto\Tl\Types\Other\UpdateRecentStickers,
			0xa229dd06 => new \Tak\Liveproto\Tl\Types\Other\UpdateConfig,
			0x3354678f => new \Tak\Liveproto\Tl\Types\Other\UpdatePtsChanged,
			0x2f2ba99f => new \Tak\Liveproto\Tl\Types\Other\UpdateChannelWebPage,
			0x6e6fe51c => new \Tak\Liveproto\Tl\Types\Other\UpdateDialogPinned,
			0xfa0f3ca2 => new \Tak\Liveproto\Tl\Types\Other\UpdatePinnedDialogs,
			0x8317c0c3 => new \Tak\Liveproto\Tl\Types\Other\UpdateBotWebhookJSON,
			0x9b9240a6 => new \Tak\Liveproto\Tl\Types\Other\UpdateBotWebhookJSONQuery,
			0xb5aefd7d => new \Tak\Liveproto\Tl\Types\Other\UpdateBotShippingQuery,
			0x8caa9a96 => new \Tak\Liveproto\Tl\Types\Other\UpdateBotPrecheckoutQuery,
			0xab0f6b1e => new \Tak\Liveproto\Tl\Types\Other\UpdatePhoneCall,
			0x46560264 => new \Tak\Liveproto\Tl\Types\Other\UpdateLangPackTooLong,
			0x56022f4d => new \Tak\Liveproto\Tl\Types\Other\UpdateLangPack,
			0xe511996d => new \Tak\Liveproto\Tl\Types\Other\UpdateFavedStickers,
			0x25f324f7 => new \Tak\Liveproto\Tl\Types\Other\UpdateChannelReadMessagesContents,
			0x7084a7be => new \Tak\Liveproto\Tl\Types\Other\UpdateContactsReset,
			0xb23fc698 => new \Tak\Liveproto\Tl\Types\Other\UpdateChannelAvailableMessages,
			0xb658f23e => new \Tak\Liveproto\Tl\Types\Other\UpdateDialogUnreadMark,
			0xd64c522b => new \Tak\Liveproto\Tl\Types\Other\UpdateMessagePoll,
			0x54c01850 => new \Tak\Liveproto\Tl\Types\Other\UpdateChatDefaultBannedRights,
			0x19360dc0 => new \Tak\Liveproto\Tl\Types\Other\UpdateFolderPeers,
			0x6a7e7366 => new \Tak\Liveproto\Tl\Types\Other\UpdatePeerSettings,
			0xb4afcfb0 => new \Tak\Liveproto\Tl\Types\Other\UpdatePeerLocated,
			0x39a51dfb => new \Tak\Liveproto\Tl\Types\Other\UpdateNewScheduledMessage,
			0xf2a71983 => new \Tak\Liveproto\Tl\Types\Other\UpdateDeleteScheduledMessages,
			0x8216fba3 => new \Tak\Liveproto\Tl\Types\Other\UpdateTheme,
			0x871fb939 => new \Tak\Liveproto\Tl\Types\Other\UpdateGeoLiveViewed,
			0x564fe691 => new \Tak\Liveproto\Tl\Types\Other\UpdateLoginToken,
			0x7699f014 => new \Tak\Liveproto\Tl\Types\Other\UpdateMessagePollVote,
			0x26ffde7d => new \Tak\Liveproto\Tl\Types\Other\UpdateDialogFilter,
			0xa5d72105 => new \Tak\Liveproto\Tl\Types\Other\UpdateDialogFilterOrder,
			0x3504914f => new \Tak\Liveproto\Tl\Types\Other\UpdateDialogFilters,
			0x2661bf09 => new \Tak\Liveproto\Tl\Types\Other\UpdatePhoneCallSignalingData,
			0xd29a27f4 => new \Tak\Liveproto\Tl\Types\Other\UpdateChannelMessageForwards,
			0xd6b19546 => new \Tak\Liveproto\Tl\Types\Other\UpdateReadChannelDiscussionInbox,
			0x695c9e7c => new \Tak\Liveproto\Tl\Types\Other\UpdateReadChannelDiscussionOutbox,
			0xebe07752 => new \Tak\Liveproto\Tl\Types\Other\UpdatePeerBlocked,
			0x8c88c923 => new \Tak\Liveproto\Tl\Types\Other\UpdateChannelUserTyping,
			0xed85eab5 => new \Tak\Liveproto\Tl\Types\Other\UpdatePinnedMessages,
			0x5bb98608 => new \Tak\Liveproto\Tl\Types\Other\UpdatePinnedChannelMessages,
			0xf89a6a4e => new \Tak\Liveproto\Tl\Types\Other\UpdateChat,
			0xf2ebdb4e => new \Tak\Liveproto\Tl\Types\Other\UpdateGroupCallParticipants,
			0x9d2216e0 => new \Tak\Liveproto\Tl\Types\Other\UpdateGroupCall,
			0xbb9bb9a5 => new \Tak\Liveproto\Tl\Types\Other\UpdatePeerHistoryTTL,
			0xd087663a => new \Tak\Liveproto\Tl\Types\Other\UpdateChatParticipant,
			0x985d3abb => new \Tak\Liveproto\Tl\Types\Other\UpdateChannelParticipant,
			0xc4870a49 => new \Tak\Liveproto\Tl\Types\Other\UpdateBotStopped,
			0xb783982 => new \Tak\Liveproto\Tl\Types\Other\UpdateGroupCallConnection,
			0x4d712f2e => new \Tak\Liveproto\Tl\Types\Other\UpdateBotCommands,
			0x7063c3db => new \Tak\Liveproto\Tl\Types\Other\UpdatePendingJoinRequests,
			0x7cb34d79 => new \Tak\Liveproto\Tl\Types\Other\UpdateBotChatInviteRequester,
			0x1e297bfa => new \Tak\Liveproto\Tl\Types\Other\UpdateMessageReactions,
			0x17b7a20b => new \Tak\Liveproto\Tl\Types\Other\UpdateAttachMenuBots,
			0x1592b79d => new \Tak\Liveproto\Tl\Types\Other\UpdateWebViewResultSent,
			0x14b85813 => new \Tak\Liveproto\Tl\Types\Other\UpdateBotMenuButton,
			0x74d8be99 => new \Tak\Liveproto\Tl\Types\Other\UpdateSavedRingtones,
			0x84cd5a => new \Tak\Liveproto\Tl\Types\Other\UpdateTranscribedAudio,
			0xfb4c496c => new \Tak\Liveproto\Tl\Types\Other\UpdateReadFeaturedEmojiStickers,
			0x28373599 => new \Tak\Liveproto\Tl\Types\Other\UpdateUserEmojiStatus,
			0x30f443db => new \Tak\Liveproto\Tl\Types\Other\UpdateRecentEmojiStatuses,
			0x6f7863f4 => new \Tak\Liveproto\Tl\Types\Other\UpdateRecentReactions,
			0x86fccf85 => new \Tak\Liveproto\Tl\Types\Other\UpdateMoveStickerSetToTop,
			0xd5a41724 => new \Tak\Liveproto\Tl\Types\Other\UpdateMessageExtendedMedia,
			0x20529438 => new \Tak\Liveproto\Tl\Types\Other\UpdateUser,
			0xec05b097 => new \Tak\Liveproto\Tl\Types\Other\UpdateAutoSaveSettings,
			0x75b3b798 => new \Tak\Liveproto\Tl\Types\Other\UpdateStory,
			0xf74e932b => new \Tak\Liveproto\Tl\Types\Other\UpdateReadStories,
			0x1bf335b9 => new \Tak\Liveproto\Tl\Types\Other\UpdateStoryID,
			0x2c084dc1 => new \Tak\Liveproto\Tl\Types\Other\UpdateStoriesStealthMode,
			0x7d627683 => new \Tak\Liveproto\Tl\Types\Other\UpdateSentStoryReaction,
			0x904dd49c => new \Tak\Liveproto\Tl\Types\Other\UpdateBotChatBoost,
			0x7b68920 => new \Tak\Liveproto\Tl\Types\Other\UpdateChannelViewForumAsMessages,
			0xae3f101d => new \Tak\Liveproto\Tl\Types\Other\UpdatePeerWallpaper,
			0xac21d3ce => new \Tak\Liveproto\Tl\Types\Other\UpdateBotMessageReaction,
			0x9cb7759 => new \Tak\Liveproto\Tl\Types\Other\UpdateBotMessageReactions,
			0xaeaf9e74 => new \Tak\Liveproto\Tl\Types\Other\UpdateSavedDialogPinned,
			0x686c85a6 => new \Tak\Liveproto\Tl\Types\Other\UpdatePinnedSavedDialogs,
			0x39c67432 => new \Tak\Liveproto\Tl\Types\Other\UpdateSavedReactionTags,
			0xf16269d4 => new \Tak\Liveproto\Tl\Types\Other\UpdateSmsJob,
			0xf9470ab2 => new \Tak\Liveproto\Tl\Types\Other\UpdateQuickReplies,
			0xf53da717 => new \Tak\Liveproto\Tl\Types\Other\UpdateNewQuickReply,
			0x53e6f1ec => new \Tak\Liveproto\Tl\Types\Other\UpdateDeleteQuickReply,
			0x3e050d0f => new \Tak\Liveproto\Tl\Types\Other\UpdateQuickReplyMessage,
			0x566fe7cd => new \Tak\Liveproto\Tl\Types\Other\UpdateDeleteQuickReplyMessages,
			0x8ae5c97a => new \Tak\Liveproto\Tl\Types\Other\UpdateBotBusinessConnect,
			0x9ddb347c => new \Tak\Liveproto\Tl\Types\Other\UpdateBotNewBusinessMessage,
			0x7df587c => new \Tak\Liveproto\Tl\Types\Other\UpdateBotEditBusinessMessage,
			0xa02a982e => new \Tak\Liveproto\Tl\Types\Other\UpdateBotDeleteBusinessMessage,
			0x1824e40b => new \Tak\Liveproto\Tl\Types\Other\UpdateNewStoryReaction,
			0x4e80a379 => new \Tak\Liveproto\Tl\Types\Other\UpdateStarsBalance,
			0x1ea2fda7 => new \Tak\Liveproto\Tl\Types\Other\UpdateBusinessBotCallbackQuery,
			0xa584b019 => new \Tak\Liveproto\Tl\Types\Other\UpdateStarsRevenueStatus,
			0x283bd312 => new \Tak\Liveproto\Tl\Types\Other\UpdateBotPurchasedPaidMedia,
			0x8b725fce => new \Tak\Liveproto\Tl\Types\Other\UpdatePaidReactionPrivacy,
			0x504aa18f => new \Tak\Liveproto\Tl\Types\Other\UpdateSentPhoneCode,
			0xa477288f => new \Tak\Liveproto\Tl\Types\Other\UpdateGroupCallChainBlocks,
			0x77b0e372 => new \Tak\Liveproto\Tl\Types\Other\UpdateReadMonoForumInbox,
			0xa4a79376 => new \Tak\Liveproto\Tl\Types\Other\UpdateReadMonoForumOutbox,
			0x9f812b08 => new \Tak\Liveproto\Tl\Types\Other\UpdateMonoForumNoPaidException,
			0xd8326f0d => new \Tak\Liveproto\Tl\Types\Other\UpdateGroupCallMessage,
			0xc957a766 => new \Tak\Liveproto\Tl\Types\Other\UpdateGroupCallEncryptedMessage,
			0x683b2c52 => new \Tak\Liveproto\Tl\Types\Other\UpdatePinnedForumTopic,
			0xdef143d0 => new \Tak\Liveproto\Tl\Types\Other\UpdatePinnedForumTopics,
			0x3e85e92c => new \Tak\Liveproto\Tl\Types\Other\UpdateDeleteGroupCallMessages,
			0x48e246c2 => new \Tak\Liveproto\Tl\Types\Other\UpdateStarGiftAuctionState,
			0xdc58f31e => new \Tak\Liveproto\Tl\Types\Other\UpdateStarGiftAuctionUserState,
			0xfb9c547a => new \Tak\Liveproto\Tl\Types\Other\UpdateEmojiGameInfo,
			0xac072444 => new \Tak\Liveproto\Tl\Types\Other\UpdateStarGiftCraftFail,
			0xbd8367b9 => new \Tak\Liveproto\Tl\Types\Other\UpdateChatParticipantRank,
			0x4880ed9a => new \Tak\Liveproto\Tl\Types\Other\UpdateManagedBot,
			0xcdd4093d => new \Tak\Liveproto\Tl\Types\Other\UpdateBotGuestChatQuery,
			0x8c0f91fb => new \Tak\Liveproto\Tl\Types\Other\UpdateAiComposeTones,
			0xbdac7e70 => new \Tak\Liveproto\Tl\Types\Other\UpdateJoinChatWebViewDecision,
			0xb22083a6 => new \Tak\Liveproto\Tl\Types\Other\UpdateNewBotConnection,
			0xc39a2ade => new \Tak\Liveproto\Tl\Types\Other\UpdateWebBrowserSettings,
			0x140502d1 => new \Tak\Liveproto\Tl\Types\Other\UpdateWebBrowserException,
			0xe317af7e => new \Tak\Liveproto\Tl\Types\Other\UpdatesTooLong,
			0x313bc7f8 => new \Tak\Liveproto\Tl\Types\Other\UpdateShortMessage,
			0x4d6deea5 => new \Tak\Liveproto\Tl\Types\Other\UpdateShortChatMessage,
			0x78d4dec1 => new \Tak\Liveproto\Tl\Types\Other\UpdateShort,
			0x725b04c3 => new \Tak\Liveproto\Tl\Types\Other\UpdatesCombined,
			0x74ae4240 => new \Tak\Liveproto\Tl\Types\Other\Updates,
			0x9015e101 => new \Tak\Liveproto\Tl\Types\Other\UpdateShortSentMessage,
			0x18b7a10d => new \Tak\Liveproto\Tl\Types\Other\DcOption,
			0xcc1a241e => new \Tak\Liveproto\Tl\Types\Other\Config,
			0x8e1a1775 => new \Tak\Liveproto\Tl\Types\Other\NearestDc,
			0xab7ec0a0 => new \Tak\Liveproto\Tl\Types\Other\EncryptedChatEmpty,
			0x66b25953 => new \Tak\Liveproto\Tl\Types\Other\EncryptedChatWaiting,
			0x48f1d94c => new \Tak\Liveproto\Tl\Types\Other\EncryptedChatRequested,
			0x61f0d4c7 => new \Tak\Liveproto\Tl\Types\Other\EncryptedChat,
			0x1e1c7c45 => new \Tak\Liveproto\Tl\Types\Other\EncryptedChatDiscarded,
			0xf141b5e1 => new \Tak\Liveproto\Tl\Types\Other\InputEncryptedChat,
			0xc21f497e => new \Tak\Liveproto\Tl\Types\Other\EncryptedFileEmpty,
			0xa8008cd8 => new \Tak\Liveproto\Tl\Types\Other\EncryptedFile,
			0x1837c364 => new \Tak\Liveproto\Tl\Types\Other\InputEncryptedFileEmpty,
			0x64bd0306 => new \Tak\Liveproto\Tl\Types\Other\InputEncryptedFileUploaded,
			0x5a17b5e5 => new \Tak\Liveproto\Tl\Types\Other\InputEncryptedFile,
			0x2dc173c8 => new \Tak\Liveproto\Tl\Types\Other\InputEncryptedFileBigUploaded,
			0xed18c118 => new \Tak\Liveproto\Tl\Types\Other\EncryptedMessage,
			0x23734b06 => new \Tak\Liveproto\Tl\Types\Other\EncryptedMessageService,
			0x72f0eaae => new \Tak\Liveproto\Tl\Types\Other\InputDocumentEmpty,
			0x1abfb575 => new \Tak\Liveproto\Tl\Types\Other\InputDocument,
			0x36f8c871 => new \Tak\Liveproto\Tl\Types\Other\DocumentEmpty,
			0x8fd4c4d8 => new \Tak\Liveproto\Tl\Types\Other\Document,
			0x9fd40bd8 => new \Tak\Liveproto\Tl\Types\Other\NotifyPeer,
			0xb4c83b4c => new \Tak\Liveproto\Tl\Types\Other\NotifyUsers,
			0xc007cec3 => new \Tak\Liveproto\Tl\Types\Other\NotifyChats,
			0xd612e8ef => new \Tak\Liveproto\Tl\Types\Other\NotifyBroadcasts,
			0x226e6308 => new \Tak\Liveproto\Tl\Types\Other\NotifyForumTopic,
			0x16bf744e => new \Tak\Liveproto\Tl\Types\Other\SendMessageTypingAction,
			0xfd5ec8f5 => new \Tak\Liveproto\Tl\Types\Other\SendMessageCancelAction,
			0xa187d66f => new \Tak\Liveproto\Tl\Types\Other\SendMessageRecordVideoAction,
			0xe9763aec => new \Tak\Liveproto\Tl\Types\Other\SendMessageUploadVideoAction,
			0xd52f73f7 => new \Tak\Liveproto\Tl\Types\Other\SendMessageRecordAudioAction,
			0xf351d7ab => new \Tak\Liveproto\Tl\Types\Other\SendMessageUploadAudioAction,
			0xd1d34a26 => new \Tak\Liveproto\Tl\Types\Other\SendMessageUploadPhotoAction,
			0xaa0cd9e4 => new \Tak\Liveproto\Tl\Types\Other\SendMessageUploadDocumentAction,
			0x176f8ba1 => new \Tak\Liveproto\Tl\Types\Other\SendMessageGeoLocationAction,
			0x628cbc6f => new \Tak\Liveproto\Tl\Types\Other\SendMessageChooseContactAction,
			0xdd6a8f48 => new \Tak\Liveproto\Tl\Types\Other\SendMessageGamePlayAction,
			0x88f27fbc => new \Tak\Liveproto\Tl\Types\Other\SendMessageRecordRoundAction,
			0x243e1c66 => new \Tak\Liveproto\Tl\Types\Other\SendMessageUploadRoundAction,
			0xd92c2285 => new \Tak\Liveproto\Tl\Types\Other\SpeakingInGroupCallAction,
			0xdbda9246 => new \Tak\Liveproto\Tl\Types\Other\SendMessageHistoryImportAction,
			0xb05ac6b1 => new \Tak\Liveproto\Tl\Types\Other\SendMessageChooseStickerAction,
			0x25972bcb => new \Tak\Liveproto\Tl\Types\Other\SendMessageEmojiInteraction,
			0xb665902e => new \Tak\Liveproto\Tl\Types\Other\SendMessageEmojiInteractionSeen,
			0x376d975c => new \Tak\Liveproto\Tl\Types\Other\SendMessageTextDraftAction,
			0xe2b23b51 => new \Tak\Liveproto\Tl\Types\Other\InputSendMessageRichMessageDraftAction,
			0xa2cb24f9 => new \Tak\Liveproto\Tl\Types\Other\SendMessageRichMessageDraftAction,
			0x4f96cb18 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyStatusTimestamp,
			0xbdfb0426 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyChatInvite,
			0xfabadc5f => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyPhoneCall,
			0xdb9e70d2 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyPhoneP2P,
			0xa4dd4c08 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyForwards,
			0x5719bacc => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyProfilePhoto,
			0x352dafa => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyPhoneNumber,
			0xd1219bdd => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyAddedByPhone,
			0xaee69d68 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyVoiceMessages,
			0x3823cc40 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyAbout,
			0xd65a11cc => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyBirthday,
			0xe1732341 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyStarGiftsAutoSave,
			0xbdc597b4 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeyNoPaidMessages,
			0x4dbe9226 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyKeySavedMusic,
			0xbc2eab30 => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyStatusTimestamp,
			0x500e6dfa => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyChatInvite,
			0x3d662b7b => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyPhoneCall,
			0x39491cc8 => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyPhoneP2P,
			0x69ec56a3 => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyForwards,
			0x96151fed => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyProfilePhoto,
			0xd19ae46d => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyPhoneNumber,
			0x42ffd42b => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyAddedByPhone,
			0x697f414 => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyVoiceMessages,
			0xa486b761 => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyAbout,
			0x2000a518 => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyBirthday,
			0x2ca4fdf8 => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyStarGiftsAutoSave,
			0x17d348d2 => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeyNoPaidMessages,
			0xff7a571b => new \Tak\Liveproto\Tl\Types\Other\PrivacyKeySavedMusic,
			0xd09e07b => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueAllowContacts,
			0x184b35ce => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueAllowAll,
			0x131cc67f => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueAllowUsers,
			0xba52007 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueDisallowContacts,
			0xd66b66c9 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueDisallowAll,
			0x90110467 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueDisallowUsers,
			0x840649cf => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueAllowChatParticipants,
			0xe94f0f86 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueDisallowChatParticipants,
			0x2f453e49 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueAllowCloseFriends,
			0x77cdc9f1 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueAllowPremium,
			0x5a4fcce5 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueAllowBots,
			0xc4e57915 => new \Tak\Liveproto\Tl\Types\Other\InputPrivacyValueDisallowBots,
			0xfffe1bac => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueAllowContacts,
			0x65427b82 => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueAllowAll,
			0xb8905fb2 => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueAllowUsers,
			0xf888fa1a => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueDisallowContacts,
			0x8b73e763 => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueDisallowAll,
			0xe4621141 => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueDisallowUsers,
			0x6b134e8e => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueAllowChatParticipants,
			0x41c87565 => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueDisallowChatParticipants,
			0xf7e8d89b => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueAllowCloseFriends,
			0xece9814b => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueAllowPremium,
			0x21461b5d => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueAllowBots,
			0xf6a5f82f => new \Tak\Liveproto\Tl\Types\Other\PrivacyValueDisallowBots,
			0xb8d0afdf => new \Tak\Liveproto\Tl\Types\Other\AccountDaysTTL,
			0x6c37c15c => new \Tak\Liveproto\Tl\Types\Other\DocumentAttributeImageSize,
			0x11b58939 => new \Tak\Liveproto\Tl\Types\Other\DocumentAttributeAnimated,
			0x6319d612 => new \Tak\Liveproto\Tl\Types\Other\DocumentAttributeSticker,
			0x43c57c48 => new \Tak\Liveproto\Tl\Types\Other\DocumentAttributeVideo,
			0x9852f9c6 => new \Tak\Liveproto\Tl\Types\Other\DocumentAttributeAudio,
			0x15590068 => new \Tak\Liveproto\Tl\Types\Other\DocumentAttributeFilename,
			0x9801d2f7 => new \Tak\Liveproto\Tl\Types\Other\DocumentAttributeHasStickers,
			0xfd149899 => new \Tak\Liveproto\Tl\Types\Other\DocumentAttributeCustomEmoji,
			0x12b299d4 => new \Tak\Liveproto\Tl\Types\Other\StickerPack,
			0x211a1788 => new \Tak\Liveproto\Tl\Types\Other\WebPageEmpty,
			0xb0d13e47 => new \Tak\Liveproto\Tl\Types\Other\WebPagePending,
			0xe89c45b2 => new \Tak\Liveproto\Tl\Types\Other\WebPage,
			0x7311ca11 => new \Tak\Liveproto\Tl\Types\Other\WebPageNotModified,
			0xad01d61d => new \Tak\Liveproto\Tl\Types\Other\Authorization,
			0xa384b779 => new \Tak\Liveproto\Tl\Types\Other\ReceivedNotifyMessage,
			0xa22cbd96 => new \Tak\Liveproto\Tl\Types\Other\ChatInviteExported,
			0xed107ab7 => new \Tak\Liveproto\Tl\Types\Other\ChatInvitePublicJoinRequests,
			0x5a686d7c => new \Tak\Liveproto\Tl\Types\Other\ChatInviteAlready,
			0x5c9d3702 => new \Tak\Liveproto\Tl\Types\Other\ChatInvite,
			0x61695cb0 => new \Tak\Liveproto\Tl\Types\Other\ChatInvitePeek,
			0xffb62b95 => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetEmpty,
			0x9de7a269 => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetID,
			0x861cc8a0 => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetShortName,
			0x28703c8 => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetAnimatedEmoji,
			0xe67f520e => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetDice,
			0xcde3739 => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetAnimatedEmojiAnimations,
			0xc88b3b02 => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetPremiumGifts,
			0x4c4d4ce => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetEmojiGenericAnimations,
			0x29d0f5ee => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetEmojiDefaultStatuses,
			0x44c1f8e9 => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetEmojiDefaultTopicIcons,
			0x49748553 => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetEmojiChannelDefaultStatuses,
			0x1cf671a0 => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetTonGifts,
			0x2dd14edc => new \Tak\Liveproto\Tl\Types\Other\StickerSet,
			0xc27ac8c7 => new \Tak\Liveproto\Tl\Types\Other\BotCommand,
			0x4d8a0299 => new \Tak\Liveproto\Tl\Types\Other\BotInfo,
			0x7d170cff => new \Tak\Liveproto\Tl\Types\Other\KeyboardButton,
			0xd80c25ec => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonUrl,
			0xe62bc960 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonCallback,
			0x417efd8f => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonRequestPhone,
			0xaa40f94d => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonRequestGeoLocation,
			0x991399fc => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonSwitchInline,
			0x89c590f9 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonGame,
			0x3fa53905 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonBuy,
			0xf51006f9 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonUrlAuth,
			0x68013e72 => new \Tak\Liveproto\Tl\Types\Other\InputKeyboardButtonUrlAuth,
			0x7a11d782 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonRequestPoll,
			0x7d5e07c7 => new \Tak\Liveproto\Tl\Types\Other\InputKeyboardButtonUserProfile,
			0xc0fd5d09 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonUserProfile,
			0xe846b1a0 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonWebView,
			0xe15c4370 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonSimpleWebView,
			0x5b0f15f5 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonRequestPeer,
			0x2b78156 => new \Tak\Liveproto\Tl\Types\Other\InputKeyboardButtonRequestPeer,
			0xbcc4af10 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonCopy,
			0x77608b83 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonRow,
			0xa03e5b85 => new \Tak\Liveproto\Tl\Types\Other\ReplyKeyboardHide,
			0x86b40b08 => new \Tak\Liveproto\Tl\Types\Other\ReplyKeyboardForceReply,
			0x85dd99d1 => new \Tak\Liveproto\Tl\Types\Other\ReplyKeyboardMarkup,
			0x48a30254 => new \Tak\Liveproto\Tl\Types\Other\ReplyInlineMarkup,
			0xbb92ba95 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityUnknown,
			0xfa04579d => new \Tak\Liveproto\Tl\Types\Other\MessageEntityMention,
			0x6f635b0d => new \Tak\Liveproto\Tl\Types\Other\MessageEntityHashtag,
			0x6cef8ac7 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityBotCommand,
			0x6ed02538 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityUrl,
			0x64e475c2 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityEmail,
			0xbd610bc9 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityBold,
			0x826f8b60 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityItalic,
			0x28a20571 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityCode,
			0x73924be0 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityPre,
			0x76a6d327 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityTextUrl,
			0xdc7b1140 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityMentionName,
			0x208e68c9 => new \Tak\Liveproto\Tl\Types\Other\InputMessageEntityMentionName,
			0x9b69e34b => new \Tak\Liveproto\Tl\Types\Other\MessageEntityPhone,
			0x4c4e743f => new \Tak\Liveproto\Tl\Types\Other\MessageEntityCashtag,
			0x9c4e7e8b => new \Tak\Liveproto\Tl\Types\Other\MessageEntityUnderline,
			0xbf0693d4 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityStrike,
			0x761e6af4 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityBankCard,
			0x32ca960f => new \Tak\Liveproto\Tl\Types\Other\MessageEntitySpoiler,
			0xc8cf05f8 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityCustomEmoji,
			0xf1ccaaac => new \Tak\Liveproto\Tl\Types\Other\MessageEntityBlockquote,
			0x904ac7c7 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityFormattedDate,
			0x71777116 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityDiffInsert,
			0xc6c1e5a7 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityDiffReplace,
			0x652c1c5 => new \Tak\Liveproto\Tl\Types\Other\MessageEntityDiffDelete,
			0xee8c1e86 => new \Tak\Liveproto\Tl\Types\Other\InputChannelEmpty,
			0xf35aec28 => new \Tak\Liveproto\Tl\Types\Other\InputChannel,
			0x5b934f9d => new \Tak\Liveproto\Tl\Types\Other\InputChannelFromMessage,
			0xae30253 => new \Tak\Liveproto\Tl\Types\Other\MessageRange,
			0x94d42ee7 => new \Tak\Liveproto\Tl\Types\Other\ChannelMessagesFilterEmpty,
			0xcd77d957 => new \Tak\Liveproto\Tl\Types\Other\ChannelMessagesFilter,
			0x1bd54456 => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipant,
			0xa9478a1a => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantSelf,
			0x2fe601d3 => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantCreator,
			0x34c3bb53 => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantAdmin,
			0xd5f0ad91 => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantBanned,
			0x1b03f006 => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantLeft,
			0xde3f3c79 => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantsRecent,
			0xb4608969 => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantsAdmins,
			0xa3b54985 => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantsKicked,
			0xb0d1865b => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantsBots,
			0x1427a5e1 => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantsBanned,
			0x656ac4b => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantsSearch,
			0xbb6ae88d => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantsContacts,
			0xe04b5ceb => new \Tak\Liveproto\Tl\Types\Other\ChannelParticipantsMentions,
			0x3380c786 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageMediaAuto,
			0x3dcd7a87 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageText,
			0x96929a85 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageMediaGeo,
			0x417bbf11 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageMediaVenue,
			0xa6edbffd => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageMediaContact,
			0x4b425864 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageGame,
			0xd7e78225 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageMediaInvoice,
			0xbddcc510 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageMediaWebPage,
			0xb43df56c => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageRichMessage,
			0x88bf9319 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineResult,
			0xa8d864a7 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineResultPhoto,
			0xfff8fdc4 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineResultDocument,
			0x4fa417f2 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineResultGame,
			0x764cf810 => new \Tak\Liveproto\Tl\Types\Other\BotInlineMessageMediaAuto,
			0x8c7f65e2 => new \Tak\Liveproto\Tl\Types\Other\BotInlineMessageText,
			0x51846fd => new \Tak\Liveproto\Tl\Types\Other\BotInlineMessageMediaGeo,
			0x8a86659c => new \Tak\Liveproto\Tl\Types\Other\BotInlineMessageMediaVenue,
			0x18d1cdc2 => new \Tak\Liveproto\Tl\Types\Other\BotInlineMessageMediaContact,
			0x354a9b09 => new \Tak\Liveproto\Tl\Types\Other\BotInlineMessageMediaInvoice,
			0x809ad9a6 => new \Tak\Liveproto\Tl\Types\Other\BotInlineMessageMediaWebPage,
			0xa617e7b => new \Tak\Liveproto\Tl\Types\Other\BotInlineMessageRichMessage,
			0x11965f3a => new \Tak\Liveproto\Tl\Types\Other\BotInlineResult,
			0x17db940b => new \Tak\Liveproto\Tl\Types\Other\BotInlineMediaResult,
			0x5dab1af4 => new \Tak\Liveproto\Tl\Types\Other\ExportedMessageLink,
			0x4e4df4bb => new \Tak\Liveproto\Tl\Types\Other\MessageFwdHeader,
			0x890c3d89 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageID,
			0xb6d915d7 => new \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageID64,
			0x3c20629f => new \Tak\Liveproto\Tl\Types\Other\InlineBotSwitchPM,
			0xedcdc05b => new \Tak\Liveproto\Tl\Types\Other\TopPeer,
			0xab661b5b => new \Tak\Liveproto\Tl\Types\Other\TopPeerCategoryBotsPM,
			0x148677e2 => new \Tak\Liveproto\Tl\Types\Other\TopPeerCategoryBotsInline,
			0x637b7ed => new \Tak\Liveproto\Tl\Types\Other\TopPeerCategoryCorrespondents,
			0xbd17a14a => new \Tak\Liveproto\Tl\Types\Other\TopPeerCategoryGroups,
			0x161d9628 => new \Tak\Liveproto\Tl\Types\Other\TopPeerCategoryChannels,
			0x1e76a78c => new \Tak\Liveproto\Tl\Types\Other\TopPeerCategoryPhoneCalls,
			0xa8406ca9 => new \Tak\Liveproto\Tl\Types\Other\TopPeerCategoryForwardUsers,
			0xfbeec0f0 => new \Tak\Liveproto\Tl\Types\Other\TopPeerCategoryForwardChats,
			0xfd9e7bec => new \Tak\Liveproto\Tl\Types\Other\TopPeerCategoryBotsApp,
			0x6c24f3dd => new \Tak\Liveproto\Tl\Types\Other\TopPeerCategoryBotsGuestChat,
			0xfb834291 => new \Tak\Liveproto\Tl\Types\Other\TopPeerCategoryPeers,
			0x1b0c841a => new \Tak\Liveproto\Tl\Types\Other\DraftMessageEmpty,
			0x60fe3294 => new \Tak\Liveproto\Tl\Types\Other\DraftMessage,
			0x6410a5d2 => new \Tak\Liveproto\Tl\Types\Other\StickerSetCovered,
			0x3407e51b => new \Tak\Liveproto\Tl\Types\Other\StickerSetMultiCovered,
			0x40d13c0e => new \Tak\Liveproto\Tl\Types\Other\StickerSetFullCovered,
			0x77b15d1c => new \Tak\Liveproto\Tl\Types\Other\StickerSetNoCovered,
			0xaed6dbb2 => new \Tak\Liveproto\Tl\Types\Other\MaskCoords,
			0x4a992157 => new \Tak\Liveproto\Tl\Types\Other\InputStickeredMediaPhoto,
			0x438865b => new \Tak\Liveproto\Tl\Types\Other\InputStickeredMediaDocument,
			0xbdf9653b => new \Tak\Liveproto\Tl\Types\Other\Game,
			0x32c3e77 => new \Tak\Liveproto\Tl\Types\Other\InputGameID,
			0xc331e80a => new \Tak\Liveproto\Tl\Types\Other\InputGameShortName,
			0x73a379eb => new \Tak\Liveproto\Tl\Types\Other\HighScore,
			0xdc3d824f => new \Tak\Liveproto\Tl\Types\Other\TextEmpty,
			0x744694e0 => new \Tak\Liveproto\Tl\Types\Other\TextPlain,
			0x6724abc4 => new \Tak\Liveproto\Tl\Types\Other\TextBold,
			0xd912a59c => new \Tak\Liveproto\Tl\Types\Other\TextItalic,
			0xc12622c4 => new \Tak\Liveproto\Tl\Types\Other\TextUnderline,
			0x9bf8bb95 => new \Tak\Liveproto\Tl\Types\Other\TextStrike,
			0x6c3f19b9 => new \Tak\Liveproto\Tl\Types\Other\TextFixed,
			0x3c2884c1 => new \Tak\Liveproto\Tl\Types\Other\TextUrl,
			0xde5a0dd6 => new \Tak\Liveproto\Tl\Types\Other\TextEmail,
			0x7e6260d7 => new \Tak\Liveproto\Tl\Types\Other\TextConcat,
			0xed6a8504 => new \Tak\Liveproto\Tl\Types\Other\TextSubscript,
			0xc7fb5e01 => new \Tak\Liveproto\Tl\Types\Other\TextSuperscript,
			0x34b8621 => new \Tak\Liveproto\Tl\Types\Other\TextMarked,
			0x1ccb966a => new \Tak\Liveproto\Tl\Types\Other\TextPhone,
			0x81ccf4f => new \Tak\Liveproto\Tl\Types\Other\TextImage,
			0x35553762 => new \Tak\Liveproto\Tl\Types\Other\TextAnchor,
			0x9d2eac97 => new \Tak\Liveproto\Tl\Types\Other\TextMath,
			0xa26156c0 => new \Tak\Liveproto\Tl\Types\Other\TextCustomEmoji,
			0x4c2a5d62 => new \Tak\Liveproto\Tl\Types\Other\TextSpoiler,
			0xcd24cf44 => new \Tak\Liveproto\Tl\Types\Other\TextMention,
			0x519524ea => new \Tak\Liveproto\Tl\Types\Other\TextHashtag,
			0x2ff29d3 => new \Tak\Liveproto\Tl\Types\Other\TextBotCommand,
			0x7b9e1801 => new \Tak\Liveproto\Tl\Types\Other\TextCashtag,
			0xac6a83aa => new \Tak\Liveproto\Tl\Types\Other\TextAutoUrl,
			0xc556a45d => new \Tak\Liveproto\Tl\Types\Other\TextAutoEmail,
			0x24c26789 => new \Tak\Liveproto\Tl\Types\Other\TextAutoPhone,
			0xb956812d => new \Tak\Liveproto\Tl\Types\Other\TextBankCard,
			0x1a9fbfc => new \Tak\Liveproto\Tl\Types\Other\TextMentionName,
			0xa5b45e2b => new \Tak\Liveproto\Tl\Types\Other\TextDate,
			0x13567e8a => new \Tak\Liveproto\Tl\Types\Other\PageBlockUnsupported,
			0x70abc3fd => new \Tak\Liveproto\Tl\Types\Other\PageBlockTitle,
			0x8ffa9a1f => new \Tak\Liveproto\Tl\Types\Other\PageBlockSubtitle,
			0xbaafe5e0 => new \Tak\Liveproto\Tl\Types\Other\PageBlockAuthorDate,
			0xbfd064ec => new \Tak\Liveproto\Tl\Types\Other\PageBlockHeader,
			0xf12bb6e1 => new \Tak\Liveproto\Tl\Types\Other\PageBlockSubheader,
			0x467a0766 => new \Tak\Liveproto\Tl\Types\Other\PageBlockParagraph,
			0xc070d93e => new \Tak\Liveproto\Tl\Types\Other\PageBlockPreformatted,
			0x48870999 => new \Tak\Liveproto\Tl\Types\Other\PageBlockFooter,
			0xdb20b188 => new \Tak\Liveproto\Tl\Types\Other\PageBlockDivider,
			0xce0d37b0 => new \Tak\Liveproto\Tl\Types\Other\PageBlockAnchor,
			0xe4e88011 => new \Tak\Liveproto\Tl\Types\Other\PageBlockList,
			0x263d7c26 => new \Tak\Liveproto\Tl\Types\Other\PageBlockBlockquote,
			0x4f4456d3 => new \Tak\Liveproto\Tl\Types\Other\PageBlockPullquote,
			0x1759c560 => new \Tak\Liveproto\Tl\Types\Other\PageBlockPhoto,
			0x7c8fe7b6 => new \Tak\Liveproto\Tl\Types\Other\PageBlockVideo,
			0x39f23300 => new \Tak\Liveproto\Tl\Types\Other\PageBlockCover,
			0xa8718dc5 => new \Tak\Liveproto\Tl\Types\Other\PageBlockEmbed,
			0xf259a80b => new \Tak\Liveproto\Tl\Types\Other\PageBlockEmbedPost,
			0x65a0fa4d => new \Tak\Liveproto\Tl\Types\Other\PageBlockCollage,
			0x31f9590 => new \Tak\Liveproto\Tl\Types\Other\PageBlockSlideshow,
			0xef1751b5 => new \Tak\Liveproto\Tl\Types\Other\PageBlockChannel,
			0x804361ea => new \Tak\Liveproto\Tl\Types\Other\PageBlockAudio,
			0x1e148390 => new \Tak\Liveproto\Tl\Types\Other\PageBlockKicker,
			0xbf4dea82 => new \Tak\Liveproto\Tl\Types\Other\PageBlockTable,
			0x1fd6f6c1 => new \Tak\Liveproto\Tl\Types\Other\PageBlockOrderedList,
			0x76768bed => new \Tak\Liveproto\Tl\Types\Other\PageBlockDetails,
			0x16115a96 => new \Tak\Liveproto\Tl\Types\Other\PageBlockRelatedArticles,
			0xa44f3ef6 => new \Tak\Liveproto\Tl\Types\Other\PageBlockMap,
			0xbaff072f => new \Tak\Liveproto\Tl\Types\Other\PageBlockHeading1,
			0x96b2aec => new \Tak\Liveproto\Tl\Types\Other\PageBlockHeading2,
			0x67e731ad => new \Tak\Liveproto\Tl\Types\Other\PageBlockHeading3,
			0xb532772b => new \Tak\Liveproto\Tl\Types\Other\PageBlockHeading4,
			0xdbbe6c6a => new \Tak\Liveproto\Tl\Types\Other\PageBlockHeading5,
			0x682a41a9 => new \Tak\Liveproto\Tl\Types\Other\PageBlockHeading6,
			0x59080c20 => new \Tak\Liveproto\Tl\Types\Other\PageBlockMath,
			0x3c29a3e2 => new \Tak\Liveproto\Tl\Types\Other\PageBlockThinking,
			0x574b617f => new \Tak\Liveproto\Tl\Types\Other\InputPageBlockMap,
			0xe6e47c4 => new \Tak\Liveproto\Tl\Types\Other\PageBlockBlockquoteBlocks,
			0x85e42301 => new \Tak\Liveproto\Tl\Types\Other\PhoneCallDiscardReasonMissed,
			0xe095c1a0 => new \Tak\Liveproto\Tl\Types\Other\PhoneCallDiscardReasonDisconnect,
			0x57adc690 => new \Tak\Liveproto\Tl\Types\Other\PhoneCallDiscardReasonHangup,
			0xfaf7e8c9 => new \Tak\Liveproto\Tl\Types\Other\PhoneCallDiscardReasonBusy,
			0x9fbbf1f7 => new \Tak\Liveproto\Tl\Types\Other\PhoneCallDiscardReasonMigrateConferenceCall,
			0x7d748d04 => new \Tak\Liveproto\Tl\Types\Other\DataJSON,
			0xcb296bf8 => new \Tak\Liveproto\Tl\Types\Other\LabeledPrice,
			0x49ee584 => new \Tak\Liveproto\Tl\Types\Other\Invoice,
			0xea02c27e => new \Tak\Liveproto\Tl\Types\Other\PaymentCharge,
			0x1e8caaeb => new \Tak\Liveproto\Tl\Types\Other\PostAddress,
			0x909c3f94 => new \Tak\Liveproto\Tl\Types\Other\PaymentRequestedInfo,
			0xcdc27a1f => new \Tak\Liveproto\Tl\Types\Other\PaymentSavedCredentialsCard,
			0x1c570ed1 => new \Tak\Liveproto\Tl\Types\Other\WebDocument,
			0xf9c8bcc6 => new \Tak\Liveproto\Tl\Types\Other\WebDocumentNoProxy,
			0x9bed434d => new \Tak\Liveproto\Tl\Types\Other\InputWebDocument,
			0xc239d686 => new \Tak\Liveproto\Tl\Types\Other\InputWebFileLocation,
			0x9f2221c9 => new \Tak\Liveproto\Tl\Types\Other\InputWebFileGeoPointLocation,
			0xf46fe924 => new \Tak\Liveproto\Tl\Types\Other\InputWebFileAudioAlbumThumbLocation,
			0xc10eb2cf => new \Tak\Liveproto\Tl\Types\Other\InputPaymentCredentialsSaved,
			0x3417d728 => new \Tak\Liveproto\Tl\Types\Other\InputPaymentCredentials,
			0xaa1c39f => new \Tak\Liveproto\Tl\Types\Other\InputPaymentCredentialsApplePay,
			0x8ac32801 => new \Tak\Liveproto\Tl\Types\Other\InputPaymentCredentialsGooglePay,
			0xb6213cdf => new \Tak\Liveproto\Tl\Types\Other\ShippingOption,
			0x32da9e9c => new \Tak\Liveproto\Tl\Types\Other\InputStickerSetItem,
			0x1e36fded => new \Tak\Liveproto\Tl\Types\Other\InputPhoneCall,
			0x5366c915 => new \Tak\Liveproto\Tl\Types\Other\PhoneCallEmpty,
			0xc5226f17 => new \Tak\Liveproto\Tl\Types\Other\PhoneCallWaiting,
			0x14b0ed0c => new \Tak\Liveproto\Tl\Types\Other\PhoneCallRequested,
			0x3660c311 => new \Tak\Liveproto\Tl\Types\Other\PhoneCallAccepted,
			0x30535af5 => new \Tak\Liveproto\Tl\Types\Other\PhoneCall,
			0x50ca4de1 => new \Tak\Liveproto\Tl\Types\Other\PhoneCallDiscarded,
			0x9cc123c7 => new \Tak\Liveproto\Tl\Types\Other\PhoneConnection,
			0x635fe375 => new \Tak\Liveproto\Tl\Types\Other\PhoneConnectionWebrtc,
			0xfc878fc8 => new \Tak\Liveproto\Tl\Types\Other\PhoneCallProtocol,
			0xc982eaba => new \Tak\Liveproto\Tl\Types\Other\CdnPublicKey,
			0x5725e40a => new \Tak\Liveproto\Tl\Types\Other\CdnConfig,
			0xcad181f6 => new \Tak\Liveproto\Tl\Types\Other\LangPackString,
			0x6c47ac9f => new \Tak\Liveproto\Tl\Types\Other\LangPackStringPluralized,
			0x2979eeb2 => new \Tak\Liveproto\Tl\Types\Other\LangPackStringDeleted,
			0xf385c1f6 => new \Tak\Liveproto\Tl\Types\Other\LangPackDifference,
			0xeeca5ce3 => new \Tak\Liveproto\Tl\Types\Other\LangPackLanguage,
			0xe6dfb825 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeTitle,
			0x55188a2e => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeAbout,
			0x6a4afc38 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeUsername,
			0x434bd2af => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangePhoto,
			0x1b7907ae => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionToggleInvites,
			0x26ae0971 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionToggleSignatures,
			0xe9e82c18 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionUpdatePinned,
			0x709b2405 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionEditMessage,
			0x42e047bb => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionDeleteMessage,
			0x183040d3 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantJoin,
			0xf89777f2 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantLeave,
			0xe31c34d8 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantInvite,
			0xe6d83d7e => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantToggleBan,
			0xd5676710 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantToggleAdmin,
			0xb1c3caa7 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeStickerSet,
			0x5f5c95f1 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionTogglePreHistoryHidden,
			0x2df5fc0a => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionDefaultBannedRights,
			0x8f079643 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionStopPoll,
			0x50c7ac8 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeLinkedChat,
			0xe6b76ae => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeLocation,
			0x53909779 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionToggleSlowMode,
			0x23209745 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionStartGroupCall,
			0xdb9f9140 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionDiscardGroupCall,
			0xf92424d2 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantMute,
			0xe64429c0 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantUnmute,
			0x56d6a247 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionToggleGroupCallSetting,
			0xfe9fc158 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantJoinByInvite,
			0x5a50fca4 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionExportedInviteDelete,
			0x410a134e => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionExportedInviteRevoke,
			0xe90ebb59 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionExportedInviteEdit,
			0x3e7f6847 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantVolume,
			0x6e941a38 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeHistoryTTL,
			0xafb6144a => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantJoinByRequest,
			0xcb2ac766 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionToggleNoForwards,
			0x278f2868 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionSendMessage,
			0xbe4e0ef8 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeAvailableReactions,
			0xf04fb3a9 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeUsernames,
			0x2cc6383 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionToggleForum,
			0x58707d28 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionCreateTopic,
			0xf06fe208 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionEditTopic,
			0xae168909 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionDeleteTopic,
			0x5d8d353b => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionPinTopic,
			0x64f36dfc => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionToggleAntiSpam,
			0x5796e780 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangePeerColor,
			0x5e477b25 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeProfilePeerColor,
			0x31bb5d52 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeWallpaper,
			0x3ea9feb1 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeEmojiStatus,
			0x46d840ab => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionChangeEmojiStickerSet,
			0x60a79c79 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionToggleSignatureProfiles,
			0x64642db3 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantSubExtend,
			0xc517f77e => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionToggleAutotranslation,
			0x5806b4ec => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventActionParticipantEditRank,
			0x1fad68cd => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEvent,
			0xea107ae4 => new \Tak\Liveproto\Tl\Types\Other\ChannelAdminLogEventsFilter,
			0x5ce14175 => new \Tak\Liveproto\Tl\Types\Other\PopularContact,
			0x46e1d13d => new \Tak\Liveproto\Tl\Types\Other\RecentMeUrlUnknown,
			0xb92c09e2 => new \Tak\Liveproto\Tl\Types\Other\RecentMeUrlUser,
			0xb2da71d2 => new \Tak\Liveproto\Tl\Types\Other\RecentMeUrlChat,
			0xeb49081d => new \Tak\Liveproto\Tl\Types\Other\RecentMeUrlChatInvite,
			0xbc0a57dc => new \Tak\Liveproto\Tl\Types\Other\RecentMeUrlStickerSet,
			0x1cc6e91f => new \Tak\Liveproto\Tl\Types\Other\InputSingleMedia,
			0xa6f8f452 => new \Tak\Liveproto\Tl\Types\Other\WebAuthorization,
			0xa676a322 => new \Tak\Liveproto\Tl\Types\Other\InputMessageID,
			0xbad88395 => new \Tak\Liveproto\Tl\Types\Other\InputMessageReplyTo,
			0x86872538 => new \Tak\Liveproto\Tl\Types\Other\InputMessagePinned,
			0xacfa1a7e => new \Tak\Liveproto\Tl\Types\Other\InputMessageCallbackQuery,
			0xfcaafeb7 => new \Tak\Liveproto\Tl\Types\Other\InputDialogPeer,
			0x64600527 => new \Tak\Liveproto\Tl\Types\Other\InputDialogPeerFolder,
			0xe56dbf05 => new \Tak\Liveproto\Tl\Types\Other\DialogPeer,
			0x514519e2 => new \Tak\Liveproto\Tl\Types\Other\DialogPeerFolder,
			0xf39b035c => new \Tak\Liveproto\Tl\Types\Other\FileHash,
			0x75588b3f => new \Tak\Liveproto\Tl\Types\Other\InputClientProxy,
			0x3334b0f0 => new \Tak\Liveproto\Tl\Types\Other\InputSecureFileUploaded,
			0x5367e5be => new \Tak\Liveproto\Tl\Types\Other\InputSecureFile,
			0x64199744 => new \Tak\Liveproto\Tl\Types\Other\SecureFileEmpty,
			0x7d09c27e => new \Tak\Liveproto\Tl\Types\Other\SecureFile,
			0x8aeabec3 => new \Tak\Liveproto\Tl\Types\Other\SecureData,
			0x7d6099dd => new \Tak\Liveproto\Tl\Types\Other\SecurePlainPhone,
			0x21ec5a5f => new \Tak\Liveproto\Tl\Types\Other\SecurePlainEmail,
			0x9d2a81e3 => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypePersonalDetails,
			0x3dac6a00 => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypePassport,
			0x6e425c4 => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypeDriverLicense,
			0xa0d0744b => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypeIdentityCard,
			0x99a48f23 => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypeInternalPassport,
			0xcbe31e26 => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypeAddress,
			0xfc36954e => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypeUtilityBill,
			0x89137c0d => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypeBankStatement,
			0x8b883488 => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypeRentalAgreement,
			0x99e3806a => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypePassportRegistration,
			0xea02ec33 => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypeTemporaryRegistration,
			0xb320aadb => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypePhone,
			0x8e3ca7ee => new \Tak\Liveproto\Tl\Types\Other\SecureValueTypeEmail,
			0x187fa0ca => new \Tak\Liveproto\Tl\Types\Other\SecureValue,
			0xdb21d0a7 => new \Tak\Liveproto\Tl\Types\Other\InputSecureValue,
			0xed1ecdb0 => new \Tak\Liveproto\Tl\Types\Other\SecureValueHash,
			0xe8a40bd9 => new \Tak\Liveproto\Tl\Types\Other\SecureValueErrorData,
			0xbe3dfa => new \Tak\Liveproto\Tl\Types\Other\SecureValueErrorFrontSide,
			0x868a2aa5 => new \Tak\Liveproto\Tl\Types\Other\SecureValueErrorReverseSide,
			0xe537ced6 => new \Tak\Liveproto\Tl\Types\Other\SecureValueErrorSelfie,
			0x7a700873 => new \Tak\Liveproto\Tl\Types\Other\SecureValueErrorFile,
			0x666220e9 => new \Tak\Liveproto\Tl\Types\Other\SecureValueErrorFiles,
			0x869d758f => new \Tak\Liveproto\Tl\Types\Other\SecureValueError,
			0xa1144770 => new \Tak\Liveproto\Tl\Types\Other\SecureValueErrorTranslationFile,
			0x34636dd8 => new \Tak\Liveproto\Tl\Types\Other\SecureValueErrorTranslationFiles,
			0x33f0ea47 => new \Tak\Liveproto\Tl\Types\Other\SecureCredentialsEncrypted,
			0x1142bd56 => new \Tak\Liveproto\Tl\Types\Other\SavedPhoneContact,
			0xd45ab096 => new \Tak\Liveproto\Tl\Types\Other\PasswordKdfAlgoUnknown,
			0x3a912d4a => new \Tak\Liveproto\Tl\Types\Other\PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow,
			0x4a8537 => new \Tak\Liveproto\Tl\Types\Other\SecurePasswordKdfAlgoUnknown,
			0xbbf2dda0 => new \Tak\Liveproto\Tl\Types\Other\SecurePasswordKdfAlgoPBKDF2HMACSHA512iter100000,
			0x86471d92 => new \Tak\Liveproto\Tl\Types\Other\SecurePasswordKdfAlgoSHA512,
			0x1527bcac => new \Tak\Liveproto\Tl\Types\Other\SecureSecretSettings,
			0x9880f658 => new \Tak\Liveproto\Tl\Types\Other\InputCheckPasswordEmpty,
			0xd27ff082 => new \Tak\Liveproto\Tl\Types\Other\InputCheckPasswordSRP,
			0x829d99da => new \Tak\Liveproto\Tl\Types\Other\SecureRequiredType,
			0x27477b4 => new \Tak\Liveproto\Tl\Types\Other\SecureRequiredTypeOneOf,
			0x1d1b1245 => new \Tak\Liveproto\Tl\Types\Other\InputAppEvent,
			0xc0de1bd9 => new \Tak\Liveproto\Tl\Types\Other\JsonObjectValue,
			0x3f6d7b68 => new \Tak\Liveproto\Tl\Types\Other\JsonNull,
			0xc7345e6a => new \Tak\Liveproto\Tl\Types\Other\JsonBool,
			0x2be0dfa4 => new \Tak\Liveproto\Tl\Types\Other\JsonNumber,
			0xb71e767a => new \Tak\Liveproto\Tl\Types\Other\JsonString,
			0xf7444763 => new \Tak\Liveproto\Tl\Types\Other\JsonArray,
			0x99c1d49d => new \Tak\Liveproto\Tl\Types\Other\JsonObject,
			0x34566b6a => new \Tak\Liveproto\Tl\Types\Other\PageTableCell,
			0xe0c0c5e5 => new \Tak\Liveproto\Tl\Types\Other\PageTableRow,
			0x6f747657 => new \Tak\Liveproto\Tl\Types\Other\PageCaption,
			0x2f58683c => new \Tak\Liveproto\Tl\Types\Other\PageListItemText,
			0x63ca67aa => new \Tak\Liveproto\Tl\Types\Other\PageListItemBlocks,
			0x15031189 => new \Tak\Liveproto\Tl\Types\Other\PageListOrderedItemText,
			0x8ff2d5f0 => new \Tak\Liveproto\Tl\Types\Other\PageListOrderedItemBlocks,
			0xb390dc08 => new \Tak\Liveproto\Tl\Types\Other\PageRelatedArticle,
			0x98657f0d => new \Tak\Liveproto\Tl\Types\Other\Page,
			0x4b7d786a => new \Tak\Liveproto\Tl\Types\Other\PollAnswer,
			0x199fed96 => new \Tak\Liveproto\Tl\Types\Other\InputPollAnswer,
			0x966e2dbf => new \Tak\Liveproto\Tl\Types\Other\Poll,
			0x3645230a => new \Tak\Liveproto\Tl\Types\Other\PollAnswerVoters,
			0xba7bb15e => new \Tak\Liveproto\Tl\Types\Other\PollResults,
			0xf041e250 => new \Tak\Liveproto\Tl\Types\Other\ChatOnlines,
			0x47a971e0 => new \Tak\Liveproto\Tl\Types\Other\StatsURL,
			0x5fb224d5 => new \Tak\Liveproto\Tl\Types\Other\ChatAdminRights,
			0x9f120418 => new \Tak\Liveproto\Tl\Types\Other\ChatBannedRights,
			0xe630b979 => new \Tak\Liveproto\Tl\Types\Other\InputWallPaper,
			0x72091c80 => new \Tak\Liveproto\Tl\Types\Other\InputWallPaperSlug,
			0x967a462e => new \Tak\Liveproto\Tl\Types\Other\InputWallPaperNoFile,
			0xad253d78 => new \Tak\Liveproto\Tl\Types\Other\CodeSettings,
			0x372efcd0 => new \Tak\Liveproto\Tl\Types\Other\WallPaperSettings,
			0xbaa57628 => new \Tak\Liveproto\Tl\Types\Other\AutoDownloadSettings,
			0xd5b3b9f9 => new \Tak\Liveproto\Tl\Types\Other\EmojiKeyword,
			0x236df622 => new \Tak\Liveproto\Tl\Types\Other\EmojiKeywordDeleted,
			0x5cc761bd => new \Tak\Liveproto\Tl\Types\Other\EmojiKeywordsDifference,
			0xa575739d => new \Tak\Liveproto\Tl\Types\Other\EmojiURL,
			0xb3fb5361 => new \Tak\Liveproto\Tl\Types\Other\EmojiLanguage,
			0xff544e65 => new \Tak\Liveproto\Tl\Types\Other\Folder,
			0xfbd2c296 => new \Tak\Liveproto\Tl\Types\Other\InputFolderPeer,
			0xe9baa668 => new \Tak\Liveproto\Tl\Types\Other\FolderPeer,
			0x3cd623ec => new \Tak\Liveproto\Tl\Types\Other\UrlAuthResultRequest,
			0x623a8fa0 => new \Tak\Liveproto\Tl\Types\Other\UrlAuthResultAccepted,
			0xa9d6db1f => new \Tak\Liveproto\Tl\Types\Other\UrlAuthResultDefault,
			0xbfb5ad8b => new \Tak\Liveproto\Tl\Types\Other\ChannelLocationEmpty,
			0x209b82db => new \Tak\Liveproto\Tl\Types\Other\ChannelLocation,
			0xca461b5d => new \Tak\Liveproto\Tl\Types\Other\PeerLocated,
			0xf8ec284b => new \Tak\Liveproto\Tl\Types\Other\PeerSelfLocated,
			0xd072acb4 => new \Tak\Liveproto\Tl\Types\Other\RestrictionReason,
			0x3c5693e9 => new \Tak\Liveproto\Tl\Types\Other\InputTheme,
			0xf5890df1 => new \Tak\Liveproto\Tl\Types\Other\InputThemeSlug,
			0xa00e67d6 => new \Tak\Liveproto\Tl\Types\Other\Theme,
			0xc3a12462 => new \Tak\Liveproto\Tl\Types\Other\BaseThemeClassic,
			0xfbd81688 => new \Tak\Liveproto\Tl\Types\Other\BaseThemeDay,
			0xb7b31ea8 => new \Tak\Liveproto\Tl\Types\Other\BaseThemeNight,
			0x6d5f77ee => new \Tak\Liveproto\Tl\Types\Other\BaseThemeTinted,
			0x5b11125a => new \Tak\Liveproto\Tl\Types\Other\BaseThemeArctic,
			0x8fde504f => new \Tak\Liveproto\Tl\Types\Other\InputThemeSettings,
			0xfa58b6d4 => new \Tak\Liveproto\Tl\Types\Other\ThemeSettings,
			0x54b56617 => new \Tak\Liveproto\Tl\Types\Other\WebPageAttributeTheme,
			0x2e94c3e7 => new \Tak\Liveproto\Tl\Types\Other\WebPageAttributeStory,
			0x50cc03d3 => new \Tak\Liveproto\Tl\Types\Other\WebPageAttributeStickerSet,
			0xcf6f6db8 => new \Tak\Liveproto\Tl\Types\Other\WebPageAttributeUniqueStarGift,
			0x31cad303 => new \Tak\Liveproto\Tl\Types\Other\WebPageAttributeStarGiftCollection,
			0x1c641c2 => new \Tak\Liveproto\Tl\Types\Other\WebPageAttributeStarGiftAuction,
			0x7781fe18 => new \Tak\Liveproto\Tl\Types\Other\WebPageAttributeAiComposeTone,
			0xf568028a => new \Tak\Liveproto\Tl\Types\Other\BankCardOpenUrl,
			0xaa472651 => new \Tak\Liveproto\Tl\Types\Other\DialogFilter,
			0x363293ae => new \Tak\Liveproto\Tl\Types\Other\DialogFilterDefault,
			0x96537bd7 => new \Tak\Liveproto\Tl\Types\Other\DialogFilterChatlist,
			0x77744d4a => new \Tak\Liveproto\Tl\Types\Other\DialogFilterSuggested,
			0xb637edaf => new \Tak\Liveproto\Tl\Types\Other\StatsDateRangeDays,
			0xcb43acde => new \Tak\Liveproto\Tl\Types\Other\StatsAbsValueAndPrev,
			0xcbce2fe0 => new \Tak\Liveproto\Tl\Types\Other\StatsPercentValue,
			0x4a27eb2d => new \Tak\Liveproto\Tl\Types\Other\StatsGraphAsync,
			0xbedc9822 => new \Tak\Liveproto\Tl\Types\Other\StatsGraphError,
			0x8ea464b6 => new \Tak\Liveproto\Tl\Types\Other\StatsGraph,
			0xde33b094 => new \Tak\Liveproto\Tl\Types\Other\VideoSize,
			0xf85c413c => new \Tak\Liveproto\Tl\Types\Other\VideoSizeEmojiMarkup,
			0xda082fe => new \Tak\Liveproto\Tl\Types\Other\VideoSizeStickerMarkup,
			0x9d04af9b => new \Tak\Liveproto\Tl\Types\Other\StatsGroupTopPoster,
			0xd7584c87 => new \Tak\Liveproto\Tl\Types\Other\StatsGroupTopAdmin,
			0x535f779d => new \Tak\Liveproto\Tl\Types\Other\StatsGroupTopInviter,
			0xfe41b34f => new \Tak\Liveproto\Tl\Types\Other\GlobalPrivacySettings,
			0x455b853d => new \Tak\Liveproto\Tl\Types\Other\MessageViews,
			0x1b97dd66 => new \Tak\Liveproto\Tl\Types\Other\MessageReplyHeader,
			0xe5af939 => new \Tak\Liveproto\Tl\Types\Other\MessageReplyStoryHeader,
			0x83d60fc2 => new \Tak\Liveproto\Tl\Types\Other\MessageReplies,
			0xe8fd8014 => new \Tak\Liveproto\Tl\Types\Other\PeerBlocked,
			0x7780bcb4 => new \Tak\Liveproto\Tl\Types\Other\GroupCallDiscarded,
			0xefb2b617 => new \Tak\Liveproto\Tl\Types\Other\GroupCall,
			0xd8aa840f => new \Tak\Liveproto\Tl\Types\Other\InputGroupCall,
			0xfe06823f => new \Tak\Liveproto\Tl\Types\Other\InputGroupCallSlug,
			0x8c10603f => new \Tak\Liveproto\Tl\Types\Other\InputGroupCallInviteMessage,
			0x2a3dc7ac => new \Tak\Liveproto\Tl\Types\Other\GroupCallParticipant,
			0x3081ed9d => new \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeSameBotPM,
			0x833c0fac => new \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypePM,
			0xd766c50a => new \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeChat,
			0x5ec4be43 => new \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeMegagroup,
			0x6334ee9a => new \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeBroadcast,
			0xe3b2d0c => new \Tak\Liveproto\Tl\Types\Other\InlineQueryPeerTypeBotPM,
			0x8c5adfd9 => new \Tak\Liveproto\Tl\Types\Other\ChatInviteImporter,
			0xf2ecef23 => new \Tak\Liveproto\Tl\Types\Other\ChatAdminWithInvites,
			0xdcb118b7 => new \Tak\Liveproto\Tl\Types\Other\GroupCallParticipantVideoSourceGroup,
			0x67753ac8 => new \Tak\Liveproto\Tl\Types\Other\GroupCallParticipantVideo,
			0x2f6cb2ab => new \Tak\Liveproto\Tl\Types\Other\BotCommandScopeDefault,
			0x3c4f04d8 => new \Tak\Liveproto\Tl\Types\Other\BotCommandScopeUsers,
			0x6fe1a881 => new \Tak\Liveproto\Tl\Types\Other\BotCommandScopeChats,
			0xb9aa606a => new \Tak\Liveproto\Tl\Types\Other\BotCommandScopeChatAdmins,
			0xdb9d897d => new \Tak\Liveproto\Tl\Types\Other\BotCommandScopePeer,
			0x3fd863d1 => new \Tak\Liveproto\Tl\Types\Other\BotCommandScopePeerAdmins,
			0xa1321f3 => new \Tak\Liveproto\Tl\Types\Other\BotCommandScopePeerUser,
			0xc3dffc04 => new \Tak\Liveproto\Tl\Types\Other\ChatTheme,
			0x3458f9c8 => new \Tak\Liveproto\Tl\Types\Other\ChatThemeUniqueGift,
			0x7dbf8673 => new \Tak\Liveproto\Tl\Types\Other\SponsoredMessage,
			0xc9b0539f => new \Tak\Liveproto\Tl\Types\Other\SearchResultsCalendarPeriod,
			0x7f648b67 => new \Tak\Liveproto\Tl\Types\Other\SearchResultPosition,
			0xa3d1cb80 => new \Tak\Liveproto\Tl\Types\Other\ReactionCount,
			0xa339f0b => new \Tak\Liveproto\Tl\Types\Other\MessageReactions,
			0xc077ec01 => new \Tak\Liveproto\Tl\Types\Other\AvailableReaction,
			0x8c79b63c => new \Tak\Liveproto\Tl\Types\Other\MessagePeerReaction,
			0x80eb48af => new \Tak\Liveproto\Tl\Types\Other\GroupCallStreamChannel,
			0x4576f3f0 => new \Tak\Liveproto\Tl\Types\Other\AttachMenuBotIconColor,
			0xb2a7386b => new \Tak\Liveproto\Tl\Types\Other\AttachMenuBotIcon,
			0xd90d8dfe => new \Tak\Liveproto\Tl\Types\Other\AttachMenuBot,
			0xf1d88a5c => new \Tak\Liveproto\Tl\Types\Other\AttachMenuBotsNotModified,
			0x3c4301c0 => new \Tak\Liveproto\Tl\Types\Other\AttachMenuBots,
			0x93bf667f => new \Tak\Liveproto\Tl\Types\Other\AttachMenuBotsBot,
			0x4d22ff98 => new \Tak\Liveproto\Tl\Types\Other\WebViewResultUrl,
			0xc94511c => new \Tak\Liveproto\Tl\Types\Other\WebViewMessageSent,
			0x7533a588 => new \Tak\Liveproto\Tl\Types\Other\BotMenuButtonDefault,
			0x4258c205 => new \Tak\Liveproto\Tl\Types\Other\BotMenuButtonCommands,
			0xc7b57ce6 => new \Tak\Liveproto\Tl\Types\Other\BotMenuButton,
			0x97e8bebe => new \Tak\Liveproto\Tl\Types\Other\NotificationSoundDefault,
			0x6f0c34df => new \Tak\Liveproto\Tl\Types\Other\NotificationSoundNone,
			0x830b9ae4 => new \Tak\Liveproto\Tl\Types\Other\NotificationSoundLocal,
			0xff6c8049 => new \Tak\Liveproto\Tl\Types\Other\NotificationSoundRingtone,
			0x7d6be90e => new \Tak\Liveproto\Tl\Types\Other\AttachMenuPeerTypeSameBotPM,
			0xc32bfa1a => new \Tak\Liveproto\Tl\Types\Other\AttachMenuPeerTypeBotPM,
			0xf146d31f => new \Tak\Liveproto\Tl\Types\Other\AttachMenuPeerTypePM,
			0x509113f => new \Tak\Liveproto\Tl\Types\Other\AttachMenuPeerTypeChat,
			0x7bfbdefc => new \Tak\Liveproto\Tl\Types\Other\AttachMenuPeerTypeBroadcast,
			0xc5b56859 => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceMessage,
			0xc326caef => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceSlug,
			0x98986c0d => new \Tak\Liveproto\Tl\Types\Other\InputInvoicePremiumGiftCode,
			0x65f00ce3 => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceStars,
			0x34e793f1 => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceChatInviteSubscription,
			0xe8625e92 => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceStarGift,
			0x4d818d5d => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceStarGiftUpgrade,
			0x4a5f5bd9 => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceStarGiftTransfer,
			0xdabab2ef => new \Tak\Liveproto\Tl\Types\Other\InputInvoicePremiumGiftStars,
			0xf4997e42 => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceBusinessBotTransferStars,
			0xc39f5324 => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceStarGiftResale,
			0x9a0b48b8 => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceStarGiftPrepaidUpgrade,
			0x3e77f614 => new \Tak\Liveproto\Tl\Types\Other\InputInvoicePremiumAuthCode,
			0x923d8d1 => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceStarGiftDropOriginalDetails,
			0x1ecafa10 => new \Tak\Liveproto\Tl\Types\Other\InputInvoiceStarGiftAuctionBid,
			0xa6751e66 => new \Tak\Liveproto\Tl\Types\Other\InputStorePaymentPremiumSubscription,
			0x616f7fe8 => new \Tak\Liveproto\Tl\Types\Other\InputStorePaymentGiftPremium,
			0xfb790393 => new \Tak\Liveproto\Tl\Types\Other\InputStorePaymentPremiumGiftCode,
			0x160544ca => new \Tak\Liveproto\Tl\Types\Other\InputStorePaymentPremiumGiveaway,
			0xf9a2a6cb => new \Tak\Liveproto\Tl\Types\Other\InputStorePaymentStarsTopup,
			0x1d741ef7 => new \Tak\Liveproto\Tl\Types\Other\InputStorePaymentStarsGift,
			0x751f08fa => new \Tak\Liveproto\Tl\Types\Other\InputStorePaymentStarsGiveaway,
			0x3fc18057 => new \Tak\Liveproto\Tl\Types\Other\InputStorePaymentAuthCode,
			0x88f8f21b => new \Tak\Liveproto\Tl\Types\Other\PaymentFormMethod,
			0x2de11aae => new \Tak\Liveproto\Tl\Types\Other\EmojiStatusEmpty,
			0xe7ff068a => new \Tak\Liveproto\Tl\Types\Other\EmojiStatus,
			0x7184603b => new \Tak\Liveproto\Tl\Types\Other\EmojiStatusCollectible,
			0x7141dbf => new \Tak\Liveproto\Tl\Types\Other\InputEmojiStatusCollectible,
			0x79f5d419 => new \Tak\Liveproto\Tl\Types\Other\ReactionEmpty,
			0x1b2286b8 => new \Tak\Liveproto\Tl\Types\Other\ReactionEmoji,
			0x8935fc73 => new \Tak\Liveproto\Tl\Types\Other\ReactionCustomEmoji,
			0x523da4eb => new \Tak\Liveproto\Tl\Types\Other\ReactionPaid,
			0xeafc32bc => new \Tak\Liveproto\Tl\Types\Other\ChatReactionsNone,
			0x52928bca => new \Tak\Liveproto\Tl\Types\Other\ChatReactionsAll,
			0x661d4037 => new \Tak\Liveproto\Tl\Types\Other\ChatReactionsSome,
			0x4345be73 => new \Tak\Liveproto\Tl\Types\Other\EmailVerifyPurposeLoginSetup,
			0x527d22eb => new \Tak\Liveproto\Tl\Types\Other\EmailVerifyPurposeLoginChange,
			0xbbf51685 => new \Tak\Liveproto\Tl\Types\Other\EmailVerifyPurposePassport,
			0x922e55a9 => new \Tak\Liveproto\Tl\Types\Other\EmailVerificationCode,
			0xdb909ec2 => new \Tak\Liveproto\Tl\Types\Other\EmailVerificationGoogle,
			0x96d074fd => new \Tak\Liveproto\Tl\Types\Other\EmailVerificationApple,
			0x5f2d1df2 => new \Tak\Liveproto\Tl\Types\Other\PremiumSubscriptionOption,
			0xb81c7034 => new \Tak\Liveproto\Tl\Types\Other\SendAsPeer,
			0xad628cc8 => new \Tak\Liveproto\Tl\Types\Other\MessageExtendedMediaPreview,
			0xee479c64 => new \Tak\Liveproto\Tl\Types\Other\MessageExtendedMedia,
			0xfcfeb29c => new \Tak\Liveproto\Tl\Types\Other\StickerKeyword,
			0xb4073647 => new \Tak\Liveproto\Tl\Types\Other\Username,
			0x23f109b => new \Tak\Liveproto\Tl\Types\Other\ForumTopicDeleted,
			0xfcdad815 => new \Tak\Liveproto\Tl\Types\Other\ForumTopic,
			0x43b46b20 => new \Tak\Liveproto\Tl\Types\Other\DefaultHistoryTTL,
			0x41bf109b => new \Tak\Liveproto\Tl\Types\Other\ExportedContactToken,
			0x5f3b8a00 => new \Tak\Liveproto\Tl\Types\Other\RequestPeerTypeUser,
			0xc9f06e1b => new \Tak\Liveproto\Tl\Types\Other\RequestPeerTypeChat,
			0x339bef6c => new \Tak\Liveproto\Tl\Types\Other\RequestPeerTypeBroadcast,
			0x3e81e078 => new \Tak\Liveproto\Tl\Types\Other\RequestPeerTypeCreateBot,
			0x481eadfa => new \Tak\Liveproto\Tl\Types\Other\EmojiListNotModified,
			0x7a1e11d1 => new \Tak\Liveproto\Tl\Types\Other\EmojiList,
			0x7a9abda9 => new \Tak\Liveproto\Tl\Types\Other\EmojiGroup,
			0x80d26cc7 => new \Tak\Liveproto\Tl\Types\Other\EmojiGroupGreeting,
			0x93bcf34 => new \Tak\Liveproto\Tl\Types\Other\EmojiGroupPremium,
			0x751f3146 => new \Tak\Liveproto\Tl\Types\Other\TextWithEntities,
			0xc84834ce => new \Tak\Liveproto\Tl\Types\Other\AutoSaveSettings,
			0x81602d47 => new \Tak\Liveproto\Tl\Types\Other\AutoSaveException,
			0xa920bd7a => new \Tak\Liveproto\Tl\Types\Other\InputBotAppID,
			0x908c0407 => new \Tak\Liveproto\Tl\Types\Other\InputBotAppShortName,
			0x5da674b7 => new \Tak\Liveproto\Tl\Types\Other\BotAppNotModified,
			0x95fcd1d6 => new \Tak\Liveproto\Tl\Types\Other\BotApp,
			0xb57295d5 => new \Tak\Liveproto\Tl\Types\Other\InlineBotWebView,
			0x4a4ff172 => new \Tak\Liveproto\Tl\Types\Other\ReadParticipantDate,
			0xf3e0da33 => new \Tak\Liveproto\Tl\Types\Other\InputChatlistDialogFilter,
			0xc5181ac => new \Tak\Liveproto\Tl\Types\Other\ExportedChatlistInvite,
			0xb6cc2d5c => new \Tak\Liveproto\Tl\Types\Other\MessagePeerVote,
			0x74cda504 => new \Tak\Liveproto\Tl\Types\Other\MessagePeerVoteInputOption,
			0x4628f6e6 => new \Tak\Liveproto\Tl\Types\Other\MessagePeerVoteMultiple,
			0x8d595cd6 => new \Tak\Liveproto\Tl\Types\Other\StoryViews,
			0x51e6ee4f => new \Tak\Liveproto\Tl\Types\Other\StoryItemDeleted,
			0xffadc913 => new \Tak\Liveproto\Tl\Types\Other\StoryItemSkipped,
			0x16a4b93c => new \Tak\Liveproto\Tl\Types\Other\StoryItem,
			0xb0bdeac5 => new \Tak\Liveproto\Tl\Types\Other\StoryView,
			0x9083670b => new \Tak\Liveproto\Tl\Types\Other\StoryViewPublicForward,
			0xbd74cf49 => new \Tak\Liveproto\Tl\Types\Other\StoryViewPublicRepost,
			0x3bd4b7c2 => new \Tak\Liveproto\Tl\Types\Other\InputReplyToMessage,
			0x5881323a => new \Tak\Liveproto\Tl\Types\Other\InputReplyToStory,
			0x69d66c45 => new \Tak\Liveproto\Tl\Types\Other\InputReplyToMonoForum,
			0x3fc9053b => new \Tak\Liveproto\Tl\Types\Other\ExportedStoryLink,
			0x712e27fd => new \Tak\Liveproto\Tl\Types\Other\StoriesStealthMode,
			0xcfc9e002 => new \Tak\Liveproto\Tl\Types\Other\MediaAreaCoordinates,
			0xbe82db9c => new \Tak\Liveproto\Tl\Types\Other\MediaAreaVenue,
			0xb282217f => new \Tak\Liveproto\Tl\Types\Other\InputMediaAreaVenue,
			0xcad5452d => new \Tak\Liveproto\Tl\Types\Other\MediaAreaGeoPoint,
			0x14455871 => new \Tak\Liveproto\Tl\Types\Other\MediaAreaSuggestedReaction,
			0x770416af => new \Tak\Liveproto\Tl\Types\Other\MediaAreaChannelPost,
			0x2271f2bf => new \Tak\Liveproto\Tl\Types\Other\InputMediaAreaChannelPost,
			0x37381085 => new \Tak\Liveproto\Tl\Types\Other\MediaAreaUrl,
			0x49a6549c => new \Tak\Liveproto\Tl\Types\Other\MediaAreaWeather,
			0x5787686d => new \Tak\Liveproto\Tl\Types\Other\MediaAreaStarGift,
			0x9a35e999 => new \Tak\Liveproto\Tl\Types\Other\PeerStories,
			0x257e962b => new \Tak\Liveproto\Tl\Types\Other\PremiumGiftCodeOption,
			0xb2539d54 => new \Tak\Liveproto\Tl\Types\Other\PrepaidGiveaway,
			0x9a9d77e0 => new \Tak\Liveproto\Tl\Types\Other\PrepaidStarsGiveaway,
			0x4b3e14d6 => new \Tak\Liveproto\Tl\Types\Other\Boost,
			0xc448415c => new \Tak\Liveproto\Tl\Types\Other\MyBoost,
			0xb826e150 => new \Tak\Liveproto\Tl\Types\Other\StoryFwdHeader,
			0xe7058e7f => new \Tak\Liveproto\Tl\Types\Other\PostInteractionCountersMessage,
			0x8a480e27 => new \Tak\Liveproto\Tl\Types\Other\PostInteractionCountersStory,
			0x1f2bf4a => new \Tak\Liveproto\Tl\Types\Other\PublicForwardMessage,
			0xedf3add0 => new \Tak\Liveproto\Tl\Types\Other\PublicForwardStory,
			0xb54b5acf => new \Tak\Liveproto\Tl\Types\Other\PeerColor,
			0xb9c0639a => new \Tak\Liveproto\Tl\Types\Other\PeerColorCollectible,
			0xb8ea86a9 => new \Tak\Liveproto\Tl\Types\Other\InputPeerColorCollectible,
			0x6090d6d5 => new \Tak\Liveproto\Tl\Types\Other\StoryReaction,
			0xbbab2643 => new \Tak\Liveproto\Tl\Types\Other\StoryReactionPublicForward,
			0xcfcd0f13 => new \Tak\Liveproto\Tl\Types\Other\StoryReactionPublicRepost,
			0xbd87cb6c => new \Tak\Liveproto\Tl\Types\Other\SavedDialog,
			0x64407ea7 => new \Tak\Liveproto\Tl\Types\Other\MonoForumDialog,
			0xcb6ff828 => new \Tak\Liveproto\Tl\Types\Other\SavedReactionTag,
			0x3bb842ac => new \Tak\Liveproto\Tl\Types\Other\OutboxReadDate,
			0xe6a1eeb8 => new \Tak\Liveproto\Tl\Types\Other\SmsJob,
			0x120b1ab9 => new \Tak\Liveproto\Tl\Types\Other\BusinessWeeklyOpen,
			0x8c92b098 => new \Tak\Liveproto\Tl\Types\Other\BusinessWorkHours,
			0xac5c1af7 => new \Tak\Liveproto\Tl\Types\Other\BusinessLocation,
			0x6f8b32aa => new \Tak\Liveproto\Tl\Types\Other\InputBusinessRecipients,
			0x21108ff7 => new \Tak\Liveproto\Tl\Types\Other\BusinessRecipients,
			0xc9b9e2b9 => new \Tak\Liveproto\Tl\Types\Other\BusinessAwayMessageScheduleAlways,
			0xc3f2f501 => new \Tak\Liveproto\Tl\Types\Other\BusinessAwayMessageScheduleOutsideWorkHours,
			0xcc4d9ecc => new \Tak\Liveproto\Tl\Types\Other\BusinessAwayMessageScheduleCustom,
			0x194cb3b => new \Tak\Liveproto\Tl\Types\Other\InputBusinessGreetingMessage,
			0xe519abab => new \Tak\Liveproto\Tl\Types\Other\BusinessGreetingMessage,
			0x832175e0 => new \Tak\Liveproto\Tl\Types\Other\InputBusinessAwayMessage,
			0xef156a5c => new \Tak\Liveproto\Tl\Types\Other\BusinessAwayMessage,
			0xff9289f5 => new \Tak\Liveproto\Tl\Types\Other\Timezone,
			0x697102b => new \Tak\Liveproto\Tl\Types\Other\QuickReply,
			0x24596d41 => new \Tak\Liveproto\Tl\Types\Other\InputQuickReplyShortcut,
			0x1190cf1 => new \Tak\Liveproto\Tl\Types\Other\InputQuickReplyShortcutId,
			0x33ed001 => new \Tak\Liveproto\Tl\Types\Other\ConnectedBot,
			0x6c8e1e06 => new \Tak\Liveproto\Tl\Types\Other\Birthday,
			0x8f34b2f5 => new \Tak\Liveproto\Tl\Types\Other\BotBusinessConnection,
			0x9c469cd => new \Tak\Liveproto\Tl\Types\Other\InputBusinessIntro,
			0x5a0a066d => new \Tak\Liveproto\Tl\Types\Other\BusinessIntro,
			0xe39460a9 => new \Tak\Liveproto\Tl\Types\Other\InputCollectibleUsername,
			0xa2e214a4 => new \Tak\Liveproto\Tl\Types\Other\InputCollectiblePhone,
			0xc4e5921e => new \Tak\Liveproto\Tl\Types\Other\InputBusinessBotRecipients,
			0xb88cf373 => new \Tak\Liveproto\Tl\Types\Other\BusinessBotRecipients,
			0x1d998733 => new \Tak\Liveproto\Tl\Types\Other\ContactBirthday,
			0x628c9224 => new \Tak\Liveproto\Tl\Types\Other\MissingInvitee,
			0x11679fa7 => new \Tak\Liveproto\Tl\Types\Other\InputBusinessChatLink,
			0xb4ae666f => new \Tak\Liveproto\Tl\Types\Other\BusinessChatLink,
			0xd62ff46a => new \Tak\Liveproto\Tl\Types\Other\RequestedPeerUser,
			0x7307544f => new \Tak\Liveproto\Tl\Types\Other\RequestedPeerChat,
			0x8ba403e4 => new \Tak\Liveproto\Tl\Types\Other\RequestedPeerChannel,
			0x430d3150 => new \Tak\Liveproto\Tl\Types\Other\SponsoredMessageReportOption,
			0xbac3a61a => new \Tak\Liveproto\Tl\Types\Other\ReactionNotificationsFromContacts,
			0x4b9e22a0 => new \Tak\Liveproto\Tl\Types\Other\ReactionNotificationsFromAll,
			0x71e4ea58 => new \Tak\Liveproto\Tl\Types\Other\ReactionsNotifySettings,
			0x93c3e27e => new \Tak\Liveproto\Tl\Types\Other\AvailableEffect,
			0xb89bfccf => new \Tak\Liveproto\Tl\Types\Other\FactCheck,
			0x95f2bfe4 => new \Tak\Liveproto\Tl\Types\Other\StarsTransactionPeerUnsupported,
			0xb457b375 => new \Tak\Liveproto\Tl\Types\Other\StarsTransactionPeerAppStore,
			0x7b560a0b => new \Tak\Liveproto\Tl\Types\Other\StarsTransactionPeerPlayMarket,
			0x250dbaf8 => new \Tak\Liveproto\Tl\Types\Other\StarsTransactionPeerPremiumBot,
			0xe92fd902 => new \Tak\Liveproto\Tl\Types\Other\StarsTransactionPeerFragment,
			0xd80da15d => new \Tak\Liveproto\Tl\Types\Other\StarsTransactionPeer,
			0x60682812 => new \Tak\Liveproto\Tl\Types\Other\StarsTransactionPeerAds,
			0xf9677aad => new \Tak\Liveproto\Tl\Types\Other\StarsTransactionPeerAPI,
			0xbd915c0 => new \Tak\Liveproto\Tl\Types\Other\StarsTopupOption,
			0x13659eb0 => new \Tak\Liveproto\Tl\Types\Other\StarsTransaction,
			0xe87acbc0 => new \Tak\Liveproto\Tl\Types\Other\FoundStory,
			0xde4c5d93 => new \Tak\Liveproto\Tl\Types\Other\GeoPointAddress,
			0xfebe5491 => new \Tak\Liveproto\Tl\Types\Other\StarsRevenueStatus,
			0x206ae6d1 => new \Tak\Liveproto\Tl\Types\Other\InputStarsTransaction,
			0x5e0589f1 => new \Tak\Liveproto\Tl\Types\Other\StarsGiftOption,
			0x23e91ba3 => new \Tak\Liveproto\Tl\Types\Other\BotPreviewMedia,
			0x5416d58 => new \Tak\Liveproto\Tl\Types\Other\StarsSubscriptionPricing,
			0x2e6eab1a => new \Tak\Liveproto\Tl\Types\Other\StarsSubscription,
			0x4ba3a95a => new \Tak\Liveproto\Tl\Types\Other\MessageReactor,
			0x94ce852a => new \Tak\Liveproto\Tl\Types\Other\StarsGiveawayOption,
			0x54236209 => new \Tak\Liveproto\Tl\Types\Other\StarsGiveawayWinnersOption,
			0x313a9547 => new \Tak\Liveproto\Tl\Types\Other\StarGift,
			0x85f0a9cd => new \Tak\Liveproto\Tl\Types\Other\StarGiftUnique,
			0x7903e3d9 => new \Tak\Liveproto\Tl\Types\Other\MessageReportOption,
			0xf0e4e0b6 => new \Tak\Liveproto\Tl\Types\Other\ReportResultChooseOption,
			0x6f09ac31 => new \Tak\Liveproto\Tl\Types\Other\ReportResultAddComment,
			0x8db33c4b => new \Tak\Liveproto\Tl\Types\Other\ReportResultReported,
			0xc99b1950 => new \Tak\Liveproto\Tl\Types\Other\BotAppSettings,
			0xdd0c66f2 => new \Tak\Liveproto\Tl\Types\Other\StarRefProgram,
			0x19a13f71 => new \Tak\Liveproto\Tl\Types\Other\ConnectedBotStarRef,
			0xbbb6b4a3 => new \Tak\Liveproto\Tl\Types\Other\StarsAmount,
			0x74aee3e0 => new \Tak\Liveproto\Tl\Types\Other\StarsTonAmount,
			0xb0cd6617 => new \Tak\Liveproto\Tl\Types\Other\BotVerifierSettings,
			0xf93cd45c => new \Tak\Liveproto\Tl\Types\Other\BotVerification,
			0x565251e2 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeModel,
			0x4e7085ea => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributePattern,
			0x9f2504e4 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeBackdrop,
			0xe0bff26c => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeOriginalDetails,
			0x41df43fc => new \Tak\Liveproto\Tl\Types\Other\SavedStarGift,
			0x69279795 => new \Tak\Liveproto\Tl\Types\Other\InputSavedStarGiftUser,
			0xf101aa7f => new \Tak\Liveproto\Tl\Types\Other\InputSavedStarGiftChat,
			0x2085c238 => new \Tak\Liveproto\Tl\Types\Other\InputSavedStarGiftSlug,
			0x206ad49e => new \Tak\Liveproto\Tl\Types\Other\PaidReactionPrivacyDefault,
			0x1f0c1ad9 => new \Tak\Liveproto\Tl\Types\Other\PaidReactionPrivacyAnonymous,
			0xdc6cfcf0 => new \Tak\Liveproto\Tl\Types\Other\PaidReactionPrivacyPeer,
			0x50a9839 => new \Tak\Liveproto\Tl\Types\Other\RequirementToContactEmpty,
			0xe581e4e9 => new \Tak\Liveproto\Tl\Types\Other\RequirementToContactPremium,
			0xb4f67e93 => new \Tak\Liveproto\Tl\Types\Other\RequirementToContactPaidMessages,
			0xa0624cf7 => new \Tak\Liveproto\Tl\Types\Other\BusinessBotRights,
			0x71f276c4 => new \Tak\Liveproto\Tl\Types\Other\DisallowedGiftsSettings,
			0xc69708d3 => new \Tak\Liveproto\Tl\Types\Other\SponsoredPeer,
			0x48aaae3c => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeIdModel,
			0x4a162433 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeIdPattern,
			0x1f01c757 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeIdBackdrop,
			0x2eb1b658 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeCounter,
			0xe7e82e12 => new \Tak\Liveproto\Tl\Types\Other\PendingSuggestion,
			0xcba9a52f => new \Tak\Liveproto\Tl\Types\Other\TodoItem,
			0x49b92a26 => new \Tak\Liveproto\Tl\Types\Other\TodoList,
			0x221bb5e4 => new \Tak\Liveproto\Tl\Types\Other\TodoCompletion,
			0xe8e37e5 => new \Tak\Liveproto\Tl\Types\Other\SuggestedPost,
			0x1b0e4f07 => new \Tak\Liveproto\Tl\Types\Other\StarsRating,
			0x9d6b13b0 => new \Tak\Liveproto\Tl\Types\Other\StarGiftCollection,
			0x9325705a => new \Tak\Liveproto\Tl\Types\Other\StoryAlbum,
			0x3e0b5b6a => new \Tak\Liveproto\Tl\Types\Other\SearchPostsFlood,
			0xb98cd696 => new \Tak\Liveproto\Tl\Types\Other\ProfileTabPosts,
			0x4d4bd46a => new \Tak\Liveproto\Tl\Types\Other\ProfileTabGifts,
			0x72c64955 => new \Tak\Liveproto\Tl\Types\Other\ProfileTabMedia,
			0xab339c00 => new \Tak\Liveproto\Tl\Types\Other\ProfileTabFiles,
			0x9f27d26e => new \Tak\Liveproto\Tl\Types\Other\ProfileTabMusic,
			0xe477092e => new \Tak\Liveproto\Tl\Types\Other\ProfileTabVoice,
			0xd3656499 => new \Tak\Liveproto\Tl\Types\Other\ProfileTabLinks,
			0xa2c0f695 => new \Tak\Liveproto\Tl\Types\Other\ProfileTabGifs,
			0x83268483 => new \Tak\Liveproto\Tl\Types\Other\InputChatThemeEmpty,
			0xc93de95c => new \Tak\Liveproto\Tl\Types\Other\InputChatTheme,
			0x87e5dfe4 => new \Tak\Liveproto\Tl\Types\Other\InputChatThemeUniqueGift,
			0x99ea331d => new \Tak\Liveproto\Tl\Types\Other\StarGiftUpgradePrice,
			0x1a8afc7e => new \Tak\Liveproto\Tl\Types\Other\GroupCallMessage,
			0xee430c85 => new \Tak\Liveproto\Tl\Types\Other\GroupCallDonor,
			0x711d692d => new \Tak\Liveproto\Tl\Types\Other\RecentStory,
			0x310240cc => new \Tak\Liveproto\Tl\Types\Other\AuctionBidLevel,
			0xfe333952 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAuctionStateNotModified,
			0x771a4e66 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAuctionState,
			0x972dabbf => new \Tak\Liveproto\Tl\Types\Other\StarGiftAuctionStateFinished,
			0x2eeed1c4 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAuctionUserState,
			0x42b00348 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAuctionAcquiredGift,
			0xd31bc45d => new \Tak\Liveproto\Tl\Types\Other\StarGiftActiveAuctionState,
			0x2e16c98 => new \Tak\Liveproto\Tl\Types\Other\InputStarGiftAuction,
			0x7ab58308 => new \Tak\Liveproto\Tl\Types\Other\InputStarGiftAuctionSlug,
			0x98613ebf => new \Tak\Liveproto\Tl\Types\Other\Passkey,
			0x3e63935c => new \Tak\Liveproto\Tl\Types\Other\InputPasskeyResponseRegister,
			0xc31fc14a => new \Tak\Liveproto\Tl\Types\Other\InputPasskeyResponseLogin,
			0x3c27b78f => new \Tak\Liveproto\Tl\Types\Other\InputPasskeyCredentialPublicKey,
			0x5b1ccb28 => new \Tak\Liveproto\Tl\Types\Other\InputPasskeyCredentialFirebasePNV,
			0xaff56398 => new \Tak\Liveproto\Tl\Types\Other\StarGiftBackground,
			0x3aae0528 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAuctionRound,
			0xaa021e5 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAuctionRoundExtendable,
			0x36437737 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeRarity,
			0xdbce6389 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeRarityUncommon,
			0xf08d516b => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeRarityRare,
			0x78fbf3a8 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeRarityEpic,
			0xcef7e7a8 => new \Tak\Liveproto\Tl\Types\Other\StarGiftAttributeRarityLegendary,
			0x4fdd3430 => new \Tak\Liveproto\Tl\Types\Other\KeyboardButtonStyle,
			0x402b4495 => new \Tak\Liveproto\Tl\Types\Other\InputMessageReadMetric,
			0x1fe9a9bf => new \Tak\Liveproto\Tl\Types\Other\InputAiComposeToneDefault,
			0x773c080 => new \Tak\Liveproto\Tl\Types\Other\InputAiComposeToneID,
			0x1fa01357 => new \Tak\Liveproto\Tl\Types\Other\InputAiComposeToneSlug,
			0xcff63ea9 => new \Tak\Liveproto\Tl\Types\Other\AiComposeTone,
			0x9bad6414 => new \Tak\Liveproto\Tl\Types\Other\AiComposeToneDefault,
			0xf1d628ec => new \Tak\Liveproto\Tl\Types\Other\AiComposeToneExample,
			0xae152a69 => new \Tak\Liveproto\Tl\Types\Other\JoinChatBotResultApproved,
			0xefa0194 => new \Tak\Liveproto\Tl\Types\Other\JoinChatBotResultDeclined,
			0x98a3a840 => new \Tak\Liveproto\Tl\Types\Other\JoinChatBotResultQueued,
			0xd6e3b813 => new \Tak\Liveproto\Tl\Types\Other\JoinChatBotResultWebView,
			0x933ca597 => new \Tak\Liveproto\Tl\Types\Other\WebDomainException,
			0x9b00622b => new \Tak\Liveproto\Tl\Types\Other\InputRichFilePhoto,
			0x83281dbd => new \Tak\Liveproto\Tl\Types\Other\InputRichFileDocument,
			0xe4c449fc => new \Tak\Liveproto\Tl\Types\Other\InputRichMessage,
			0xdacb836a => new \Tak\Liveproto\Tl\Types\Other\InputRichMessageHTML,
			0x4b572c => new \Tak\Liveproto\Tl\Types\Other\InputRichMessageMarkdown,
			0xbaf39d8b => new \Tak\Liveproto\Tl\Types\Other\RichMessage,
			0x5162463 => new \Tak\Liveproto\Tl\Types\Other\ResPQ,
			0x83c95aec => new \Tak\Liveproto\Tl\Types\Other\PQInnerData,
			0xa9f55f95 => new \Tak\Liveproto\Tl\Types\Other\PQInnerDataDc,
			0x3c6a84d4 => new \Tak\Liveproto\Tl\Types\Other\PQInnerDataTemp,
			0x56fddf88 => new \Tak\Liveproto\Tl\Types\Other\PQInnerDataTempDc,
			0x75a3f765 => new \Tak\Liveproto\Tl\Types\Other\BindAuthKeyInner,
			0x79cb045d => new \Tak\Liveproto\Tl\Types\Other\ServerDHParamsFail,
			0xd0e8075c => new \Tak\Liveproto\Tl\Types\Other\ServerDHParamsOk,
			0xb5890dba => new \Tak\Liveproto\Tl\Types\Other\ServerDHInnerData,
			0x6643b654 => new \Tak\Liveproto\Tl\Types\Other\ClientDHInnerData,
			0x3bcbf734 => new \Tak\Liveproto\Tl\Types\Other\DhGenOk,
			0x46dc1fb9 => new \Tak\Liveproto\Tl\Types\Other\DhGenRetry,
			0xa69dae02 => new \Tak\Liveproto\Tl\Types\Other\DhGenFail,
			0x62d6b459 => new \Tak\Liveproto\Tl\Types\Other\MsgsAck,
			0xa7eff811 => new \Tak\Liveproto\Tl\Types\Other\BadMsgNotification,
			0xedab447b => new \Tak\Liveproto\Tl\Types\Other\BadServerSalt,
			0x7d861a08 => new \Tak\Liveproto\Tl\Types\Other\MsgResendReq,
			0xda69fb52 => new \Tak\Liveproto\Tl\Types\Other\MsgsStateReq,
			0x4deb57d => new \Tak\Liveproto\Tl\Types\Other\MsgsStateInfo,
			0x8cc0d131 => new \Tak\Liveproto\Tl\Types\Other\MsgsAllInfo,
			0x276d3ec6 => new \Tak\Liveproto\Tl\Types\Other\MsgDetailedInfo,
			0x809db6df => new \Tak\Liveproto\Tl\Types\Other\MsgNewDetailedInfo,
			0x5e2ad36e => new \Tak\Liveproto\Tl\Types\Other\RpcAnswerUnknown,
			0xcd78e586 => new \Tak\Liveproto\Tl\Types\Other\RpcAnswerDroppedRunning,
			0xa43ad8b7 => new \Tak\Liveproto\Tl\Types\Other\RpcAnswerDropped,
			0x949d9dc => new \Tak\Liveproto\Tl\Types\Other\FutureSalt,
			0xae500895 => new \Tak\Liveproto\Tl\Types\Other\FutureSalts,
			0x347773c5 => new \Tak\Liveproto\Tl\Types\Other\Pong,
			0xe22045fc => new \Tak\Liveproto\Tl\Types\Other\DestroySessionOk,
			0x62d350c9 => new \Tak\Liveproto\Tl\Types\Other\DestroySessionNone,
			0x9ec20908 => new \Tak\Liveproto\Tl\Types\Other\NewSessionCreated,
			0x9299359f => new \Tak\Liveproto\Tl\Types\Other\HttpWait,
			0xd433ad73 => new \Tak\Liveproto\Tl\Types\Other\IpPort,
			0x37982646 => new \Tak\Liveproto\Tl\Types\Other\IpPortSecret,
			0x4679b65f => new \Tak\Liveproto\Tl\Types\Other\AccessPointRule,
			0xf660e1d4 => new \Tak\Liveproto\Tl\Types\Other\DestroyAuthKeyOk,
			0xa9f2259 => new \Tak\Liveproto\Tl\Types\Other\DestroyAuthKeyNone,
			0xea109b13 => new \Tak\Liveproto\Tl\Types\Other\DestroyAuthKeyFail,
			0xaa963b05 => new \Tak\Liveproto\Tl\Types\Storage\FileUnknown,
			0x40bc6f52 => new \Tak\Liveproto\Tl\Types\Storage\FilePartial,
			0x7efe0e => new \Tak\Liveproto\Tl\Types\Storage\FileJpeg,
			0xcae1aadf => new \Tak\Liveproto\Tl\Types\Storage\FileGif,
			0xa4f63c0 => new \Tak\Liveproto\Tl\Types\Storage\FilePng,
			0xae1e508d => new \Tak\Liveproto\Tl\Types\Storage\FilePdf,
			0x528a0677 => new \Tak\Liveproto\Tl\Types\Storage\FileMp3,
			0x4b09ebbc => new \Tak\Liveproto\Tl\Types\Storage\FileMov,
			0xb3cea0e4 => new \Tak\Liveproto\Tl\Types\Storage\FileMp4,
			0x1081464c => new \Tak\Liveproto\Tl\Types\Storage\FileWebp,
			0x5e002502 => new \Tak\Liveproto\Tl\Types\Auth\SentCode,
			0x2390fe44 => new \Tak\Liveproto\Tl\Types\Auth\SentCodeSuccess,
			0xf8827ebf => new \Tak\Liveproto\Tl\Types\Auth\SentCodePaymentRequired,
			0x2ea2c0d4 => new \Tak\Liveproto\Tl\Types\Auth\Authorization,
			0x44747e9a => new \Tak\Liveproto\Tl\Types\Auth\AuthorizationSignUpRequired,
			0xb434e2b8 => new \Tak\Liveproto\Tl\Types\Auth\ExportedAuthorization,
			0x137948a5 => new \Tak\Liveproto\Tl\Types\Auth\PasswordRecovery,
			0x72a3158c => new \Tak\Liveproto\Tl\Types\Auth\CodeTypeSms,
			0x741cd3e3 => new \Tak\Liveproto\Tl\Types\Auth\CodeTypeCall,
			0x226ccefb => new \Tak\Liveproto\Tl\Types\Auth\CodeTypeFlashCall,
			0xd61ad6ee => new \Tak\Liveproto\Tl\Types\Auth\CodeTypeMissedCall,
			0x6ed998c => new \Tak\Liveproto\Tl\Types\Auth\CodeTypeFragmentSms,
			0x3dbb5986 => new \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeApp,
			0xc000bba2 => new \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeSms,
			0x5353e5a7 => new \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeCall,
			0xab03c6d9 => new \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeFlashCall,
			0x82006484 => new \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeMissedCall,
			0xf450f59b => new \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeEmailCode,
			0xa5491dea => new \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeSetUpEmailRequired,
			0xd9565c39 => new \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeFragmentSms,
			0x9fd736 => new \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeFirebaseSms,
			0xa416ac81 => new \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeSmsWord,
			0xb37794af => new \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeSmsPhrase,
			0x629f1980 => new \Tak\Liveproto\Tl\Types\Auth\LoginToken,
			0x68e9916 => new \Tak\Liveproto\Tl\Types\Auth\LoginTokenMigrateTo,
			0x390d5c5e => new \Tak\Liveproto\Tl\Types\Auth\LoginTokenSuccess,
			0xc3a2835f => new \Tak\Liveproto\Tl\Types\Auth\LoggedOut,
			0xe2037789 => new \Tak\Liveproto\Tl\Types\Auth\PasskeyLoginOptions,
			0xb74ba9d2 => new \Tak\Liveproto\Tl\Types\Contacts\ContactsNotModified,
			0xeae87e42 => new \Tak\Liveproto\Tl\Types\Contacts\Contacts,
			0x77d01c3b => new \Tak\Liveproto\Tl\Types\Contacts\ImportedContacts,
			0xade1591 => new \Tak\Liveproto\Tl\Types\Contacts\Blocked,
			0xe1664194 => new \Tak\Liveproto\Tl\Types\Contacts\BlockedSlice,
			0xb3134d9d => new \Tak\Liveproto\Tl\Types\Contacts\Found,
			0x7f077ad9 => new \Tak\Liveproto\Tl\Types\Contacts\ResolvedPeer,
			0xde266ef5 => new \Tak\Liveproto\Tl\Types\Contacts\TopPeersNotModified,
			0x70b772a8 => new \Tak\Liveproto\Tl\Types\Contacts\TopPeers,
			0xb52c939d => new \Tak\Liveproto\Tl\Types\Contacts\TopPeersDisabled,
			0x114ff30d => new \Tak\Liveproto\Tl\Types\Contacts\ContactBirthdays,
			0xea32b4b1 => new \Tak\Liveproto\Tl\Types\Contacts\SponsoredPeersEmpty,
			0xeb032884 => new \Tak\Liveproto\Tl\Types\Contacts\SponsoredPeers,
			0x15ba6c40 => new \Tak\Liveproto\Tl\Types\Messages\Dialogs,
			0x71e094f3 => new \Tak\Liveproto\Tl\Types\Messages\DialogsSlice,
			0xf0e3e596 => new \Tak\Liveproto\Tl\Types\Messages\DialogsNotModified,
			0x1d73e7ea => new \Tak\Liveproto\Tl\Types\Messages\Messages,
			0x5f206716 => new \Tak\Liveproto\Tl\Types\Messages\MessagesSlice,
			0xc776ba4e => new \Tak\Liveproto\Tl\Types\Messages\ChannelMessages,
			0x74535f21 => new \Tak\Liveproto\Tl\Types\Messages\MessagesNotModified,
			0x64ff9fd5 => new \Tak\Liveproto\Tl\Types\Messages\Chats,
			0x9cd81144 => new \Tak\Liveproto\Tl\Types\Messages\ChatsSlice,
			0xe5d7d19c => new \Tak\Liveproto\Tl\Types\Messages\ChatFull,
			0xb45c69d1 => new \Tak\Liveproto\Tl\Types\Messages\AffectedHistory,
			0xc0e24635 => new \Tak\Liveproto\Tl\Types\Messages\DhConfigNotModified,
			0x2c221edd => new \Tak\Liveproto\Tl\Types\Messages\DhConfig,
			0x560f8935 => new \Tak\Liveproto\Tl\Types\Messages\SentEncryptedMessage,
			0x9493ff32 => new \Tak\Liveproto\Tl\Types\Messages\SentEncryptedFile,
			0xf1749a22 => new \Tak\Liveproto\Tl\Types\Messages\StickersNotModified,
			0x30a6ec7e => new \Tak\Liveproto\Tl\Types\Messages\Stickers,
			0xe86602c3 => new \Tak\Liveproto\Tl\Types\Messages\AllStickersNotModified,
			0xcdbbcebb => new \Tak\Liveproto\Tl\Types\Messages\AllStickers,
			0x84d19185 => new \Tak\Liveproto\Tl\Types\Messages\AffectedMessages,
			0x6e153f16 => new \Tak\Liveproto\Tl\Types\Messages\StickerSet,
			0xd3f924eb => new \Tak\Liveproto\Tl\Types\Messages\StickerSetNotModified,
			0xe8025ca2 => new \Tak\Liveproto\Tl\Types\Messages\SavedGifsNotModified,
			0x84a02a0d => new \Tak\Liveproto\Tl\Types\Messages\SavedGifs,
			0xe021f2f6 => new \Tak\Liveproto\Tl\Types\Messages\BotResults,
			0x36585ea4 => new \Tak\Liveproto\Tl\Types\Messages\BotCallbackAnswer,
			0x26b5dde6 => new \Tak\Liveproto\Tl\Types\Messages\MessageEditData,
			0x3371c354 => new \Tak\Liveproto\Tl\Types\Messages\PeerDialogs,
			0xc6dc0c66 => new \Tak\Liveproto\Tl\Types\Messages\FeaturedStickersNotModified,
			0xbe382906 => new \Tak\Liveproto\Tl\Types\Messages\FeaturedStickers,
			0xb17f890 => new \Tak\Liveproto\Tl\Types\Messages\RecentStickersNotModified,
			0x88d37c56 => new \Tak\Liveproto\Tl\Types\Messages\RecentStickers,
			0x4fcba9c8 => new \Tak\Liveproto\Tl\Types\Messages\ArchivedStickers,
			0x38641628 => new \Tak\Liveproto\Tl\Types\Messages\StickerSetInstallResultSuccess,
			0x35e410a8 => new \Tak\Liveproto\Tl\Types\Messages\StickerSetInstallResultArchive,
			0x9a3bfd99 => new \Tak\Liveproto\Tl\Types\Messages\HighScores,
			0x9e8fa6d3 => new \Tak\Liveproto\Tl\Types\Messages\FavedStickersNotModified,
			0x2cb51097 => new \Tak\Liveproto\Tl\Types\Messages\FavedStickers,
			0xd54b65d => new \Tak\Liveproto\Tl\Types\Messages\FoundStickerSetsNotModified,
			0x8af09dd2 => new \Tak\Liveproto\Tl\Types\Messages\FoundStickerSets,
			0xe844ebff => new \Tak\Liveproto\Tl\Types\Messages\SearchCounter,
			0xa927fec5 => new \Tak\Liveproto\Tl\Types\Messages\InactiveChats,
			0x4899484e => new \Tak\Liveproto\Tl\Types\Messages\VotesList,
			0xb6c4f543 => new \Tak\Liveproto\Tl\Types\Messages\MessageViews,
			0xa6341782 => new \Tak\Liveproto\Tl\Types\Messages\DiscussionMessage,
			0x1662af0b => new \Tak\Liveproto\Tl\Types\Messages\HistoryImport,
			0x5e0fb7b9 => new \Tak\Liveproto\Tl\Types\Messages\HistoryImportParsed,
			0xef8d3e6c => new \Tak\Liveproto\Tl\Types\Messages\AffectedFoundMessages,
			0xbdc62dcc => new \Tak\Liveproto\Tl\Types\Messages\ExportedChatInvites,
			0x1871be50 => new \Tak\Liveproto\Tl\Types\Messages\ExportedChatInvite,
			0x222600ef => new \Tak\Liveproto\Tl\Types\Messages\ExportedChatInviteReplaced,
			0x81b6b00a => new \Tak\Liveproto\Tl\Types\Messages\ChatInviteImporters,
			0xb69b72d7 => new \Tak\Liveproto\Tl\Types\Messages\ChatAdminsWithInvites,
			0xa24de717 => new \Tak\Liveproto\Tl\Types\Messages\CheckedHistoryImportPeer,
			0xffda656d => new \Tak\Liveproto\Tl\Types\Messages\SponsoredMessages,
			0x1839490f => new \Tak\Liveproto\Tl\Types\Messages\SponsoredMessagesEmpty,
			0x147ee23c => new \Tak\Liveproto\Tl\Types\Messages\SearchResultsCalendar,
			0x53b22baf => new \Tak\Liveproto\Tl\Types\Messages\SearchResultsPositions,
			0x6880b94d => new \Tak\Liveproto\Tl\Types\Messages\PeerSettings,
			0x31bd492d => new \Tak\Liveproto\Tl\Types\Messages\MessageReactionsList,
			0x9f071957 => new \Tak\Liveproto\Tl\Types\Messages\AvailableReactionsNotModified,
			0x768e3aad => new \Tak\Liveproto\Tl\Types\Messages\AvailableReactions,
			0xcfb9d957 => new \Tak\Liveproto\Tl\Types\Messages\TranscribedAudio,
			0xb06fdbdf => new \Tak\Liveproto\Tl\Types\Messages\ReactionsNotModified,
			0xeafdf716 => new \Tak\Liveproto\Tl\Types\Messages\Reactions,
			0x367617d3 => new \Tak\Liveproto\Tl\Types\Messages\ForumTopics,
			0x6fb4ad87 => new \Tak\Liveproto\Tl\Types\Messages\EmojiGroupsNotModified,
			0x881fb94b => new \Tak\Liveproto\Tl\Types\Messages\EmojiGroups,
			0x33db32f8 => new \Tak\Liveproto\Tl\Types\Messages\TranslateResult,
			0xeb50adf5 => new \Tak\Liveproto\Tl\Types\Messages\BotApp,
			0xfd5e12bd => new \Tak\Liveproto\Tl\Types\Messages\WebPage,
			0xf83ae221 => new \Tak\Liveproto\Tl\Types\Messages\SavedDialogs,
			0x44ba9dd9 => new \Tak\Liveproto\Tl\Types\Messages\SavedDialogsSlice,
			0xc01f6fe8 => new \Tak\Liveproto\Tl\Types\Messages\SavedDialogsNotModified,
			0x889b59ef => new \Tak\Liveproto\Tl\Types\Messages\SavedReactionTagsNotModified,
			0x3259950a => new \Tak\Liveproto\Tl\Types\Messages\SavedReactionTags,
			0xc68d6695 => new \Tak\Liveproto\Tl\Types\Messages\QuickReplies,
			0x5f91eb5b => new \Tak\Liveproto\Tl\Types\Messages\QuickRepliesNotModified,
			0x2ad93719 => new \Tak\Liveproto\Tl\Types\Messages\DialogFilters,
			0xfaff629d => new \Tak\Liveproto\Tl\Types\Messages\MyStickers,
			0x7f5defa6 => new \Tak\Liveproto\Tl\Types\Messages\InvitedUsers,
			0xd1ed9a5b => new \Tak\Liveproto\Tl\Types\Messages\AvailableEffectsNotModified,
			0xbddb616e => new \Tak\Liveproto\Tl\Types\Messages\AvailableEffects,
			0x8ecf0511 => new \Tak\Liveproto\Tl\Types\Messages\BotPreparedInlineMessage,
			0xff57708d => new \Tak\Liveproto\Tl\Types\Messages\PreparedInlineMessage,
			0x6010c534 => new \Tak\Liveproto\Tl\Types\Messages\FoundStickersNotModified,
			0x82c9e290 => new \Tak\Liveproto\Tl\Types\Messages\FoundStickers,
			0x8c9a88ac => new \Tak\Liveproto\Tl\Types\Messages\WebPagePreview,
			0xda2ad647 => new \Tak\Liveproto\Tl\Types\Messages\EmojiGameOutcome,
			0x59e65335 => new \Tak\Liveproto\Tl\Types\Messages\EmojiGameUnavailable,
			0x44e56023 => new \Tak\Liveproto\Tl\Types\Messages\EmojiGameDiceInfo,
			0x90d7adfa => new \Tak\Liveproto\Tl\Types\Messages\ComposedMessageWithAI,
			0x445663a7 => new \Tak\Liveproto\Tl\Types\Messages\ChatInviteJoinResultOk,
			0x2f51c337 => new \Tak\Liveproto\Tl\Types\Messages\ChatInviteJoinResultWebView,
			0xa56c2a3e => new \Tak\Liveproto\Tl\Types\Updates\State,
			0x5d75a138 => new \Tak\Liveproto\Tl\Types\Updates\DifferenceEmpty,
			0xf49ca0 => new \Tak\Liveproto\Tl\Types\Updates\Difference,
			0xa8fb1981 => new \Tak\Liveproto\Tl\Types\Updates\DifferenceSlice,
			0x4afe8f6d => new \Tak\Liveproto\Tl\Types\Updates\DifferenceTooLong,
			0x3e11affb => new \Tak\Liveproto\Tl\Types\Updates\ChannelDifferenceEmpty,
			0xa4bcc6fe => new \Tak\Liveproto\Tl\Types\Updates\ChannelDifferenceTooLong,
			0x2064674e => new \Tak\Liveproto\Tl\Types\Updates\ChannelDifference,
			0x8dca6aa5 => new \Tak\Liveproto\Tl\Types\Photos\Photos,
			0x15051f54 => new \Tak\Liveproto\Tl\Types\Photos\PhotosSlice,
			0x20212ca8 => new \Tak\Liveproto\Tl\Types\Photos\Photo,
			0x96a18d5 => new \Tak\Liveproto\Tl\Types\Upload\File,
			0xf18cda44 => new \Tak\Liveproto\Tl\Types\Upload\FileCdnRedirect,
			0x21e753bc => new \Tak\Liveproto\Tl\Types\Upload\WebFile,
			0xeea8e46e => new \Tak\Liveproto\Tl\Types\Upload\CdnFileReuploadNeeded,
			0xa99fca4f => new \Tak\Liveproto\Tl\Types\Upload\CdnFile,
			0xccbbce30 => new \Tak\Liveproto\Tl\Types\Help\AppUpdate,
			0xc45a6536 => new \Tak\Liveproto\Tl\Types\Help\NoAppUpdate,
			0x18cb9f78 => new \Tak\Liveproto\Tl\Types\Help\InviteText,
			0x17c6b5f6 => new \Tak\Liveproto\Tl\Types\Help\Support,
			0x780a0310 => new \Tak\Liveproto\Tl\Types\Help\TermsOfService,
			0xe0310d7 => new \Tak\Liveproto\Tl\Types\Help\RecentMeUrls,
			0xe3309f7f => new \Tak\Liveproto\Tl\Types\Help\TermsOfServiceUpdateEmpty,
			0x28ecf961 => new \Tak\Liveproto\Tl\Types\Help\TermsOfServiceUpdate,
			0x66afa166 => new \Tak\Liveproto\Tl\Types\Help\DeepLinkInfoEmpty,
			0x6a4ee832 => new \Tak\Liveproto\Tl\Types\Help\DeepLinkInfo,
			0xbfb9f457 => new \Tak\Liveproto\Tl\Types\Help\PassportConfigNotModified,
			0xa098d6af => new \Tak\Liveproto\Tl\Types\Help\PassportConfig,
			0x8c05f1c9 => new \Tak\Liveproto\Tl\Types\Help\SupportName,
			0xf3ae2eed => new \Tak\Liveproto\Tl\Types\Help\UserInfoEmpty,
			0x1eb3758 => new \Tak\Liveproto\Tl\Types\Help\UserInfo,
			0x98f6ac75 => new \Tak\Liveproto\Tl\Types\Help\PromoDataEmpty,
			0x8a4d87a => new \Tak\Liveproto\Tl\Types\Help\PromoData,
			0x4203c5ef => new \Tak\Liveproto\Tl\Types\Help\CountryCode,
			0xc3878e23 => new \Tak\Liveproto\Tl\Types\Help\Country,
			0x93cc1f32 => new \Tak\Liveproto\Tl\Types\Help\CountriesListNotModified,
			0x87d0759e => new \Tak\Liveproto\Tl\Types\Help\CountriesList,
			0x5334759c => new \Tak\Liveproto\Tl\Types\Help\PremiumPromo,
			0x7cde641d => new \Tak\Liveproto\Tl\Types\Help\AppConfigNotModified,
			0xdd18782e => new \Tak\Liveproto\Tl\Types\Help\AppConfig,
			0x26219a58 => new \Tak\Liveproto\Tl\Types\Help\PeerColorSet,
			0x767d61eb => new \Tak\Liveproto\Tl\Types\Help\PeerColorProfileSet,
			0xadec6ebe => new \Tak\Liveproto\Tl\Types\Help\PeerColorOption,
			0x2ba1f5ce => new \Tak\Liveproto\Tl\Types\Help\PeerColorsNotModified,
			0xf8ed08 => new \Tak\Liveproto\Tl\Types\Help\PeerColors,
			0x970708cc => new \Tak\Liveproto\Tl\Types\Help\TimezonesListNotModified,
			0x7b74ed71 => new \Tak\Liveproto\Tl\Types\Help\TimezonesList,
			0x5a592a6c => new \Tak\Liveproto\Tl\Types\Help\ConfigSimple,
			0x50a04e45 => new \Tak\Liveproto\Tl\Types\Account\PrivacyRules,
			0x4bff8ea0 => new \Tak\Liveproto\Tl\Types\Account\Authorizations,
			0x957b50fb => new \Tak\Liveproto\Tl\Types\Account\Password,
			0x9a5c33e5 => new \Tak\Liveproto\Tl\Types\Account\PasswordSettings,
			0xc23727c9 => new \Tak\Liveproto\Tl\Types\Account\PasswordInputSettings,
			0xdb64fd34 => new \Tak\Liveproto\Tl\Types\Account\TmpPassword,
			0xed56c9fc => new \Tak\Liveproto\Tl\Types\Account\WebAuthorizations,
			0xad2e1cd8 => new \Tak\Liveproto\Tl\Types\Account\AuthorizationForm,
			0x811f854f => new \Tak\Liveproto\Tl\Types\Account\SentEmailCode,
			0x4dba4501 => new \Tak\Liveproto\Tl\Types\Account\Takeout,
			0x1c199183 => new \Tak\Liveproto\Tl\Types\Account\WallPapersNotModified,
			0xcdc3858c => new \Tak\Liveproto\Tl\Types\Account\WallPapers,
			0x63cacf26 => new \Tak\Liveproto\Tl\Types\Account\AutoDownloadSettings,
			0xf41eb622 => new \Tak\Liveproto\Tl\Types\Account\ThemesNotModified,
			0x9a3d8c6d => new \Tak\Liveproto\Tl\Types\Account\Themes,
			0x57e28221 => new \Tak\Liveproto\Tl\Types\Account\ContentSettings,
			0xe3779861 => new \Tak\Liveproto\Tl\Types\Account\ResetPasswordFailedWait,
			0xe9effc7d => new \Tak\Liveproto\Tl\Types\Account\ResetPasswordRequestedWait,
			0xe926d63e => new \Tak\Liveproto\Tl\Types\Account\ResetPasswordOk,
			0xe011e1c4 => new \Tak\Liveproto\Tl\Types\Account\ChatThemesNotModified,
			0xbe098173 => new \Tak\Liveproto\Tl\Types\Account\ChatThemes,
			0xfbf6e8b1 => new \Tak\Liveproto\Tl\Types\Account\SavedRingtonesNotModified,
			0xc1e92cc5 => new \Tak\Liveproto\Tl\Types\Account\SavedRingtones,
			0xb7263f6d => new \Tak\Liveproto\Tl\Types\Account\SavedRingtone,
			0x1f307eb7 => new \Tak\Liveproto\Tl\Types\Account\SavedRingtoneConverted,
			0xd08ce645 => new \Tak\Liveproto\Tl\Types\Account\EmojiStatusesNotModified,
			0x90c467d1 => new \Tak\Liveproto\Tl\Types\Account\EmojiStatuses,
			0x2b96cd1b => new \Tak\Liveproto\Tl\Types\Account\EmailVerified,
			0xe1bb0d61 => new \Tak\Liveproto\Tl\Types\Account\EmailVerifiedLogin,
			0x4c3e069d => new \Tak\Liveproto\Tl\Types\Account\AutoSaveSettings,
			0x17d7f87b => new \Tak\Liveproto\Tl\Types\Account\ConnectedBots,
			0xec43a2d1 => new \Tak\Liveproto\Tl\Types\Account\BusinessChatLinks,
			0x9a23af21 => new \Tak\Liveproto\Tl\Types\Account\ResolvedBusinessChatLinks,
			0x1e109708 => new \Tak\Liveproto\Tl\Types\Account\PaidMessagesRevenue,
			0x4fc81d6e => new \Tak\Liveproto\Tl\Types\Account\SavedMusicIdsNotModified,
			0x998d6636 => new \Tak\Liveproto\Tl\Types\Account\SavedMusicIds,
			0xf8e0aa1c => new \Tak\Liveproto\Tl\Types\Account\Passkeys,
			0xe16b5ce1 => new \Tak\Liveproto\Tl\Types\Account\PasskeyRegistrationOptions,
			0xc31c8f4e => new \Tak\Liveproto\Tl\Types\Account\WebBrowserSettingsNotModified,
			0x79eb8cb3 => new \Tak\Liveproto\Tl\Types\Account\WebBrowserSettings,
			0x9ab0feaf => new \Tak\Liveproto\Tl\Types\Channels\ChannelParticipants,
			0xf0173fe9 => new \Tak\Liveproto\Tl\Types\Channels\ChannelParticipantsNotModified,
			0xdfb80317 => new \Tak\Liveproto\Tl\Types\Channels\ChannelParticipant,
			0xed8af74d => new \Tak\Liveproto\Tl\Types\Channels\AdminLogResults,
			0xf496b0c6 => new \Tak\Liveproto\Tl\Types\Channels\SendAsPeers,
			0x846f9e42 => new \Tak\Liveproto\Tl\Types\Channels\SponsoredMessageReportResultChooseOption,
			0x3e3bcf2f => new \Tak\Liveproto\Tl\Types\Channels\SponsoredMessageReportResultAdsHidden,
			0xad798849 => new \Tak\Liveproto\Tl\Types\Channels\SponsoredMessageReportResultReported,
			0xa0058751 => new \Tak\Liveproto\Tl\Types\Payments\PaymentForm,
			0x7bf6b15c => new \Tak\Liveproto\Tl\Types\Payments\PaymentFormStars,
			0xb425cfe1 => new \Tak\Liveproto\Tl\Types\Payments\PaymentFormStarGift,
			0xd1451883 => new \Tak\Liveproto\Tl\Types\Payments\ValidatedRequestedInfo,
			0x4e5f810d => new \Tak\Liveproto\Tl\Types\Payments\PaymentResult,
			0xd8411139 => new \Tak\Liveproto\Tl\Types\Payments\PaymentVerificationNeeded,
			0x70c4fe03 => new \Tak\Liveproto\Tl\Types\Payments\PaymentReceipt,
			0xdabbf83a => new \Tak\Liveproto\Tl\Types\Payments\PaymentReceiptStars,
			0xfb8fe43c => new \Tak\Liveproto\Tl\Types\Payments\SavedInfo,
			0x3e24e573 => new \Tak\Liveproto\Tl\Types\Payments\BankCardData,
			0xaed0cbd9 => new \Tak\Liveproto\Tl\Types\Payments\ExportedInvoice,
			0xeb983f8f => new \Tak\Liveproto\Tl\Types\Payments\CheckedGiftCode,
			0x4367daa0 => new \Tak\Liveproto\Tl\Types\Payments\GiveawayInfo,
			0xe175e66f => new \Tak\Liveproto\Tl\Types\Payments\GiveawayInfoResults,
			0x6c9ce8ed => new \Tak\Liveproto\Tl\Types\Payments\StarsStatus,
			0x6c207376 => new \Tak\Liveproto\Tl\Types\Payments\StarsRevenueStats,
			0x1dab80b7 => new \Tak\Liveproto\Tl\Types\Payments\StarsRevenueWithdrawalUrl,
			0x394e7f21 => new \Tak\Liveproto\Tl\Types\Payments\StarsRevenueAdsAccountUrl,
			0xa388a368 => new \Tak\Liveproto\Tl\Types\Payments\StarGiftsNotModified,
			0x2ed82995 => new \Tak\Liveproto\Tl\Types\Payments\StarGifts,
			0x98d5ea1d => new \Tak\Liveproto\Tl\Types\Payments\ConnectedStarRefBots,
			0xb4d5d859 => new \Tak\Liveproto\Tl\Types\Payments\SuggestedStarRefBots,
			0x3de1dfed => new \Tak\Liveproto\Tl\Types\Payments\StarGiftUpgradePreview,
			0x416c56e8 => new \Tak\Liveproto\Tl\Types\Payments\UniqueStarGift,
			0x95f389b1 => new \Tak\Liveproto\Tl\Types\Payments\SavedStarGifts,
			0x84aa3a9c => new \Tak\Liveproto\Tl\Types\Payments\StarGiftWithdrawalUrl,
			0x947a12df => new \Tak\Liveproto\Tl\Types\Payments\ResaleStarGifts,
			0xa0ba4f17 => new \Tak\Liveproto\Tl\Types\Payments\StarGiftCollectionsNotModified,
			0x8a2932f3 => new \Tak\Liveproto\Tl\Types\Payments\StarGiftCollections,
			0x512fe446 => new \Tak\Liveproto\Tl\Types\Payments\UniqueStarGiftValueInfo,
			0x374fa7ad => new \Tak\Liveproto\Tl\Types\Payments\CheckCanSendGiftResultOk,
			0xd5e58274 => new \Tak\Liveproto\Tl\Types\Payments\CheckCanSendGiftResultFail,
			0x6b39f4ec => new \Tak\Liveproto\Tl\Types\Payments\StarGiftAuctionState,
			0x7d5bd1f0 => new \Tak\Liveproto\Tl\Types\Payments\StarGiftAuctionAcquiredGifts,
			0xdb33dad0 => new \Tak\Liveproto\Tl\Types\Payments\StarGiftActiveAuctionsNotModified,
			0xaef6abbc => new \Tak\Liveproto\Tl\Types\Payments\StarGiftActiveAuctions,
			0x46c6e36f => new \Tak\Liveproto\Tl\Types\Payments\StarGiftUpgradeAttributes,
			0xec82e140 => new \Tak\Liveproto\Tl\Types\Phone\PhoneCall,
			0x9e727aad => new \Tak\Liveproto\Tl\Types\Phone\GroupCall,
			0xf47751b6 => new \Tak\Liveproto\Tl\Types\Phone\GroupParticipants,
			0xafe5623f => new \Tak\Liveproto\Tl\Types\Phone\JoinAsPeers,
			0x204bd158 => new \Tak\Liveproto\Tl\Types\Phone\ExportedGroupCallInvite,
			0xd0e482b2 => new \Tak\Liveproto\Tl\Types\Phone\GroupCallStreamChannels,
			0x2dbf3432 => new \Tak\Liveproto\Tl\Types\Phone\GroupCallStreamRtmpUrl,
			0x9d1dbd26 => new \Tak\Liveproto\Tl\Types\Phone\GroupCallStars,
			0x396ca5fc => new \Tak\Liveproto\Tl\Types\Stats\BroadcastStats,
			0xef7ff916 => new \Tak\Liveproto\Tl\Types\Stats\MegagroupStats,
			0x7fe91c14 => new \Tak\Liveproto\Tl\Types\Stats\MessageStats,
			0x50cd067c => new \Tak\Liveproto\Tl\Types\Stats\StoryStats,
			0x93037e20 => new \Tak\Liveproto\Tl\Types\Stats\PublicForwards,
			0x2999beed => new \Tak\Liveproto\Tl\Types\Stats\PollStats,
			0x85fea03f => new \Tak\Liveproto\Tl\Types\Stickers\SuggestedShortName,
			0x3b6d152e => new \Tak\Liveproto\Tl\Types\Users\UserFull,
			0x62d706b8 => new \Tak\Liveproto\Tl\Types\Users\Users,
			0x315a4974 => new \Tak\Liveproto\Tl\Types\Users\UsersSlice,
			0xe3878aa4 => new \Tak\Liveproto\Tl\Types\Users\SavedMusicNotModified,
			0x34a2f297 => new \Tak\Liveproto\Tl\Types\Users\SavedMusic,
			0x10e6e3a6 => new \Tak\Liveproto\Tl\Types\Chatlists\ExportedChatlistInvite,
			0x10ab6dc7 => new \Tak\Liveproto\Tl\Types\Chatlists\ExportedInvites,
			0xfa87f659 => new \Tak\Liveproto\Tl\Types\Chatlists\ChatlistInviteAlready,
			0xf10ece2f => new \Tak\Liveproto\Tl\Types\Chatlists\ChatlistInvite,
			0x93bd878d => new \Tak\Liveproto\Tl\Types\Chatlists\ChatlistUpdates,
			0xe8a775b0 => new \Tak\Liveproto\Tl\Types\Bots\BotInfo,
			0x1991b13b => new \Tak\Liveproto\Tl\Types\Bots\PopularAppBots,
			0xca71d64 => new \Tak\Liveproto\Tl\Types\Bots\PreviewInfo,
			0x3c60b621 => new \Tak\Liveproto\Tl\Types\Bots\ExportedBotToken,
			0xf13bbcd7 => new \Tak\Liveproto\Tl\Types\Bots\RequestedButton,
			0xdd1fbf93 => new \Tak\Liveproto\Tl\Types\Bots\AccessSettings,
			0x1158fe3e => new \Tak\Liveproto\Tl\Types\Stories\AllStoriesNotModified,
			0x6efc5e81 => new \Tak\Liveproto\Tl\Types\Stories\AllStories,
			0x63c3dd0a => new \Tak\Liveproto\Tl\Types\Stories\Stories,
			0x59d78fc5 => new \Tak\Liveproto\Tl\Types\Stories\StoryViewsList,
			0xde9eed1d => new \Tak\Liveproto\Tl\Types\Stories\StoryViews,
			0xcae68768 => new \Tak\Liveproto\Tl\Types\Stories\PeerStories,
			0xaa5f789c => new \Tak\Liveproto\Tl\Types\Stories\StoryReactionsList,
			0xe2de7737 => new \Tak\Liveproto\Tl\Types\Stories\FoundStories,
			0xc387c04e => new \Tak\Liveproto\Tl\Types\Stories\CanSendStoryCount,
			0x564edaeb => new \Tak\Liveproto\Tl\Types\Stories\AlbumsNotModified,
			0xc3987a3a => new \Tak\Liveproto\Tl\Types\Stories\Albums,
			0x86f8613c => new \Tak\Liveproto\Tl\Types\Premium\BoostsList,
			0x9ae228e2 => new \Tak\Liveproto\Tl\Types\Premium\MyBoosts,
			0x4959427a => new \Tak\Liveproto\Tl\Types\Premium\BoostsStatus,
			0xdc8b44cf => new \Tak\Liveproto\Tl\Types\Smsjobs\EligibleToJoin,
			0x2aee9191 => new \Tak\Liveproto\Tl\Types\Smsjobs\Status,
			0x6ebdff91 => new \Tak\Liveproto\Tl\Types\Fragment\CollectibleInfo,
			0xc1f46103 => new \Tak\Liveproto\Tl\Types\Aicompose\TonesNotModified,
			0x6c9d0efe => new \Tak\Liveproto\Tl\Types\Aicompose\Tones,
			0x1f814f1f => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessage,
			0xaa48327d => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageService,
			0x89f5c4a => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaEmpty,
			0x32798a8c => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaPhoto,
			0x4cee6ef3 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaVideo,
			0x35480a59 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaGeoPoint,
			0x588a0a97 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaContact,
			0xa1733aec => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionSetMessageTTL,
			0xb095434b => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaDocument,
			0x6080758f => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaAudio,
			0xc4f40be => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionReadMessages,
			0x65614304 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionDeleteMessages,
			0x8ac1f475 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionScreenshotMessages,
			0x6719e45c => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionFlushHistory,
			0x204d3878 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessage,
			0x73164160 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageService,
			0x524a415d => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaVideo,
			0x57e0a9cb => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaAudio,
			0x1be31789 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageLayer,
			0x16bf744e => new \Tak\Liveproto\Tl\Types\Secret\SendMessageTypingAction,
			0xfd5ec8f5 => new \Tak\Liveproto\Tl\Types\Secret\SendMessageCancelAction,
			0xa187d66f => new \Tak\Liveproto\Tl\Types\Secret\SendMessageRecordVideoAction,
			0x92042ff7 => new \Tak\Liveproto\Tl\Types\Secret\SendMessageUploadVideoAction,
			0xd52f73f7 => new \Tak\Liveproto\Tl\Types\Secret\SendMessageRecordAudioAction,
			0xe6ac8a6f => new \Tak\Liveproto\Tl\Types\Secret\SendMessageUploadAudioAction,
			0x990a3c1a => new \Tak\Liveproto\Tl\Types\Secret\SendMessageUploadPhotoAction,
			0x8faee98e => new \Tak\Liveproto\Tl\Types\Secret\SendMessageUploadDocumentAction,
			0x176f8ba1 => new \Tak\Liveproto\Tl\Types\Secret\SendMessageGeoLocationAction,
			0x628cbc6f => new \Tak\Liveproto\Tl\Types\Secret\SendMessageChooseContactAction,
			0x511110b0 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionResend,
			0xf3048883 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionNotifyLayer,
			0xccb27641 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionTyping,
			0xf3c9611b => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionRequestKey,
			0x6fe1735b => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionAcceptKey,
			0xdd05ec6b => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionAbortKey,
			0xec2e0b9b => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionCommitKey,
			0xa82fdd63 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionNoop,
			0x6c37c15c => new \Tak\Liveproto\Tl\Types\Secret\DocumentAttributeImageSize,
			0x11b58939 => new \Tak\Liveproto\Tl\Types\Secret\DocumentAttributeAnimated,
			0xfb0a5727 => new \Tak\Liveproto\Tl\Types\Secret\DocumentAttributeSticker,
			0x5910cccb => new \Tak\Liveproto\Tl\Types\Secret\DocumentAttributeVideo,
			0x51448e5 => new \Tak\Liveproto\Tl\Types\Secret\DocumentAttributeAudio,
			0x15590068 => new \Tak\Liveproto\Tl\Types\Secret\DocumentAttributeFilename,
			0xe17e23c => new \Tak\Liveproto\Tl\Types\Secret\PhotoSizeEmpty,
			0x77bfb61b => new \Tak\Liveproto\Tl\Types\Secret\PhotoSize,
			0xe9a734fa => new \Tak\Liveproto\Tl\Types\Secret\PhotoCachedSize,
			0x7c596b46 => new \Tak\Liveproto\Tl\Types\Secret\FileLocationUnavailable,
			0x53d69076 => new \Tak\Liveproto\Tl\Types\Secret\FileLocation,
			0xfa95b0dd => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaExternalDocument,
			0x36b091de => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessage,
			0xf1fa8d78 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaPhoto,
			0x970c8c0e => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaVideo,
			0x7afe8ae2 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaDocument,
			0x3a556302 => new \Tak\Liveproto\Tl\Types\Secret\DocumentAttributeSticker,
			0xded218e0 => new \Tak\Liveproto\Tl\Types\Secret\DocumentAttributeAudio,
			0xbb92ba95 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityUnknown,
			0xfa04579d => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityMention,
			0x6f635b0d => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityHashtag,
			0x6cef8ac7 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityBotCommand,
			0x6ed02538 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityUrl,
			0x64e475c2 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityEmail,
			0xbd610bc9 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityBold,
			0x826f8b60 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityItalic,
			0x28a20571 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityCode,
			0x73924be0 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityPre,
			0x76a6d327 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityTextUrl,
			0x861cc8a0 => new \Tak\Liveproto\Tl\Types\Secret\InputStickerSetShortName,
			0xffb62b95 => new \Tak\Liveproto\Tl\Types\Secret\InputStickerSetEmpty,
			0x8a0df56f => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaVenue,
			0xe50511d8 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaWebPage,
			0x9852f9c6 => new \Tak\Liveproto\Tl\Types\Secret\DocumentAttributeAudio,
			0xef02ce6 => new \Tak\Liveproto\Tl\Types\Secret\DocumentAttributeVideo,
			0x88f27fbc => new \Tak\Liveproto\Tl\Types\Secret\SendMessageRecordRoundAction,
			0xbb718624 => new \Tak\Liveproto\Tl\Types\Secret\SendMessageUploadRoundAction,
			0x91cc4674 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessage,
			0x9c4e7e8b => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityUnderline,
			0xbf0693d4 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityStrike,
			0x20df5d0 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityBlockquote,
			0x6abd9782 => new \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageMediaDocument,
			0x32ca960f => new \Tak\Liveproto\Tl\Types\Secret\MessageEntitySpoiler,
			0xc8cf05f8 => new \Tak\Liveproto\Tl\Types\Secret\MessageEntityCustomEmoji,
			default => throw new \Exception('Constructor '.dechex($constructorId).' not found ( layer : 227 ) !')
		};
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

use Tak\Liveproto\Utils\Logging;

use Tak\Asyncio\Promise\DeferredFuture;

use Stringable;

/*
 * A client must never mark msgs_ack, msg_container, msg_copy, gzip_packed constructors (i.e. containers and acknowledgements) as content-related, or else a bad_msg_notification with error_code=34 will be emitted
 * [contentRelated = false]
 * [sequence % 2 === 1]
 */

class MTRequest implements Stringable {
	public ? Instance $tl = null;
	public ? Binary $binary = null;
	private ? DeferredFuture $deferred = null;

	public function __construct(string | Instance | Binary $tl,public ? int $messageId = null,public mixed $identifier = null,public ? int $sequence = null,public bool $contentRelated = true,public bool $keepOldSalt = false,public float $timeout = 0,public ? object $cancellation = null){
		if(is_string($tl)):
			list($what,$space,$name) = array_pad(array_map(ucfirst(...),explode(chr(46),$tl,3)),-3,null);
			if(in_array($space,['Functions','Types','Cores'])):
				$what = $space;
				$space = null;
			endif;
			$space = is_null($space) ? 'Other' : $space;
			$whats = is_null($what) ? ['Functions','Types','Cores'] : array($what);
			foreach($whats as $what):
				if($tl = $this->createObject('Tak\\Liveproto\\Tl\\'.$what.'\\'.$space.'\\'.$name)):
					break;
				endif;
			endforeach;
		endif;
		if($tl instanceof Binary):
			$this->binary = $tl;
		elseif($tl instanceof Instance):
			$this->tl = $tl;
		else:
			throw new \LogicException('The tl you requested was not found');
		endif;
	}
	public function withParameters(mixed ...$arguments) : self {
		if(is_null($this->tl) === false):
			$this->tl = new $this->tl($arguments);
			$this->binary = $this->tl->stream();
			return $this;
		else:
			throw new \InvalidArgumentException('This request does not assign a new parameter');
		endif;
	}
	public function getBinary(bool $renew = false) : Binary {
		$this->binary = ($renew || is_null($this->binary)) ? $this->tl->stream() : $this->binary;
		return $this->binary;
	}
	public function getConstructor() : Instance {
		$constructorId = $this->getBinary()->readInt();
		$this->getBinary()->undo();
		return All::getConstructor($constructorId);
	}
	public function hash() : string {
		return md5(spl_object_hash($this->getBinary()));
	}
	public function createObject(string $class) : object | false {
		return class_exists($class) ? new $class : false;
	}
	public function toMessage(int $msg_id,int $seqno) : string {
		# message msg_id:long seqno:int bytes:int body:Object = Message; #
		$message = new Binary();
		$this->messageId ??= $msg_id;
		$message->writeLong($this->messageId);
		$this->sequence ??= $seqno;
		$message->writeInt($this->sequence);
		$packet = $this->getBinary()->read();
		$packetLength = strlen($packet);
		# gzip_packed#3072cfa1 packed_data:string = Object; #
		if($packetLength > 512 and boolval($this->sequence % 2 === 1)):
			$gzip = new Binary();
			$gzip->writeInt(0x3072cfa1);
			$gzip->writeBytes(gzencode($packet));
			$compressed = $gzip->read();
			$compressedLength = strlen($compressed);
			if($packetLength > $compressedLength):
				Logging::log('Gzip','compressed size : '.$compressedLength.' , using compressed payload ( saves '.intval($packetLength - $compressedLength).' bytes )');
				$message->writeInt($compressedLength);
				$message->write($compressed);
				return $message->read();
			endif;
		endif;
		$message->writeInt($packetLength);
		$message->write($packet);
		return $message->read();
	}
	static public function fromMessage(Binary $message) : self {
		# message msg_id:long seqno:int bytes:int body:Object = Message; #
		$msg_id = $message->readLong();
		$seqno = $message->readInt();
		$packetLength = $message->readInt();
		$packet = $message->read($packetLength);
		$body = new Binary();
		$body->write($packet);
		return new self($body,messageId : $msg_id,sequence : $seqno);
	}
	public function getDeferred(bool $lazyInit = true) : ? DeferredFuture {
		$this->deferred = boolval($lazyInit and is_null($this->deferred)) ? new DeferredFuture : $this->deferred;
		return $this->deferred;
	}
	public function __clone() : void {
		$this->messageId = null;
		$this->sequence = null;
		$this->deferred = null;
	}
	public function __toString() : string {
		return md5(spl_object_hash($this->getBinary()));
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl;

use Tak\Liveproto\Utils\Tools;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Logging;

use Iterator;

use Closure;

use Throwable;

final class Pagination implements Iterator {
	protected ? Closure $computeLongHash;
	private int $hash = 0;
	private array $results = array();
	private int $position = 0;

	public function __construct(protected Closure $callback,public int $offset,public int $limit,Closure | array | null $hasher = null){
		if(is_array($hasher)):
			$this->computeLongHash = empty($hasher) ? null : fn(int $hash,array $results) : int => fn(int $hash,array $results) : int => Helper::hashGeneration($hash,Tools::populateIds($results,$hasher));
		else:
			$this->computeLongHash = $hasher;
		endif;
	}
	public function current() : mixed {
		return $this->results[$this->position];
	}
	public function key() : mixed {
		return $this->position;
	}
	public function next() : void {
		$this->position++;
	}
	public function rewind() : void {
		$this->position = 0;
	}
	public function exists() : bool {
		return isset($this->results[$this->position]);
	}
	public function valid() : bool {
		if($this->exists() === false):
			try {
				Logging::log('Pagination','offset = '.$this->offset.' & limit = '.$this->limit.' & hash = '.$this->hash,0);
				$results = call_user_func($this->callback,$this->offset,abs($this->limit),$this->hash);
				if(empty($results) === false):
					$this->results = array_merge($this->results,$results);
					$this->offset += $this->limit;
					if(is_callable($this->computeLongHash)):
						$this->hash = call_user_func($this->computeLongHash,$this->hash,$results);
					endif;
				endif;
			} catch(Throwable $error){
				Logging::log('Pagination',$error->getMessage(),E_NOTICE);
			}
		endif;
		return $this->exists();
	}
	public function __debugInfo() : array {
		return array(
			'hash'=>$this->hash,
			'position'=>$this->position
		);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Tl\Pagination;

use Tak\Liveproto\Enums\FileType;

use Tak\Liveproto\Attributes\Type;

use Tak\Attributes\Common\Vector;

use Tak\Attributes\Common\Is;

use Iterator;

use Closure;

trait Messages {
	public function send_content(
		string | int | object $peer,
		? string $message = null,
		? string $parse_mode = null,
		string | object | null $media = null,
		string | int | null | object $send_as = null,
		array | null | object $reply_markup = null,
		FileType $file_type = FileType::DOCUMENT,
		array $uploaded = array(),
		mixed ...$args
	) : object | array {
		$inputPeer = $this->get_input_peer($peer);
		$inputSendAs = $this->get_input_peer($send_as);
		$messages = str_split(strval($message),1 << ($media ? 10 : 12)) ?: array(null);
		if(is_string($media)):
			$inputMedia = $this->get_input_media_uploaded($media,$file_type,...$uploaded);
		elseif(is_object($media)):
			$inputMedia = $this->get_input_media($media);
		else:
			$inputMedia = null;
		endif;
		$inputReplyMarkup = is_array($reply_markup) ? $this->create_reply_markup($reply_markup) : $reply_markup;
		$parser = match(strtolower(strval($parse_mode))){
			'html' , 'htm' => $this->html(...),
			'markdown' , 'markdownv2' , 'md' => $this->markdown(...),
			default => null
		};
		$sents = array();
		foreach($messages as $text):
			if(is_null($parser) === false):
				list($text,$entities) = $parser(strval($text));
				$args['entities'] = $entities;
			endif;
			if(is_null($inputMedia)):
				$sents []= $this->messages->sendMessage(...$args,peer : $inputPeer,message : strval($text),random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),send_as : ($send_as ? $inputSendAs : null),reply_markup : $inputReplyMarkup);
			else:
				$sents []= $this->messages->sendMedia(...$args,peer : $inputPeer,media : $inputMedia,message : strval($text),random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),send_as : ($send_as ? $inputSendAs : null),reply_markup : $inputReplyMarkup);
			endif;
		endforeach;
		return count($sents) > 1 ? $sents : reset($sents);
	}
	public function edit_content(
		string | int | object $peer,
		int $id,
		? string $message = null,
		? string $parse_mode = null,
		string | object | null $media = null,
		array | null | object $reply_markup = null,
		FileType $file_type = FileType::DOCUMENT,
		array $uploaded = array(),
		mixed ...$args
	) : object {
		$inputPeer = $this->get_input_peer($peer);
		if(is_string($media)):
			$inputMedia = $this->get_input_media_uploaded($media,$file_type,...$uploaded);
		elseif(is_object($media)):
			$inputMedia = $this->get_input_media($media);
		else:
			$inputMedia = null;
		endif;
		$inputReplyMarkup = is_array($reply_markup) ? $this->create_reply_markup($reply_markup) : $reply_markup;
		$parser = match(strtolower(strval($parse_mode))){
			'html' , 'htm' => $this->html(...),
			'markdown' , 'markdownv2' , 'md' => $this->markdown(...),
			default => null
		};
		if(is_null($parser) === false and is_null($message) === false):
			list($message,$entities) = $parser($message);
			$args['entities'] = $entities;
		endif;
		return $this->messages->editMessage(...$args,peer : $inputPeer,id : $id,message : $message,media : $inputMedia,reply_markup : $inputReplyMarkup);
	}
	public function send_message_draft(
		string | int | object $peer,
		int $draft_id,
		string $message,
		? string $parse_mode = null,
		mixed ...$args
	) : bool | array {
		$inputPeer = $this->get_input_peer($peer);
		$messages = str_split(strval($message),1 << 12);
		$parser = match(strtolower(strval($parse_mode))){
			'html' , 'htm' => $this->html(...),
			'markdown' , 'markdownv2' , 'md' => $this->markdown(...),
			default => null
		};
		$drafteds = array();
		foreach($messages as $text):
			list($text,$entities) = is_null($parser) ? array(strval($text),array()) : $parser(strval($text));
			$action = $this->sendMessageTextDraftAction(random_id : $draft_id,text : $this->textWithEntities(text : $text,entities : $entities));
			$drafteds []= $this->messages->setTyping(...$args,peer : $inputPeer,action : $action);
		endforeach;
		return count($drafteds) > 1 ? $drafteds : reset($drafteds);
	}
	/* TODO : Add messages.getPersonalChannelHistory method to make supporting completely */
	protected function fetch_messages(
		string | int | null | object $peer = null,
		string | int | null | object $offset_peer = null,
		int $offset = 0,
		int $offset_id = 0,
		int $offset_date = 0,
		int $limit = 100,
		int $min_id = 0,
		int $max_id = 0,
		int $min_date = 0,
		int $max_date = 0,
		bool $unread_mentions = false,
		bool $unread_reactions = false,
		bool $recent_locations = false,
		bool $posts = false,
		bool $search = false,
		bool $saved = false,
		bool $scheduled = false,
		#[Vector(new Is('int'))] ? array $id = null,
		#[Type('MessagesFilter')] ? object $filter = null,
		? string $query = null,
		int | bool | null $reply_to = null,
		? int $shortcut_id = null,
		Closure | array | null $hashgen = null,
		mixed ...$args
	) : Iterator {
		$inputPeer = $this->get_input_peer($peer);
		$inputOffsetPeer = $this->get_input_peer($offset_peer);
		if($unread_mentions):
			$fetchResults = fn(int $offset,int $limit) : array => $this->messages->getUnreadMentions(...$args,peer : $inputPeer,offset_id : $offset_id,add_offset : $offset,limit : $limit,max_id : $max_id,min_id : $min_id)->messages;
		elseif($unread_reactions):
			$fetchResults = fn(int $offset,int $limit) : array => $this->messages->getUnreadReactions(...$args,peer : $inputPeer,offset_id : $offset_id,add_offset : $offset,limit : $limit,max_id : $max_id,min_id : $min_id)->messages;
		elseif($recent_locations):
			$fetchResults = fn(int $offset,int $limit,int $hash) : array => $this->messages->getRecentLocations(...$args,peer : $inputPeer,limit : $limit,hash : $hash)->messages;
			$hashgen = array('id','edit_date');
		elseif($posts):
			$fetchResults = fn(int $offset,int $limit) : array => $this->channels->searchPosts(...$args,query : $query,offset_rate : $offset,offset_peer : $inputOffsetPeer,offset_id : $offset_id,limit : $limit)->messages;
		elseif($search):
			if(is_null($peer)):
				$fetchResults = fn(int $offset,int $limit) : array => $this->messages->searchGlobal(...$args,q : strval($query),filter : is_null($filter) ? $this->inputMessagesFilterEmpty() : $filter,min_date : $min_date,max_date : $max_date,offset_rate : $offset,offset_peer : $inputOffsetPeer,offset_id : $offset_id,limit : $limit)->messages;
			else:
				$fetchResults = fn(int $offset,int $limit,int $hash) : array => $this->messages->search(...$args,peer : $inputPeer,q : strval($query),filter : is_null($filter) ? $this->inputMessagesFilterEmpty() : $filter,min_date : $min_date,max_date : $max_date,offset_id : $offset_id,add_offset : $offset,limit : $limit,max_id : $max_id,min_id : $min_id,hash : $hash)->messages;
			endif;
		elseif($scheduled):
			if(is_null($id)):
				$fetchResults = fn(int $offset,int $limit,int $hash) : array => $this->messages->getScheduledHistory(...$args,peer : $inputPeer,hash : $hash)->messages;
				$hashgen = array('id','edit_date','date');
			else:
				$fetchResults = fn(int $offset,int $limit) : array => ($slice = array_slice($id,$offset,$limit)) ? $this->messages->getScheduledMessages(...$args,peer : $inputPeer,id : $slice)->messages : null;
			endif;
		elseif(is_int($reply_to)):
			$fetchResults = fn(int $offset,int $limit,int $hash) : array => $this->messages->getReplies(...$args,peer : $inputPeer,msg_id : $reply_to,offset_id : $offset_id,offset_date : $offset_date,add_offset : $offset,limit : $limit,max_id : $max_id,min_id : $min_id,hash : $hash)->messages;
		elseif(is_null($shortcut_id) === false):
			$fetchResults = fn(int $offset,int $limit,int $hash) : array => $this->messages->getQuickReplyMessages(...$args,shortcut_id : $shortcut_id,id : $id,hash : $hash)->messages;
			$hashgen = array('id','edit_date');
		elseif(is_null($id) === false):
			$id = array_map(fn(int $value) : object => $reply_to ? $this->inputMessageReplyTo(id : $value) : $this->inputMessageID(id : $value),$id);
			if(is_null($peer)):
				$fetchResults = fn(int $offset,int $limit) : array => ($slice = array_slice($id,$offset,$limit)) ? $this->messages->getMessages(...$args,id : $slice)->messages : null;
			else:
				$inputChannel = $this->get_input_channel($peer);
				$fetchResults = fn(int $offset,int $limit) : array => ($slice = array_slice($id,$offset,$limit)) ? $this->channels->getMessages(...$args,channel : $inputChannel,id : $slice)->messages : null;
			endif;
		elseif(is_null($peer) === false):
			if($saved):
				$fetchResults = fn(int $offset,int $limit,int $hash) : array => $this->messages->getSavedHistory(...$args,peer : $inputPeer,offset_id : $offset_id,offset_date : $offset_date,add_offset : $offset,limit : $limit,max_id : $max_id,min_id : $min_id,hash : $hash)->messages;
			else:
				$fetchResults = fn(int $offset,int $limit,int $hash) : array => $this->messages->getHistory(...$args,peer : $inputPeer,offset_id : $offset_id,offset_date : $offset_date,add_offset : $offset,limit : $limit,max_id : $max_id,min_id : $min_id,hash : $hash)->messages;
			endif;
		else:
			$messages = $this->messages->searchSentMedia(...$args,q : strval($query),filter : is_null($filter) ? $this->inputMessagesFilterEmpty() : $filter,limit : 0x7fffffff)->messages;
			$fetchResults = fn(int $offset,int $limit) : array => array_slice($messages,$offset,$limit);
		endif;
		return new Pagination($fetchResults,$offset,$limit,$hashgen);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Attributes\Type;

trait Inline {
	protected function edit_inline(
		#[Type('InputBotInlineMessageID')] object $id,
		? string $message = null,
		? string $parse_mode = null,
		string | object | null $media = null,
		array | null | object $reply_markup = null,
		FileType $file_type = FileType::DOCUMENT,
		array $uploaded = array(),
		mixed ...$args
	) : bool {
		if(is_string($media)):
			$inputMedia = $this->get_input_media_uploaded($media,$file_type,...$uploaded);
		elseif(is_object($media)):
			$inputMedia = $this->get_input_media($media);
		else:
			$inputMedia = null;
		endif;
		$inputReplyMarkup = is_array($reply_markup) ? $this->create_reply_markup($reply_markup) : $reply_markup;
		$parser = match(strtolower(strval($parse_mode))){
			'html' , 'htm' => $this->html(...),
			'markdown' , 'markdownv2' , 'md' => $this->markdown(...),
			default => null
		};
		if(is_null($parser) === false and is_null($message) === false):
			list($message,$entities) = $parser($message);
			$args['entities'] = $entities;
		endif;
		return $this->messages->editInlineBotMessage(...$args,id : $id,message : $message,media : $inputMedia,reply_markup : $inputReplyMarkup);
	}
	public function inline_query(
		string | int | object $bot,
		? string $query = null,
		? string $offset = null,
		string | int | null | object $peer = null,
		? object $geo_point = null
	) : mixed {
		$results = $this->messages->getInlineBotResults(bot : $this->get_input_peer($bot),peer : $this->get_input_peer($peer),query : strval($query),offset : strval($offset),geo_point : $geo_point);
		$results->click = function(? int $index = null,? string $id = null,? string $type = null,mixed ...$args) use($results,$peer) : mixed {
			if(is_null($id) === false):
				$array = array_filter($results->results,fn(object $result) : bool => $result->id === $id);
				$result = reset($array);
			elseif(is_null($type) === false):
				$array = array_values(array_filter($results->results,fn(object $result) : bool => $result->type === $type));
				$result = is_null($index) ? reset($array) : $array[$index];
			elseif(is_null($index) === false):
				$result = $results->results[$index];
			else:
				throw new \InvalidArgumentException('One of the index / id / type parameters must be entered in the inline query function !');
			endif;
			if(is_object($result)):
				return $this->click_inline($results->query_id,$result->id,$peer,...$args);
			else:
				throw new \Exception('Your desired result was not found !');
			endif;
		};
		return $results;
	}
	public function get_prepared_inline_message(string | int | object $bot,string $id) : mixed {
		$result = $this->messages->getPreparedInlineMessage(bot : $this->get_input_peer($bot),id : $id);
		$result->click = function(string | int | object $peer,mixed ...$args) use($result) : mixed {
			return $this->click_inline($result->query_id,$result->result->id,$peer,...$args);
		};
		return $result;
	}
	public function click_inline(
		int $query_id,
		string $id,
		string | int | null | object $peer = null,
		mixed ...$args
	) : mixed {
		$result = $this->messages->sendInlineBotResult($this->get_input_peer($peer),random_int(PHP_INT_MIN,PHP_INT_MAX),$query_id,$id,...$args);
		if(is_array($result->updates)):
			$array = array_filter($result->updates,fn(object $update) : bool => $update->message instanceof \Tak\Liveproto\Tl\Types\Other\Message);
			$update = reset($array);
			if(is_object($update) and is_object($update->message->reply_markup)):
				$result->click = fn(mixed ...$arguments) : mixed => $this->click_button($update->message,...$arguments);
			endif;
		endif;
		return $result;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Crypto\Aes;

use function Tak\Asyncio\async;

use function Tak\Asyncio\File\openFile;

use function Tak\Asyncio\File\getSize;

use function Tak\Asyncio\File\isFile;

use Generator;

use ArrayIterator;

use InfiniteIterator;

trait Upload {
	protected function perform_upload(
		mixed $source,
		int $size = -1,
		? int $dc_id = null,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		TransferKind $transfer_kind = TransferKind::FILE
	) : mixed {
		switch($transfer_kind):
			case TransferKind::FILE:
				return $this->upload_file($source,$dc_id,$progresscallback,$key,$iv);
			case TransferKind::STREAM:
				return $this->upload_chunks($size,$dc_id,$progresscallback,$key,$iv);
			case TransferKind::CALLBACK:
				return $this->upload_callback($source,$size,$dc_id,$progresscallback,$key,$iv);
			default:
				throw new \InvalidArgumentException('Transfer kind '.$transfer_kind->value.' is not yet supported !');
		endswitch;
	}
	public function upload_chunks(
		int $size = -1,
		? int $dc_id = null,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		int $offset = 0,
		int $limit = 512
	) : Generator {
		$partSizeKB = ($size < 0xa00000 ? 128 : ($size < 0x6400000 ? 256 : 512));
		$limit = intval($size > 0 ? $partSizeKB : $limit) * 1024;
		$partCount = intval($size > 0 ? intdiv($size + $limit - 1,$limit) : -1);
		$fileId = Helper::generateRandomLong();
		$isBig = boolval($size <= 0 || $size > 0xa00000);
		$dc_id ??= $this->load->dc;
		$requests = array();
		$md5 = hash_init('md5');
		$pause = false;
		$connections = $this->getMediaConnections(dc_id : $dc_id,pfs : false,count : match(true){
			boolval($size < 10 * 1024 * 1024) => 1,
			boolval($size >= 10 * 1024 * 1024 and $size < 25 * 1024 * 1024) => 2,
			boolval($size >= 25 * 1024 * 1024 and $size < 50 * 1024 * 1024) => 3,
			boolval($size >= 50 * 1024 * 1024 and $size < 100 * 1024 * 1024) => 4,
			default => null
		});
		Logging::log('Upload','A total of '.count($connections).' connections were received');
		$clients = new InfiniteIterator(new ArrayIterator($connections));
		$start = microtime(true);
		while($pause === false):
			$part = yield $limit => $offset;
			if(is_null($part)):
				$pause = true;
				goto finished;
			endif;
			if(is_null($key) === false and is_null($iv) === false):
				$part = Aes::encrypt($part,$key,$iv);
			endif;
			if($isBig):
				$requests []= ['file_id'=>$fileId,'file_part'=>intval($offset / $limit),'file_total_parts'=>$partCount,'bytes'=>$partCount < 0 ? str_pad($part,$limit,chr(0),STR_PAD_RIGHT) : $part];
			else:
				hash_update($md5,$part);
				$requests []= ['file_id'=>$fileId,'file_part'=>intval($offset / $limit),'bytes'=>$part];
			endif;
			$offset += $limit;
			if(strlen($part) !== $limit || boolval($size <= $offset and $size > 0)):
				$pause = true;
			endif;
			if(count($requests) === $this->settings->getParallelUploads() || $pause):
				finished:
				$clients->next();
				if($isBig):
					$areSaved = $clients->current()->upload->saveBigFilePartMultiple(...$requests,responses : true);
				else:
					$areSaved = $clients->current()->upload->saveFilePartMultiple(...$requests,responses : true);
				endif;
				$requests = array();
				if(in_array(false,$areSaved,true) === false):
					if($size > 0 and empty($areSaved) === false):
						$percent = min(100,($offset / $size) * 100);
						if(is_null($progresscallback) === false):
							if(async($progresscallback(...),$percent)->await() === false):
								Logging::log('Upload','Canceled !',E_WARNING);
								throw new \RuntimeException('Upload canceled !');
							endif;
						else:
							Logging::log('Upload',$percent.'%');
						endif;
					endif;
				else:
					throw new \RuntimeException('Failed to upload file parts !');
				endif;
			endif;
		endwhile;
		$finish = microtime(true);
		Logging::log('Upload','Average upload speed : '.round(floatval($offset / ($finish - $start)) / 1024 / 1024,2).' Mb/s');
		$parts = intval($offset / $limit);
		$filename = strval('DC_'.$dc_id.'_size_'.$size.'_FILE_ID_'.$fileId);
		if(is_null($key) === false and is_null($iv) === false):
			$hash = new Binary();
			$hash->write(md5($key.$iv,true));
			$fingerprint = $hash->readInt() ^ $hash->readInt();
			return $isBig ? $this->inputEncryptedFileBigUploaded(id : $fileId,parts : $parts,key_fingerprint : $fingerprint) : $this->inputEncryptedFileUploaded(id : $fileId,parts : $parts,md5_checksum : hash_final($md5,true),key_fingerprint : $fingerprint);
		else:
			return $isBig ? $this->inputFileBig(id : $fileId,parts : $parts,name : $filename) : $this->inputFile(id : $fileId,parts : $parts,name : $filename,md5_checksum : hash_final($md5,true));
		endif;
	}
	public function upload_callback(
		callable $lambda,
		int $size = -1,
		? int $dc_id = null,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null
	) : object {
		$generator = $this->upload_chunks($size,$dc_id,$progresscallback,$key,$iv);
		while($generator->valid()):
			$buffer = call_user_func($lambda,$generator->value(),$generator->key());
			$generator->send($buffer);
		endwhile;
		return $generator->getReturn();
	}
	public function upload_file(
		string $path,
		? int $dc_id = null,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null
	) : object {
		if(isFile($path)):
			$size = getSize($path);
			$generator = $this->upload_chunks($size,$dc_id,$progresscallback,$key,$iv);
			$stream = openFile($path,'rb');
			Logging::log('Upload','Start uploading the '.basename($path).' file ...');
			while($generator->valid()):
				$buffer = $stream->read($generator->key());
				$generator->send($buffer);
			endwhile;
			$stream->close();
			Logging::log('Upload','Finish uploading the '.basename($path).' file ...');
			return $generator->getReturn();
		else:
			throw new \Exception('File '.$path.' not found !');
		endif;
	}
	public function upload_secret_file(string $path,mixed ...$arguments) : array {
		$arguments += ['key'=>random_bytes(32),'iv'=>random_bytes(32)];
		return array($this->upload_file($path,...$arguments),$arguments['key'],$arguments['iv']);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Crypto\Rle;

use Tak\Liveproto\Utils\Tools;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Instance;

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Enums\FileType;

use Tak\Liveproto\Enums\PhotoSizeType;

use Tak\Liveproto\Enums\TransferKind;

use Tak\Liveproto\Attributes\Type;

# https://github.com/tdlib/td/blob/master/td/telegram/files/FileLocation.hpp #
trait FileId {
	private const WEB_LOCATION_FLAG =  1 << 24;
	private const FILE_REFERENCE_FLAG = 1 << 25;
	public const REMOVE_PHOTO_VOLUME_AND_LOCALID = 32;
	public const ADD_PHOTO_SIZE_SOURCE = 22;

	public function from_file_id(string $file_id) : object {
		$file = Rle::decode(Tools::base64_url_decode($file_id));
		$version = ord(substr($file,-1,1));
		$subVersion = intval($version >= 4 ? ord(substr($file,-2,1)) : 0);
		$reader = new Binary();
		$reader->write($file);
		$type = $reader->readInt();
		$dc = $reader->readInt();
		$fileReference = ($type & self::FILE_REFERENCE_FLAG ? $reader->readBytes() : null);
		$url = ($type & self::WEB_LOCATION_FLAG ? $reader->readBytes() : null);
		$type &= ~ self::FILE_REFERENCE_FLAG;
		$type &= ~ self::WEB_LOCATION_FLAG;
		if($type < 0 or $type >= FileType::SIZE->toId()):
			Logging::log('FileId','Invalid FileType !',E_ERROR);
		endif;
		if(is_null($url) === false):
			$accessHash = $reader->readLong();
			$headers = get_headers($url,true);
			$size = 0;
			$mimeType = null;
			if($headers !== false):
				$headers = array_change_key_case($headers,CASE_LOWER);
				if(isset($headers['content-length'])):
					$size = $headers['content-length'];
				endif;
				if(isset($headers['content-type'])):
					$mimeType = $headers['content-type'];
				endif;
			endif;
			$input = $this->inputWebDocument(url : $url,size : $size,mime_type : $mimeType,attributes : array($this->documentAttributeFilename(file_name : basename($url))));
			$data = array(
				'version'=>$version,
				'sub_version'=>$subVersion,
				'dc_id'=>$dc,
				'file_reference'=>$fileReference,
				'url'=>$url,
				'access_hash'=>$accessHash,
				'input_location'=>$input
			);
			$anonymous = new class($data) extends Instance {
				public function download(mixed $to,mixed ...$args) : mixed {
					return $this->download_web_document($to,$this->input_location,...$args);
				}
			};
			return $anonymous->setClient($this);
		else:
			$id = $reader->readLong();
			$accessHash = $reader->readLong();
			$input = $this->inputDocumentFileLocation(id : $id,access_hash : $accessHash,file_reference : $fileReference,thumb_size : strval(null));
		endif;
		$volumeId = null;
		$localId = null;
		$secret = null;
		if($type <= FileType::PHOTO->toId()):
			if($subVersion >= self::REMOVE_PHOTO_VOLUME_AND_LOCALID):
				$source = $reader->readInt();
			else:
				$volumeId = $reader->readLong();
				if($subVersion >= self::ADD_PHOTO_SIZE_SOURCE):
					# PhotoSizeType::LEGACY #
					$source = $reader->readInt();
				else:
					# PhotoSizeType::FULL_LEGACY #
					$source = PhotoSizeType::FULL_LEGACY->value;
				endif;
			endif;
			$photoSizeType = PhotoSizeType::from($source);
			switch($photoSizeType):
				case PhotoSizeType::LEGACY:
					$secret = $reader->readLong();
					$localId = $reader->readInt();
					$input = $this->inputPhotoLegacyFileLocation(id : $id,access_hash : $accessHash,file_reference : $fileReference,volume_id : $volumeId,local_id : $localId,secret : $secret);
					break;
				case PhotoSizeType::THUMBNAIL:
					$type = $reader->readInt();
					$input = $this->inputPhotoFileLocation(id : $id,access_hash : $accessHash,file_reference : $fileReference,thumb_size : chr($reader->readInt()));
					break;
				case PhotoSizeType::DIALOGPHOTO_SMALL:
				case PhotoSizeType::DIALOGPHOTO_BIG:
					$dialogId = $reader->readLong();
					$dialogAccessHash = $reader->readLong();
					$input = $this->inputPeerPhotoFileLocation(peer : $this->get_input_peer($dialogId,$dialogAccessHash),photo_id : $id,big : ($photoSizeType === PhotoSizeType::DIALOGPHOTO_BIG ? true : null));
					break;
				case PhotoSizeType::STICKERSET_THUMBNAIL:
					$stickerSetId = $reader->readLong();
					$stickerSetAccessHash = $reader->readLong();
					$input = $this->inputStickerSetThumb(stickerset : $this->inputStickerSetID(id : $stickerSetId,access_hash : $stickerSetAccessHash),thumb_version : 0);
					break;
				case PhotoSizeType::FULL_LEGACY:
					$secret = $reader->readLong();
					$localId = $reader->readInt();
					$input = $this->inputPhotoLegacyFileLocation(id : $id,access_hash : $accessHash,file_reference : $fileReference,volume_id : $volumeId,local_id : $localId,secret : $secret);
					break;
				case PhotoSizeType::DIALOGPHOTO_SMALL_LEGACY:
				case PhotoSizeType::DIALOGPHOTO_BIG_LEGACY:
					$dialogId = $reader->readLong();
					$dialogAccessHash = $reader->readLong();
					$input = $this->inputPeerPhotoFileLocation(peer : $this->get_input_peer($dialogId,$dialogAccessHash),photo_id : $id,big : ($photoSizeType === PhotoSizeType::DIALOGPHOTO_BIG_LEGACY ? true : null));
					break;
				case PhotoSizeType::STICKERSET_THUMBNAIL_LEGACY:
					$stickerSetId = $reader->readLong();
					$stickerSetAccessHash = $reader->readLong();
					$input = $this->inputStickerSetThumb(stickerset : $this->inputStickerSetID(id : $stickerSetId,access_hash : $stickerSetAccessHash),thumb_version : 0);
					break;
				case PhotoSizeType::STICKERSET_THUMBNAIL_VERSION:
					$stickerSetId = $reader->readLong();
					$stickerSetAccessHash = $reader->readLong();
					$stickerThumbVersion = $reader->readInt();
					$input = $this->inputStickerSetThumb(stickerset : $this->inputStickerSetID(id : $stickerSetId,access_hash : $stickerSetAccessHash),thumb_version : $stickerThumbVersion);
					break;
			endswitch;
			if(is_null($localId) and $subVersion < self::REMOVE_PHOTO_VOLUME_AND_LOCALID):
				$localId = $reader->readInt();
			endif;
		endif;
		$x = strlen($reader->read());
		$x -= intval($version >= 4 ? 2 : 1);
		if($x > 0):
			Logging::log('FileId','File ID '.$file_id.' has '.strval($x).' bytes left !',E_WARNING);
		endif;
		$data = array(
			'version'=>$version,
			'sub_version'=>$subVersion,
			'dc_id'=>$dc,
			'file_reference'=>$fileReference,
			'file_type'=>FileType::fromId($type),
			'id'=>$id,
			'access_hash'=>$accessHash,
			'volume_id'=>$volumeId,
			'local_id'=>$localId,
			'input_location'=>$input
		);
		$anonymous = new class($data) extends Instance {
			public function download(mixed $destination,mixed ...$args) : mixed {
				return $this->perform_download($destination,-1,$this->dc_id,$this->input_location,...$args);
			}
			/*
			public function getMessageMedia() : object {
				switch($this->file_type):
					case FileType::PROFILE_PHOTO:
						$download = $this->download_chunks(-1,$this->dc_id,$this->input_location);
						$upload = $this->upload_chunks($size,$this->dc_id);
						foreach($download as $buffer):
							if($upload->valid()):
								$upload->send($buffer);
							endif;
						endforeach;
						$upload->getReturn();
						break;
				endswitch;
			}
			*/
		};
		return $anonymous->setClient($this);
	}
	protected function to_file_id(
		FileType $file_type,
		int $dc_id,
		#[Type('InputFileLocation')] Instance $input_location,
		int $version = 4,
		int $sub_version = 54
	) : string {
		$type = $file_type->toId();
		if(isset($input_location->file_reference)):
			$type |= self::FILE_REFERENCE_FLAG;
		endif;
		if(isset($input_location->url)):
			$type |= self::WEB_LOCATION_FLAG;
		endif;
		$writer = new Binary();
		$writer->writeInt($type);
		$writer->writeInt($dc_id);
		if(isset($input_location->file_reference)):
			$writer->writeBytes($input_location->file_reference);
		endif;
		if(isset($input_location->url)):
			$writer->writeBytes($input_location->url);
			$writer->writeLong(0);
			if($version === 4):
				$writer->writeByte($sub_version);
			endif;
			$writer->writeByte($version);
			$file = $writer->read();
			return Tools::base64_url_encode(Rle::encode($file));
		endif;
		switch($input_location->getClass()):
			case 'inputPhotoFileLocation':
			case 'inputDocumentFileLocation':
				$writer->writeLong($input_location->id);
				$writer->writeLong($input_location->access_hash);
				if(empty($input_location->thumb_size) === false):
					$writer->writeInt(PhotoSizeType::THUMBNAIL->value);
					$writer->writeInt($file_type->toId());
					$writer->writeInt(ord($input_location->thumb_size));
				endif;
				break;
			case 'inputPhotoLegacyFileLocation':
				$writer->writeLong($input_location->id);
				$writer->writeLong($input_location->access_hash);
				$writer->writeLong($input_location->volume_id);
				$writer->writeLong($input_location->secret);
				$writer->writeInt($input_location->local_id);
				break;
			case 'inputPeerPhotoFileLocation':
				$writer->writeLong($input_location->photo_id);
				$writer->writeLong(0);
				$writer->writeInt($input_location->big ? PhotoSizeType::DIALOGPHOTO_BIG->value : PhotoSizeType::DIALOGPHOTO_SMALL->value);
				$writer->writeLong(match($input_location->peer->getClass()){
					'inputPeerEmpty' => 0,
					'inputPeerSelf' => intval($this->get_peer('me')->id),
					'inputPeerChat' => $input_location->peer->chat_id,
					'inputPeerUser' => $input_location->peer->user_id,
					'inputPeerChannel' => $input_location->peer->channel_id
				});
				$writer->writeLong(match($input_location->peer->getClass()){
					'inputPeerEmpty' => 0,
					'inputPeerSelf' => intval($this->get_peer('me')->access_hash),
					'inputPeerChat' => 0,
					'inputPeerUser' => $input_location->peer->access_hash,
					'inputPeerChannel' => $input_location->peer->access_hash
				});
				break;
			case 'inputStickerSetThumb':
				$writer->writeLong(0);
				$writer->writeLong(0);
				$writer->writeInt($input_location->thumb_version === 0 ? PhotoSizeType::STICKERSET_THUMBNAIL->value : PhotoSizeType::STICKERSET_THUMBNAIL_VERSION->value);
				$writer->writeLong($input_location->stickerset->id);
				$writer->writeLong($input_location->stickerset->access_hash);
				if($input_location->thumb_version !== 0):
					$writer->writeInt($input_location->thumb_version);
				endif;
				break;
			default:
				throw new \InvalidArgumentException('The input location '.$input_location->getClass().' is not valid');
		endswitch;
		if($version >= 4):
			$writer->writeByte($sub_version);
		endif;
		$writer->writeByte($version);
		$file = $writer->read();
		return Tools::base64_url_encode(Rle::encode($file));
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Crypto\Aes;

use Tak\Liveproto\Errors\Security;

use Tak\Liveproto\Errors\RpcError;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Enums\TransferKind;

use Tak\Liveproto\Attributes\Type;

use ArrayIterator;

use InfiniteIterator;

use Throwable;

use Generator;

use function Tak\Asyncio\async;

use function Tak\Asyncio\File\openFile;

use function Tak\Asyncio\File\isDirectory;

use function Tak\Asyncio\File\move;

trait Download {
	private const ONE_MB = (1 << 20);
	private const ALIGNMENT_DEFAULT = (1 << 12);
	private const ALIGNMENT_PRECISE = (1 << 10);

	private function align_range(int $offset,int $limit,bool $precise) : array {
		$chunkStart = intdiv($offset,self::ONE_MB) * self::ONE_MB;
		$chunkEnd = $chunkStart + self::ONE_MB - 1;
		$align = intval($precise ? self::ALIGNMENT_PRECISE : self::ALIGNMENT_DEFAULT);
		$offset = intdiv($offset,$align) * $align;
		$offset = max($offset,$chunkStart);
		$maxLimitInChunk = intval($chunkEnd - $offset + 1);
		if($precise):
			$limit = intdiv($limit + $align - 1,$align) * $align;
			$limit = min($limit,self::ONE_MB);
			if($limit > $maxLimitInChunk):
				$limit = intdiv($maxLimitInChunk,$align) * $align;
			endif;
		else:
			$allowed = array(0x100000,0x80000,0x40000,0x20000,0x10000,0x8000,0x4000,0x2000,0x1000);
			if($filtered = array_filter($allowed,fn(int $v) : bool => boolval($v <= $maxLimitInChunk))):
				$limit = max($filtered);
			else:
				throw new \InvalidArgumentException('No valid limit !');
			endif;
		endif;
		/*
		 * Next line is not documented anywhere
		 * So I'm not sure if it's even necessary for the offset to be divisible by the limit
		 */
		$offset = intdiv($offset,$limit) * $limit;
		if(intdiv($offset,self::ONE_MB) !== intdiv($offset + $limit - 1,self::ONE_MB)):
			throw new \InvalidArgumentException('Crosses 1MB chunk !');
		endif;
		return array($offset,$limit);
	}
	public function inputify_file_location(object $media,? string $thumb_size = null) : object {
		$className = $media->getClass();
		return match($className){
			'photo' => $this->inputPhotoFileLocation(id : $media->id,access_hash : $media->access_hash,file_reference : $media->file_reference,thumb_size : strval($thumb_size)),
			'document' => $this->inputDocumentFileLocation(id : $media->id,access_hash : $media->access_hash,file_reference : $media->file_reference,thumb_size : strval($thumb_size)),
			'encryptedFile' => $this->inputEncryptedFileLocation(id : $media->id,access_hash : $media->access_hash),
			'user' , 'chat' , 'channel' => $this->inputPeerPhotoFileLocation(peer : $this->get_input_peer($media->id),photo_id : $media->photo->photo_id,big : true),
			'stickerSet' => $this->inputStickerSetThumb(stickerset : $this->inputStickerSetID(id : $media->id,access_hash : $media->access_hash),thumb_version : intval($media->thumb_version)),
			default => throw new \InvalidArgumentException('The media ( '.$className.' ) is invalid or not supported !')
		};
	}
	protected function perform_download(
		mixed $destination,
		int $size,
		int $dc_id,
		#[Type('InputFileLocation')] object $location,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		TransferKind $transfer_kind = TransferKind::FILE,
		? string $mime_type = null
	) : mixed {
		switch($transfer_kind):
			case TransferKind::FILE:
				return $this->download_file(strval($destination),strval($mime_type),$size,$dc_id,$location,$progresscallback,$key,$iv);
			case TransferKind::STREAM:
				return $this->download_chunks($size,$dc_id,$location,$progresscallback,$key,$iv);
			case TransferKind::BROWSER:
				return $this->download_browser(strval($destination),strval($mime_type),$size,$dc_id,$location,$progresscallback,$key,$iv);
			default:
				throw new \InvalidArgumentException('Transfer kind '.$transfer_kind->value.' is not yet supported !');
		endswitch;
	}
	protected function apply_raw_buffer(
		mixed $destination,
		string $bytes,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		TransferKind $transfer_kind = TransferKind::FILE,
		? string $mime_type = null
	) : mixed {
		if(is_null($key) === false and is_null($iv) === false):
			$bytes = Aes::decrypt($bytes,$key,$iv);
		endif;
		if(is_null($progresscallback) === false):
			if(async($progresscallback(...),floatval(100))->await() === false):
				Logging::log('Download','Canceled !',E_WARNING);
				throw new \RuntimeException('Download canceled !');
			endif;
		else:
			Logging::log('Download','100%');
		endif;
		switch($transfer_kind):
			case TransferKind::FILE:
				if(isDirectory($destination)):
					$destination = $destination.DIRECTORY_SEPARATOR.md5($bytes);
				endif;
				$stream = openFile($destination,'wb');
				$stream->write($bytes);
				$stream->close();
				if(empty(pathinfo($destination,PATHINFO_EXTENSION))):
					$extension = $this->getFileExtension($mime_type ?: strval(mime_content_type($destination)));
					if(empty($extension) === false):
						$newpath = $destination.chr(46).$extension;
						move($destination,$newpath);
						return $newpath;
					endif;
				endif;
				return $destination;
			case TransferKind::STREAM:
				yield $bytes;
			case TransferKind::BROWSER:
				$extension = $this->getFileExtension($mime_type);
				$filename = md5($bytes).(empty($extension) ? null : chr(46).$extension);
				set_time_limit(0);
				ignore_user_abort(false);
				header('HTTP/1.1 200 OK');
				header('Content-Type: application/octet-stream');
				header('Content-Length: '.strlen($bytes));
				header('Content-Disposition: attachment; filename='.rawurlencode($filename));
				header('Cache-Control: private, must-revalidate');
				header('Pragma: public');
				if($_SERVER['REQUEST_METHOD'] === 'HEAD'):
					return null;
				endif;
				if(connection_aborted()):
					Logging::log('Download','Connection aborted : client disconnected !',E_WARNING);
					return null;
				else:
					echo($bytes);
					flush();
				endif;
				return 200;
			default:
				throw new \InvalidArgumentException('Transfer kind '.$transfer_kind->value.' is not yet supported !');
		endswitch;
	}
	protected function download_chunks(
		int $size,
		int $dc_id,
		#[Type('InputFileLocation')] object $location,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		int $offset = 0,
		int $limit = 1024
	) : Generator {
		$partSizeKB = ($size < 0x80000 ? 128 : ($size < 0x100000 ? 256 : 512));
		$limit = intval($size > 0 ? $partSizeKB : $limit) * 1024;
		list($offset,$limit) = $this->align_range($offset,$limit,false);
		$client = $this->switchDC(dc_id : $dc_id,media : true,renew : true);
		try {
			$getFile = $client->upload->getFile(location : $location,offset : $offset,limit : $limit,cdn_supported : true,timeout : 10);
		} catch(RpcError $error){
			if($error->getCode() == 303):
				$dc_id = $error->getValue();
				return $this->download_chunks($size,$dc_id,$location,$progresscallback,$key,$iv,$offset,$limit);
			else:
				throw $error;
			endif;
		}
		$processes = array();
		$pause = false;
		$connections = boolval($size < 10 * 1024 * 1024) ? array($client) : $this->getMediaConnections(dc_id : $dc_id,pfs : true,count : match(true){
			boolval($size >= 10 * 1024 * 1024 and $size < 30 * 1024 * 1024) => 1,
			boolval($size >= 30 * 1024 * 1024 and $size < 50 * 1024 * 1024) => 2,
			boolval($size >= 50 * 1024 * 1024 and $size < 200 * 1024 * 1024) => 3,
			default => null
		});
		Logging::log('Download','A total of '.count($connections).' connections were received');
		$clients = new InfiniteIterator(new ArrayIterator($connections));
		if($getFile instanceof \Tak\Liveproto\Tl\Types\Upload\FileCdnRedirect):
			$client = $this->switchDC(dc_id : $getFile->dc_id,cdn : true,media : true,renew : true);
			while($size > $offset or $size <= 0):
				$cdnFile = $client->upload->getCdnFile(file_token : $getFile->file_token,offset : $offset,limit : $limit,timeout : 10);
				if($cdnFile instanceof \Tak\Liveproto\Tl\Types\Upload\CdnFileReuploadNeeded):
					try {
						$client->upload->reuploadCdnFile(file_token : $getFile->file_token,request_token : $cdnFile->request_token);
						continue;
					} catch(Throwable $error){
						Logging::log('Download Cdn',$error->getMessage(),E_ERROR);
						break;
					}
				endif;
				$key = $getFile->encryption_key;
				$iv = substr($getFile->encryption_iv,0,-4).pack('N',$offset >> 4);
				$cdnFile->bytes = openssl_decrypt($cdnFile->bytes,'AES-256-CTR',$key,OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,$iv);
				$hashes = $client->upload->getCdnFileHashes(file_token : $getFile->file_token,offset : $offset);
				foreach($hashes as $i => $value):
					$hash = substr($cdnFile->bytes,$value->limit * $i,$value->limit);
					assert($value->hash === hash('sha256',$hash,true),new Security('File validation failed !'));
				endforeach;
				$offset += strlen($cdnFile->bytes);
				$pointer = yield $offset => $cdnFile->bytes;
				if(is_int($pointer)):
					list($offset,$limit) = $this->align_range($pointer,$limit,false);
					Logging::log('Download Cdn','New status offset = '.$offset.' & limit = '.$limit);
					continue;
				endif;
				if(is_null($cdnFile->bytes) || $limit > strlen($cdnFile->bytes)) break;
				if($size > 0):
					$percent = min(100,($offset / $size) * 100);
					if(is_null($progresscallback) === false):
						if(async($progresscallback(...),$percent)->await() === false):
							Logging::log('Download Cdn','Canceled !',E_WARNING);
							throw new \RuntimeException('Download from Cdn canceled !');
						endif;
					else:
						Logging::log('Download Cdn',$percent.'%');
					endif;
				endif;
			endwhile;
		elseif($getFile instanceof \Tak\Liveproto\Tl\Types\Upload\File):
			$start = microtime(true);
			while($pause === false):
				$requests = array();
				for($i = 0;$i < $this->settings->getParallelDownloads();$i++):
					$requests []= ['location'=>$location,'offset'=>$offset,'limit'=>$limit,'precise'=>true,'timeout'=>10];
					$offset += $limit;
					if($size <= $offset and $size > 0):
						$pause = true;
						break;
					endif;
				endfor;
				$clients->next();
				$dispatcher = $clients->current()->upload->getFileMultiple(...);
				$processes[$offset] = async(function() use($dispatcher,$key,$iv,$requests) : array {
					$files = $dispatcher(...$requests,cooldown : 0.1,responses : true);
					foreach($files as $index => $file):
						if(is_null($key) === false and is_null($iv) === false):
							$file->bytes = Aes::decrypt($file->bytes,$key,$iv);
						endif;
						$file->offset = $requests[$index]['offset'];
					endforeach;
					return $files;
				});
				foreach($processes as $parts => $future):
					if($pause || $future->isComplete() || count($processes) >= $this->settings->getMediaWorkers()):
						$results = $future->await();
						unset($processes[$parts]);
						foreach($results as $result):
							$pointer = yield $result->offset => $result->bytes;
							if(is_int($pointer)):
								list($offset,$limit) = $this->align_range($pointer,$limit,false);
								Logging::log('Download','New status offset = '.$offset.' & limit = '.$limit);
								if($size <= $offset and $size > 0):
									$pause = true;
								else:
									$processes = array();
									$pause = false;
								endif;
								break 2;
							endif;
							if(is_null($result->bytes) || $limit > strlen($result->bytes)) break;
						endforeach;
						if($size > 0):
							$percent = min(100,($parts / $size) * 100);
							if(is_null($progresscallback) === false):
								if(async($progresscallback(...),$percent)->await() === false):
									Logging::log('Download','Canceled !',E_WARNING);
									throw new \RuntimeException('Download canceled !');
								endif;
							else:
								Logging::log('Download',$percent.'%');
							endif;
						endif;
					else:
						break;
					endif;
				endforeach;
			endwhile;
			$finish = microtime(true);
			Logging::log('Download','Average download speed : '.round(floatval($offset / ($finish - $start)) / 1024 / 1024,2).' Mb/s');
		endif;
	}
	protected function download_browser(
		string $path,
		string $mime_type,
		int $size,
		int $dc_id,
		#[Type('InputFileLocation')] object $location,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null
	) : ? int {
		if(headers_sent()):
			throw new \RuntimeException('Headers already sent');
		endif;
		$start = 0;
		$end = $size - 1;
		$statusCode = 200;
		$extension = $this->getFileExtension($mime_type);
		$filename = empty($path) ? md5(serialize($location)).(empty($extension) ? null : chr(46).$extension) : $path;
		if(empty($_SERVER['HTTP_RANGE']) === false):
			if(preg_match('/bytes=(?<rstart>\d*)-(?<rend>\d*)/',trim($_SERVER['HTTP_RANGE']),$match)):
				$rstart = intval($match['rstart']);
				$rend = intval($match['rend']);
				switch(strval(null)):
					case $match['rstart']:
						$start = intval($rend >= $size ? 0 : $size - $rend);
						break;
					case $match['rend']:
						$start = $rstart;
						break;
					default:
						$start = $rstart;
						$end = min($end,$rend);
						break;
				endswitch;
				if($start > $end || $start < 0 || $end >= $size):
					header('HTTP/1.1 416 Range Not Satisfiable');
					header('Content-Range: bytes */'.$size);
					Logging::log('Download','Range not satisfiable !',E_WARNING);
					return null;
				endif;
				$statusCode = 206;
			endif;
		endif;
		$length = intval($end - $start + 1);
		set_time_limit(0);
		ignore_user_abort(false);
		if($statusCode === 206):
			header('HTTP/1.1 206 Partial Content');
		else:
			header('HTTP/1.1 200 OK');
		endif;
		header('Content-Type: application/octet-stream');
		header('Accept-Ranges: bytes');
		header('Content-Length: '.$length);
		if($statusCode === 206):
			header('Content-Range: bytes '.$start.'-'.$end.'/'.$size);
		endif;
		header('Content-Disposition: attachment; filename='.rawurlencode($filename));
		header('Cache-Control: private, must-revalidate');
		header('Pragma: public');
		if($_SERVER['REQUEST_METHOD'] === 'HEAD'):
			return null;
		endif;
		$isFirst = true;
		$isLast = false;
		try {
			$generator = $this->download_chunks($size,$dc_id,$location,$progresscallback,$key,$iv,$start);
			foreach($generator as $offset => $buffer):
				if(connection_aborted()):
					Logging::log('Download','Connection aborted : client disconnected !',E_WARNING);
					return null;
				else:
					if($isFirst):
						$buffer = substr($buffer,$start - $offset);
						$isFirst = false;
					endif;
					$length -= strlen($buffer);
					if($length < 0):
						$buffer = substr($buffer,0,$length);
						$isLast = true;
					endif;
					echo($buffer);
					flush();
					if($isLast) break;
				endif;
			endforeach;
		} catch(Throwable $error){
			header('HTTP/1.1 500 Server error');
			throw $error;
		}
		return $statusCode;
	}
	protected function download_file(
		string $path,
		string $mime_type,
		int $size,
		int $dc_id,
		#[Type('InputFileLocation')] object $location,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null
	) : string {
		$generator = $this->download_chunks($size,$dc_id,$location,$progresscallback,$key,$iv);
		if(isDirectory($path)):
			$path = $path.DIRECTORY_SEPARATOR.md5(serialize($location));
		endif;
		$stream = openFile($path,'wb');
		Logging::log('Download','Start downloading the '.basename($path).' file ...');
		foreach($generator as $chunk):
			$stream->write($chunk);
		endforeach;
		$stream->close();
		try {
			if(empty(pathinfo($path,PATHINFO_EXTENSION))):
				$extension = $this->getFileExtension($mime_type ?: strval(mime_content_type($path)));
				if(empty($extension) === false):
					$newpath = $path.chr(46).$extension;
					move($path,$newpath);
					return $newpath;
				endif;
			endif;
		} catch(Throwable $error){
			Logging::log('Download','Could not change the '.basename($path).' file extension ...');
		}
		Logging::log('Download','Finish downloading the '.basename($path).' file ...');
		return $path;
	}
	protected function download_photo(
		mixed $to,
		#[Type('MessageMediaPhoto','Photo')] object $file,
		bool $big = true,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		TransferKind $transfer_kind = TransferKind::FILE
	) : mixed {
		if($file instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaPhoto):
			$file = $file->photo ? $file->photo : throw new \InvalidArgumentException('The message does not contain the photo property !');
		endif;
		if($file instanceof \Tak\Liveproto\Tl\Types\Other\Photo):
			$dc_id = $file->dc_id;
			if($big):
				$file->sizes = $this->photoCachedIgnore($file->sizes);
			endif;
			$photoSize = end($file->sizes);
			if(in_array($photoSize->getClass(),array('photoCachedSize','photoPathSize','photoStrippedSize'))):
				return $this->apply_raw_buffer($to,$this->fetchCachedPhoto($photoSize),$progresscallback,$key,$iv,$transfer_kind);
			endif;
			$type = $photoSize->type;
			$size = $this->getPhotoSize($photoSize);
			$location = $this->inputPhotoFileLocation(id : $file->id,access_hash : $file->access_hash,file_reference : $file->file_reference,thumb_size : $type);
			return $this->perform_download($to,$size,$dc_id,$location,$progresscallback,$key,$iv,$transfer_kind);
		else:
			throw new \InvalidArgumentException('Your media does not contain photo !');
		endif;
	}
	protected function download_profile_photo(
		mixed $to,
		#[Type('User','Chat','Channel','UserFull','ChatFull','ChannelFull')] object $file,
		bool $big = true,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		TransferKind $transfer_kind = TransferKind::FILE
	) : mixed {
		if($file instanceof \Tak\Liveproto\Tl\Types\Other\User or $file instanceof \Tak\Liveproto\Tl\Types\Other\Chat or $file instanceof \Tak\Liveproto\Tl\Types\Other\Channel):
			$size = -1;
			$peer = $this->get_input_peer($file->id);
			$photo = $file->photo ? $file->photo : throw new \InvalidArgumentException('The user does not contain the photo property !');
			$dc_id = $photo->dc_id;
			$location = $this->inputPeerPhotoFileLocation(peer : $peer,photo_id : $photo->photo_id,big : $big);
			return $this->perform_download($to,$size,$dc_id,$location,$progresscallback,$key,$iv,$transfer_kind);
		elseif($file instanceof \Tak\Liveproto\Tl\Types\Other\UserFull):
			$photo = $file->profile_photo ? $file->profile_photo : throw new \InvalidArgumentException('The user does not contain the profile photo property !');
			return $this->download_photo($to,$photo,$big,$progresscallback,$key,$iv,$transfer_kind);
		elseif($file instanceof \Tak\Liveproto\Tl\Types\Other\ChatFull or $file instanceof \Tak\Liveproto\Tl\Types\Other\ChannelFull):
			$photo = $file->chat_photo ? $file->chat_photo : throw new \InvalidArgumentException('The user does not contain the chat photo property !');
			return $this->download_photo($to,$photo,$big,$progresscallback,$key,$iv);
		else:
			return $this->download_photo($to,$file,$big,$progresscallback,$key,$iv);
		endif;
	}
	protected function download_document(
		mixed $to,
		#[Type('MessageMediaDocument','Document')] object $file,
		bool $thumb = false,
		bool $big = true,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		TransferKind $transfer_kind = TransferKind::FILE
	) : mixed {
		if($file instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaDocument):
			$file = $file->document ? $file->document : throw new \InvalidArgumentException('The message does not contain the document property !');
		endif;
		if($file instanceof \Tak\Liveproto\Tl\Types\Other\Document):
			$dc_id = $file->dc_id;
			$size = $file->size;
			if($file->thumbs === null or $thumb === false):
				$type = strval(null);
			else:
				if($big):
					$file->thumbs = $this->photoCachedIgnore($file->thumbs);
				endif;
				$file->mime_type = 'image/png';
				$thumb = end($file->thumbs);
				if(in_array($thumb->getClass(),array('photoCachedSize','photoPathSize','photoStrippedSize'))):
					return $this->apply_raw_buffer($to,$this->fetchCachedPhoto($thumb),$progresscallback,$key,$iv,$transfer_kind);
				endif;
				$type = $thumb->type;
				$size = $this->getPhotoSize($thumb);
			endif;
			$location = $this->inputDocumentFileLocation(id : $file->id,access_hash : $file->access_hash,file_reference : $file->file_reference,thumb_size : $type);
			return $this->perform_download($to,$size,$dc_id,$location,$progresscallback,$key,$iv,$transfer_kind,$file->mime_type);
		else:
			throw new \InvalidArgumentException('Your media does not contain document !');
		endif;
	}
	public function download_web_document(
		mixed $to,
		#[Type('WebDocument','WebDocumentNoProxy','DecryptedMessageMediaWebPage','InputWebDocument')] object $file,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		TransferKind $transfer_kind = TransferKind::FILE
	) : mixed {
		$url = isset($file->url) ? $file->url : throw new \InvalidArgumentException('The web document does not contain the url property !');
		$mimeType = isset($file->mime_type) ? $file->mime_type : null;
		$headers = get_headers($url,true);
		if($headers !== false):
			$headers = array_change_key_case($headers,CASE_LOWER);
			if(isset($headers['content-type'])):
				$mimeType = $headers['content-type'];
			endif;
		endif;
		$buffer = @file_get_contents($url);
		if(is_string($buffer)):
			return $this->apply_raw_buffer($to,$buffer,$progresscallback,$key,$iv,$transfer_kind,$mimeType);
		else:
			throw new \RuntimeException('Error retrieving buffer : '.$url);
		endif;
	}
	protected function download_contact(
		mixed $to,
		#[Type('MessageMediaContact','InputMediaContact','BotInlineMessageMediaContact','InputBotInlineMessageMediaContact')] object $file,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		TransferKind $transfer_kind = TransferKind::FILE
	) : mixed {
		$vcard = isset($file->vcard) ? $file->vcard : throw new \InvalidArgumentException('The contact does not contain the vcard property !');
		return $this->apply_raw_buffer($to,$vcard,$progresscallback,$key,$iv,$transfer_kind,'text/vcard');
	}
	protected function download_secret_file(
		mixed $to,
		#[Type('UpdateNewEncryptedMessage','DecryptedMessage','EncryptedFile')] object $file,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		TransferKind $transfer_kind = TransferKind::FILE
	) : mixed {
		if($file instanceof \Tak\Liveproto\Tl\Types\Other\UpdateNewEncryptedMessage):
			$file = $file->decrypted;
		endif;
		if($file instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessage):
			if(is_object($file->media)):
				$key = $file->media->key;
				$iv = $file->media->iv;
				$file = $file->file;
			endif;
		endif;
		if($file instanceof \Tak\Liveproto\Tl\Types\Other\EncryptedFile):
			if(is_null($key) === false and is_null($iv) === false):
				$hash = new Binary();
				$hash->write(md5($key.$iv,true));
				$fingerprint = $hash->readInt() ^ $hash->readInt();
				if($fingerprint !== $file->key_fingerprint):
					throw new \LogicException('Invalid key fingerprint !');
				endif;
				$size = $file->size;
				$dc_id = $file->dc_id;
				$location = $this->inputEncryptedFileLocation(id : $file->id,access_hash : $file->access_hash);
				return $this->perform_download($to,$size,$dc_id,$location,$progresscallback,$key,$iv,$transfer_kind);
			else:
				throw new \InvalidArgumentException('The value of key and iv arguments should not be null !');
			endif;
		else:
			throw new \InvalidArgumentException('File object is not instance of EncryptedFile !');
		endif;
	}
	public function download_media(
		mixed $destination,
		object $media,
		bool $thumb = false,
		bool $big = true,
		? callable $progresscallback = null,
		? string $key = null,
		? string $iv = null,
		TransferKind $transfer_kind = TransferKind::FILE
	) : mixed {
		try {
			if($media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaContact or $media instanceof \Tak\Liveproto\Tl\Types\Other\InputMediaContact or $media instanceof \Tak\Liveproto\Tl\Types\Other\BotInlineMessageMediaContact or $media instanceof \Tak\Liveproto\Tl\Types\Other\InputBotInlineMessageMediaContact):
				return $this->download_contact($destination,$media,$progresscallback,$key,$iv,$transfer_kind);
			elseif($media instanceof \Tak\Liveproto\Tl\Types\Other\WebDocument or $media instanceof \Tak\Liveproto\Tl\Types\Other\WebDocumentNoProxy):
				return $this->download_web_document($destination,$media,$progresscallback,$key,$iv,$transfer_kind);
			elseif($media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaDocument or $media instanceof \Tak\Liveproto\Tl\Types\Other\Document):
				return $this->download_document($destination,$media,$thumb,$big,$progresscallback,$key,$iv,$transfer_kind);
			elseif($media instanceof \Tak\Liveproto\Tl\Types\Other\MessageMediaPhoto or $media instanceof \Tak\Liveproto\Tl\Types\Other\Photo):
				return $this->download_photo($destination,$media,$big,$progresscallback,$key,$iv,$transfer_kind);
			elseif($media instanceof \Tak\Liveproto\Tl\Types\Other\UpdateNewEncryptedMessage or $media instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessage or $media instanceof \Tak\Liveproto\Tl\Types\Other\EncryptedFile):
				return $this->download_secret_file($destination,$media,$progresscallback,$key,$iv,$transfer_kind);
			else:
				return $this->download_profile_photo($destination,$media,$big,$progresscallback,$key,$iv,$transfer_kind);
			endif;
		} catch(Throwable $e){
			error_log($e->getMessage());
			throw new \InvalidArgumentException('Invalid input media !',$e->getCode(),$e);
		}
	}
	protected function getPhotoSize(#[Type('PhotoSize')] object $photoSize) : int {
		return match($photoSize->getClass()){
			'photoSizeEmpty' => 0,
			'photoSize' => $photoSize->size,
			'photoSizeProgressive' => max($photoSize->sizes),
			'photoCachedSize' => strlen($photoSize->bytes),
			'photoPathSize' => strlen($this->decode_vector_thumbnail($photoSize->bytes)),
			'photoStrippedSize' => strlen($this->get_stripped_thumbnail($photoSize->bytes)),
			default => throw new \InvalidArgumentException('Unknown photoSize !')
		};
	}
	protected function fetchCachedPhoto(#[Type('PhotoSize')] object $photoSize) : string {
		return match($photoSize->getClass()){
			'photoStrippedSize' => $this->get_stripped_thumbnail($photoSize->bytes),
			'photoPathSize' => $this->decode_vector_thumbnail($photoSize->bytes),
			'photoCachedSize' => $photoSize->bytes,
			default => throw new \InvalidArgumentException('Invalid photoSize for get cache of it !')
		};
	}
	protected function photoCachedIgnore(#[Vector(new Type('PhotoSize'))] array $photoSizes) : object {
		$photoSizes = array_filter($photoSizes,fn(object $photoSize) : bool => in_array($photoSize->getClass(),array('photoCachedSize','photoStrippedSize')) === false);
		if(empty($photoSizes)):
			throw new \InvalidArgumentException('There is no PhotoSize that does not require caching');
		endif;
		return $photoSizes;
	}
	private function getFileExtension(object | string $type) : ? string {
		if(is_object($type)):
			/** @deprecated */
			return match(true){
				$type instanceof \Tak\Liveproto\Tl\Types\Storage\FileJpeg => 'jpeg',
				$type instanceof \Tak\Liveproto\Tl\Types\Storage\FileGif => 'gif',
				$type instanceof \Tak\Liveproto\Tl\Types\Storage\FilePng => 'png',
				$type instanceof \Tak\Liveproto\Tl\Types\Storage\FilePdf => 'pdf',
				$type instanceof \Tak\Liveproto\Tl\Types\Storage\FileMp3 => 'mp3',
				$type instanceof \Tak\Liveproto\Tl\Types\Storage\FileMov => 'mov',
				$type instanceof \Tak\Liveproto\Tl\Types\Storage\FileMp4 => 'mp4',
				$type instanceof \Tak\Liveproto\Tl\Types\Storage\FileWebp => 'webp',
				default => null
			};
		else:
			return match(strtolower($type)){
				'text/h323' => '323',
				'application/internet-property-stream' => 'acx',
				'application/postscript' => 'ps',
				'audio/x-aiff' => 'aiff',
				'video/x-ms-asf' => 'asx',
				'audio/basic' => 'snd',
				'video/x-msvideo' => 'avi',
				'application/olescript' => 'axs',
				'text/plain' => 'txt',
				'application/x-bcpio' => 'bcpio',
				'image/bmp' => 'bmp',
				'application/vnd.ms-pkiseccat' => 'cat',
				'application/x-netcdf' => 'nc',
				'application/x-x509-ca-cert' => 'der',
				'application/x-msclip' => 'clp',
				'image/x-cmx' => 'cmx',
				'image/cis-cod' => 'cod',
				'application/x-cpio' => 'cpio',
				'application/x-mscardfile' => 'crd',
				'application/pkix-crl' => 'crl',
				'application/x-csh' => 'csh',
				'text/css' => 'css',
				'application/x-director' => 'dir',
				'application/x-msdownload' => 'dll',
				'application/msword' => 'dot',
				'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx',
				'application/x-dvi' => 'dvi',
				'text/x-setext' => 'etx',
				'application/envoy' => 'evy',
				'application/fractals' => 'fif',
				'model/vrml' => 'vrml',
				'image/gif' => 'gif',
				'application/x-gtar' => 'gtar',
				'application/gzip' , 'application/x-gzip' => 'gz',
				'application/x-hdf' => 'hdf',
				'application/winhlp' => 'hlp',
				'application/mac-binhex40' => 'hqx',
				'application/hta' => 'hta',
				'text/x-component' => 'htc',
				'text/html' => 'html',
				'text/webviewhtml' => 'htt',
				'image/x-icon' => 'ico',
				'image/ief' => 'ief',
				'application/x-iphone' => 'iii',
				'application/x-internet-signup' => 'isp',
				'image/pipeg' => 'jfif',
				'image/jpeg' => 'jpeg',
				'image/png' => 'png',
				'application/x-javascript' => 'js',
				'application/x-latex' => 'latex',
				'video/x-la-asf' => 'lsx',
				'application/x-msmediaview' => 'mvb',
				'audio/x-mpegurl' => 'm3u',
				'application/x-troff-man' => 'man',
				'application/x-msaccess' => 'mdb',
				'application/x-troff-me' => 'me',
				'message/rfc822' => 'nws',
				'audio/mid' => 'rmi',
				'application/x-msmoney' => 'mny',
				'video/quicktime' => 'mov',
				'video/x-sgi-movie' => 'movie',
				'video/mpeg' => 'mpv2',
				'audio/mpeg' => 'mp3',
				'audio/ogg' => 'ogg',
				'application/vnd.ms-project' => 'mpp',
				'application/x-troff-ms' => 'ms',
				'application/vnd.ms-outlook' => 'msg',
				'application/oda' => 'oda',
				'application/pkcs10' => 'p10',
				'application/x-pkcs12' => 'pfx',
				'application/x-pkcs7-certificates' => 'spc',
				'application/x-pkcs7-mime' => 'p7m',
				'application/x-pkcs7-certreqresp' => 'p7r',
				'application/x-pkcs7-signature' => 'p7s',
				'image/x-portable-bitmap' => 'pbm',
				'application/pdf' => 'pdf',
				'image/x-portable-graymap' => 'pgm',
				'application/ynd.ms-pkipko' => 'pko',
				'application/x-perfmon' => 'pmw',
				'image/x-portable-anymap' => 'pnm',
				'application/vnd.ms-powerpoint' => 'ppt',
				'image/x-portable-pixmap' => 'ppm',
				'application/pics-rules' => 'prf',
				'application/x-mspublisher' => 'pub',
				'audio/x-pn-realaudio' => 'ram',
				'image/x-cmu-raster' => 'ras',
				'image/x-rgb' => 'rgb',
				'application/x-troff' => 'tr',
				'application/rtf' => 'rtf',
				'text/richtext' => 'rtx',
				'application/x-msschedule' => 'scd',
				'text/scriptlet' => 'sct',
				'application/set-payment-initiation' => 'setpay',
				'application/set-registration-initiation' => 'setreg',
				'application/x-sh' => 'sh',
				'application/x-shar' => 'shar',
				'application/x-stuffit' => 'sit',
				'application/futuresplash' => 'spl',
				'application/x-wais-source' => 'src',
				'application/vnd.ms-pkicertstore' => 'sst',
				'application/vnd.ms-pkistl' => 'stl',
				'application/x-sv4cpio' => 'sv4cpio',
				'application/x-sv4crc' => 'sv4crc',
				'image/svg+xml' => 'svg',
				'application/x-shockwave-flash' => 'swf',
				'application/x-tar' => 'tar',
				'application/x-tcl' => 'tcl',
				'application/x-tex' => 'tex',
				'application/x-texinfo' => 'texinfo',
				'application/x-compressed' => 'tgz',
				'image/tiff' => 'tiff',
				'application/x-msterminal' => 'trm',
				'text/tab-separated-values' => 'tsv',
				'text/iuls' => 'uls',
				'application/x-ustar' => 'ustar',
				'text/x-vcard' => 'vcf',
				'text/vcard' => 'vcard',
				'audio/x-wav' => 'wav',
				'application/vnd.ms-works' => 'wps',
				'application/x-msmetafile' => 'wmf',
				'application/x-mswrite' => 'wri',
				'wri' => 'application/x-mswrite',
				'image/x-xbitmap' => 'xbm',
				'image/x-xpixmap' => 'xpm',
				'image/x-xwindowdump' => 'xwd',
				'application/x-compress' => 'z',
				'image/webp' => 'webp',
				'application/zip' , 'application/x-zip-compressed' => 'zip',
				'video/mp4' => 'mp4',
				default => null
			};
		endif;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Errors\Security;

trait Utilities {
	public function getDhConfig() : object {
		$version = is_null($this->dhConfig) === false ? $this->dhConfig->version : 0;
		$getDhConfig = $this->messages->getDhConfig(version : $version,random_length : 0x100);
		if($getDhConfig instanceof \Tak\Liveproto\Tl\Types\Messages\DhConfig):
			$getDhConfig->p = strval(gmp_import($getDhConfig->p));
			Security::checkGoodPrime($getDhConfig->p,$getDhConfig->g);
			$this->dhConfig = $getDhConfig;
		elseif(is_null($this->dhConfig)):
			throw new \Exception('dh config not modified !');
		endif;
		return $this->dhConfig;
	}
	public function getMediaConnections(int $dc_id,bool $pfs = false,? int $count = null) : array {
		if(is_null($count) || $count <= 0):
			$count = $this->settings->getMinConnections();
		endif;
		$media = $this->mediaSocket($dc_id,$pfs);
		$new = min($count - count($media),$this->settings->getMaxConnections());
		if(count($media) < $this->settings->getMaxConnections()):
			if($new === 0) $new++;
		endif;
		if($new > 0):
			for($i = 0;$i < $new;$i++):
				$this->connections []= $pfs ? $this->getTemp(dc_id : $dc_id,expires_in : 24 * 60 * 60) : $this->switchDC(dc_id : $dc_id,media : true,renew : true);
			endfor;
		endif;
		$media = $this->mediaSocket($dc_id,$pfs);
		shuffle($media);
		return array_slice($media,- $count);
	}
	private function mediaSocket(int $dc_id,bool $pfs) : array {
		return array_filter($this->connections,fn(object $client) : bool => $client->load->dc === $dc_id and boolval($pfs === false || $client->load->expires_at > time()));
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Enums\PeerType;

use Tak\Liveproto\Attributes\Type;

use Throwable;

trait Peers {
	private const MIN_CHAT_ID = -999999999999;
	private const MIN_CHANNEL_ID = (1 << 31) - 2000000000000;
	private const MIN_MONOFORUM_CHANNEL_ID = -4000000000000;
	private const MAX_MONOFORUM_CHANNEL_ID = - (1 << 31) - 1 - 2000000000000;
	private const MIN_SECRET_CHAT_ID = - (1 << 31) - 2000000000000;

	public function get_input_peer(string | int | null | object $peer,int $hash = 0) : object {
		if(is_null($peer)):
			return $this->inputPeerEmpty();
		elseif(is_object($peer)):
			if(isset($peer->id) and is_int($peer->id)):
				return $this->get_input_peer($peer->id,$hash);
			elseif(isset($peer->user_id) and is_int($peer->user_id)):
				return $this->get_input_peer($peer->user_id,$hash);
			elseif(isset($peer->chat_id) and is_int($peer->chat_id)):
				return $this->get_input_peer($peer->chat_id,$hash);
			elseif(isset($peer->channel_id) and is_int($peer->channel_id)):
				return $this->get_input_peer($peer->channel_id,$hash);
			else:
				throw new \Error('A valid peer id was not found in your object');
			endif;
		elseif(is_string($peer)):
			if(in_array($peer,array('me','bot'))):
				return $this->inputPeerSelf();
			elseif(filter_var($peer,FILTER_VALIDATE_URL)):
				$path = parse_url($peer,PHP_URL_PATH);
				if(is_null($path) === false):
					$hash = trim(basename($path),chr(43));
					$checked = $this->messages->checkChatInvite($hash);
					if($checked instanceof \Tak\Liveproto\Tl\Types\Other\ChatInvite):
						throw new \BadMethodCallException('You must first use the `importChatInvite` method to join the chat');
					else:
						return $this->get_input_peer($checked->chat->id,isset($checked->chat->access_hash) ? $checked->chat->access_hash : 0);
					endif;
				else:
					throw new \InvalidArgumentException('This method only accepts private links for chats as https://t.me/+abcd...');
				endif;
			elseif(str_starts_with($peer,'+')):
				$phone = preg_replace('/[^0-9]/i',strval(null),$peer);
				$resolve = $this->contacts->resolvePhone($phone);
			else:
				$username = preg_replace('/[^a-z_0-9]/i',strval(null),$peer);
				$resolve = $this->contacts->resolveUsername($username);
			endif;
			return $this->get_input_peer($resolve->peer);
		elseif(is_int($peer)):
			if($peer < 0):
				if(self::MIN_CHAT_ID <= $peer):
					$peer = - $peer;
				elseif(self::MIN_CHANNEL_ID <= $peer):
					$peer = - $peer - 1000000000000;
				elseif(self::MIN_MONOFORUM_CHANNEL_ID <= $peer and self::MAX_MONOFORUM_CHANNEL_ID > $peer):
					$peer = - $peer - 1000000000000;
				elseif(self::MIN_SECRET_CHAT_ID <= $peer):
					$peer = $peer - 2000000000000;
				endif;
			endif;
			if($chat = $this->load->peers->getPeer(type : 'chats',by : 'id',what : $peer)):
				return $chat['access_hash'] ? $this->inputPeerChannel(channel_id : $peer,access_hash : $chat['access_hash']) : $this->inputPeerChat(chat_id : $peer);
			elseif($user = $this->load->peers->getPeer(type : 'users',by : 'id',what : $peer)):
				return $this->inputPeerUser(user_id : $peer,access_hash : $user['access_hash']);
			elseif($secret = $this->load->peers->getPeer(type : 'secrets',by : 'id',what : $peer)):
				return $this->inputEncryptedChat(chat_id : $peer,access_hash : $secret['access_hash']);
			else:
				try {
					$entity = $this->inputPeerUser(user_id : $peer,access_hash : $hash);
					$this->users->getFullUser($entity);
					/*
					 * Well, these results are automatically saved, so there's no need to save again
					 * $user = $this->users->getFullUser($entity)->users[false];
					 * $this->load->peers->setPeers(type : 'users',peers : [array('id'=>$user->id,'access_hash'=>intval($user->access_hash))]);
					 */
					return $entity;
				} catch(Throwable){
					try {
						$entity = $this->inputPeerChannel(channel_id : $peer,access_hash : $hash);
						$this->channels->getFullChannel($entity);
						/*
						 * Well, these results are automatically saved, so there's no need to save again
						 * $channel = $this->channels->getFullChannel($entity)->chats[false];
						 * $this->load->peers->setPeers(type : 'chats',peers : [array('id'=>$channel->id,'access_hash'=>intval($channel->access_hash))]);
						 */
						return $entity;
					} catch(Throwable){
						return $this->inputPeerChat(chat_id : $peer);
					}
				}
			endif;
		endif;
	}
	protected function get_input_peer_from_message(#[Type('Message')] object $message) : object {
		if(isset($message->from_id->user_id)):
			$inputPeer = $this->get_input_peer(peer : $message->peer_id);
			$entity = $this->inputPeerUserFromMessage(peer : $inputPeer,msg_id : $message->id,user_id : $message->from_id->user_id);
			if($this->load->peers->getPeer(type : 'users',by : 'id',what : $message->from_id->user_id) == false):
				$this->users->getFullUser($entity);
			endif;
			return $entity;
		elseif(isset($message->from_id->channel_id)):
			$inputPeer = $this->get_input_peer(peer : $message->peer_id);
			$entity = $this->inputPeerChannelFromMessage(peer : $inputPeer,msg_id : $message->id,channel_id : $message->from_id->channel_id);
			if($this->load->peers->getPeer(type : 'chats',by : 'id',what : $message->from_id->channel_id) == false):
				$this->channels->getFullChannel($entity);
			endif;
			return $entity;
		elseif(isset($message->from_id->chat_id)):
			return $this->inputPeerChat(chat_id : $message->from_id->chat_id);
		else:
			throw new \InvalidArgumentException('Field `from_id` is missing or invalid in the message');
		endif;
	}
	public function get_peer(string | int | object $peer) : object {
		$peer = $this->get_input_peer($peer);
		if(isset($peer->channel_id)):
			return $this->channels->getFullChannel($peer)->chats[false];
		elseif(isset($peer->chat_id)):
			return $this->messages->getFullChat($peer->chat_id)->chats[false];
		else:
			return $this->users->getFullUser($peer)->users[false];
		endif;
	}
	public function get_full_peer(string | int | object $peer) : object {
		$peer = $this->get_input_peer($peer);
		if(isset($peer->channel_id)):
			return $this->channels->getFullChannel($peer)->full_chat;
		elseif(isset($peer->chat_id)):
			return $this->messages->getFullChat($peer->chat_id)->full_chat;
		else:
			return $this->users->getFullUser($peer)->full_user;
		endif;
	}
	public function get_peer_id(string | int | object $peer) : int {
		$hash = md5(serialize($peer));
		$this->peersId = array_slice(array : $this->peersId,offset : -200,preserve_keys : true);
		if(key_exists($hash,$this->peersId) === false):
			$id = match(true){
				isset($peer->user_id) and is_int($peer->user_id) => $peer->user_id,
				isset($peer->chat_id) and is_int($peer->chat_id) => $peer->chat_id,
				isset($peer->channel_id) and is_int($peer->channel_id) => $peer->channel_id,
				default => $this->get_full_peer($peer)->id
			};
			$this->peersId[$hash] = $id;
		endif;
		return $this->peersId[$hash];
	}
	public function get_peer_type(string | int | object $peer) : object {
		$hash = md5(serialize($peer));
		$this->peersType = array_slice(array : $this->peersType,offset : -200,preserve_keys : true);
		if(key_exists($hash,$this->peersType) === false):
			$info = $this->get_peer($peer);
			if(str_contains(get_class($info),'User')):
				$this->peersType[$hash] = match(true){
					$info->self => PeerType::SELF,
					$info->bot => PeerType::BOT,
					default => PeerType::USER
				};
			elseif(str_contains(get_class($info),'Chat')):
				$this->peersType[$hash] = PeerType::CHAT;
			elseif(str_contains(get_class($info),'Channel')):
				$this->peersType[$hash] = match(true){
					$info->broadcast => PeerType::CHANNEL,
					$info->megagroup => PeerType::MEGAGROUP,
					$info->gigagroup => PeerType::GIGAGROUP
				};
			else:
				$this->peersType[$hash] = PeerType::UNKNOWN;
			endif;
		endif;
		return $this->peersType[$hash];
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Crypto\Password;

use Tak\Liveproto\Enums\EmailPurpose;

use Tak\Liveproto\Enums\Authentication;

trait Account {
	public function update_password(
		#[\SensitiveParameter] ? string $password = null,
		#[\SensitiveParameter] ? string $new = null,
		? string $hint = null,
		? string $email = null
	) : bool {
		$account = $this->account->getPassword();
		$account->new_algo->salt1 .= random_bytes(32);
		$checker = new Password();
		$password = is_null($password) ? (isset($this->load->password) ? $this->load->password : null) : $password;
		if(isset($account->has_password) === false and is_null($password) === false):
			$password = null;
		endif;
		if(is_null($password) === false):
			$password = $checker->srp($account,$password);
		else:
			$password = $this->inputCheckPasswordEmpty();
		endif;
		if(is_null($new) === false):
			$new_hash = $checker->digest($account,$new);
			$new_algo = $account->new_algo;
			$hint = strval($hint);
		else:
			$new_hash = null;
			$new_algo = null;
			$hint = null;
		endif;
		$new_settings = $this->account->passwordInputSettings(new_algo : $new_algo,new_password_hash : $new_hash,hint : $hint,email : $email);
		$result = $this->account->updatePasswordSettings(password : $password,new_settings : $new_settings);
		if(is_null($new) === false and $result === true):
			$this->load->password = $new;
		endif;
		return $result;
	}
	public function send_email_code(string $email,EmailPurpose $email_purpose = EmailPurpose::LOGINSETUP) : object {
		$purpose = $this->email_purpose($email_purpose);
		$result = $this->account->sendVerifyEmailCode(purpose : $purpose,email : $email);
		if($this->load->step === Authentication::NEED_EMAIL):
			if($result instanceof \Tak\Liveproto\Tl\Types\Account\SentEmailCode):
				$this->load->step = Authentication::NEED_EMAIL_VERIFY;
			endif;
		endif;
		return $result;
	}
	public function verify_email(string | int $code,EmailPurpose $email_purpose = EmailPurpose::LOGINSETUP) : object {
		$purpose = $this->email_purpose($email_purpose);
		$verification = $this->emailVerificationCode(code : strval($code));
		$result = $this->account->verifyEmail(purpose : $purpose,verification : $verification);
		if($result instanceof \Tak\Liveproto\Tl\Types\Account\EmailVerifiedLogin):
			$result->sent_code = $this->apply_sent_code($result->sent_code);
		endif;
		return $result;
	}
	private function email_purpose(EmailPurpose $purpose) : object {
		$args = match($purpose){
			EmailPurpose::LOGINSETUP => array('phone_number'=>$this->load->phonenumber,'phone_code_hash'=>$this->load->phonecodehash),
			EmailPurpose::LOGINCHANGE => array(),
			EmailPurpose::PASSPORT => array(),
			default => \Exception('Unknown email purpose !')
		};
		return call_user_func(array($this,$purpose->value),...$args);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Crypto\Aes;

use Tak\Liveproto\Errors\Security;

use Tak\Liveproto\Utils\Binary;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Enums\RekeyState;

use function Tak\Asyncio\File\getSize;

trait SecretChat {
	public function send_secret_message(
		string | int | object $peer,
		string $message,
		int $ttl,
		mixed ...$arguments
	) : object {
		$chat = $this->get_secret_chat($peer);
		$message = $this->secret->decryptedMessage(random_int(PHP_INT_MIN,PHP_INT_MAX),$ttl,$message,...$arguments);
		$data = $this->encrypt_secret_message($chat['id'],$message);
		$peer = $this->inputEncryptedChat(chat_id : $chat['id'],access_hash : $chat['access_hash']);
		return $this->messages->sendEncrypted(peer : $peer,random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),data : $data);
	}
	public function send_secret_file(
		string | int | object $peer,
		object $file,
		string $message,
		int $ttl,
		mixed ...$arguments
	) : object {
		$chat = $this->get_secret_chat($peer);
		$message = $this->secret->decryptedMessage(random_int(PHP_INT_MIN,PHP_INT_MAX),$ttl,$message,...$arguments);
		$data = $this->encrypt_secret_message($chat['id'],$message);
		$peer = $this->inputEncryptedChat(chat_id : $chat['id'],access_hash : $chat['access_hash']);
		return $this->messages->sendEncryptedFile(peer : $peer,random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),data : $data,file : $file);
	}
	public function send_secret_media(
		string | int | object $peer,
		string $path,
		string $caption,
		int $ttl
	) : object {
		list($file,$key,$iv) = $this->upload_secret_file($path);
		$mime = strval(mime_content_type($path));
		if(str_starts_with($mime,'image')):
			list($width,$height) = getimagesize($path);
			$media = $this->secret->decryptedMessageMediaPhoto(thumb : strval(null),thumb_w : 0,thumb_h : 0,w : $width,h : $height,size : getSize($path),key : $key,iv : $iv,caption : $caption);
		elseif(str_starts_with($mime,'video')):
			$media = $this->secret->decryptedMessageMediaVideo(thumb : strval(null),thumb_w : 0,thumb_h : 0,duration : $ttl,mime_type : $mime,w : 0,h : 0,size : getSize($path),key : $key,iv : $iv,caption : $caption);
		elseif(str_starts_with($mime,'audio')):
			# $media = $this->secret->decryptedMessageMediaAudio(duration : $ttl,mime_type : $mime,size : getSize($path),key : $key,iv : $iv);
			$attributes = array($this->secret->documentAttributeAudio(duration : $ttl));
			$media = $this->secret->decryptedMessageMediaDocument(thumb : strval(null),thumb_w : 0,thumb_h : 0,mime_type : $mime,size : getSize($path),key : $key,iv : $iv,attributes : $attributes,caption : $caption);
		else:
			$attributes = array($this->secret->documentAttributeFilename(file_name : $path));
			$media = $this->secret->decryptedMessageMediaDocument(thumb : strval(null),thumb_w : 0,thumb_h : 0,mime_type : $mime,size : getSize($path),key : $key,iv : $iv,attributes : $attributes,caption : $caption);
		endif;
		return $this->send_secret_file($peer,$file,$caption,$ttl,media : $media);
	}
	public function start_secret_chat(string | int | object $peer) : mixed {
		$user = $this->get_input_user($peer);
		$dhConfig = $this->getDhConfig();
		$a = gmp_import(random_bytes(0x100) ^ $dhConfig->random);
		$g_a = gmp_powm($dhConfig->g,$a,$dhConfig->p);
		Security::checkG(strval($g_a),strval($dhConfig->p),true);
		$result = $this->messages->requestEncryption(user_id : $user,random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),g_a : gmp_export($g_a));
		$string = gmp_export($a);
		$auth_key = str_pad($string,0x100,chr(0),STR_PAD_LEFT);
		$this->set_secret(id : $result->id,access_hash : (isset($result->access_hash) ? $result->access_hash : 0),peer : $result->participant_id,auth_key : $auth_key,layer : $this->layer(secret : true),temp : true);
		return $result;
	}
	public function accept_secret_chat(object $chat) : object {
		# encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat; #
		$dhConfig = $this->getDhConfig();
		$b = gmp_import(random_bytes(0x100) ^ $dhConfig->random);
		$g_a = gmp_import($chat->g_a);
		Security::checkG(strval($g_a),strval($dhConfig->p),true);
		$pow = gmp_powm($g_a,$b,$dhConfig->p);
		$string = gmp_export($pow);
		$auth_key = str_pad($string,0x100,chr(0),STR_PAD_LEFT);
		$writer = new Binary();
		$writer->write(substr(sha1($auth_key,true),-8));
		$keyfingerprint = $writer->readLong();
		$g_b = gmp_powm($dhConfig->g,$b,$dhConfig->p);
		Security::checkG(strval($g_b),strval($dhConfig->p),true);
		$peer = $this->inputEncryptedChat(chat_id : $chat->id,access_hash : $chat->access_hash);
		$result = $this->messages->acceptEncryption(peer : $peer,g_b : gmp_export($g_b),key_fingerprint : $keyfingerprint);
		$this->set_secret(id : $chat->id,access_hash : $chat->access_hash,peer : $chat->participant_id,auth_key : $auth_key,layer : $this->layer(secret : true));
		$this->notify_layer($chat->id);
		return $result;
	}
	public function finish_secret_chat_creation(object $chat) : void {
		# encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat; #
		$dhConfig = $this->getDhConfig();
		$g_a_or_b = gmp_import($chat->g_a_or_b);
		Security::checkG(strval($g_a_or_b),strval($dhConfig->p),true);
		$temp = $this->get_secret($chat->id);
		$a = gmp_import($temp['auth_key']);
		$pow = gmp_powm($g_a_or_b,$a,$dhConfig->p);
		$string = gmp_export($pow);
		$auth_key = str_pad($string,0x100,chr(0),STR_PAD_LEFT);
		$writer = new Binary();
		$writer->write(substr(sha1($auth_key,true),-8));
		$keyfingerprint = $writer->readLong();
		if($keyfingerprint !== $chat->key_fingerprint):
			throw new \LogicException('Invalid key fingerprint !');
		endif;
		$this->set_secret(id : $chat->id,access_hash : $chat->access_hash,peer : $chat->participant_id,auth_key : $auth_key,layer : $this->layer(secret : true),creator : true);
		$this->notify_layer($chat->id);
	}
	public function close_secret_chat(string | int | object $peer,mixed ...$arguments) : bool {
		$id = $this->remove_secret($peer);
		return $this->messages->discardEncryption($id,...$arguments);
	}
	public function getTTL(string | int | object $peer) : int {
		$chat = $this->get_secret_chat($peer);
		return intval($chat['ttl'] === 0 ? $this->messages->getDefaultHistoryTTL()->period : $chat['ttl']);
	}
	public function send_action(string | int | object $peer,object $action) : void {
		$chat = $this->get_secret_chat($peer);
		$message = $this->secret->decryptedMessageService(random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),action : $action);
		$data = $this->encrypt_secret_message($chat['id'],$message);
		$peer = $this->inputEncryptedChat(chat_id : $chat['id'],access_hash : $chat['access_hash']);
		$this->messages->sendEncryptedService(peer : $peer,random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),data : $data);
	}
	public function notify_layer(int $chat_id) : void {
		$chat = $this->get_secret($chat_id);
		$layer = min($chat['layer'],$this->layer(secret : true));
		Logging::log('Secret Chat','Notify layer : '.strval($layer));
		$action = $this->secret->decryptedMessageActionNotifyLayer(layer : $layer);
		$this->send_action($chat_id,$action);
	}
	private function handle_decrypted_message(object $decrypted,object $message) : object | null {
		Logging::log('Secret Chat','handle decrypted message : '.get_class($decrypted));
		if($decrypted instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageService):
			Logging::log('Secret Chat','handle decrypted message action : '.get_class($decrypted->action));
			if($decrypted->action instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionRequestKey):
				$this->accept_rekey($message->chat_id,$decrypted->action->exchange_id,$decrypted->action->g_a);
				return null;
			elseif($decrypted->action instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionAcceptKey):
				$this->commit_rekey($message->chat_id,$decrypted->action->exchange_id,$decrypted->action->g_b,$decrypted->action->key_fingerprint);
				return null;
			elseif($decrypted->action instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionCommitKey):
				$this->complete_rekey($message->chat_id,$decrypted->action->exchange_id,$decrypted->action->key_fingerprint);
				return null;
			elseif($decrypted->action instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionAbortKey):
				$this->abort_rekey($message->chat_id,$decrypted->action->exchange_id);
				return null;
			elseif($decrypted->action instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionNoop):
				return null;
			elseif($decrypted->action instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionResend):
				$chat = $this->get_secret($message->chat_id);
				$decrypted->action->start_seq_no -= intval($chat['creator'] === true);
				$decrypted->action->end_seq_no -= intval($chat['creator'] === true);
				$decrypted->action->start_seq_no >>= 1;
				$decrypted->action->end_seq_no >>= 1;
				for($seq = $decrypted->action->start_seq_no;$seq <= $decrypted->action->end_seq_no;$seq++):
					Logging::log('Secret Chat','attempt to resend seq no : '.$seq);
					$data = $this->encrypt_secret_message($message->chat_id,$chat['outgoing'][$seq]);
					$peer = $this->inputEncryptedChat(chat_id : $chat['id'],access_hash : $chat['access_hash']);
					$this->messages->sendEncrypted(peer : $peer,random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),data : $data);
					Logging::log('Secret Chat','resend seq no : '.$seq);
				endfor;
				return null;
			elseif($decrypted->action instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionSetMessageTTL):
				$chat = $this->get_secret($message->chat_id);
				$chat['ttl'] = $decrypted->action->ttl_seconds;
				$this->set_secret(...$chat);
			elseif($decrypted->action instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageActionNotifyLayer):
				$chat = $this->get_secret($message->chat_id);
				$chat['layer'] = $decrypted->action->layer;
				$this->set_secret(...$chat);
				if(time() - $chat['created'] > 15):
					$this->notify_layer($message->chat_id);
				endif;
				return null;
			endif;
		elseif($decrypted instanceof \Tak\Liveproto\Tl\Types\Secret\DecryptedMessageLayer):
			$chat = $this->get_secret($message->chat_id);
			$chat['layer'] = $decrypted->layer;
			$chat['in_seq_no']++;
			$this->set_secret(...$chat);
			if(time() - $chat['created'] > 15):
				$this->notify_layer($message->chat_id);
			endif;
			return $this->handle_decrypted_message($decrypted->message,$message);
		endif;
		$decrypted->file = isset($message->file) ? $message->file : false;
		$decrypted->chat_id = $message->chat_id;
		$decrypted->date = $message->date;
		return $decrypted;
	}
	public function handle_encrypted_update(object $update) : object | null {
		# encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; #
		# encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; #
		$chat = $this->get_secret($update->message->chat_id);
		$writer = new Binary();
		$writer->write(substr($update->message->bytes,0,8));
		$writer->write(substr(sha1($chat['auth_key'],true),-8));
		$authkeyid = $writer->readLong();
		$keyfingerprint = $writer->readLong();
		if($keyfingerprint !== $authkeyid):
			throw new \LogicException('Invalid key fingerprint !');
		endif;
		$msgKey = substr($update->message->bytes,8,16);
		list($key,$iv) = Helper::keyCalculate($chat['auth_key'],$msgKey,$chat['creator'] === false);
		$cipher = substr($update->message->bytes,24);
		$plain = Aes::decrypt($cipher,$key,$iv);
		$ourKey = hash('sha256',substr($chat['auth_key'],88 + ($chat['creator'] ? 8 : 0),32).$plain,true);
		if($msgKey !== substr($ourKey,8,16)) Logging::log('Decode Message','received msg key does not match with expected one !',E_ERROR);
		$plainReader = new Binary();
		$plainReader->write($plain);
		$msgLength = $plainReader->readInt();
		$message = $plainReader->read($msgLength);
		if($msgLength > strlen($plain)):
			throw new \LogicException('Message data length is too big !');
		elseif(strlen($plain) - $msgLength < 16):
			throw new \LogicException('Padding is too small !');
		elseif(strlen($plain) - $msgLength > 1024 + 4):
			throw new \LogicException('Padding is too big ! ');
		elseif(strlen($plain) % 16 !== 0):
			throw new \LogicException('Length of decrypted data is not divisible by 16');
		endif;
		$chat['ttr']--;
		$chat['incoming'][$chat['in_seq_no']] = $update->message;
		$this->set_secret(...$chat);
		if($chat['ttr'] <= 0 or $chat['updated'] < strtotime('- 1 week')):
			$this->rekey($update->message->chat_id);
		endif;
		$decryptedReader = new Binary();
		$decryptedReader->write($message);
		$decrypted = $decryptedReader->readObject();
		return $this->handle_decrypted_message($decrypted,$update->message);
	}
	public function encrypt_secret_message(int $chat_id,object $message) : string {
		$chat = $this->get_secret($chat_id);
		$chat['ttr']--;
		$messageLayer = $this->secret->decryptedMessageLayer(random_bytes : random_bytes(15 + 4 * rand(0,2)),layer : $chat['layer'],in_seq_no : $this->generateSecretInSeqNo($chat),out_seq_no : $this->generateSecretOutSeqNo($chat),message : $message);
		$chat['out_seq_no']++;
		$chat['outgoing'][$chat['out_seq_no']] = $message;
		$this->set_secret(...$chat);
		if($chat['ttr'] <= 0 or $chat['updated'] < strtotime('- 1 week')):
			$this->rekey($chat['id']);
		endif;
		$packet = $messageLayer->read();
		$plainWriter = new Binary();
		$plainWriter->writeInt(strlen($packet));
		$plainWriter->write($packet);
		$data = $plainWriter->read();
		$posmod = function(int $a,int $b) : int {
			$modulo = $a % $b;
			$padding = $modulo < 0 ? $modulo + abs($b) : $modulo;
			return $padding < 12 ? $padding + 16 : $padding;
		};
		$padding = random_bytes($posmod(-strlen($data),16));
		$msgKeyLarge = hash('sha256',substr($chat['auth_key'],88 + ($chat['creator'] ? 0 : 8),32).$data.$padding,true);
		$msgKey = substr($msgKeyLarge,8,16);
		list($key,$iv) = Helper::keyCalculate($chat['auth_key'],$msgKey,$chat['creator'] === true);
		$encrypt = Aes::encrypt($data.$padding,$key,$iv);
		$cipherWriter = new Binary();
		$cipherWriter->write(substr(sha1($chat['auth_key'],true),-8));
		$cipherWriter->write($msgKey);
		$cipherWriter->write($encrypt);
		return $cipherWriter->read();
	}
	private function rekey(int $chat_id) : void {
		$chat = $this->get_secret($chat_id);
		if($chat['rekey'] !== RekeyState::IDLE):
			return;
		endif;
		Logging::log('Secret Chat','rekey ...');
		$dhConfig = $this->getDhConfig();
		$a = gmp_import(random_bytes(0x100) ^ $dhConfig->random);
		$g_a = gmp_powm($dhConfig->g,$a,$dhConfig->p);
		Security::checkG(strval($g_a),strval($dhConfig->p),true);
		$e = random_int(PHP_INT_MIN,PHP_INT_MAX);
		$chat['rekey'] = RekeyState::REQUESTED;
		$chat['param'] = $a;
		$chat['exchangeid'] = $e;
		$this->set_secret(...$chat);
		$action = $this->secret->decryptedMessageActionRequestKey(exchange_id : $e,g_a : gmp_export($g_a));
		$this->send_action($chat_id,$action);
	}
	private function accept_rekey(int $chat_id,int $exchange_id,string $g_a) : void {
		$chat = $this->get_secret($chat_id);
		if($chat['rekey'] !== RekeyState::IDLE):
			if($chat['exchangeid'] > $exchange_id):
				return;
			elseif($chat['exchangeid'] === $exchange_id):
				$chat['rekey'] = RekeyState::IDLE;
				$this->set_secret(...$chat);
				return;
			endif;
		endif;
		Logging::log('Secret Chat','accept rekey ...');
		$dhConfig = $this->getDhConfig();
		$b = gmp_import(random_bytes(0x100) ^ $dhConfig->random);
		$g_a = gmp_import($g_a);
		Security::checkG(strval($g_a),strval($dhConfig->p),true);
		$pow = gmp_powm($g_a,$b,$dhConfig->p);
		$string = gmp_export($pow);
		$auth_key = str_pad($string,0x100,chr(0),STR_PAD_LEFT);
		$writer = new Binary();
		$writer->write(substr(sha1($auth_key,true),-8));
		$keyfingerprint = $writer->readLong();
		$chat['rekey'] = RekeyState::ACCEPTED;
		$chat['auth_key'] = $auth_key;
		$chat['exchangeid'] = $exchange_id;
		$chat['key_fingerprint'] = $keyfingerprint;
		$this->set_secret(...$chat);
		$g_b = gmp_powm($dhConfig->g,$b,$dhConfig->p);
		Security::checkG(strval($g_b),strval($dhConfig->p),true);
		$action = $this->secret->decryptedMessageActionAcceptKey(exchange_id : $exchange_id,g_b : gmp_export($g_b),key_fingerprint : $keyfingerprint);
		$this->send_action($chat_id,$action);
	}
	private function commit_rekey(int $chat_id,int $exchange_id,string $g_b,int $key_fingerprint) : void {
		$chat = $this->get_secret($chat_id);
		if($chat['rekey'] !== RekeyState::REQUESTED or $chat['exchangeid'] !== $exchange_id):
			$chat['rekey'] = RekeyState::IDLE;
			$this->set_secret(...$chat);
			return;
		endif;
		Logging::log('Secret Chat','commit rekey ...');
		$dhConfig = $this->getDhConfig();
		$g_b = gmp_import($g_b);
		Security::checkG(strval($g_b),strval($dhConfig->p),true);
		$pow = gmp_powm($g_b,$chat['param'],$dhConfig->p);
		$string = gmp_export($pow);
		$auth_key = str_pad($string,0x100,chr(0),STR_PAD_LEFT);
		$writer = new Binary();
		$writer->write(substr(sha1($auth_key,true),-8));
		$keyfingerprint = $writer->readLong();
		if($keyfingerprint !== $key_fingerprint):
			$action = $this->secret->decryptedMessageActionAbortKey(exchange_id : $exchange_id);
			$message = $this->secret->decryptedMessageService(random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),action : $action);
			$data = $this->encrypt_secret_message($chat_id,$message);
			$peer = $this->inputEncryptedChat(chat_id : $chat['id'],access_hash : $chat['access_hash']);
			$this->messages->sendEncryptedService(peer : $peer,random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),data : $data);
			throw new \LogicException('Invalid key fingerprint !');
		endif;
		unset($chat['param']);
		$chat['rekey'] = RekeyState::IDLE;
		$chat['ttr'] = 100;
		$chat['updated'] = time();
		$chat['auth_key'] = $auth_key;
		$chat['key_fingerprint'] = $keyfingerprint;
		$this->set_secret(...$chat);
		$action = $this->secret->decryptedMessageActionCommitKey(exchange_id : $exchange_id,key_fingerprint : $keyfingerprint);
		$this->send_action($chat_id,$action);
	}
	private function complete_rekey(int $chat_id,int $exchange_id,int $key_fingerprint) : void {
		$chat = $this->get_secret($chat_id);
		if($chat['rekey'] !== RekeyState::ACCEPTED or $chat['exchangeid'] !== $exchange_id):
			return;
		endif;
		Logging::log('Secret Chat','complete rekey ...');
		if($chat['key_fingerprint'] !== $key_fingerprint):
			$action = $this->secret->decryptedMessageActionAbortKey(exchange_id : $exchange_id);
			$message = $this->secret->decryptedMessageService(random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),action : $action);
			$data = $this->encrypt_secret_message($chat_id,$message);
			$peer = $this->inputEncryptedChat(chat_id : $chat['id'],access_hash : $chat['access_hash']);
			$this->messages->sendEncryptedService(peer : $peer,random_id : random_int(PHP_INT_MIN,PHP_INT_MAX),data : $data);
			throw new \LogicException('Invalid key fingerprint !');
		endif;
		$chat['rekey'] = RekeyState::IDLE;
		$chat['ttr'] = 100;
		$chat['updated'] = time();
		$this->set_secret(...$chat);
		$action = $this->secret->decryptedMessageActionNoop();
		$this->send_action($chat_id,$action);
	}
	private function abort_rekey(int $chat_id,int $exchange_id) : void {
		$chat = $this->get_secret($chat_id);
		if($chat['rekey'] === RekeyState::IDLE or $chat['exchangeid'] !== $exchange_id):
			return;
		endif;
		Logging::log('Secret Chat','abort rekey ...');
		unset($chat['param']);
		$chat['exchangeid'] = 0;
		$this->set_secret(...$chat);
	}
	private function generateSecretInSeqNo(array $chat) : int {
		return intval($chat['in_seq_no'] * 2 + intval($chat['creator'] === false));
	}
	private function generateSecretOutSeqNo(array $chat) : int {
		return intval($chat['out_seq_no'] * 2 + intval($chat['creator'] === true));
	}
	public function get_secret_chat(string | int | object $peer) :  array {
		$hash = md5(serialize($peer));
		$this->secretChats = array_slice(array : $this->secretChats,offset : -200,preserve_keys : true);
		if(key_exists($hash,$this->secretChats) === false):
			try {
				$this->secretChats[$hash] = $this->get_peer_id($peer);
			} catch(\Throwable){
				/* You may get an `CHAT_ID_INVALID` error , Ignore it */
				try {
					$this->secretChats[$hash] = intval($peer);
				} catch(\Throwable){
					throw new \InvalidArgumentException('Peer not found !');
				}
			}
		endif;
		return $this->get_secret($this->secretChats[$hash]);
	}
	public function remove_secret_chat(string | int | object $peer) : void {
		$chat = $this->get_secret_chat(peer : $peer);
		$this->load->peers->deletePeer(type : 'secrets',by : 'id',what : $chat['id']);
	}
	public function get_secret(int $chat_id) : array {
		foreach(['id','peer'] as $by):
			if($secret = $this->load->peers->getPeer(type : 'secrets',by : $by,what : $chat_id)):
				return $secret;
			endif;
		endforeach;
		throw new \RuntimeException('Chat '.strval($chat_id).' not found !');
	}
	public function set_secret(mixed ...$arguments) : void {
		$correct = array_filter($arguments,is_string(...),ARRAY_FILTER_USE_KEY);
		$correct += ['rekey'=>RekeyState::IDLE,'ttl'=>0,'ttr'=>100,'updated'=>time(),'created'=>time(),'creator'=>false,'temp'=>false,'in_seq_no'=>0,'out_seq_no'=>0,'incoming'=>[],'outgoing'=>[]];
		$this->load->peers->setPeers(type : 'secrets',peers : array($correct));
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Utils\StringTools;

use DOMDocument;

use DOMNode;

use DOMText;

trait Entities {
	public function parse_diff(string $oldText,string $newText) : array {
		$diff = StringTools::diff($oldText,$newText);
		$entities = [];
		foreach($diff as $item):
			$entities []= match($item['type']){
				'replace' => $this->messageEntityDiffReplace(offset : $item['offset'],length : $item['length'],old_text : $item['old']),
				'delete' => $this->messageEntityDiffDelete(offset : $item['offset'],length : $item['length']),
				'insert' => $this->messageEntityDiffInsert(offset : $item['offset'],length : $item['length'])
			};
		endforeach;
		return $entities;
	}
	public function markdown(string $text) : array {
		$markdown = str_split($text);
		$signs = [
			chr(42) => [1,2],
			chr(95) => [1,2],
			chr(96) => [1,3],
			chr(34) => [1],
			chr(39) => [2],
			chr(124) => [2],
			chr(126) => [2],
		];
		$counter = 0;
		$entities = [];
		while(false !== ($message = current($markdown))):
			if(key_exists($message,$signs)):
				foreach(array_reverse($signs[$message]) as $possible):
					for($i = 1;$i < $possible;$i++):
						if(next($markdown) !== $message):
							for($j = 0;$j < $i;$j++) prev($markdown);
							continue 2;
						endif;
					endfor;
					$pos = stripos(implode($markdown),str_repeat($message,$possible),$counter + $possible);
					if($pos === false):
						for($j = 1;$j < $possible;$j++) prev($markdown);
					else:
						$length = $pos - $counter - $possible;
						$slice = array_slice($markdown,$counter,$length + ($possible * 2),true);
						for($first = 0;$first < $possible;$first++):
							$firstkey = array_key_first($slice);
							unset($slice[$firstkey]);
							unset($markdown[$firstkey]);
						endfor;
						for($last = 0;$last < $possible;$last++):
							$lastkey = array_key_last($slice);
							unset($slice[$lastkey]);
							unset($markdown[$lastkey]);
						endfor;
						$additional = array();
						if($message === chr(96) and $possible === 3):
							$newline = stripos(implode($slice),chr(10));
							if(intval($newline)):
								$language = array_slice($slice,0,$newline + 1,true);
								if($language !== $slice):
									foreach(array_keys($language) as $lankey):
										unset($slice[$lankey]);
										unset($markdown[$lankey]);
									endforeach;
									array_pop($language);
									$additional['language'] = implode($language);
								else:
									$additional['language'] = strval(null);
								endif;
							else:
								$additional['language'] = strval(null);
							endif;
						endif;
						$entities[] = [str_repeat($message,$possible) => ['offset'=>StringTools::offset($markdown,$counter),'length'=>StringTools::length($slice),'i'=>key($markdown),...$additional]];
						continue 2;
					endif;
				endforeach;
			endif;
			if($message === chr(91)):
				$pos = stripos(implode($markdown),chr(93).chr(40),$counter + 1);
				if($pos !== false):
					$url = stripos(implode($markdown),chr(41),$pos);
					if($url !== false):
						$lengthtext = $pos - $counter - 1;
						$slicetext = array_slice($markdown,$counter,$lengthtext + 2,true);
						$firstkey = array_key_first($slicetext);
						unset($slicetext[$firstkey]);
						unset($markdown[$firstkey]);
						$lastkey = array_key_last($slicetext);
						unset($slicetext[$lastkey]);
						unset($markdown[$lastkey]);
						$lengthurl = $url - $pos;
						$sliceurl = array_slice($markdown,$counter + $lengthtext,$lengthurl,true);
						$firstkey = array_key_first($sliceurl);
						unset($sliceurl[$firstkey]);
						unset($markdown[$firstkey]);
						$lastkey = array_key_last($sliceurl);
						unset($sliceurl[$lastkey]);
						unset($markdown[$lastkey]);
						$entities[] = [chr(91).chr(93).chr(40).chr(41) => ['offset'=>StringTools::offset($markdown,$counter),'length'=>StringTools::length($slicetext),'url'=>implode($sliceurl),'i'=>key($markdown)]];
						foreach(array_keys($sliceurl) as $del):
							unset($markdown[$del]);
						endforeach;
					endif;
				endif;
			endif;
			if($message === chr(92)):
				$key = key($markdown);
				$next = next($markdown);
				if(key_exists($next,$signs + array_fill_keys(array(chr(91)),null))):
					$entities[] = [$message => ['offset'=>StringTools::offset($markdown,$counter),'length'=>INF,'i'=>key($markdown)]];
					unset($markdown[$key]);
				else:
					prev($markdown);
				endif;
			endif;
			next($markdown);
			$counter++;
		endwhile;
		foreach($entities as $indexone => $entityone):
			foreach($entityone as $keyone => $valueone):
				foreach($entities as $indextwo => $entitytwo):
					foreach($entitytwo as $keytwo => $valuetwo):
						if($entityone !== $entitytwo):
							if($valueone['offset'] <= $valuetwo['offset'] and ($valueone['offset'] + $valueone['length']) > $valuetwo['offset'] and $valueone['i'] < $valuetwo['i']):
								$valueone['length'] = $entities[$indexone][$keyone]['length'] -= strlen($keytwo) - (isset($valuetwo['url']) ? 3 : 0);
							endif;
							/* I will add `and $valuetwo['end'] === true` to this condition for characters that have no ending character and are single like > quote */
							if($valueone['offset'] < ($valuetwo['offset'] + $valuetwo['length']) and ($valueone['offset'] + $valueone['length']) > ($valuetwo['offset'] + $valuetwo['length']) and $valueone['i'] < $valuetwo['i']):
								$entities[$indexone][$keyone]['length'] -= isset($valuetwo['url']) ? strlen($valuetwo['url']) + 3 : (isset($valuetwo['language']) ? strlen($valuetwo['language']) + 3 : strlen($keytwo));
							endif;
						endif;
					endforeach;
				endforeach;
			endforeach;
		endforeach;
		foreach($entities as $index => $entity):
			foreach($entity as $key => $value):
				if($value['length'] > 0 and $key !== chr(92)):
					$entity = match($key){
						'~~' => $this->messageEntityStrike(...),
						'__' =>  $this->messageEntityUnderline(...),
						'\'\'' , '"' => $this->messageEntityBlockquote(...),
						'*' , '**' => $this->messageEntityBold(...),
						'_' => $this->messageEntityItalic(...),
						'`' => $this->messageEntityCode(...),
						'||' => $this->messageEntitySpoiler(...),
						'```' => fn(int $offset,int $length) => $this->messageEntityPre(offset : $offset,length : $length,language : $value['language']),
						'[]()' => fn(int $offset,int $length) => $this->href($offset,$length,$value['url'])
					};
					$entities[$index] = $entity($value['offset'],$value['length']);
				else:
					unset($entities[$index]);
				endif;
			endforeach;
		endforeach;
		return array(implode($markdown),$entities);
	}
	public function markdown_escape(string $text) : string {
		$signs = [
			chr(42),
			chr(95),
			chr(96),
			chr(34),
			chr(39),
			chr(124),
			chr(126),
			chr(91)
		];
		$escaped = array_map(fn(string $character) : string => strval(chr(92).$character),$signs);
		return str_replace($signs,$escaped,$text);
	}
	public function html(string $text) : array {
		$dom = new DOMDocument();
		$text = preg_replace('/\<br(\s*)?\/?\>/i',chr(10),$text);
		$text = preg_replace('/<(q|quote|blockquote)\s+expandable>/','<$1 collapsed=\'true\'>',$text);
		$load = $dom->loadxml('<body>'.trim($text).'</body>');
		if($load):
			list($length,$message,$entities) = $this->dom($dom->getElementsByTagName('body')->item(0));
			return array($message,$entities);
		else:
			throw new \ParseError('Opening and ending tag mismatch : '.$text);
		endif;
	}
	private function dom(
		DOMNode | DOMText $node,
		int $offset = 0,
		? string $message = null,
		array $entities = array()
	) : array {
		if($node instanceof DOMText):
			$text = str_replace(['&lt;','&gt;','&amp;'],['<','>','&'],$node->wholeText);
			$message .= $text;
			return array(StringTools::length($text),$message,$entities);
		endif;
		$length = 0;
		$entity = match($node->nodeName){
			's' , 'strike' , 'del' => $this->messageEntityStrike(...),
			'u' , 'underline' , 'ins' =>  $this->messageEntityUnderline(...),
			'b' , 'bold' , 'strong' => $this->messageEntityBold(...),
			'i' , 'italic' , 'em' => $this->messageEntityItalic(...),
			'code' => $this->messageEntityCode(...),
			'spoiler' , 'tg-spoiler' => $this->messageEntitySpoiler(...),
			'span' => boolval($node->hasAttribute('class') and $node->getAttribute('class') === 'tg-spoiler') ? $this->messageEntitySpoiler(...) : null,
			'q' , 'quote' , 'blockquote' => fn(int $offset,int $length) => $this->messageEntityBlockquote(offset : $offset,length : $length,collapsed : $node->hasAttribute('collapsed') ? true : null),
			'pre' => fn(int $offset,int $length) => $this->messageEntityPre(offset : $offset,length : $length,language : ($code = $node->getElementsByTagName('code')->item(0) and $code->hasAttribute('class')) ? preg_replace('/^language-/',strval(null),$code->getAttribute('class')) : $node->getAttribute('language')),
			'tg-emoji' , 'emoji' => fn(int $offset,int $length) => $this->messageEntityCustomEmoji(offset : $offset,length : $length,document_id : intval($node->hasAttribute('emoji-id') ? $node->getAttribute('emoji-id') : $node->getAttribute('id'))),
			'tg-time' , 'time' => fn(int $offset,int $length) => boolval($node->hasAttribute('format') and preg_match('~^(?<format>r|w?[dD]?[tT]?)$~',$node->getAttribute('format'),$match)) ? $this->messageEntityFormattedDate(offset : $offset,length : $length,date : intval($node->hasAttribute('unix') ? $node->getAttribute('unix') : $node->getAttribute('date')),relative : str_contains($match['format'],'r'),day_of_week : str_contains($match['format'],'w'),short_date : str_contains($match['format'],'d'),long_date : str_contains($match['format'],'D'),short_time : str_contains($match['format'],'t'),long_time : str_contains($match['format'],'T')) : $this->messageEntityFormattedDate(offset : $offset,length : $length,date : intval($node->hasAttribute('unix') ? $node->getAttribute('unix') : $node->getAttribute('date'))),
			'a' => fn(int $offset,int $length) => $this->href($offset,$length,$node->getAttribute('href')),
			default => null
		};
		foreach($node->childNodes as $sub):
			list($len,$message,$entities) = $this->dom($sub,$offset + $length,$message,$entities);
			$length += $len;
		endforeach;
		if($entity !== null):
			$realLength = $length;
			for($x = strlen($message) - 1;$x >= 0;$x--):
				if(in_array($message[$x],array(chr(32),chr(13),chr(10)))):
					$realLength--;
				else:
					break;
				endif;
			endfor;
			if($realLength > 0):
				$entities []= $entity($offset,$realLength);
			endif;
		endif;
		return array($length,$message,$entities);
	}
	public function html_escape(string $text) : string {
		return str_replace(['&','<','>'],['&amp;','&lt;','&gt;'],$text);
	}
	private function href(int $offset,int $length,string $href) : object {
		if(preg_match('~^mention:(?<id>.+)~',$href,$matches) || preg_match('~^tg://user\\?id=(?<id>\d+)~',$href,$matches)):
			return $this->inputMessageEntityMentionName(offset : $offset,length : $length,user_id : $this->get_input_user(filter_var($matches['id'],FILTER_VALIDATE_INT) ? intval($matches['id']) : $matches['id']));
		elseif(preg_match('~^emoji:(?<id>\d+)$~',$href,$matches) || preg_match('~^tg://emoji\\?id=(?<id>\d+)~',$href,$matches)):
			return $this->messageEntityCustomEmoji(offset : $offset,length : $length,document_id : intval($matches['id']));
		elseif(preg_match('~^time:(?<unix>\d+)(?:&format:(?<format>r|w?[dD]?[tT]?))?$~',$href,$matches) || preg_match('~^tg://time\?unix=(?<unix>\d+)(?:&format=(?<format>r|w?[dD]?[tT]?))?$~',$href,$matches)):
			$format = strval(isset($matches['format']) ? $matches['format'] : null);
			return $this->messageEntityFormattedDate(offset : $offset,length : $length,date : intval($matches['unix']),relative : str_contains($format,'r'),day_of_week : str_contains($format,'w'),short_date : str_contains($format,'d'),long_date : str_contains($format,'D'),short_time : str_contains($format,'t'),long_time : str_contains($format,'T'));
		else:
			return $this->messageEntityTextUrl(offset : $offset,length : $length,url : $href);
		endif;
	}
	public function format_entities(string $text,array $entities) : array {
		foreach($entities as $i => $object):
			$entity = $entities[$i] = clone $object;
			$entity->text = StringTools::substr($text,$entity->offset,$entity->length);
			if(isset($entity->url)):
				$entity->open = static fn(mixed ...$args) : string | false => @file_get_contents($entity->url,...$args);
			endif;
		endforeach;
		return $entities;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Utils\Instance;

use Tak\Liveproto\Attributes\Type;

use Tak\Liveproto\Enums\FileType;

trait Media {
	public function inputify_media(Instance $media) : mixed {
		return match($media->getClass()){
			'photo' => $this->inputPhoto(id : $media->id,access_hash : $media->access_hash,file_reference : $media->file_reference),
			'photoEmpty' => $this->inputPhotoEmpty(),
			'geoPoint' => $this->inputGeoPoint(lat : $media->lat,long : $media->long,accuracy_radius : $media->accuracy_radius),
			'geoPointEmpty' => $this->inputGeoPointEmpty(),
			'document' => $this->inputDocument(id : $media->id,access_hash : $media->access_hash,file_reference : $media->file_reference),
			'documentEmpty' => $this->inputDocumentEmpty(),
			'webDocument' , 'webDocumentNoProxy' => $this->inputWebDocument(url : $media->url,size : $media->size,mime_type : $media->mime_type,attributes : $media->attributes),
			'game' => $this->inputGameID(id : $media->id,access_hash : $media->access_hash),
			default => throw new \RuntimeException('Unsupported Media type : '.$media->getClass())
		};
	}
	protected function get_input_media(#[Type('MessageMedia')] Instance $messageMedia) : Instance {
		return match($messageMedia->getClass()){
			# inputMediaPhoto#e3af4434 flags:# spoiler:flags.1?true live_photo:flags.2?true id:InputPhoto ttl_seconds:flags.0?int videoq:flags.2?InputDocument = InputMedia; #
			# messageMediaPhoto#e216eb63 flags:# spoiler:flags.3?true live_photo:flags.4?true photo:flags.0?Photo ttl_seconds:flags.2?int video:flags.4?Document = MessageMedia; #
			'messageMediaPhoto' => is_null($messageMedia->photo) ? $this->inputMediaEmpty() : $this->inputMediaPhoto(
				id : $this->inputify_media($messageMedia->photo),
				live_photo : $messageMedia->live_photo,
				video : is_null($messageMedia->video) ? null : $this->inputify_media($messageMedia->video),
				spoiler : $messageMedia->spoiler,
				ttl_seconds : $messageMedia->ttl_seconds
			),
			# inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; #
			# messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; #
			'messageMediaGeo' => $this->inputMediaGeoPoint(
				geo_point : $this->inputify_media($messageMedia->geo)
			),
			# inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; #
			# messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; #
			'messageMediaContact' => $this->inputMediaContact(
				phone_number : $messageMedia->phone_number,
				first_name : $messageMedia->first_name,
				last_name : $messageMedia->last_name,
				vcard : $messageMedia->vcard
			),
			# inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia; #
			# messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true live_photo:flags.11?true document:flags.0?Document alt_documents:flags.5?Vector<Document> video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia; #
			'messageMediaDocument' => boolval(is_null($messageMedia->document) and is_null($messageMedia->alt_documents)) ? $this->inputMediaEmpty() : $this->inputMediaDocument(
				spoiler : $messageMedia->spoiler,
				id : isset($messageMedia->document) ? $this->inputify_media($messageMedia->document) : $this->inputify_media(current($messageMedia->alt_documents)),
				video_cover : isset($messageMedia->video_cover) ? $this->inputify_media($messageMedia->video_cover) : null,
				video_timestamp : $messageMedia->video_timestamp,
				ttl_seconds : $messageMedia->ttl_seconds,
				query : null
			),
			# inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; #
			# messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia; #
			'messageMediaWebPage' => $this->inputMediaWebPage(
				force_large_media : $messageMedia->force_large_media,
				force_small_media : $messageMedia->force_small_media,
				optional : true,
				url : strval($messageMedia->webpage->url)
			),
			# inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; #
			# messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; #
			'messageMediaVenue' => $this->inputMediaVenue(
				geo_point : $this->inputify_media($messageMedia->geo),
				title : $messageMedia->title,
				address : $messageMedia->address,
				provider : $messageMedia->provider,
				venue_id : $messageMedia->venue_id,
				venue_type : $messageMedia->venue_type
			),
			# inputMediaGame#d33f43f3 id:InputGame = InputMedia; #
			# messageMediaGame#fdb19008 game:Game = MessageMedia; #
			'messageMediaGame' => $this->inputMediaGame(
				id : $this->inputify_media($messageMedia->game)
			),
			# inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; #
			# messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia; #
			'messageMediaInvoice' => $this->inputMediaInvoice(
				title : $messageMedia->title,
				description : $messageMedia->description,
				photo : isset($messageMedia->photo) ? $this->inputify_media($messageMedia->photo) : null,
				invoice : $this->invoice(
					currency : $messageMedia->currency,
					prices : array(
						$this->labeledPrice(
							label : 'credits',
							amount : $messageMedia->total_amount,
						),
					),
				),
				payload : md5(serialize($messageMedia)),
				provider : null,
				provider_data : $this->dataJSON(
					data : json_encode(array()),
				),
				start_param : $messageMedia->start_param,
				extended_media : isset($messageMedia->extended_media->media) ? $this->get_input_media($messageMedia->extended_media->media) : null
			),
			# inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; #
			# messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia; #
			'messageMediaGeoLive' => $this->inputMediaGeoLive(
				stopped : false,
				geo_point : $this->inputify_media($messageMedia->geo),
				heading : $messageMedia->heading,
				period : $messageMedia->period,
				proximity_notification_radius : $messageMedia->proximity_notification_radius
			),
			# inputMediaPoll#883a4108 flags:# poll:Poll correct_answers:flags.0?Vector<int> attached_media:flags.3?InputMedia solution:flags.1?string solution_entities:flags.1?Vector<MessageEntity> solution_media:flags.2?InputMedia = InputMedia; #
			# messageMediaPoll#773f4e66 flags:# poll:Poll results:PollResults attached_media:flags.0?MessageMedia = MessageMedia; #
			'messageMediaPoll' => $this->inputMediaPoll(
				poll : $messageMedia->poll,
				correct_answers : array_filter($messageMedia->results->results,fn(object $pollAnswerVoters) : bool => boolval($pollAnswerVoters->correct)),
				attached_media : is_null($messageMedia->attached_media) ? null : $this->get_input_media($messageMedia->attached_media),
				solution : $messageMedia->results->solution,
				solution_entities : $messageMedia->results->solution_entities,
				solution_media : is_null($messageMedia->results->solution_media) ? null : $this->get_input_media($messageMedia->results->solution_media)
			),
			# inputMediaDice#e66fbf7b emoticon:string = InputMedia; #
			# messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia; #
			'messageMediaDice' => $this->inputMediaDice(
				emoticon : $messageMedia->emoticon
			),
			# inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; #
			# messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; #
			'messageMediaStory' => $this->inputMediaStory(
				peer : $this->get_input_peer($messageMedia->peer),
				id : $messageMedia->id
			),
			# inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector<InputMedia> payload:flags.0?string = InputMedia; #
			# messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector<MessageExtendedMedia> = MessageMedia; #
			'messageMediaPaidMedia' => $this->inputMediaPaidMedia(
				stars_amount : $messageMedia->stars_amount,
				extended_media : array_map(fn(object $messageExtendedMedia) : mixed => $this->get_input_media($messageExtendedMedia->media),array_filter($messageMedia->extended_media,fn(object $messageExtendedMedia) : bool => isset($messageExtendedMedia->media))),
				payload : null
			),
			# inputMediaTodo#9fc55fde todo:TodoList = InputMedia; #
			# messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector<TodoCompletion> = MessageMedia; #
			'messageMediaToDo' => $this->inputMediaTodo(
				todo : $messageMedia->todo
			),
			# messageMediaUnsupported#9f84f49e = MessageMedia; #
			'messageMediaUnsupported' => $this->inputMediaEmpty(),
			# inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; #
			# inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; #
			default => throw new \RuntimeException('Unsupported MessageMedia type : '.$messageMedia->getClass())
		};
	}
	protected function get_message_media(#[Type('InputMedia')] Instance $inputMedia,string | int | null | object $peer = null,mixed ...$args) : Instance {
		$inputPeer = is_null($peer) ? ($this->is_bot() ? $this->inputPeerEmpty() : $this->inputPeerSelf()) : $this->get_input_peer($peer);
		return $this->messages->uploadMedia($inputPeer,$inputMedia,...$args);
	}
	public function get_input_media_uploaded(string $path,FileType $file_type,mixed ...$arguments) : mixed {
		$inputFile = $this->upload_file($path);
		return match($file_type){
			# inputMediaUploadedPhoto#7d8375da flags:# spoiler:flags.2?true live_photo:flags.3?true file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int video:flags.3?InputDocument = InputMedia; #
			FileType::PHOTO => $this->inputMediaUploadedPhoto($inputFile,...$arguments),
			# inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true live_photo:flags.8?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; #
			default => $this->inputMediaUploadedDocument($inputFile,strval(mime_content_type($path)),...array_merge(['attributes'=>array($this->documentAttributeFilename(file_name : basename($path)))],$arguments))
		};
	}
	public function decode_vector_thumbnail(string $bytes) : string {
		$lookup = 'AACAAAAHAAALMAAAQASTAVAAAZaacaaaahaaalmaaaqastava.az0123456789-,';
		$path = 'M';
		$len = strlen($bytes);
		for($i = 0; $i < $len; $i++):
			$num = ord($bytes[$i]);
			if($num >= 192):
				$idx = $num - 192;
				$path .= $lookup[$idx];
			else:
				if($num >= 128):
					$path .= ',';
				elseif($num >= 64):
					$path .= '-';
				endif;
				$path .= strval($num & 63);
			endif;
		endfor;
		$path .= 'z';
		$svg = <<<'SVG'
			<?xml version="1.0" encoding="utf-8"?>
			<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" xml:space="preserve">
				<path d="%s"/>
			</svg>
		SVG;
		return sprintf($svg,$path);
	}
	public function get_stripped_thumbnail(string $stripped) : string {
		if(strlen($stripped) < 3 or substr($stripped,0,1) !== chr(1)):
			return $stripped;
		else:
			$header =
				"\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49".
				"\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x28\x1c".
				"\x1e\x23\x1e\x19\x28\x23\x21\x23\x2d\x2b\x28\x30\x3c\x64\x41\x3c\x37\x37".
				"\x3c\x7b\x58\x5d\x49\x64\x91\x80\x99\x96\x8f\x80\x8c\x8a\xa0\xb4\xe6\xc3".
				"\xa0\xaa\xda\xad\x8a\x8c\xc8\xff\xcb\xda\xee\xf5\xff\xff\xff\x9b\xc1\xff".
				"\xff\xff\xfa\xff\xe6\xfd\xff\xf8\xff\xdb\x00\x43\x01\x2b\x2d\x2d\x3c\x35".
				"\x3c\x76\x41\x41\x76\xf8\xa5\x8c\xa5\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8".
				"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8".
				"\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8".
				"\xf8\xf8\xf8\xf8\xf8\xff\xc0\x00\x11\x08\x00\x00\x00\x00\x03\x01\x22\x00".
				"\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01".
				"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08".
				"\x09\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05".
				"\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06".
				"\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\x42\xb1\xc1\x15\x52".
				"\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17\x18\x19\x1a\x25\x26\x27\x28".
				"\x29\x2a\x34\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53".
				"\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75".
				"\x76\x77\x78\x79\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96".
				"\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6".
				"\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6".
				"\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4".
				"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01".
				"\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08".
				"\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05".
				"\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41".
				"\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33".
				"\x52\xf0\x15\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26".
				"\x27\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a".
				"\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74".
				"\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94".
				"\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4".
				"\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4".
				"\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4".
				"\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00".
				"\x3f\x00";
			$footer = "\xff\xd9";
			$header[164] = $stripped[1];
			$header[166] = $stripped[2];
			return $header.substr($stripped,3).$footer;
		endif;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Crypto\Password;

use Tak\Liveproto\Attributes\Type;

trait Buttons {
	public function create_reply_markup(
		? array $keyboard = null,
		? array $inline_keyboard = null,
		bool $remove_keyboard = false,
		bool $force_reply = false,
		mixed ...$args
	) : object {
		if(is_array($keyboard)):
			return $this->replyKeyboardMarkup(...$args,rows : array_map($this->compose_row(...),$keyboard));
		elseif(is_array($inline_keyboard)):
			return $this->replyInlineMarkup(...$args,rows : array_map($this->compose_row(...),$inline_keyboard));
		elseif($remove_keyboard):
			return $this->replyKeyboardHide(...$args);
		elseif($force_reply):
			return $this->replyKeyboardForceReply(...$args);
		else:
			throw new \InvalidArgumentException('No valid markup configuration provided');
		endif;
	}
	public function compose_row(array $buttons) : object {
		$column = array();
		$approval = fn(array $button,array $requirements,array $optionals = []) : bool => array_all($requirements,fn(string $key) : bool => in_array($key,array_keys($button))) and empty(array_diff(array_keys($button),$requirements,$optionals));
		$stripPrefix = fn(array $data,string $prefix) : array => array_combine(array_map(fn(string $key) : string => str_starts_with($key,$prefix) ? substr($key,strlen($prefix)) : $key,array_keys($data)),$data);
		foreach($buttons as $button):
			if(is_array($button) and array_is_list($button) === false):
				$style = boolval(array_key_exists('style',$button) and is_string($button['style'])) ? strtolower($button['style']) : null;
				$icon = boolval(array_key_exists('icon_custom_emoji_id',$button) and ctype_digit($button['icon_custom_emoji_id'])) ? intval($button['icon_custom_emoji_id']) : null;
				$design = boolval(is_null($style) and is_null($icon)) ? null : $this->keyboardButtonStyle(bg_primary : boolval($style === 'primary'),bg_danger : boolval($style === 'danger'),bg_success : boolval($style === 'success'),icon : $icon);
				unset($button['style'],$button['icon_custom_emoji_id']);
				$column []= match(true){
					$approval($button,['text']) => $this->keyboardButton(
						text : strval($button['text']),
						style : $design
					),
					$approval($button,['text','url']) => $this->keyboardButtonUrl(
						text : strval($button['text']),
						url : $button['url'],
						style : $design
					),
					$approval($button,['text','callback_data'],['requires_password']) => $this->keyboardButtonCallback(
						requires_password : boolval($button['requires_password'] ?? false),
						text : strval($button['text']),
						data : $button['callback_data'],
						style : $design
					),
					$approval($button,['text','request_contact']) => boolval($button['request_contact']) ? $this->keyboardButtonRequestPhone(
						text : strval($button['text']),
						style : $design
					) : $this->keyboardButton(
						text : strval($button['text']),
						style : $design
					),
					$approval($button,['text','request_location']) => boolval($button['request_location']) ? $this->keyboardButtonRequestGeoLocation(
						text : strval($button['text']),
						style : $design
					) : $this->keyboardButton(
						text : strval($button['text']),
						style : $design
					),
					$approval($button,['text','switch_inline_query']) => $this->keyboardButtonSwitchInline(
						text : strval($button['text']),
						query : $button['switch_inline_query'],
						style : $design
					),
					$approval($button,['text','switch_inline_query_current_chat']) => $this->keyboardButtonSwitchInline(
						same_peer : true,
						text : strval($button['text']),
						query : $button['switch_inline_query_current_chat'],
						style : $design
					),
					$approval($button,['text','switch_inline_query_chosen_chat']) => $this->keyboardButtonSwitchInline(
						text : strval($button['text']),
						query : strval($button['switch_inline_query_chosen_chat']['query'] ?? null),
						peer_types : array_filter(array(
							isset($button['switch_inline_query_chosen_chat']['allow_user_chats']) ? $this->inlineQueryPeerTypePM() : null,
							isset($button['switch_inline_query_chosen_chat']['allow_bot_chats']) ? $this->inlineQueryPeerTypeBotPM() : null,
							isset($button['switch_inline_query_chosen_chat']['allow_group_chats']) ? $this->inlineQueryPeerTypeChat() : null,
							isset($button['switch_inline_query_chosen_chat']['allow_group_chats']) ? $this->inlineQueryPeerTypeMegagroup() : null,
							isset($button['switch_inline_query_chosen_chat']['allow_channel_chats']) ? $this->inlineQueryPeerTypeBroadcast() : null
						)),
						style : $design
					),
					$approval($button,['text','callback_game']) => $this->keyboardButtonGame(
						text : strval($button['text']),
						style : $design
					),
					$approval($button,['text','pay']) => boolval($button['pay']) ? $this->keyboardButtonBuy(
						text : strval($button['text']),
						style : $design
					) : $this->keyboardButton(
						text : strval($button['text']),
						style : $design
					),
					$approval($button,['text','login_url']) => $this->inputKeyboardButtonUrlAuth(
						request_write_access : boolval($button['login_url']['request_write_access'] ?? false),
						text : strval($button['text']),
						fwd_text : boolval(is_array($button['login_url']) and array_key_exists('forward_text',$button['login_url'])) ? strval($button['login_url']['forward_text']) : null,
						url : $button['login_url']['url'] ?? throw new \InvalidArgumentException('The login url does not provide url'),
						bot : $this->get_input_user($button['login_url']['bot_username'] ?? 'bot'),
						style : $design
					),
					$approval($button,['text','request_poll']) => $this->keyboardButtonRequestPoll(
						quiz : boolval(is_array($button['request_poll']) and array_key_exists('type',$button['request_poll'])) ? $button['request_poll']['type'] === 'quiz' : false,
						text : strval($button['text']),
						style : $design
					),
					$approval($button,['text','mention_user']) => $this->inputKeyboardButtonUserProfile(
						text : strval($button['text']),
						user_id : $this->get_input_user($button['mention_user']),
						style : $design
					),
					$approval($button,['text','web_app']) => boolval($button['web_app']['is_simple'] ?? false) ? $this->keyboardButtonSimpleWebView(
						text : strval($button['text']),
						url : $button['web_app']['url'] ?? throw new \InvalidArgumentException('The web app does not provide url'),
						style : $design
					) : $this->keyboardButtonWebView(
						text : strval($button['text']),
						url : $button['web_app']['url'] ?? throw new \InvalidArgumentException('The web app does not provide url'),
						style : $design
					),
					$approval($button,['text','request_users']) => $this->inputKeyboardButtonRequestPeer(
						name_requested : boolval($button['request_users']['request_name'] ?? false),
						username_requested : boolval($button['request_users']['request_username'] ?? false),
						photo_requested : boolval($button['request_users']['request_photo'] ?? false),
						text : strval($button['text']),
						button_id : $button['request_users']['request_id'] ?? 0,
						peer_type : $this->requestPeerTypeUser(
							bot : boolval($button['request_users']['user_is_bot'] ?? false),
							premium : boolval($button['request_users']['user_is_premium'] ?? false)
						),
						max_quantity : $button['request_users']['max_quantity'] ?? 1,
						style : $design
					),
					$approval($button,['text','request_chat']) => $this->inputKeyboardButtonRequestPeer(
						name_requested : boolval($button['request_chat']['request_title'] ?? false),
						username_requested : boolval($button['request_chat']['request_username'] ?? false),
						photo_requested : boolval($button['request_chat']['request_photo'] ?? false),
						text : strval($button['text']),
						button_id : $button['request_chat']['request_id'] ?? 0,
						peer_type : boolval($button['request_chat']['chat_is_channel'] ?? false) ? $this->requestPeerTypeBroadcast(
							creator : boolval($button['request_chat']['chat_is_created'] ?? false),
							has_username : boolval($button['request_chat']['chat_has_username'] ?? false),
							user_admin_rights : boolval(is_array($button['request_chat']) and array_key_exists('user_administrator_rights',$button['request_chat'])) ? $this->chatAdminRights(...$stripPrefix($button['request_chat']['user_administrator_rights'],'can_')) : null,
							bot_admin_rights : boolval(is_array($button['request_chat']) and array_key_exists('bot_administrator_rights',$button['request_chat'])) ? $this->chatAdminRights(...$stripPrefix($button['request_chat']['bot_administrator_rights'],'can_')) : null
						) : $this->requestPeerTypeChat(
							creator : boolval($button['request_chat']['chat_is_created'] ?? false),
							bot_participant : boolval($button['request_chat']['bot_is_member'] ?? false),
							has_username : boolval($button['request_chat']['chat_has_username'] ?? false),
							forum : boolval($button['request_chat']['chat_is_forum'] ?? false),
							user_admin_rights : boolval(is_array($button['request_chat']) and array_key_exists('user_administrator_rights',$button['request_chat'])) ? $this->chatAdminRights(...$stripPrefix($button['request_chat']['user_administrator_rights'],'can_')) : null,
							bot_admin_rights : boolval(is_array($button['request_chat']) and array_key_exists('bot_administrator_rights',$button['request_chat'])) ? $this->chatAdminRights(...$stripPrefix($button['request_chat']['bot_administrator_rights'],'can_')) : null
						),
						max_quantity : $button['request_chat']['max_quantity'] ?? 1,
						style : $design
					),
					$approval($button,['text','request_managed_bot']) => $this->inputKeyboardButtonRequestPeer(
						// name_requested : boolval($button['request_managed_bot']['request_name'] ?? false),
						// username_requested : boolval($button['request_managed_bot']['request_username'] ?? false),
						// photo_requested : boolval($button['request_managed_bot']['request_photo'] ?? false),
						text : strval($button['text']),
						button_id : $button['request_managed_bot']['request_id'] ?? 0,
						peer_type : $this->requestPeerTypeCreateBot(
							bot_managed : true,
							suggested_name : $button['request_managed_bot']['suggested_name'] ?? null,
							suggested_username : $button['request_managed_bot']['suggested_username'] ?? null
						),
						max_quantity : $button['request_managed_bot']['max_quantity'] ?? 1,
						style : $design
					),
					$approval($button,['text','copy_text']) => $this->keyboardButtonCopy(
						text : strval($button['text']),
						copy_text : strval($button['copy_text']['text'] ?? $button['text']),
						style : $design
					),
					default => throw new \InvalidArgumentException('The button is in invalid format : '.json_encode($button,flags : JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT)) 
				};
			endif;
		endforeach;
		return $this->keyboardButtonRow(buttons : $column);
	}
	protected function click_button(
		#[Type('Message')] object $message,
		? int $i = null,
		? int $j = null,
		? string $text = null,
		? string $data = null,
		? string $query = null,
		? callable $filter = null,
		? string $password = null,
		? array $contact = null,
		? array $geo = null,
		string | int | null | object $user = null
	) : mixed {
		if($message instanceof \Tak\Liveproto\Tl\Types\Other\Message):
			if(is_object($message->reply_markup)):
				$button = $this->get_button($message->reply_markup,$i,$j,$text,$data,$query,$filter);
				$peer = $this->get_input_peer($message->peer_id);
				if($button instanceof \Tak\Liveproto\Tl\Types\Other\KeyboardButton):
					return $this->messages->sendMessage(peer : $peer,message : $button->text,random_id : random_int(PHP_INT_MIN,PHP_INT_MAX));
				elseif($button instanceof \Tak\Liveproto\Tl\Types\Other\KeyboardButtonUrl):
					return @file_get_contents($button->url);
				elseif($button instanceof \Tak\Liveproto\Tl\Types\Other\KeyboardButtonCallback):
					if($button->requires_password):
						$password = is_null($password) ? (isset($this->load->password) ? $this->load->password : null) : $password;
						if(is_null($password) === false):
							$account = $this->account->getPassword();
							$checker = new Password();
							$password = $checker->srp($account,$password);
						else:
							throw new \InvalidArgumentException('The password argument is required !');
						endif;
					else:
						$password = null;
					endif;
					return $this->messages->getBotCallbackAnswer(peer : $peer,msg_id : $message->id,data : $button->data,password : $password);
				elseif($button instanceof \Tak\Liveproto\Tl\Types\Other\KeyboardButtonRequestPhone):
					if(is_null($contact) === false):
						if(isset($contact['phone'],$contact['firstname'])):
							$contact = $this->inputMediaContact(phone_number : strval($contact['phone']),first_name : strval($contact['firstname']),last_name : strval(isset($contact['lastname']) ? $contact['lastname'] : null),vcard : strval(isset($contact['vcard']) ? $contact['vcard'] : null));
						else:
							throw new \InvalidArgumentException('The contact argument should be an array containing phone and firstname ( lastname & vcard optional ) !');
						endif;
					else:
						$me = $this->get_me();
						$contact = $this->inputMediaContact(phone_number : $me->phone,first_name : $me->first_name,last_name : strval($me->last_name),vcard : strval(null));
					endif;
					return $this->messages->sendMedia(peer : $peer,media : $contact,message : $button->text,random_id : random_int(PHP_INT_MIN,PHP_INT_MAX));
				elseif($button instanceof \Tak\Liveproto\Tl\Types\Other\KeyboardButtonRequestGeoLocation):
					if(is_null($geo) === false):
						if(isset($geo['lat'],$geo['long'])):
							$geo = $this->inputMediaGeoPoint(geo_point : $this->inputGeoPoint(lat : floatval($geo['lat']),long : floatval($geo['long'])));
						else:
							throw new \InvalidArgumentException('The geo argument should be an array containing lat and long !');
						endif;
					else:
						throw new \InvalidArgumentException('The geo argument is required !');
					endif;
					return $this->messages->sendMedia(peer : $peer,media : $geo,message : $button->text,random_id : random_int(PHP_INT_MIN,PHP_INT_MAX));
				elseif($button instanceof \Tak\Liveproto\Tl\Types\Other\KeyboardButtonSwitchInline):
					if($button->same_peer):
						$bot = is_int($message->via_bot_id) ? $this->get_input_peer($message->via_bot_id) : $peer;
					elseif(is_null($user) === false):
						$bot = is_int($message->via_bot_id) ? $this->get_input_peer($message->via_bot_id) : $peer;
						$peer = $this->get_input_peer($user);
					else:
						throw new \InvalidArgumentException('The user argument is required !');
					endif;
					return $this->inline_query(bot : $bot,query : $button->query,peer : $peer);
					# return $this->messages->startBot(bot : $this->get_input_peer($message->via_bot_id),peer : $peer,start_param : $button->query,random_id : random_int(PHP_INT_MIN,PHP_INT_MAX));
				elseif($button instanceof \Tak\Liveproto\Tl\Types\Other\KeyboardButtonGame):
					return $this->messages->getBotCallbackAnswer(peer : $peer,msg_id : $message->id,game : true);
				elseif($button instanceof \Tak\Liveproto\Tl\Types\Other\KeyboardButtonRequestPeer):
					if(is_null($user) === false):
						$requested = $this->get_input_peer($user);
					else:
						throw new \InvalidArgumentException('The user argument is required !');
					endif;
					return $this->messages->sendBotRequestedPeer(peer : $peer,msg_id : $message->id,button_id : $button->button_id,requested_peer : $requested);
				elseif($button instanceof \Tak\Liveproto\Tl\Types\Other\KeyboardButtonCopy):
					return $button->copy_text;
				else:
					throw new \Exception('Unsupported button type !');
				endif;
			else:
				throw new \InvalidArgumentException('Your message does not contain reply markup !');
			endif;
		else:
			throw new \InvalidArgumentException('The message is invalid !');
		endif;
	}
	protected function get_button(
		#[Type('ReplyMarkup')] object $reply_markup,
		? int $i = null,
		? int $j = null,
		? string $text = null,
		? string $data = null,
		? string $query = null,
		? callable $filter = null
	) : object {
		$index = (is_null($i) === false and is_null($j)) ? $i : null;
		$x = 0;
		$y = 0;
		if($reply_markup instanceof \Tak\Liveproto\Tl\Types\Other\ReplyKeyboardMarkup or $reply_markup instanceof \Tak\Liveproto\Tl\Types\Other\ReplyInlineMarkup):
			foreach($reply_markup->rows as $row):
				foreach($row->buttons as $button):
					if(is_null($index) === false and $index === ($x + $y)):
						return $button;
					elseif($i === $x and $j === $y):
						return $button;
					elseif(is_null($text) === false and $button->text === $text):
						return $button;
					elseif(is_null($data) === false and $button->data === $data):
						return $button;
					elseif(is_null($query) === false and $button->query === $query):
						return $button;
					elseif(is_null($filter) === false and $filter($button)):
						return $button;
					endif;
					$y++;
				endforeach;
				$x++;
			endforeach;
		else:
			throw new \InvalidArgumentException('The reply markup must be an object of replyKeyboardMarkup / replyInlineMarkup !');
		endif;
		throw new \Exception('The button you wanted was not found !');
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Attributes\Type;

trait Channels {
	public function get_input_channel(string | int | null | object $channel) : mixed {
		$entity = $this->get_input_peer($channel);
		$class = $entity->getClass();
		return match($class){
			'inputPeerEmpty' => $this->inputChannelEmpty(),
			'inputPeerChannel' => $this->inputChannel(channel_id : $entity->channel_id,access_hash : $entity->access_hash),
			default => throw new \InvalidArgumentException('This entity('.$class.') does not belong to a channel !')
		};
	}
	protected function get_input_channel_from_message(#[Type('Message')] object $message) : object {
		if(isset($message->from_id->channel_id)):
			$inputPeer = $this->get_input_peer(peer : $message->peer_id);
			return $this->inputChannelFromMessage(peer : $inputPeer,msg_id : $message->id,channel_id : $message->from_id->channel_id);
		else:
			throw new \InvalidArgumentException('Field `from_id` is missing or invalid in the message');
		endif;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Utils\Logging;

use Tak\Liveproto\Tl\Pagination;

use Tak\Liveproto\Attributes\Type;

use Iterator;

use Closure;

trait Dialog {
	protected function parse_dialogs(#[Type('messages.Dialogs','messages.SavedDialogs','messages.peerDialogs')] object $results) : array {
		$dialogs = array();
		$peers = array_merge($results->chats,$results->users);
		foreach($results->dialogs as $dialog):
			$message = array_filter($results->messages,fn(object $message) => $message->id === $dialog->top_message);
			$peer = array_filter($peers,fn(object $peer) => $peer->id === $this->get_peer_id($dialog->peer));
			$dialogs []= (object) ['dialog'=>$dialog,'message'=>reset($message),'peer'=>reset($peer)];
		endforeach;
		return $dialogs;
	}
	public function get_dialogs(
		string | int | null | object $offset_peer = null,
		int $offset = 0,
		int $offset_id = 0,
		int $offset_date = 0,
		int $limit = 100,
		bool $saved = false,
		bool $pinned = false,
		Closure | array | null $hashgen = null,
		mixed ...$args
	) : Iterator {
		if($saved):
			if($pinned):
				$fetchResults = function(int $offset,int $limit) use($args) : array {
					Logging::log('Pinned Saved Dialog','offset = '.$offset.' & limit = '.$limit);
					$results = $this->messages->getPinnedSavedDialogs(...$args);
					switch($results->getClass()):
						# messages.savedDialogs#f83ae221 dialogs:Vector<SavedDialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SavedDialogs; #
						# messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector<SavedDialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SavedDialogs; #
						case 'messages.savedDialogs':
						case 'messages.savedDialogsSlice':
							return array_slice($this->parse_dialogs($results),$offset,$limit);
						# messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; #
						case 'messages.savedDialogsNotModified':
							return array();
					endswitch;
				};
			else:
				$fetchResults = function(int $offset,int $limit,int $hash) use(&$offset_peer,&$offset_id,&$offset_date,$args) : array {
					Logging::log('Saved Dialog','offset id = '.$offset_id.' & offset date = '.$offset_date.' & limit = '.$limit);
					$inputOffsetPeer = $this->get_input_peer($offset_peer);
					$results = $this->messages->getSavedDialogs(...$args,offset_peer : $inputOffsetPeer,offset_id : $offset_id,offset_date : $offset_date,limit : $limit,hash : $hash);
					switch($results->getClass()):
						# messages.savedDialogs#f83ae221 dialogs:Vector<SavedDialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SavedDialogs; #
						# messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector<SavedDialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SavedDialogs; #
						case 'messages.savedDialogs':
						case 'messages.savedDialogsSlice':
							foreach(array_reverse($results->messages) as $last):
								if($last->getClass() !== 'messageEmpty'):
									list($offset_peer,$offset_id,$offset_date) = array($last->peer_id,$last->id - 1,$last->date);
									break;
								endif;
							endforeach;
							return $this->parse_dialogs($results);
						# messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; #
						case 'messages.savedDialogsNotModified':
							return array();
					endswitch;
				};
				/*
				 * TODO :
				 * Unfortunately, generating a hash to cache the results of this method did not work
				 * https://github.com/DrKLO/Telegram/blob/ddc90f16be1ab952114005347e0102365ba6460b/TMessagesProj/src/main/java/org/telegram/messenger/SavedMessagesController.java#L253-L257
				 * I followed the same procedure as Telegram Android, but I don't know where is the problem
				$hashgen = function(int $hash,array $results) : int {
					foreach(array_reverse($results) as $result):
						$hash = Helper::hashGeneration($hash,array(intval($result->dialog->pinned),$this->get_peer_id($result->dialog->peer),$result->message->id,$result->message->date));
					endforeach;
					return $hash;
				};
				 */
			endif;
		else:
			if($pinned):
				$fetchResults = function(int $offset,int $limit) use($args) : array {
					Logging::log('Pinned Dialog','offset = '.$offset.' & limit = '.$limit);
					$args += ['folder_id'=>0];
					$results = $this->messages->getPinnedDialogs(...$args);
					switch($results->getClass()):
						# messages.peerDialogs#3371c354 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> state:updates.State = messages.PeerDialogs; #
						case 'messages.peerDialogs':
							return array_slice($this->parse_dialogs($results),$offset,$limit);
						default:
							return array();
					endswitch;
				};
			else:
				$fetchResults = function(int $offset,int $limit,int $hash) use(&$offset_peer,&$offset_id,&$offset_date,$args) : array {
					Logging::log('Dialog','offset id = '.$offset_id.' & offset date = '.$offset_date.' & limit = '.$limit);
					$inputOffsetPeer = $this->get_input_peer($offset_peer);
					$results = $this->messages->getDialogs(...$args,offset_peer : $inputOffsetPeer,offset_id : $offset_id,offset_date : $offset_date,limit : $limit,hash : $hash);
					switch($results->getClass()):
						# messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs; #
						# messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs; #
						case 'messages.dialogs':
						case 'messages.dialogsSlice':
							foreach(array_reverse($results->messages) as $last):
								if($last->getClass() !== 'messageEmpty'):
									list($offset_peer,$offset_id,$offset_date) = array($last->peer_id,$last->id,$last->date);
									break;
								endif;
							endforeach;
							return $this->parse_dialogs($results);
						# messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; #
						case 'messages.dialogsNotModified':
							return array();
					endswitch;
				};
			endif;
		endif;
		return new Pagination($fetchResults,$offset,$limit,$hashgen);
	}
	public function get_difference(
		int $pts = 1,
		int $date = 1,
		int $qts = 1,
		? int $total_limit = 0x7fffffff,
		? int $pts_limit = null,
		? int $qts_limit = null,
		bool $deep = false
	) : \Generator {
		while(true):
			Logging::log('Difference','pts = '.$pts.' & date = '.$date.' & qts = '.$qts);
			try {
				$difference = $this->updates->getDifference(pts : $pts,date : $date,qts : $qts,pts_total_limit : $total_limit,pts_limit : $pts_limit,qts_limit : $qts_limit,timeout : 3);
			} catch(\Throwable $error){
				$difference = new \Tak\Liveproto\Tl\Types\Updates\DifferenceEmpty;
			}
			if($difference instanceof \Tak\Liveproto\Tl\Types\Updates\Difference):
				$pts = $difference->state->pts;
				$date = $difference->state->date;
				$qts = $difference->state->qts;
			elseif($difference instanceof \Tak\Liveproto\Tl\Types\Updates\DifferenceSlice):
				$pts = $difference->intermediate_state->pts;
				$date = $difference->intermediate_state->date;
				$qts = $difference->intermediate_state->qts;
			elseif($difference instanceof \Tak\Liveproto\Tl\Types\Updates\DifferenceTooLong):
				$pts = $deep ? $this->search_pts($pts,$difference->pts,$qts,$date) : $difference->pts;
				continue;
			elseif($difference instanceof \Tak\Liveproto\Tl\Types\Updates\DifferenceEmpty):
				break;
			else:
				throw new Exception('Unknown difference update !');
			endif;
			yield $difference;
		endwhile;
	}
	public function get_channel_difference(
		mixed $channel,
		? object $filter = null,
		int $pts = 1,
		int $limit = 0x7fffffff
	) : \Generator {
		$inputChannel = $this->get_input_channel($channel);
		while(true):
			Logging::log('Channel Difference','pts = '.$pts.' & limit = '.$limit.' & channel id = '.$this->get_peer_id($inputChannel));
			$difference = $this->updates->getChannelDifference(channel : $inputChannel,filter : is_null($filter) ? $this->channelMessagesFilterEmpty() : $filter,pts : $pts,limit : $limit,force : true);
			if($difference instanceof \Tak\Liveproto\Tl\Types\Updates\ChannelDifference):
				$pts = $difference->pts;
			elseif($difference instanceof \Tak\Liveproto\Tl\Types\Updates\ChannelDifferenceTooLong):
				if(isset($difference->dialog->pts) and is_null($difference->final)):
					$pts = $difference->dialog->pts;
					continue;
				else:
					break;
				endif;
			elseif($difference instanceof \Tak\Liveproto\Tl\Types\Updates\ChannelDifferenceEmpty):
				break;
			else:
				throw new Exception('Unknown channel difference update !');
			endif;
			yield $difference;
			if($difference->final) break;
		endwhile;
	}
	private function search_pts(
		int $bottom,
		int $top,
		int $qts,
		int $date
	) : int {
		Logging::log('Difference','Finding PTS...');
		while($bottom <= $top):
			$pts = ($bottom + $top) >> 1;
			try {
				$difference = $this->updates->getDifference(pts : $pts,date : $date,qts : $qts,pts_total_limit : 0x7fffffff,timeout : 3);
			} catch(\Throwable $error){
				Logging::log('Difference',$error->getMessage(),E_WARNING);
				$difference = new \Tak\Liveproto\Tl\Types\Updates\DifferenceTooLong;
			}
			if($difference instanceof \Tak\Liveproto\Tl\Types\Updates\DifferenceTooLong):
				$bottom = $pts + 1;
			else:
				$top = $pts - 1;
			endif;
		endwhile;
		return $bottom;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Attributes\Type;

trait Users {
	public function get_input_user(string | int | null | object $user) : mixed {
		$entity = $this->get_input_peer($user);
		$class = $entity->getClass();
		return match($class){
			'inputPeerEmpty' => $this->inputUserEmpty(),
			'inputPeerSelf' => $this->inputUserSelf(),
			'inputPeerUser' => $this->inputUser(user_id : $entity->user_id,access_hash : $entity->access_hash),
			default => throw new \InvalidArgumentException('This entity('.$class.') does not belong to a user !')
		};
	}
	protected function get_input_user_from_message(#[Type('Message')] object $message) : object {
		if(isset($message->from_id->user_id)):
			$inputPeer = $this->get_input_peer(peer : $message->peer_id);
			return $this->inputUserFromMessage(peer : $inputPeer,msg_id : $message->id,user_id : $message->from_id->user_id);
		else:
			throw new \InvalidArgumentException('Field `from_id` is missing or invalid in the message');
		endif;
	}
	public function get_me() : object {
		return $this->get_peer('me');
	}
	public function is_bot() : bool {
		return boolval($this->get_me()->bot);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl\Methods;

use Tak\Liveproto\Errors\RpcError;

use Tak\Liveproto\Utils\Tools;

use Tak\Liveproto\Crypto\Password;

use Tak\Liveproto\Enums\Authentication;

use Tak\Liveproto\Attributes\Type;

use Tak\Attributes\Common\Vector;

use Tak\Attributes\Common\Is;

trait Auth {
	protected function apply_sent_code(#[Type('auth.SentCode')] object $result) : object {
		switch($result->getClass()):
			case 'auth.sentCode':
				if(empty($result->phone_code_hash) and isset($this->load->phonecodehash)):
					return $this->resend_code();
				endif;
				$this->load->phonecodehash = $result->phone_code_hash;
				if($result->type instanceof \Tak\Liveproto\Tl\Types\Auth\SentCodeTypeSetUpEmailRequired):
					$this->load->step = Authentication::NEED_EMAIL;
				else:
					$this->load->step = Authentication::NEED_CODE;
				endif;
				return $result;
			case 'auth.sentCodeSuccess':
				$this->load->step = Authentication::LOGIN;
				return $result;
			case 'auth.sentCodePaymentRequired':
				$this->load->step = Authentication::NEED_CODE_PAYMENT_REQUIRED;
				return $result;
		endswitch;
	}
	public function send_code(string $phone_number,mixed ...$settings) : object {
		try {
			$settings += ['logout_tokens'=>$this->load->logout_tokens];
			$result = $this->auth->sendCode(phone_number : $phone_number,settings : $this->codeSettings(...$settings),api_id : $this->load->api_id,api_hash : $this->load->api_hash);
			$this->load->phonenumber = $phone_number;
			return $this->apply_sent_code($result);
		} catch(RpcError $error){
			if($error->getCode() == 303):
				$this->changeDC($error->getValue());
				return $this->send_code($phone_number,...$settings);
			else:
				throw $error;
			endif;
		}
	}
	public function sign_up(string $first_name,string $last_name) : object {
		$result = $this->auth->signUp(first_name : $first_name,last_name : $last_name,phone_number : $this->load->phonenumber,phone_code_hash : $this->load->phonecodehash);
		$this->save_authorization($result);
		$this->load->step = Authentication::LOGIN;
		return $result;
	}
	public function sign_in(
		string | int | null $code = null,
		#[\SensitiveParameter] ? string $password = null,
		#[\SensitiveParameter] ? string $bot_token = null,
		#[\SensitiveParameter] ? string $web_token = null,
		? string $email = null
	) : object {
		if(is_null($code) === false):
			try {
				$result = $this->auth->signIn(phone_code : strval($code),email_verification : $email,phone_number : $this->load->phonenumber,phone_code_hash : $this->load->phonecodehash);
				if($result instanceof \Tak\Liveproto\Tl\Types\Auth\Authorization):
					$this->load->step = Authentication::LOGIN;
				elseif($result instanceof \Tak\Liveproto\Tl\Types\Auth\AuthorizationSignUpRequired):
					$this->load->step = Authentication::NEED_SIGNUP;
				endif;
			} catch(\Throwable $error){
				if($error->getMessage() === 'SESSION_PASSWORD_NEEDED'):
					$this->load->step = Authentication::NEED_PASSWORD;
				endif;
				throw $error;
			}
		elseif(is_null($password) === false):
			$account = $this->account->getPassword();
			$checker = new Password();
			$input = $checker->srp($account,$password);
			$result = $this->auth->checkPassword(password : $input);
			$this->load->password = $password;
			$this->load->step = Authentication::LOGIN;
		elseif(is_null($bot_token) === false):
			try {
				$result = $this->auth->importBotAuthorization(bot_auth_token : $bot_token,api_id : $this->load->api_id,api_hash : $this->load->api_hash,flags : 0);
				$this->load->step = Authentication::LOGIN;
			} catch(\Throwable $error){
				if($error->getCode() == 303):
					$this->changeDC($error->getValue());
					$result = $this->sign_in(bot_token : $bot_token);
				else:
					throw $error;
				endif;
			}
		elseif(is_null($web_token) === false):
			try {
				$result = $this->auth->importWebTokenAuthorization(web_auth_token : $web_token,api_id : $this->load->api_id,api_hash : $this->load->api_hash);
				$this->load->step = Authentication::LOGIN;
			} catch(\Throwable $error){
				if($error->getCode() == 303):
					$this->changeDC($error->getValue());
					$result = $this->sign_in(web_token : $web_token);
				else:
					throw $error;
				endif;
			}
		else:
			throw new \LogicException('One of the code / password / bot_token / web_token parameters must be entered in the sign_in method !');
		endif;
		$this->save_authorization($result);
		return $result;
	}
	public function resend_code() : object {
		$result = $this->auth->resendCode(phone_number : $this->load->phonenumber,phone_code_hash : $this->load->phonecodehash);
		return $this->apply_sent_code($result);
	}
	public function cancel_code() : bool {
		$result = $this->auth->cancelCode(phone_number : $this->load->phonenumber,phone_code_hash : $this->load->phonecodehash);
		if($result):
			$this->load->step = Authentication::NEED_AUTHENTICATION;
		endif;
		return $result;
	}
	public function reset_login_email() : bool {
		$result = $this->auth->resetLoginEmail(phone_number : $this->load->phonenumber,phone_code_hash : $this->load->phonecodehash);
		return $this->apply_sent_code($result);
	}
	public function firebase_sms(? string $safety = null,? string $push = null) : bool {
		if(is_null($safety) and is_null($push)):
			$safety = 'ysFoP5VLrJhIlp1ZgFfziiX5IEGhdgzdWJ5diTzjTMI=';
		endif;
		$result = $this->auth->requestFirebaseSms(phone_number : $this->load->phonenumber,phone_code_hash : $this->load->phonecodehash,safety_net_token : $safety,ios_push_secret : $push);
		return $result;
	}
	public function log_out() : object {
		$result = $this->auth->logOut();
		$this->save_authorization($result);
		$this->load->step = Authentication::NEED_AUTHENTICATION;
		return $result;
	}
	protected function save_authorization(#[Type('auth.Authorization')] object $authorization) : void {
		if(isset($authorization->future_auth_token)):
			if(is_string($authorization->future_auth_token)):
				$this->load->logout_tokens []= $authorization->future_auth_token;
				$this->load->logout_tokens = array_slice($this->load->logout_tokens,-20);
			endif;
		endif;
	}
	protected function login_token(#[Vector(new Is('int'))] array $except_ids = array()) : string {
		$loginToken = $this->auth->exportLoginToken(except_ids : $except_ids,api_id : $this->load->api_id,api_hash : $this->load->api_hash);
		$token = 'tg://login?token='.Tools::base64_url_encode($loginToken->token);
		return $token;
	}
	public function accept_token(string $token) : object {
		if(preg_match('~^tg:\/\/login\?token=(?<base64>[A-Za-z0-9_-]+)$~i',$token,$match)):
			$token = Tools::base64_url_decode($match['base64']);
			if($token === false) throw new \InvalidArgumentException('The base64 token of the input link is not valid !');
		endif;
		$result = $this->auth->acceptLoginToken(token : $token);
		return $result;
	}
	protected function wait_token(#[Vector(new Is('int'))] array $except_ids = array(),int $timeout = 30) : void {
		$this->fetchUpdate(updates : array('updateLoginToken'),timeout : $timeout)->await();
		$loginToken = $this->auth->exportLoginToken(except_ids : $except_ids,api_id : $this->load->api_id,api_hash : $this->load->api_hash);
		if($loginToken instanceof \Tak\Liveproto\Tl\Types\Auth\LoginTokenMigrateTo):
			$this->changeDC($loginToken->dc_id);
			$loginToken = $this->auth->importLoginToken(token : $loginToken->token);
		endif;
		if($loginToken instanceof \Tak\Liveproto\Tl\Types\Auth\LoginTokenSuccess):
			$this->load->step = Authentication::LOGIN;
		endif;
	}
}

?>FROM php:8.4-cli

ENV DEBIAN_FRONTEND=noninteractive

RUN set -eux; \
	apt-get update; \
	apt-get install -y --no-install-recommends \
	  build-essential autoconf pkg-config ca-certificates gnupg wget curl \
	  git unzip lsb-release apt-transport-https \
	  libzip-dev zlib1g-dev libicu-dev libgmp-dev libcurl4-openssl-dev \
	  libxml2-dev libonig-dev libsqlite3-dev libmagic-dev; \
	rm -rf /var/lib/apt/lists/*

RUN set -eux; \
	docker-php-ext-configure zip; \
	docker-php-ext-install -j"$(nproc)" xml; \
	docker-php-ext-install -j"$(nproc)" gmp; \
	docker-php-ext-install -j"$(nproc)" zip; \
	docker-php-ext-install -j"$(nproc)" sockets; \
	docker-php-ext-install -j"$(nproc)" mbstring; \
	docker-php-ext-install -j"$(nproc)" fileinfo; \
	docker-php-ext-install -j"$(nproc)" curl; \
	docker-php-ext-install -j"$(nproc)" intl; \
	docker-php-ext-install -j"$(nproc)" pdo pdo_sqlite;

RUN set -eux; \
	curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

WORKDIR /app

COPY .github/composer.json /app/
RUN set -eux; \
	composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader

COPY . /app

CMD ["php", "-v"]MIT License

Copyright (c) 2025 Taha

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

I want to express my sincere gratitude to the Telegram Android open-source project and to TDLib.
Studying your codebase, documentation, and example implementations provided essential guidance during the development of my MTProto library.
Your clear design patterns, protocol handling examples, and focused attention to performance and reliability significantly accelerated my work and helped me avoid many pitfalls.
Thank you to every contributor - your open, shared effort made this possible
# Security Policy

## Supported Versions

| Version | Supported          |
| ------- | ------------------ |
| 1.0.0   | :white_check_mark: |
| < 0.0.24   | :x:                |

## Reporting a Vulnerability

Hey there 👋 , thanks for helping make [LiveProto](https://github.com/TakNone/LiveProto) 🌱 safer ! We love when people take the time to share security issues with us responsibly

### Preferred contact methods ( use either ) :

 - Telegram : https://TakNone.t.me

 - Email : MrTakNone@gmail.com.github/ export-ignore
docs/ export-ignore
examples/ export-ignore
{
    "name": "taknone/liveproto",
    "license": "MIT",
    "description": "An async , pure PHP MTProto Telegram client",
    "type": "library",
    "keywords": [
        "telegram",
        "client",
        "api",
        "php",
        "liveproto",
        "live",
        "proto",
        "telegram-client",
        "mtproto",
        "async"
    ],
    "autoload": {
        "psr-4": {
            "Tak\\Liveproto\\": "src"
        },
        "files": [
            "src/loader.php"
        ]
    },
    "authors": [
        {
            "name": "Tak None",
            "email": "MrTakNone@gmail.com",
            "role": "Developer"
        }
    ],
    "minimum-stability": "beta",
    "require": {
        "php-64bit": ">=8.4",
        "taknone/asyncio": "*",
        "taknone/attributes": "*",
        "taknone/bootstrapper": "*",
        "ext-openssl": "*",
        "ext-gmp": "*",
        "ext-json": "*",
        "ext-xml": "*",
        "ext-dom": "*",
        "ext-filter": "*",
        "ext-hash": "*",
        "ext-zlib": "*",
        "ext-fileinfo": "*",
        "phpseclib/phpseclib": "^3.0.46"
    },
    "config": {
        "allow-plugins": {
            "taknone/bootstrapper": true
        }
    },
    "suggest": {
        "ext-swoole": "Required for high-performance Swoole coroutine support ( > 5.0.0 )",
        "ext-tgcrypto": "Speeds up encryption / decryption processes for Telegram MTproto",
        "ext-pcntl": "Allows for better signal handling"
    }
}# Attributes

[![PHP Version](https://img.shields.io/badge/php-8%2B-blue)](https://www.php.net/) [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)

Attribute-based validation for PHP 8.4+ : validate method parameters, return values and property access using compact, reusable attributes

# Validator - Declarative validation using PHP 8+ attributes

A lightweight, framework-agnostic library that lets you declare validation rules as PHP attributes. Validate method parameters, method return values, and property get/set using compact, reusable attribute classes ( for example `#[Range]`, `#[Pattern]`, `#[Vector]` ) Built-in caching of reflection metadata keeps runtime overhead low

---

# 📦 Installation

Install via Composer :

```bash
composer require taknone/attributes
```

Then enable Composer autoload in your project :

```php
require_once __DIR__.'/vendor/autoload.php';
```

---

# 🚀 Quickstart

The repository includes an [`examples`](examples) directory with runnable examples and small helper scripts

---

# Contributing

PRs welcome ! Follow a few rules :

1. Run and add example for new validators
2. Keep attribute constructor arguments constant expressions ( required by PHP attributes )
3. Document behavior for corner cases ( nullability, casting, unique semantics )

---

# License

MIT — see [`LICENSE`](LICENSE)

---

# Support / Contact

If you need help integrating `Attributes` into your project, open an issue or reach out via the repository's issue tracker<?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class Is implements ValidatorInterface {
	public function __construct(private array | string $types){
		if(is_string($types)){
			$this->types = array_map(trim(...),explode(chr(124),$types));
		}
	}
	public function validate(string $name,mixed $value) : mixed {
		$raise = false;
		foreach($this->types as $type){
			$raise |= str_contains(gettype($value),strtolower($type));
		}
		if(boolval($raise) === false){
			throw new InvalidArgumentException('$'.$name.' must be'.strval(count($this->types) > 1 ? ' one of ' : chr(32)).implode(chr(32).chr(44).chr(32),$this->types).' type');
		}
		return $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class Contains implements ValidatorInterface {
	public function __construct(public string $needle){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(is_string($value) === false){
			throw new InvalidArgumentException('$'.$name.' must be string for Contains');
		}
		if(str_contains($value,$this->needle) === false){
			throw new InvalidArgumentException('$'.$name.' must be contains '.$this->needle.' , given '.var_export($value,true));
		}
		return $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class To implements ValidatorInterface {
	public function __construct(public string $type){
	}
	public function validate(string $name,mixed $value) : mixed {
		settype($value,$this->type);
		return $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use ReflectionClass;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class Func implements ValidatorInterface {
	public function __construct(public mixed $callable,public bool $enableCheck = true){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(is_callable($this->callable)){
			$result = call_user_func($this->callable,$value);
			if($result === false and $this->enableCheck){
				throw new InvalidArgumentException('$'.$name.' the function returned false');
			}
			$ensure = boolval(is_bool($result) and $this->enableCheck);
			return $ensure ? $value : $result;
		} else {
			return $value;
		}
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class EndsWith implements ValidatorInterface {
	public function __construct(public string $needle){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(is_string($value) === false){
			throw new InvalidArgumentException('$'.$name.' must be string for EndsWith');
		}
		if(str_ends_with($value,$this->needle) === false){
			throw new InvalidArgumentException('$'.$name.' must be ends with '.$this->needle.' , given '.var_export($value,true));
		}
		return $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class Range implements ValidatorInterface {
	public function __construct(public float | int $min,public float | int $max){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(is_numeric($value) === false){
			throw new InvalidArgumentException('$'.$name.' must be numeric for Range');
		}
		if($value < $this->min || $value > $this->max){
			throw new InvalidArgumentException('$'.$name.' must be between '.$this->min.' and '.$this->max.' , given '.var_export($value,true));
		}
		return $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class FilterVar implements ValidatorInterface {
	public function __construct(public int $filter = FILTER_DEFAULT,public array | int $options = FILTER_NULL_ON_FAILURE,public bool $return = false){
	}
	public function validate(string $name,mixed $value) : mixed {
		$result = filter_var($value,$this->filter,$this->options);
		if($result === false){
			throw new InvalidArgumentException('$'.$name.' filter a variable failed');
		}
		return $this->return ? $result : $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class Hash implements ValidatorInterface {
	public function __construct(public string $algo,public bool $binary = false,public array $options = array()){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(is_string($value) === false){
			throw new InvalidArgumentException('$'.$name.' must be string for Hash');
		}
		return hash($this->algo,$value,$this->binary,$this->options);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class StartsWith implements ValidatorInterface {
	public function __construct(public string $needle){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(is_string($value) === false){
			throw new InvalidArgumentException('$'.$name.' must be string for StartsWith');
		}
		if(str_starts_with($value,$this->needle) === false){
			throw new InvalidArgumentException('$'.$name.' must be starts with '.$this->needle.' , given '.var_export($value,true));
		}
		return $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class InOrder implements ValidatorInterface {
	public function __construct(public int $flags = SORT_REGULAR){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(is_array($value) === false){
			throw new InvalidArgumentException('$'.$name.' must be array for InOrder');
		}
		sort($value,$this->flags);
		return $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use ReflectionClass;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class BindAs implements ValidatorInterface {
	public function __construct(public string $class,public string $method = '__construct',public bool $spread = false){
	}
	public function validate(string $name,mixed $value) : mixed {
		$spread = boolval($this->spread and is_array($value));
		$args = ($spread ? $value : array($value));
		$class = new ReflectionClass($this->class);
		if($this->method === '__construct'){
			// return $class->newInstanceArgs($args); //
			return $class->newLazyGhost(fn(object $object) : mixed => call_user_func_array([$object,$this->method],$args));
		}
		$method = $class->getMethod($this->method);
		return $method->invokeArgs($method->isStatic() ? null : $class->newInstanceWithoutConstructor(),$args);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class Operators implements ValidatorInterface {
	public function __construct(public mixed $what,public string $operator){
	}
	public function validate(string $name,mixed $value) : mixed {
		$result = match(strtolower($this->operator)){
			'add' , '+' => $this->what + $value,
			'sub' , '-' => $this->what - $value,
			'mul' , '*' => $this->what * $value,
			'div' , '+' => $this->what / $value,
			'mod' , '%' => $this->what % $value,
			'pow' , '**' => $this->what ** $value,
			'concat' , '.' => $this->what . $value,
			'shl' , '<<' => $this->what << $value,
			'shr' , '>>' => $this->what >> $value,
			'xor' , '^' => $this->what ^ $value,
			'exclude' , '~' => $this->what &~ $value,
			'or' , '|' => $this->what || $value,
			'and' , '&' => $this->what && $value,
			'not' , '!' => $this->what != $value,
			'equal' , '=' => $this->what == $value,
			'lt' , '<' => $this->what < $value,
			'gt' , '>' => $this->what > $value,
			'lte' , '<=' => $this->what <= $value,
			'gte' , '>=' => $this->what >= $value,
			'spaceship' , '<=>' => $this->what <=> $value,
			'instanceof' , 'is' => $value instanceof $this->what,
			default => throw new InvalidArgumentException('Unsupported operator : '.$this->operator)
		};
		if($result === false){
			throw new InvalidArgumentException('NOT '.var_export($this->what,true).chr(32).$this->operator.chr(32).var_export($value,true));
		}
		return is_bool($result) ? $value : $result;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL)]
final class IP implements ValidatorInterface {
	public const V4 = (1 << 4);
	public const V6 = (1 << 6);
	public const BOTH = self::V4 | self::V6;

	public function __construct(public int $flags = self::BOTH){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(boolval($this->flags & self::V4)){
			if(filter_var($value,FILTER_VALIDATE_IP,FILTER_FLAG_IPV4)){
				return $value;
			}
		}
		if(boolval($this->flags & self::V6)){
			if(filter_var($value,FILTER_VALIDATE_IP,FILTER_FLAG_IPV6)){
				return $value;
			}
		}
		if(boolval($this->flags & self::BOTH) === false){
			throw new InvalidArgumentException('$'.$name.' The IP::V4 / IP::V6 flags are not set');
		}
		throw new InvalidArgumentException('$'.$name.' invalid IP , given '.var_export($value,true));
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class In implements ValidatorInterface {
	public function __construct(public array $values){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(in_array($value,$this->values,true) === false){
			$values = implode(chr(32).chr(44).chr(32),array_map(static fn(mixed $v) => var_export($v,true),$this->values));
			throw new InvalidArgumentException('$'.$name.' must be one of : '.$values.' , given '.var_export($value,true));
		}
		return $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class Pattern implements ValidatorInterface {
	public function __construct(public string $regex,public bool | int | string $matches = false){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(is_string($value) === false){
			throw new InvalidArgumentException('$'.$name.' must be a string to match pattern');
		}
		if(preg_match($this->regex,$value,$matches) === false){
			throw new InvalidArgumentException('$'.$name.' does not match pattern '.$this->regex.' , given '.var_export($value,true));
		}
		return $this->matches !== false ? ($this->matches !== true ? $matches[$this->matches] : $matches) : $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL)]
final class Json implements ValidatorInterface {
	public function __construct(public bool $enableCheck = true,public int $flags = JSON_THROW_ON_ERROR,public int $depth = 512){
	}
	public function validate(string $name,mixed $value) : mixed {
		$validation = boolval($this->enableCheck and is_string($value));
		if($validation and json_validate($value) === false){
			throw new InvalidArgumentException('$'.$name.' invalid JSON , given '.var_export($value,true));
		}
		return $validation ? $value : json_encode($value,$this->flags,$this->depth);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class Vector implements ValidatorInterface {
	public function __construct(protected ValidatorInterface $validator){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(is_array($value) === false){
			throw new InvalidArgumentException('$'.$name.' must be array for Vector');
		}
		foreach($value as $k => $v){
			$value[$k] = $this->validator->validate($name,$v);
		}
		return $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Common;

use Tak\Attributes\ValidatorInterface;

use Attribute;

use InvalidArgumentException;

#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
final class Reverse implements ValidatorInterface {
	public function __construct(){
	}
	public function validate(string $name,mixed $value) : mixed {
		if(is_string($value)){
			$chars = preg_split('//u',$value,-1,PREG_SPLIT_NO_EMPTY);
			return implode(strval(null),array_reverse($chars));
		} elseif(is_array($value)){
			return array_reverse($value);
		} else {
			throw new InvalidArgumentException('$'.$name.' must be array / string for Reverse');
		}
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD)]
interface InvokeInterface {
	public function invoke(callable $callback,array $arguments) : mixed;
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_PARAMETER | Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
interface ValidatorInterface {
	public function validate(string $name,mixed $value) : mixed;
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Return;

use Tak\Attributes\ReturnFilterInterface;

use Tak\Attributes\ValidatorInterface;

use Iterator;

use Generator;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
final class Iterate implements ReturnFilterInterface {
	public function __construct(protected ValidatorInterface $validator){
	}
	public function filter(string $name,mixed $value) : mixed {
		if($value instanceof Iterator){
			for($value->rewind(); $value->valid(); $value->next()){
				$k = $value->key();
				$current = $value->current();
				$v = $this->validator->validate('YIELD',$current);
				yield $k => $v;
			}
		}
		return $value instanceof Generator ? $value->getReturn() : $value;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Return;

use Tak\Attributes\ReturnFilterInterface;

use Tak\Attributes\ValidatorInterface;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
final class Result implements ReturnFilterInterface {
	public function __construct(protected ValidatorInterface $validator){
	}
	public function filter(string $name,mixed $value) : mixed {
		return $this->validator->validate('RETURN',$value);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD)]
interface PropertyInterface {
	public function check(string $name,mixed $value) : mixed;
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes;

use Tak\Attributes\Property\Set;

use Tak\Attributes\Property\Get;

use Attribute;

use Reflector;

use ReflectionClass;

use ReflectionMethod;

use ReflectionProperty;

use ReflectionAttribute;

use ReflectionNamedType;

use Error;

use BadMethodCallException;

trait AttributesEngine {
	private static array $metadataCache = array();

	public function __call(string $name,array $args) : mixed {
		return $this->invokeValidatedMethod(static::class,$name,$args);
	}
	public static function __callStatic(string $name,array $args) : mixed {
		$staticClass = new ReflectionClass(static::class);
		$instance = $staticClass->newInstanceWithoutConstructor();
		return $instance->invokeValidatedMethod(static::class,$name,$args);
	}
	public function __set(string $name,mixed $value) : void {
		if(property_exists($this,$name)){
			$reflection = new ReflectionProperty($this,$name);
			$identifier = 'property::'.$reflection->getDeclaringClass()->getName().'::'.$reflection->getName();
			if(array_key_exists($identifier,self::$metadataCache) === false){
				self::$metadataCache[$identifier] = $this->buildMetadata($reflection);
			}
			$metas = self::$metadataCache[$identifier];
			$null = boolval($metas['allowsNull'] and is_null($value));
			$default = boolval($metas['hasDefault'] and call_user_func($metas['hasDefault']) === $value);
			if($null === false and $default === false){
				foreach($metas['setValidators'] as $validator){
					$value = $validator->check($name,$value);
				}
			}
			if(empty($metas['setValidators']) and empty($metas['getValidators'])){
				throw new Error('Cannot access property '.static::class.'::$'.$name);
			} else {
				$reflection->setValue($this,$value);
			}
		} else {
			throw new Error('Property '.$name.' does not exist on '.static::class);
		}
	}
	public function __get(string $name) : mixed {
		if(property_exists($this,$name)){
			$reflection = new ReflectionProperty($this,$name);
			$identifier = 'property::'.$reflection->getDeclaringClass()->getName().'::'.$reflection->getName();
			if(array_key_exists($identifier,self::$metadataCache) === false){
				self::$metadataCache[$identifier] = $this->buildMetadata($reflection);
			}
			$metas = self::$metadataCache[$identifier];
			$value = $reflection->getValue($this);
			foreach($metas['getValidators'] as $validator){
				$value = $validator->check($name,$value);
			}
			if(empty($metas['getValidators']) and empty($metas['setValidators'])){
				throw new Error('Cannot access property '.static::class.'::$'.$name);
			} else {
				return $value;
			}
		} else {
			throw new Error('Property '.$name.' does not exist on '.static::class);
		}
	}
	private function invokeValidatedMethod(string $className,string $methodName,array $arguments,bool $isAccessible = false) : mixed {
		if(method_exists($className,$methodName) === false){
			throw new BadMethodCallException('Method '.$className.'::'.$methodName.' does not exist');
		}
		$reflection = new ReflectionMethod($className,$methodName);
		if($reflection->isProtected() === false){
			throw new Error('Call to method '.$className.'::'.$methodName.'() that is not protected');
		}
		$identifier = 'method::'.$reflection->getDeclaringClass()->getName().'::'.$reflection->getName();
		if(array_key_exists($identifier,self::$metadataCache) === false){
			self::$metadataCache[$identifier] = $this->buildMetadata($reflection);
		}
		$metas = self::$metadataCache[$identifier];
		$parametersName = array_column($metas['parameters'],'name');
		$args = array();
		foreach($arguments as $key => $value){
			$index = is_string($key) ? array_search($key,$parametersName,true) : $key;
			$pMeta = $metas['parameters'][$index];
			$null = boolval($pMeta['allowsNull'] and is_null($value));
			$default = boolval($pMeta['hasDefault'] and call_user_func($pMeta['hasDefault']) === $value);
			if($null === false and $default === false){
				foreach($pMeta['validators'] as $validator){
					$value = $validator->validate($pMeta['name'],$value);
				}
			}
			$args[$pMeta['name']] = $value;
		}
		foreach($metas['parameters'] as $pMeta){
			$isAccessible |= empty($pMeta['validators']) === false;
		}
		$isAccessible |= empty($metas['performers']) === false;
		$isAccessible |= empty($metas['return']) === false;
		if(boolval($isAccessible) === false){
			throw new Error('Call to method '.$className.'::'.$methodName.'() from global scope');
		}
		$run = fn(mixed ...$params) : mixed => $reflection->invokeArgs($reflection->isStatic() ? null : $this,$params);
		foreach($metas['performers'] as $performer){
			$run = fn(mixed ...$params) : mixed => $performer->invoke($run,$params);
		}
		$result = call_user_func_array($run,$args);
		foreach($metas['return'] as $returnFilter){
			$result = $returnFilter->filter($identifier,$result);
		}
		return $result;
	}
	private function buildMetadata(Reflector $reflection) : array {
		if($reflection instanceof ReflectionMethod){
			$parameters = $reflection->getParameters();
			$args = array();
			foreach($parameters as $parameter){
				$type = $parameter->getType();
				$args []= array(
					'name'=>$parameter->getName(),
					'allowsNull'=>$parameter->allowsNull(),
					'hasDefault'=>$parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue(...) : false,
					'validators'=>$this->resolveAttributeInstances($parameter,ValidatorInterface::class)
				);
			}
			$returnFilters = $this->resolveAttributeInstances($reflection,ReturnFilterInterface::class);
			$invokes = $this->resolveAttributeInstances($reflection,InvokeInterface::class);
			return array(
				'parameters'=>$args,
				'return'=>$returnFilters,
				'performers'=>$invokes
			);
		} elseif($reflection instanceof ReflectionProperty){
			$type = $reflection->getType();
			return array(
				'name'=>$reflection->getName(),
				'allowsNull'=>boolval($type?->allowsNull() ?? true),
				'hasDefault'=>$reflection->hasDefaultValue() ? $reflection->getDefaultValue(...) : false,
				'setValidators'=>$this->resolveAttributeInstances($reflection,Set::class),
				'getValidators'=>$this->resolveAttributeInstances($reflection,Get::class)
			);
		}
	}
	private function resolveAttributeInstances(Reflector $reflection,string $class) : array {
		$attributes = $reflection->getAttributes($class,ReflectionAttribute::IS_INSTANCEOF);
		return array_map(static fn(ReflectionAttribute $attr) : object => $attr->newInstance(),$attributes);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD)]
interface ReturnFilterInterface {
	public function filter(string $name,mixed $value) : mixed;
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Property;

use Tak\Attributes\PropertyInterface;

use Tak\Attributes\ValidatorInterface;

use Attribute;

#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
final class Get implements PropertyInterface {
	public function __construct(protected ValidatorInterface $validator){
	}
	public function check(string $name,mixed $value) : mixed {
		return $this->validator->validate($name,$value);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Property;

use Tak\Attributes\PropertyInterface;

use Tak\Attributes\ValidatorInterface;

use Attribute;

#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
final class Set implements PropertyInterface {
	public function __construct(protected ValidatorInterface $validator){
	}
	public function check(string $name,mixed $value) : mixed {
		return $this->validator->validate($name,$value);
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Invoke;

use Tak\Attributes\InvokeInterface;

use Attribute;

use Throwable;

use function Tak\Asyncio\async;

#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
final class Async implements InvokeInterface {
	public function __construct(public bool $await = true,public bool $catch = true,public bool $ignore = false){
	}
	public function invoke(callable $callback,array $arguments) : mixed {
		$future = async($callback,...$arguments);
		if($this->catch){
			$future = $future->catch(fn(Throwable $error) : bool => error_log(strval($error)));
		}
		if($this->ignore){
			$future = $future->ignore();
		}
		return $this->await ? $future->await() : null;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Invoke;

use Tak\Attributes\InvokeInterface;

use Attribute;

use ReflectionFunction;

#[Attribute(Attribute::TARGET_METHOD)]
final class Cache implements InvokeInterface {
	private static array $cache = array();

	public function __construct(public float $ttl = 60){
	}
	public function invoke(callable $callback,array $arguments) : mixed {
		$timer = $this->ttl + microtime(true);
		$reflection = new ReflectionFunction($callback);
		$hash = md5(strval($reflection));
		if(array_key_exists($hash,self::$cache) === false || self::$cache[$hash]['expires_at'] <= microtime(true)){
			self::$cache[$hash] = array('expires_at'=>$timer,'result'=>call_user_func_array($callback,$arguments));
		}
		return self::$cache[$hash]['result'];
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Invoke;

use Tak\Attributes\InvokeInterface;

use Attribute;

use Throwable;

#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
final class IgnoreErrors implements InvokeInterface {
	public function __construct(public bool $log = true){
	}
	public function invoke(callable $callback,array $arguments) : mixed {
		try {
			return call_user_func_array($callback,$arguments);
		} catch(Throwable $error){
			if($this->log){
				error_log(strval($error));
			}
			return null;
		}
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Invoke;

use Tak\Attributes\InvokeInterface;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
final class TimeIt implements InvokeInterface {
	private static array $cache = array();

	public function __construct(public mixed $callable = null){
	}
	public function invoke(callable $callback,array $arguments) : mixed {
		$start = microtime(true);
		$result = call_user_func_array($callback,$arguments);
		$finish = microtime(true);
		if(is_callable($this->callable)){
			call_user_func($this->callable,$finish - $start);
		} else {
			echo 'It took ' , $finish - $start , ' seconds' , PHP_EOL;
		}
		return $result;
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Invoke;

use Tak\Attributes\InvokeInterface;

use Tak\Asyncio\Loop;

use Attribute;

use Throwable;

use function Tak\Asyncio\async;

#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
final class Repeat implements InvokeInterface {
	public function __construct(public float $interval,public float $timeout = -1){
	}
	public function invoke(callable $callback,array $arguments) : mixed {
		$future = async($callback,...$arguments);
		$id = Loop::repeat($this->interval,function(string $id) use($callback,$arguments) : void {
			call_user_func_array($callback,$arguments);
		});
		if($this->timeout > 0){
			Loop::unreference(Loop::delay($this->timeout,static fn() : null => Loop::cancel($id)));
		}
		return $future->await();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Attributes\Invoke;

use Tak\Attributes\InvokeInterface;

use Attribute;

use Throwable;

use RuntimeException;

use function Tak\Asyncio\delay;

#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
final class Retry implements InvokeInterface {
	public function __construct(public int $attempts,public float $delay){
	}
	public function invoke(callable $callback,array $arguments) : mixed {
		for($i = 0;$i < $this->attempts;$i++){
			try {
				return call_user_func_array($callback,$arguments);
			} catch(Throwable){
				delay($this->delay);
			}
		}
		throw new RuntimeException($this->attempts.' attempts were made to execute the method and all attempts failed');
	}
}

?>MIT License

Copyright (c) 2025 Taha

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
{
    "name": "taknone/attributes",
    "license": "MIT",
    "description": "Attribute-based validation for PHP 8.4+",
    "type": "library",
    "keywords": [
        "attribute",
        "validation",
        "filter",
        "php",
        "checker",
        "reflection",
        "async"
    ],
    "autoload": {
        "psr-4": {
            "Tak\\Attributes\\": "src"
        }
    },
    "authors": [
        {
            "name": "Tak None",
            "email": "MrTakNone@gmail.com"
        }
    ],
    "minimum-stability": "stable",
    "require": {
        "php": ">=8.4",
        "ext-json": "*",
        "ext-filter": "*",
        "ext-hash": "*",
        "taknone/asyncio": "*"
    }
}
<?php

use Tak\Attributes\AttributesEngine;

use Tak\Attributes\Common\Operators;

use Tak\Attributes\Common\To;

use Tak\Attributes\Common\Hash;

use Tak\Attributes\Common\Pattern;

use Tak\Attributes\Common\Func;

use Tak\Attributes\Return\Result;

function callMe(string $name) : string {
	return 'Mr.'.$name;
}

final class UserService {
	use AttributesEngine;

	#[Result(new Pattern(regex : '~hash\s:\s(?<hash>.+)~i',matches : 'hash'))]
	protected function register(
		#[Operators(18,'<='),Operators(25,'>')] int $age,
		#[Operators(0,'not'),Operators(1,'<<')] int $flag,
		#[Func(callable : 'callMe',enableCheck : false)] string $name,
		#[To('string'),Hash('sha256')] string $hash
	) : mixed {
		echo 'Hello ' , $name , PHP_EOL;
		return sprintf('age %d , flag : %d , hash : %s',$age,$flag,$hash);
	}
}

$service = new UserService();

var_dump($service->register(18,4,'TakNone',100101110101110));

?><?php

use Tak\Attributes\AttributesEngine;

use Tak\Attributes\Common\Json;

use Tak\Attributes\Common\Contains;

use Tak\Attributes\Common\EndsWith;

use Tak\Attributes\Common\StartsWith;

use Tak\Attributes\Common\In;

use Tak\Attributes\Common\To;

use Tak\Attributes\Return\Iterate;

final class UserService {
	use AttributesEngine;

	#[Iterate(new To('string'))]
	protected function register(
		#[Json(enableCheck : false)] string $json,
		#[StartsWith('@'),Contains('User'),EndsWith('!')] string $username,
		#[In(['user','admin'])] string $role = 'user'
	) : Generator {
		yield 1000;
		yield 2000;
		yield 3000;
		return sprintf('registered %s (%s) details %s',$username,$role,$json);
	}
}

$service = new UserService();

$generator = $service->register(['user'=>'you'],'@My User Name !','admin');

foreach($generator as $stringNumber){
	var_dump($stringNumber);
}

var_dump($generator->getReturn());

?><?php

use Tak\Attributes\AttributesEngine;

use Tak\Attributes\Common\Json;

use Tak\Attributes\Common\Contains;

use Tak\Attributes\Common\EndsWith;

use Tak\Attributes\Common\StartsWith;

use Tak\Attributes\Common\To;

final class UserService {
	use AttributesEngine;

	protected function register(
		#[Json] string $json,
		#[StartsWith('@'),Contains('User'),EndsWith('!')] string $username,
		#[To('string')] string $stringNumber
	) : mixed {
		return sprintf('registered %s (%s) details %s',$username,$stringNumber,$json);
	}
}

$service = new UserService();

var_dump($service->register(json_encode(['user'=>'me']),'@My User Name !',123456789));

?><?php

use Tak\Attributes\AttributesEngine;

use Tak\Attributes\Invoke\Retry;

use Tak\Attributes\Invoke\TimeIt;

use Tak\Attributes\Invoke\IgnoreErrors;

use Tak\Attributes\Common\FilterVar;

use Tak\Attributes\Common\Vector;

use Tak\Attributes\Common\InOrder;

use Tak\Attributes\Common\Reverse;

use Tak\Attributes\Common\Is;

use Tak\Attributes\Common\To;

final class UserService {
	public int $counter = 0;

	use AttributesEngine;

	#[Retry(attempts : 5,delay : 0.2)]
	#[IgnoreErrors(log : false)]
	#[TimeIt]
	protected function register(
		#[FilterVar(FILTER_VALIDATE_URL,FILTER_FLAG_PATH_REQUIRED)] string $url,
		#[Vector(new Is('int')),Vector(new To('string'))] array $numbers,
		#[InOrder,Reverse] array $organized
	) : never {
		var_dump($organized);
		echo 'Counter : ' , ++$this->counter , PHP_EOL;
		throw new \Exception('I\'ll force you to try again and again !');
	}
}

$service = new UserService();

var_dump($service->register('https://example.com/withpath',array(1,2,3,4,5,6,7),array(5,2,7,4,1,0,3,6)));

?><?php

use Tak\Attributes\AttributesEngine;

use Tak\Attributes\Property\Set;

use Tak\Attributes\Property\Get;

use Tak\Attributes\Invoke\Async;

use Tak\Attributes\Invoke\Cache;

use Tak\Attributes\Invoke\IgnoreErrors;

use Tak\Attributes\Common\Pattern;

use Tak\Attributes\Common\Range;

use Tak\Attributes\Common\In;

use Tak\Attributes\Common\BindAs;

class Role {
	public function __construct(public string $role){
	}
}

final class UserService {
	#[Set(new In(['user','admin']))]
	#[Get(new BindAs('Role'))]
	protected string $role;

	use AttributesEngine;

	#[IgnoreErrors]
	#[Async(await : true)]
	#[Cache(ttl : 10)]
	protected function register(
		#[Range(18,99)] int $age,
		#[Pattern('/^[A-Za-z0-9_]{5,10}$/')] ? string $username = null,
		#[In(['user','admin'])] string $role = 'user'
	) : mixed {
		return sprintf('registered %s (%d) as %s',$username,$age,$role);
	}
}

$service = new UserService();

$service->role = 'admin';

var_dump($service->register(20,'alice_01','user'));

var_dump($service->role);

?><?php

use Tak\Attributes\AttributesEngine;

use Tak\Attributes\Invoke\Repeat;

use Tak\Attributes\Invoke\Cache;

use Tak\Attributes\Common\Json;

use Tak\Attributes\Common\Contains;

use Tak\Attributes\Common\EndsWith;

use Tak\Attributes\Common\StartsWith;

use Tak\Attributes\Common\In;

use Tak\Asyncio\Loop;

final class UserService {
	public int $counter = 0;

	use AttributesEngine;

	#[Cache(ttl : 0.4)]
	#[Repeat(interval : 0.2,timeout : 1.2)]
	protected function register(
		#[Json(enableCheck : false)] string $json,
		#[StartsWith('@'),Contains('User'),EndsWith('!')] string $username,
		#[In(['user','admin'])] string $role = 'user'
	) : mixed {
		echo 'Counter : ' , ++$this->counter , PHP_EOL;
		return sprintf('registered %s (%s) details %s',$username,$role,$json);
	}
}

$service = new UserService();

var_dump($service->register(['user'=>'me'],'@My User Name !','admin'));

Loop::run();

?><?php

use Tak\Attributes\AttributesEngine;

use Tak\Attributes\Common\IP;

use Tak\Attributes\Common\FilterVar;

use Tak\Attributes\Common\BindAs;

use Tak\Attributes\Common\Range;

final class Age {
	public function __construct(public int $age){
		printf('Age %d'.PHP_EOL,$age);
	}
}

final class Ages {
	public function __construct(int $ageOne,int $ageTwo){
		printf('Ages %d && %d'.PHP_EOL,$ageOne,$ageTwo);
	}
}

final class UserService {
	use AttributesEngine;

	protected function register(
		#[Range(40,50),BindAs('Age')] Age $age,
		#[BindAs(class : 'Ages',spread : true)] Ages $ages,
		#[FilterVar(FILTER_VALIDATE_EMAIL)] string $email,
		#[IP(IP::BOTH)] string $ip,
		#[IP(IP::V4)] string $ipv4 = '127.0.0.1'
	) : mixed {
		return sprintf('registered %s (%d) with %s',$email,$age->age,$ip);
	}
}

$service = new UserService();

var_dump($service->register(age : 45,ages : array(96,69),email : 'mrtaknone@gmail.com',ip : '2001:4860:4860::8888'));

?># bootstrapper
Composer plugin to set up LiveProto library requirements - runs tasks on install / update and autoload dump
<?php

declare(strict_types=1);

namespace Tak\Liveproto;

use Composer\Composer;

final class Util {
	public function __construct(private Composer $composer){
	}
	public function findInstallPath(string $packageName) : ? string {
		$localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
		$packages = $localRepo->getPackages();
		foreach($packages as $pkg){
			if($pkg->getName() === $packageName){
				return $this->composer->getInstallationManager()->getInstallPath($pkg);
			}
		}
		return null;
	}
}

?><?php

declare(strict_types=1);

namespace Tak\Liveproto;

use Composer\Composer;

use Composer\IO\IOInterface;

use Composer\Plugin\PluginInterface;

use Composer\EventDispatcher\EventSubscriberInterface;

use Composer\Script\Event;

use Composer\Script\ScriptEvents;

class Plugin implements PluginInterface , EventSubscriberInterface {
	private Composer $composer;
	private IOInterface $io;
	private ? string $path = null;
	protected bool $setuped = false;

	public function activate(Composer $composer,IOInterface $io) : void {
		$this->composer = $composer;
		$this->io = $io;
		$util = new Util($composer);
		$this->path = $util->findInstallPath('taknone/liveproto');
	}
	public function deactivate(Composer $composer,IOInterface $io) : void {
	}
	public function uninstall(Composer $composer,IOInterface $io) : void {
	}
	public static function getSubscribedEvents() : array {
		return array(
			ScriptEvents::POST_AUTOLOAD_DUMP=>'onPostAutoloadDump',
			ScriptEvents::POST_INSTALL_CMD=>'onPostInstall',
			ScriptEvents::POST_UPDATE_CMD =>'onPostUpdate',
		);
	}
	public function onPostAutoloadDump(Event $event) : void {
		if(is_null($this->path) === false){
			if($this->setuped === false){
				$this->io->write('<info>Setup...</info>');
				setup($this->path);
				$this->setuped = true;
			} else {
				$this->io->write('<comment>Already setuped !</comment>');
			}
		} else {
			$this->io->write('<error>Package path `taknone/liveproto` not found</error>');
		}
	}
	public function onPostInstall(Event $event) : void {
		$this->io->write('<comment>TLGenerator : post-install hook</comment>');
		$this->onPostAutoloadDump($event);
	}
	public function onPostUpdate(Event $event) : void {
		$this->io->write('<comment>TLGenerator : post-update hook</comment>');
		$this->onPostAutoloadDump($event);
	}
}

?>---types---

boolFalse#bc799737 = Bool;
boolTrue#997275b5 = Bool;

true#3fedd339 = True;

vector#1cb5c415 {t:Type} # [ t ] = Vector t;

error#c4b9f9bb code:int text:string = Error;

null#56730bcc = Null;

inputPeerEmpty#7f3b18ea = InputPeer;
inputPeerSelf#7da07ec9 = InputPeer;
inputPeerChat#35a95cb9 chat_id:long = InputPeer;
inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer;
inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer;
inputPeerUserFromMessage#a87b0a1c peer:InputPeer msg_id:int user_id:long = InputPeer;
inputPeerChannelFromMessage#bd2a0840 peer:InputPeer msg_id:int channel_id:long = InputPeer;

inputUserEmpty#b98886cf = InputUser;
inputUserSelf#f7c1b13f = InputUser;
inputUser#f21158c6 user_id:long access_hash:long = InputUser;
inputUserFromMessage#1da448e2 peer:InputPeer msg_id:int user_id:long = InputUser;

inputPhoneContact#6a1dc4be flags:# client_id:long phone:string first_name:string last_name:string note:flags.0?TextWithEntities = InputContact;

inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile;
inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile;
inputFileStoryDocument#62dc8b48 id:InputDocument = InputFile;

inputMediaEmpty#9664f57f = InputMedia;
inputMediaUploadedPhoto#7d8375da flags:# spoiler:flags.2?true live_photo:flags.3?true file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int video:flags.3?InputDocument = InputMedia;
inputMediaPhoto#e3af4434 flags:# spoiler:flags.1?true live_photo:flags.2?true id:InputPhoto ttl_seconds:flags.0?int video:flags.2?InputDocument = InputMedia;
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia;
inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia;
inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia;
inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia;
inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia;
inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia;
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia;
inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia;
inputMediaPoll#883a4108 flags:# poll:Poll correct_answers:flags.0?Vector<int> attached_media:flags.3?InputMedia solution:flags.1?string solution_entities:flags.1?Vector<MessageEntity> solution_media:flags.2?InputMedia = InputMedia;
inputMediaDice#e66fbf7b emoticon:string = InputMedia;
inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia;
inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia;
inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector<InputMedia> payload:flags.0?string = InputMedia;
inputMediaTodo#9fc55fde todo:TodoList = InputMedia;
inputMediaStakeDice#f3a9244a game_hash:string ton_amount:long client_seed:bytes = InputMedia;

inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto;
inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto;

inputGeoPointEmpty#e4c123d6 = InputGeoPoint;
inputGeoPoint#48222faf flags:# lat:double long:double accuracy_radius:flags.0?int = InputGeoPoint;

inputPhotoEmpty#1cd7bf0d = InputPhoto;
inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto;

inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation;
inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation;
inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation;
inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation;
inputTakeoutFileLocation#29be5899 = InputFileLocation;
inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation;
inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation;
inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation;
inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation;
inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation;

peerUser#59511722 user_id:long = Peer;
peerChat#36c6019a chat_id:long = Peer;
peerChannel#a2a5371e channel_id:long = Peer;

storage.fileUnknown#aa963b05 = storage.FileType;
storage.filePartial#40bc6f52 = storage.FileType;
storage.fileJpeg#7efe0e = storage.FileType;
storage.fileGif#cae1aadf = storage.FileType;
storage.filePng#a4f63c0 = storage.FileType;
storage.filePdf#ae1e508d = storage.FileType;
storage.fileMp3#528a0677 = storage.FileType;
storage.fileMov#4b09ebbc = storage.FileType;
storage.fileMp4#b3cea0e4 = storage.FileType;
storage.fileWebp#1081464c = storage.FileType;

userEmpty#d3bc4b7a id:long = User;
user#31774388 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true contact_require_premium:flags2.10?true bot_business:flags2.11?true bot_has_main_app:flags2.13?true bot_forum_view:flags2.16?true bot_forum_can_manage_topics:flags2.17?true bot_can_manage_bots:flags2.18?true bot_guestchat:flags2.19?true bot_guard:flags2.20?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector<RestrictionReason> bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector<Username> stories_max_id:flags2.5?RecentStory color:flags2.8?PeerColor profile_color:flags2.9?PeerColor bot_active_users:flags2.12?int bot_verification_icon:flags2.14?long send_paid_messages_stars:flags2.15?long = User;

userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto;

userStatusEmpty#9d05049 = UserStatus;
userStatusOnline#edb93949 expires:int = UserStatus;
userStatusOffline#8c703f was_online:int = UserStatus;
userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus;
userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus;
userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus;

chatEmpty#29562865 id:long = Chat;
chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat;
chatForbidden#6592a1a7 id:long title:string = Chat;
channel#1c32b11c flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true broadcast_messages_allowed:flags2.16?true monoforum:flags2.17?true forum_tabs:flags2.19?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector<RestrictionReason> admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector<Username> stories_max_id:flags2.4?RecentStory color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long linked_monoforum_id:flags2.18?long = Chat;
channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true monoforum:flags.10?true id:long access_hash:long title:string until_date:flags.16?int = Chat;

chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull;
channelFull#a04e8d3a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long main_tab:flags2.22?ProfileTab guard_bot_id:flags2.23?long = ChatFull;

chatParticipant#38e79fde flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant;
chatParticipantCreator#e1f867b8 flags:# user_id:long rank:flags.0?string = ChatParticipant;
chatParticipantAdmin#360d5d2 flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant;

chatParticipantsForbidden#8763d3e1 flags:# chat_id:long self_participant:flags.0?ChatParticipant = ChatParticipants;
chatParticipants#3cbc93f8 chat_id:long participants:Vector<ChatParticipant> version:int = ChatParticipants;

chatPhotoEmpty#37c1011c = ChatPhoto;
chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto;

messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message;
message#7600b9d3 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int from_rank:flags2.12?string peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long guestchat_via_from:flags2.19?Peer reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int summary_from_language:flags2.11?string rich_message:flags2.13?RichMessage = Message;
messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message;

messageMediaEmpty#3ded6320 = MessageMedia;
messageMediaPhoto#e216eb63 flags:# spoiler:flags.3?true live_photo:flags.4?true photo:flags.0?Photo ttl_seconds:flags.2?int video:flags.4?Document = MessageMedia;
messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia;
messageMediaUnsupported#9f84f49e = MessageMedia;
messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector<Document> video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia;
messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia;
messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia;
messageMediaGame#fdb19008 game:Game = MessageMedia;
messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia;
messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia;
messageMediaPoll#773f4e66 flags:# poll:Poll results:PollResults attached_media:flags.0?MessageMedia = MessageMedia;
messageMediaDice#8cbec07 flags:# value:int emoticon:string game_outcome:flags.0?messages.EmojiGameOutcome = MessageMedia;
messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia;
messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector<long> countries_iso2:flags.1?Vector<string> prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia;
messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector<long> months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia;
messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector<MessageExtendedMedia> = MessageMedia;
messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector<TodoCompletion> = MessageMedia;
messageMediaVideoStream#ca5cab89 flags:# rtmp_stream:flags.0?true call:InputGroupCall = MessageMedia;

messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#bd47cbad title:string users:Vector<long> = MessageAction;
messageActionChatEditTitle#b5a1ce5a title:string = MessageAction;
messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction;
messageActionChatDeletePhoto#95e3fbef = MessageAction;
messageActionChatAddUser#15cefd00 users:Vector<long> = MessageAction;
messageActionChatDeleteUser#a43f30cc user_id:long = MessageAction;
messageActionChatJoinedByLink#31224c3 inviter_id:long = MessageAction;
messageActionChannelCreate#95d2ac92 title:string = MessageAction;
messageActionChatMigrateTo#e1037f92 channel_id:long = MessageAction;
messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageAction;
messageActionPinMessage#94bd38ed = MessageAction;
messageActionHistoryClear#9fbab604 = MessageAction;
messageActionGameScore#92a72876 game_id:long score:int = MessageAction;
messageActionPaymentSentMe#ffa00ccc flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge subscription_until_date:flags.4?int = MessageAction;
messageActionPaymentSent#c624b16e flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string subscription_until_date:flags.4?int = MessageAction;
messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction;
messageActionScreenshotTaken#4792929b = MessageAction;
messageActionCustomAction#fae69f56 message:string = MessageAction;
messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction;
messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
messageActionContactSignUp#f3f25f76 = MessageAction;
messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction;
messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction;
messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector<long> = MessageAction;
messageActionSetMessagesTTL#3c134d7b flags:# period:int auto_setting_from:flags.0?long = MessageAction;
messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction;
messageActionSetChatTheme#b91bbd3a theme:ChatTheme = MessageAction;
messageActionChatJoinedByRequest#ebbca3cb = MessageAction;
messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction;
messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction;
messageActionGiftPremium#48e91302 flags:# currency:string amount:long days:int crypto_currency:flags.0?string crypto_amount:flags.0?long message:flags.1?TextWithEntities = MessageAction;
messageActionTopicCreate#d999256 flags:# title_missing:flags.1?true title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction;
messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction;
messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction;
messageActionRequestedPeer#31518e9b button_id:int peers:Vector<Peer> = MessageAction;
messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction;
messageActionGiftCode#31c48347 flags:# via_giveaway:flags.0?true unclaimed:flags.5?true boost_peer:flags.1?Peer days:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long message:flags.4?TextWithEntities = MessageAction;
messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction;
messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction;
messageActionBoostApply#cc02aa6d boosts:int = MessageAction;
messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector<RequestedPeer> = MessageAction;
messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction;
messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction;
messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction;
messageActionStarGift#ea2c31d3 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true prepaid_upgrade:flags.13?true upgrade_separate:flags.16?true auction_acquired:flags.17?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long prepaid_upgrade_hash:flags.14?string gift_msg_id:flags.15?int to_id:flags.18?Peer gift_num:flags.19?int = MessageAction;
messageActionStarGiftUnique#e6c31522 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true craft:flags.16?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long can_craft_at:flags.15?int = MessageAction;
messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction;
messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction;
messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector<Peer> = MessageAction;
messageActionTodoCompletions#cc7c5c89 completed:Vector<int> incompleted:Vector<int> = MessageAction;
messageActionTodoAppendTasks#c7edbc83 list:Vector<TodoItem> = MessageAction;
messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction;
messageActionSuggestedPostSuccess#95ddcf69 price:StarsAmount = MessageAction;
messageActionSuggestedPostRefund#69f916f8 flags:# payer_initiated:flags.0?true = MessageAction;
messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction;
messageActionSuggestBirthday#2c8f2a25 birthday:Birthday = MessageAction;
messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declined:flags.1?true gift:StarGift price:StarsAmount expires_at:int = MessageAction;
messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction;
messageActionNewCreatorPending#b07ed085 new_creator_id:long = MessageAction;
messageActionChangeCreator#e188503b new_creator_id:long = MessageAction;
messageActionNoForwardsToggle#bf7d6572 prev_value:Bool new_value:Bool = MessageAction;
messageActionNoForwardsRequest#3e2793ba flags:# expired:flags.0?true prev_value:Bool new_value:Bool = MessageAction;
messageActionPollAppendAnswer#9da1cd6c answer:PollAnswer = MessageAction;
messageActionPollDeleteAnswer#399674dc answer:PollAnswer = MessageAction;
messageActionManagedBotCreated#16605e3e bot_id:long = MessageAction;

dialog#fc89f7f3 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;

photoEmpty#2331b22d id:long = Photo;
photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> video_sizes:flags.1?Vector<VideoSize> dc_id:int = Photo;

photoSizeEmpty#e17e23c type:string = PhotoSize;
photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize;
photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize;
photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector<int> = PhotoSize;
photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize;

geoPointEmpty#1117dd5f = GeoPoint;
geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint;

auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode;
auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode;
auth.sentCodePaymentRequired#f8827ebf store_product:string phone_code_hash:string support_email_address:string support_email_subject:string premium_days:int currency:string amount:long = auth.SentCode;

auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization;
auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization;

auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization;

inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer;
inputNotifyUsers#193b4417 = InputNotifyPeer;
inputNotifyChats#4a95e84e = InputNotifyPeer;
inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer;
inputNotifyForumTopic#5c467992 peer:InputPeer top_msg_id:int = InputNotifyPeer;

inputPeerNotifySettings#cacb6ae2 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_sound:flags.8?NotificationSound = InputPeerNotifySettings;

peerNotifySettings#99622c0c flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_ios_sound:flags.8?NotificationSound stories_android_sound:flags.9?NotificationSound stories_other_sound:flags.10?NotificationSound = PeerNotifySettings;

peerSettings#f47741f7 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true business_bot_paused:flags.11?true business_bot_can_reply:flags.12?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int business_bot_id:flags.13?long business_bot_manage_url:flags.13?string charge_paid_message_stars:flags.14?long registration_month:flags.15?string phone_country:flags.16?string name_change_date:flags.17?int photo_change_date:flags.18?int = PeerSettings;

wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper;
wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper;

inputReportReasonSpam#58dbcab8 = ReportReason;
inputReportReasonViolence#1e22c78d = ReportReason;
inputReportReasonPornography#2e59d922 = ReportReason;
inputReportReasonChildAbuse#adf44ee3 = ReportReason;
inputReportReasonOther#c1e4a2b1 = ReportReason;
inputReportReasonCopyright#9b89f93a = ReportReason;
inputReportReasonGeoIrrelevant#dbd4feed = ReportReason;
inputReportReasonFake#f5ddd6e7 = ReportReason;
inputReportReasonIllegalDrugs#a8eb2be = ReportReason;
inputReportReasonPersonalDetails#9ec7863d = ReportReason;

userFull#6cbe645 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true noforwards_my_enabled:flags2.23?true noforwards_peer_enabled:flags2.24?true unofficial_security_risk:flags2.26?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme:flags.15?ChatTheme private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int main_tab:flags2.20?ProfileTab saved_music:flags2.21?Document note:flags2.22?TextWithEntities bot_manager_id:flags2.25?long = UserFull;

contact#145ade0b user_id:long mutual:Bool = Contact;

importedContact#c13e3c50 user_id:long client_id:long = ImportedContact;

contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus;

contacts.contactsNotModified#b74ba9d2 = contacts.Contacts;
contacts.contacts#eae87e42 contacts:Vector<Contact> saved_count:int users:Vector<User> = contacts.Contacts;

contacts.importedContacts#77d01c3b imported:Vector<ImportedContact> popular_invites:Vector<PopularContact> retry_contacts:Vector<long> users:Vector<User> = contacts.ImportedContacts;

contacts.blocked#ade1591 blocked:Vector<PeerBlocked> chats:Vector<Chat> users:Vector<User> = contacts.Blocked;
contacts.blockedSlice#e1664194 count:int blocked:Vector<PeerBlocked> chats:Vector<Chat> users:Vector<User> = contacts.Blocked;

messages.dialogs#15ba6c40 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.dialogsSlice#71e094f3 count:int dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Dialogs;
messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs;

messages.messages#1d73e7ea messages:Vector<Message> topics:Vector<ForumTopic> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesSlice#5f206716 flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector<Message> topics:Vector<ForumTopic> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector<Message> topics:Vector<ForumTopic> chats:Vector<Chat> users:Vector<User> = messages.Messages;
messages.messagesNotModified#74535f21 count:int = messages.Messages;

messages.chats#64ff9fd5 chats:Vector<Chat> = messages.Chats;
messages.chatsSlice#9cd81144 count:int chats:Vector<Chat> = messages.Chats;

messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector<Chat> users:Vector<User> = messages.ChatFull;

messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory;

inputMessagesFilterEmpty#57e2f66c = MessagesFilter;
inputMessagesFilterPhotos#9609a51c = MessagesFilter;
inputMessagesFilterVideo#9fc00e65 = MessagesFilter;
inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter;
inputMessagesFilterDocument#9eddf188 = MessagesFilter;
inputMessagesFilterUrl#7ef0dd87 = MessagesFilter;
inputMessagesFilterGif#ffc86587 = MessagesFilter;
inputMessagesFilterVoice#50f5c392 = MessagesFilter;
inputMessagesFilterMusic#3751b49e = MessagesFilter;
inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter;
inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter;
inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter;
inputMessagesFilterRoundVideo#b549da53 = MessagesFilter;
inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter;
inputMessagesFilterGeo#e7026d0d = MessagesFilter;
inputMessagesFilterContacts#e062db83 = MessagesFilter;
inputMessagesFilterPinned#1bb00451 = MessagesFilter;
inputMessagesFilterPoll#fa2bc90a = MessagesFilter;

updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update;
updateMessageID#4e90bfd6 id:int random_id:long = Update;
updateDeleteMessages#a20db0e5 messages:Vector<int> pts:int pts_count:int = Update;
updateUserTyping#2a17bf5c flags:# user_id:long top_msg_id:flags.0?int action:SendMessageAction = Update;
updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction = Update;
updateChatParticipants#7761198 participants:ChatParticipants = Update;
updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update;
updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector<Username> = Update;
updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update;
updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update;
updateEncryptedChatTyping#1710f156 chat_id:int = Update;
updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update;
updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update;
updateChatParticipantAdd#3dda5451 chat_id:long user_id:long inviter_id:long date:int version:int = Update;
updateChatParticipantDelete#e32f3d77 chat_id:long user_id:long version:int = Update;
updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update;
updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update;
updateServiceNotification#ebe46819 flags:# popup:flags.0?true invert_media:flags.2?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector<MessageEntity> = Update;
updatePrivacy#ee3b272a key:PrivacyKey rules:Vector<PrivacyRule> = Update;
updateUserPhone#5492a13 user_id:long phone:string = Update;
updateReadHistoryInbox#9e84bc99 flags:# folder_id:flags.0?int peer:Peer top_msg_id:flags.1?int max_id:int still_unread_count:int pts:int pts_count:int = Update;
updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update;
updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update;
updateReadMessagesContents#f8227181 flags:# messages:Vector<int> pts:int pts_count:int date:flags.0?int = Update;
updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update;
updateChannel#635b4c09 channel_id:long = Update;
updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;
updateReadChannelInbox#922e6e10 flags:# folder_id:flags.0?int channel_id:long max_id:int still_unread_count:int pts:int = Update;
updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector<int> pts:int pts_count:int = Update;
updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update;
updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update;
updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update;
updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true emojis:flags.1?true order:Vector<long> = Update;
updateStickerSets#31c24808 flags:# masks:flags.0?true emojis:flags.1?true = Update;
updateSavedGifs#9375341e = Update;
updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update;
updateBotInlineSend#12f12a07 flags:# user_id:long query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update;
updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update;
updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update;
updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update;
updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update;
updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update;
updateDraftMessage#edfc111e flags:# peer:Peer top_msg_id:flags.0?int saved_peer_id:flags.1?Peer draft:DraftMessage = Update;
updateReadFeaturedStickers#571d2742 = Update;
updateRecentStickers#9a422c20 = Update;
updateConfig#a229dd06 = Update;
updatePtsChanged#3354678f = Update;
updateChannelWebPage#2f2ba99f channel_id:long webpage:WebPage pts:int pts_count:int = Update;
updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update;
updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector<DialogPeer> = Update;
updateBotWebhookJSON#8317c0c3 data:DataJSON = Update;
updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update;
updateBotShippingQuery#b5aefd7d query_id:long user_id:long payload:bytes shipping_address:PostAddress = Update;
updateBotPrecheckoutQuery#8caa9a96 flags:# query_id:long user_id:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update;
updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update;
updateLangPackTooLong#46560264 lang_code:string = Update;
updateLangPack#56022f4d difference:LangPackDifference = Update;
updateFavedStickers#e511996d = Update;
updateChannelReadMessagesContents#25f324f7 flags:# channel_id:long top_msg_id:flags.0?int saved_peer_id:flags.1?Peer messages:Vector<int> = Update;
updateContactsReset#7084a7be = Update;
updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update;
updateDialogUnreadMark#b658f23e flags:# unread:flags.0?true peer:DialogPeer saved_peer_id:flags.1?Peer = Update;
updateMessagePoll#d64c522b flags:# peer:flags.1?Peer msg_id:flags.1?int top_msg_id:flags.2?int poll_id:long poll:flags.0?Poll results:PollResults = Update;
updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update;
updateFolderPeers#19360dc0 folder_peers:Vector<FolderPeer> pts:int pts_count:int = Update;
updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update;
updatePeerLocated#b4afcfb0 peers:Vector<PeerLocated> = Update;
updateNewScheduledMessage#39a51dfb message:Message = Update;
updateDeleteScheduledMessages#f2a71983 flags:# peer:Peer messages:Vector<int> sent_messages:flags.0?Vector<int> = Update;
updateTheme#8216fba3 theme:Theme = Update;
updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update;
updateLoginToken#564fe691 = Update;
updateMessagePollVote#7699f014 poll_id:long peer:Peer options:Vector<bytes> positions:Vector<int> qts:int = Update;
updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update;
updateDialogFilterOrder#a5d72105 order:Vector<int> = Update;
updateDialogFilters#3504914f = Update;
updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update;
updateChannelMessageForwards#d29a27f4 channel_id:long id:int forwards:int = Update;
updateReadChannelDiscussionInbox#d6b19546 flags:# channel_id:long top_msg_id:int read_max_id:int broadcast_id:flags.0?long broadcast_post:flags.0?int = Update;
updateReadChannelDiscussionOutbox#695c9e7c channel_id:long top_msg_id:int read_max_id:int = Update;
updatePeerBlocked#ebe07752 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer = Update;
updateChannelUserTyping#8c88c923 flags:# channel_id:long top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update;
updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector<int> pts:int pts_count:int = Update;
updatePinnedChannelMessages#5bb98608 flags:# pinned:flags.0?true channel_id:long messages:Vector<int> pts:int pts_count:int = Update;
updateChat#f89a6a4e chat_id:long = Update;
updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector<GroupCallParticipant> version:int = Update;
updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update;
updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update;
updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update;
updateChannelParticipant#985d3abb flags:# via_chatlist:flags.3?true channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update;
updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update;
updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update;
updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector<BotCommand> = Update;
updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector<long> = Update;
updateBotChatInviteRequester#7cb34d79 flags:# peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int query_id:flags.0?long = Update;
updateMessageReactions#1e297bfa flags:# peer:Peer msg_id:int top_msg_id:flags.0?int saved_peer_id:flags.1?Peer reactions:MessageReactions = Update;
updateAttachMenuBots#17b7a20b = Update;
updateWebViewResultSent#1592b79d query_id:long = Update;
updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update;
updateSavedRingtones#74d8be99 = Update;
updateTranscribedAudio#84cd5a flags:# pending:flags.0?true peer:Peer msg_id:int transcription_id:long text:string = Update;
updateReadFeaturedEmojiStickers#fb4c496c = Update;
updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update;
updateRecentEmojiStatuses#30f443db = Update;
updateRecentReactions#6f7863f4 = Update;
updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update;
updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector<MessageExtendedMedia> = Update;
updateUser#20529438 user_id:long = Update;
updateAutoSaveSettings#ec05b097 = Update;
updateStory#75b3b798 peer:Peer story:StoryItem = Update;
updateReadStories#f74e932b peer:Peer max_id:int = Update;
updateStoryID#1bf335b9 id:int random_id:long = Update;
updateStoriesStealthMode#2c084dc1 stealth_mode:StoriesStealthMode = Update;
updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Update;
updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update;
updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update;
updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update;
updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector<Reaction> new_reactions:Vector<Reaction> qts:int = Update;
updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector<ReactionCount> qts:int = Update;
updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update;
updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector<DialogPeer> = Update;
updateSavedReactionTags#39c67432 = Update;
updateSmsJob#f16269d4 job_id:string = Update;
updateQuickReplies#f9470ab2 quick_replies:Vector<QuickReply> = Update;
updateNewQuickReply#f53da717 quick_reply:QuickReply = Update;
updateDeleteQuickReply#53e6f1ec shortcut_id:int = Update;
updateQuickReplyMessage#3e050d0f message:Message = Update;
updateDeleteQuickReplyMessages#566fe7cd shortcut_id:int messages:Vector<int> = Update;
updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Update;
updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update;
updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update;
updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector<int> qts:int = Update;
updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update;
updateStarsBalance#4e80a379 balance:StarsAmount = Update;
updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update;
updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update;
updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update;
updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update;
updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update;
updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector<bytes> next_offset:int = Update;
updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update;
updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update;
updateMonoForumNoPaidException#9f812b08 flags:# exception:flags.0?true channel_id:long saved_peer_id:Peer = Update;
updateGroupCallMessage#d8326f0d call:InputGroupCall message:GroupCallMessage = Update;
updateGroupCallEncryptedMessage#c957a766 call:InputGroupCall from_id:Peer encrypted_message:bytes = Update;
updatePinnedForumTopic#683b2c52 flags:# pinned:flags.0?true peer:Peer topic_id:int = Update;
updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector<int> = Update;
updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector<int> = Update;
updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update;
updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update;
updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update;
updateStarGiftCraftFail#ac072444 = Update;
updateChatParticipantRank#bd8367b9 chat_id:long user_id:long rank:string version:int = Update;
updateManagedBot#4880ed9a user_id:long bot_id:long qts:int = Update;
updateBotGuestChatQuery#cdd4093d flags:# query_id:long message:Message reference_messages:flags.0?Vector<Message> qts:int = Update;
updateAiComposeTones#8c0f91fb = Update;
updateJoinChatWebViewDecision#bdac7e70 peer:Peer query_id:long result:JoinChatBotResult = Update;
updateNewBotConnection#b22083a6 flags:# confirmed:flags.0?true bot_id:long date:flags.1?int device:flags.1?string location:flags.1?string = Update;
updateWebBrowserSettings#c39a2ade flags:# open_external_browser:flags.0?true display_close_button:flags.1?true = Update;
updateWebBrowserException#140502d1 flags:# delete:flags.1?true open_external_browser:flags.0?Bool exception:WebDomainException = Update;

updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;

updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference;
updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> state:updates.State = updates.Difference;
updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference;
updates.differenceTooLong#4afe8f6d pts:int = updates.Difference;

updatesTooLong#e317af7e = Updates;
updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector<MessageEntity> ttl_period:flags.25?int = Updates;
updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector<MessageEntity> ttl_period:flags.25?int = Updates;
updateShort#78d4dec1 update:Update date:int = Updates;
updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates;
updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates;
updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> ttl_period:flags.25?int = Updates;

photos.photos#8dca6aa5 photos:Vector<Photo> users:Vector<User> = photos.Photos;
photos.photosSlice#15051f54 count:int photos:Vector<Photo> users:Vector<User> = photos.Photos;

photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;

upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector<FileHash> = upload.File;

dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;

config#cc1a241e flags:# default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true force_try_ipv6:flags.14?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int channels_read_media_period:int tmp_sessions:flags.0?int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction autologin_token:flags.16?string = Config;

nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;

help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector<MessageEntity> document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate;
help.noAppUpdate#c45a6536 = help.AppUpdate;

help.inviteText#18cb9f78 message:string = help.InviteText;

encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat;
encryptedChatWaiting#66b25953 id:int access_hash:long date:int admin_id:long participant_id:long = EncryptedChat;
encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat;
encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat;
encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat;

inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat;

encryptedFileEmpty#c21f497e = EncryptedFile;
encryptedFile#a8008cd8 id:long access_hash:long size:long dc_id:int key_fingerprint:int = EncryptedFile;

inputEncryptedFileEmpty#1837c364 = InputEncryptedFile;
inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile;
inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile;
inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile;

encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage;
encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage;

messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig;
messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig;

messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage;
messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage;

inputDocumentEmpty#72f0eaae = InputDocument;
inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument;

documentEmpty#36f8c871 id:long = Document;
document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector<PhotoSize> video_thumbs:flags.1?Vector<VideoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document;

help.support#17c6b5f6 phone_number:string user:User = help.Support;

notifyPeer#9fd40bd8 peer:Peer = NotifyPeer;
notifyUsers#b4c83b4c = NotifyPeer;
notifyChats#c007cec3 = NotifyPeer;
notifyBroadcasts#d612e8ef = NotifyPeer;
notifyForumTopic#226e6308 peer:Peer top_msg_id:int = NotifyPeer;

sendMessageTypingAction#16bf744e = SendMessageAction;
sendMessageCancelAction#fd5ec8f5 = SendMessageAction;
sendMessageRecordVideoAction#a187d66f = SendMessageAction;
sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction;
sendMessageRecordAudioAction#d52f73f7 = SendMessageAction;
sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction;
sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction;
sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction;
sendMessageGeoLocationAction#176f8ba1 = SendMessageAction;
sendMessageChooseContactAction#628cbc6f = SendMessageAction;
sendMessageGamePlayAction#dd6a8f48 = SendMessageAction;
sendMessageRecordRoundAction#88f27fbc = SendMessageAction;
sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction;
speakingInGroupCallAction#d92c2285 = SendMessageAction;
sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction;
sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction;
sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction;
sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction;
sendMessageTextDraftAction#376d975c random_id:long text:TextWithEntities = SendMessageAction;
inputSendMessageRichMessageDraftAction#e2b23b51 random_id:long rich_message:InputRichMessage = SendMessageAction;
sendMessageRichMessageDraftAction#a2cb24f9 random_id:long rich_message:RichMessage = SendMessageAction;

contacts.found#b3134d9d my_results:Vector<Peer> results:Vector<Peer> chats:Vector<Chat> users:Vector<User> = contacts.Found;

inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey;
inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey;
inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey;
inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey;
inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey;
inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey;
inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey;
inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey;
inputPrivacyKeyVoiceMessages#aee69d68 = InputPrivacyKey;
inputPrivacyKeyAbout#3823cc40 = InputPrivacyKey;
inputPrivacyKeyBirthday#d65a11cc = InputPrivacyKey;
inputPrivacyKeyStarGiftsAutoSave#e1732341 = InputPrivacyKey;
inputPrivacyKeyNoPaidMessages#bdc597b4 = InputPrivacyKey;
inputPrivacyKeySavedMusic#4dbe9226 = InputPrivacyKey;

privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
privacyKeyChatInvite#500e6dfa = PrivacyKey;
privacyKeyPhoneCall#3d662b7b = PrivacyKey;
privacyKeyPhoneP2P#39491cc8 = PrivacyKey;
privacyKeyForwards#69ec56a3 = PrivacyKey;
privacyKeyProfilePhoto#96151fed = PrivacyKey;
privacyKeyPhoneNumber#d19ae46d = PrivacyKey;
privacyKeyAddedByPhone#42ffd42b = PrivacyKey;
privacyKeyVoiceMessages#697f414 = PrivacyKey;
privacyKeyAbout#a486b761 = PrivacyKey;
privacyKeyBirthday#2000a518 = PrivacyKey;
privacyKeyStarGiftsAutoSave#2ca4fdf8 = PrivacyKey;
privacyKeyNoPaidMessages#17d348d2 = PrivacyKey;
privacyKeySavedMusic#ff7a571b = PrivacyKey;

inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule;
inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule;
inputPrivacyValueAllowUsers#131cc67f users:Vector<InputUser> = InputPrivacyRule;
inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule;
inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule;
inputPrivacyValueDisallowUsers#90110467 users:Vector<InputUser> = InputPrivacyRule;
inputPrivacyValueAllowChatParticipants#840649cf chats:Vector<long> = InputPrivacyRule;
inputPrivacyValueDisallowChatParticipants#e94f0f86 chats:Vector<long> = InputPrivacyRule;
inputPrivacyValueAllowCloseFriends#2f453e49 = InputPrivacyRule;
inputPrivacyValueAllowPremium#77cdc9f1 = InputPrivacyRule;
inputPrivacyValueAllowBots#5a4fcce5 = InputPrivacyRule;
inputPrivacyValueDisallowBots#c4e57915 = InputPrivacyRule;

privacyValueAllowContacts#fffe1bac = PrivacyRule;
privacyValueAllowAll#65427b82 = PrivacyRule;
privacyValueAllowUsers#b8905fb2 users:Vector<long> = PrivacyRule;
privacyValueDisallowContacts#f888fa1a = PrivacyRule;
privacyValueDisallowAll#8b73e763 = PrivacyRule;
privacyValueDisallowUsers#e4621141 users:Vector<long> = PrivacyRule;
privacyValueAllowChatParticipants#6b134e8e chats:Vector<long> = PrivacyRule;
privacyValueDisallowChatParticipants#41c87565 chats:Vector<long> = PrivacyRule;
privacyValueAllowCloseFriends#f7e8d89b = PrivacyRule;
privacyValueAllowPremium#ece9814b = PrivacyRule;
privacyValueAllowBots#21461b5d = PrivacyRule;
privacyValueDisallowBots#f6a5f82f = PrivacyRule;

account.privacyRules#50a04e45 rules:Vector<PrivacyRule> chats:Vector<Chat> users:Vector<User> = account.PrivacyRules;

accountDaysTTL#b8d0afdf days:int = AccountDaysTTL;

documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
documentAttributeAnimated#11b58939 = DocumentAttribute;
documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute;
documentAttributeVideo#43c57c48 flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int video_start_ts:flags.4?double video_codec:flags.5?string = DocumentAttribute;
documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute;
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
documentAttributeHasStickers#9801d2f7 = DocumentAttribute;
documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true text_color:flags.1?true alt:string stickerset:InputStickerSet = DocumentAttribute;

messages.stickersNotModified#f1749a22 = messages.Stickers;
messages.stickers#30a6ec7e hash:long stickers:Vector<Document> = messages.Stickers;

stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;

messages.allStickersNotModified#e86602c3 = messages.AllStickers;
messages.allStickers#cdbbcebb hash:long sets:Vector<StickerSet> = messages.AllStickers;

messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages;

webPageEmpty#211a1788 flags:# id:long url:flags.0?string = WebPage;
webPagePending#b0d13e47 flags:# id:long url:flags.0?string date:int = WebPage;
webPage#e89c45b2 flags:# has_large_media:flags.13?true video_cover_photo:flags.14?true id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector<WebPageAttribute> = WebPage;
webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage;

authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization;

account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector<Authorization> = account.Authorizations;

account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password;

account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings;

account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings;

auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery;

receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage;

chatInviteExported#a22cbd96 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int subscription_expired:flags.10?int title:flags.8?string subscription_pricing:flags.9?StarsSubscriptionPricing = ExportedChatInvite;
chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite;

chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
chatInvite#5c9d3702 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true can_refulfill_subscription:flags.11?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector<User> color:int subscription_pricing:flags.10?StarsSubscriptionPricing subscription_form_id:flags.12?long bot_verification:flags.13?BotVerification = ChatInvite;
chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite;

inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
inputStickerSetDice#e67f520e emoticon:string = InputStickerSet;
inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet;
inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet;
inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet;
inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet;
inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet;
inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet;
inputStickerSetTonGifts#1cf671a0 = InputStickerSet;

stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true creator:flags.11?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector<PhotoSize> thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet;

messages.stickerSet#6e153f16 set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = messages.StickerSet;
messages.stickerSetNotModified#d3f924eb = messages.StickerSet;

botCommand#c27ac8c7 command:string description:string = BotCommand;

botInfo#4d8a0299 flags:# has_preview_medias:flags.6?true user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector<BotCommand> menu_button:flags.3?BotMenuButton privacy_policy_url:flags.7?string app_settings:flags.8?BotAppSettings verifier_settings:flags.9?BotVerifierSettings = BotInfo;

keyboardButton#7d170cff flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton;
keyboardButtonUrl#d80c25ec flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton;
keyboardButtonCallback#e62bc960 flags:# requires_password:flags.0?true style:flags.10?KeyboardButtonStyle text:string data:bytes = KeyboardButton;
keyboardButtonRequestPhone#417efd8f flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton;
keyboardButtonRequestGeoLocation#aa40f94d flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton;
keyboardButtonSwitchInline#991399fc flags:# same_peer:flags.0?true style:flags.10?KeyboardButtonStyle text:string query:string peer_types:flags.1?Vector<InlineQueryPeerType> = KeyboardButton;
keyboardButtonGame#89c590f9 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton;
keyboardButtonBuy#3fa53905 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton;
keyboardButtonUrlAuth#f51006f9 flags:# style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton;
inputKeyboardButtonUrlAuth#68013e72 flags:# request_write_access:flags.0?true style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton;
keyboardButtonRequestPoll#7a11d782 flags:# style:flags.10?KeyboardButtonStyle quiz:flags.0?Bool text:string = KeyboardButton;
inputKeyboardButtonUserProfile#7d5e07c7 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:InputUser = KeyboardButton;
keyboardButtonUserProfile#c0fd5d09 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:long = KeyboardButton;
keyboardButtonWebView#e846b1a0 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton;
keyboardButtonSimpleWebView#e15c4370 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton;
keyboardButtonRequestPeer#5b0f15f5 flags:# style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton;
inputKeyboardButtonRequestPeer#2b78156 flags:# name_requested:flags.0?true username_requested:flags.1?true photo_requested:flags.2?true style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton;
keyboardButtonCopy#bcc4af10 flags:# style:flags.10?KeyboardButtonStyle text:string copy_text:string = KeyboardButton;

keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;

replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup;
replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup;
replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true persistent:flags.4?true rows:Vector<KeyboardButtonRow> placeholder:flags.3?string = ReplyMarkup;
replyInlineMarkup#48a30254 rows:Vector<KeyboardButtonRow> = ReplyMarkup;

messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity;
messageEntityMention#fa04579d offset:int length:int = MessageEntity;
messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity;
messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity;
messageEntityUrl#6ed02538 offset:int length:int = MessageEntity;
messageEntityEmail#64e475c2 offset:int length:int = MessageEntity;
messageEntityBold#bd610bc9 offset:int length:int = MessageEntity;
messageEntityItalic#826f8b60 offset:int length:int = MessageEntity;
messageEntityCode#28a20571 offset:int length:int = MessageEntity;
messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity;
messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity;
messageEntityMentionName#dc7b1140 offset:int length:int user_id:long = MessageEntity;
inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity;
messageEntityPhone#9b69e34b offset:int length:int = MessageEntity;
messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity;
messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity;
messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity;
messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity;
messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity;
messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity;
messageEntityBlockquote#f1ccaaac flags:# collapsed:flags.0?true offset:int length:int = MessageEntity;
messageEntityFormattedDate#904ac7c7 flags:# relative:flags.0?true short_time:flags.1?true long_time:flags.2?true short_date:flags.3?true long_date:flags.4?true day_of_week:flags.5?true offset:int length:int date:int = MessageEntity;
messageEntityDiffInsert#71777116 offset:int length:int = MessageEntity;
messageEntityDiffReplace#c6c1e5a7 offset:int length:int old_text:string = MessageEntity;
messageEntityDiffDelete#652c1c5 offset:int length:int = MessageEntity;

inputChannelEmpty#ee8c1e86 = InputChannel;
inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel;
inputChannelFromMessage#5b934f9d peer:InputPeer msg_id:int channel_id:long = InputChannel;

contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer;

messageRange#ae30253 min_id:int max_id:int = MessageRange;

updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference;
updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;
updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector<Message> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> = updates.ChannelDifference;

channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter;
channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector<MessageRange> = ChannelMessagesFilter;

channelParticipant#1bd54456 flags:# user_id:long date:int subscription_until_date:flags.0?int rank:flags.2?string = ChannelParticipant;
channelParticipantSelf#a9478a1a flags:# via_request:flags.0?true user_id:long inviter_id:long date:int subscription_until_date:flags.1?int rank:flags.2?string = ChannelParticipant;
channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant;
channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant;
channelParticipantBanned#d5f0ad91 flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights rank:flags.2?string = ChannelParticipant;
channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant;

channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter;
channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter;
channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter;
channelParticipantsBots#b0d1865b = ChannelParticipantsFilter;
channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter;
channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter;
channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter;
channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter;

channels.channelParticipants#9ab0feaf count:int participants:Vector<ChannelParticipant> chats:Vector<Chat> users:Vector<User> = channels.ChannelParticipants;
channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants;

channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector<Chat> users:Vector<User> = channels.ChannelParticipant;

help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector<MessageEntity> min_age_confirm:flags.1?int = help.TermsOfService;

messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs;
messages.savedGifs#84a02a0d hash:long gifs:Vector<Document> = messages.SavedGifs;

inputBotInlineMessageMediaAuto#3380c786 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaWebPage#bddcc510 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true optional:flags.6?true message:string entities:flags.1?Vector<MessageEntity> url:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageRichMessage#b43df56c flags:# reply_markup:flags.2?ReplyMarkup rich_message:InputRichMessage = InputBotInlineMessage;

inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult;
inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult;
inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult;
inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult;

botInlineMessageMediaAuto#764cf810 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true safe:flags.8?true message:string entities:flags.1?Vector<MessageEntity> url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
botInlineMessageRichMessage#a617e7b flags:# reply_markup:flags.2?ReplyMarkup rich_message:RichMessage = BotInlineMessage;

botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult;
botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult;

messages.botResults#e021f2f6 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM switch_webview:flags.3?InlineBotWebView results:Vector<BotInlineResult> cache_time:int users:Vector<User> = messages.BotResults;

exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;

messageFwdHeader#4e4df4bb flags:# imported:flags.7?true saved_out:flags.11?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int saved_from_id:flags.8?Peer saved_from_name:flags.9?string saved_date:flags.10?int psa_type:flags.6?string = MessageFwdHeader;

auth.codeTypeSms#72a3158c = auth.CodeType;
auth.codeTypeCall#741cd3e3 = auth.CodeType;
auth.codeTypeFlashCall#226ccefb = auth.CodeType;
auth.codeTypeMissedCall#d61ad6ee = auth.CodeType;
auth.codeTypeFragmentSms#6ed998c = auth.CodeType;

auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType;
auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType;
auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType;
auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType;
auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType;
auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType;
auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType;
auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType;
auth.sentCodeTypeFirebaseSms#9fd736 flags:# nonce:flags.0?bytes play_integrity_project_id:flags.2?long play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType;
auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType;
auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType;

messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer;

messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData;

inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID;
inputBotInlineMessageID64#b6d915d7 dc_id:int owner_id:long id:int access_hash:long = InputBotInlineMessageID;

inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM;

messages.peerDialogs#3371c354 dialogs:Vector<Dialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> state:updates.State = messages.PeerDialogs;

topPeer#edcdc05b peer:Peer rating:double = TopPeer;

topPeerCategoryBotsPM#ab661b5b = TopPeerCategory;
topPeerCategoryBotsInline#148677e2 = TopPeerCategory;
topPeerCategoryCorrespondents#637b7ed = TopPeerCategory;
topPeerCategoryGroups#bd17a14a = TopPeerCategory;
topPeerCategoryChannels#161d9628 = TopPeerCategory;
topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory;
topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory;
topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory;
topPeerCategoryBotsApp#fd9e7bec = TopPeerCategory;
topPeerCategoryBotsGuestChat#6c24f3dd = TopPeerCategory;

topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector<TopPeer> = TopPeerCategoryPeers;

contacts.topPeersNotModified#de266ef5 = contacts.TopPeers;
contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<Chat> users:Vector<User> = contacts.TopPeers;
contacts.topPeersDisabled#b52c939d = contacts.TopPeers;

draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage;
draftMessage#60fe3294 flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector<MessageEntity> media:flags.5?InputMedia date:int effect:flags.7?long suggested_post:flags.8?SuggestedPost rich_message:flags.9?RichMessage = DraftMessage;

messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers;
messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;

messages.recentStickersNotModified#b17f890 = messages.RecentStickers;
messages.recentStickers#88d37c56 hash:long packs:Vector<StickerPack> stickers:Vector<Document> dates:Vector<int> = messages.RecentStickers;

messages.archivedStickers#4fcba9c8 count:int sets:Vector<StickerSetCovered> = messages.ArchivedStickers;

messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult;
messages.stickerSetInstallResultArchive#35e410a8 sets:Vector<StickerSetCovered> = messages.StickerSetInstallResult;

stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered;
stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector<Document> = StickerSetCovered;
stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector<StickerPack> keywords:Vector<StickerKeyword> documents:Vector<Document> = StickerSetCovered;
stickerSetNoCovered#77b15d1c set:StickerSet = StickerSetCovered;

maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords;

inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia;
inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia;

game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game;

inputGameID#32c3e77 id:long access_hash:long = InputGame;
inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame;

highScore#73a379eb pos:int user_id:long score:int = HighScore;

messages.highScores#9a3bfd99 scores:Vector<HighScore> users:Vector<User> = messages.HighScores;

textEmpty#dc3d824f = RichText;
textPlain#744694e0 text:string = RichText;
textBold#6724abc4 text:RichText = RichText;
textItalic#d912a59c text:RichText = RichText;
textUnderline#c12622c4 text:RichText = RichText;
textStrike#9bf8bb95 text:RichText = RichText;
textFixed#6c3f19b9 text:RichText = RichText;
textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText;
textEmail#de5a0dd6 text:RichText email:string = RichText;
textConcat#7e6260d7 texts:Vector<RichText> = RichText;
textSubscript#ed6a8504 text:RichText = RichText;
textSuperscript#c7fb5e01 text:RichText = RichText;
textMarked#34b8621 text:RichText = RichText;
textPhone#1ccb966a text:RichText phone:string = RichText;
textImage#81ccf4f document_id:long w:int h:int = RichText;
textAnchor#35553762 text:RichText name:string = RichText;
textMath#9d2eac97 source:string = RichText;
textCustomEmoji#a26156c0 document_id:long alt:string = RichText;
textSpoiler#4c2a5d62 text:RichText = RichText;
textMention#cd24cf44 text:RichText = RichText;
textHashtag#519524ea text:RichText = RichText;
textBotCommand#2ff29d3 text:RichText = RichText;
textCashtag#7b9e1801 text:RichText = RichText;
textAutoUrl#ac6a83aa text:RichText = RichText;
textAutoEmail#c556a45d text:RichText = RichText;
textAutoPhone#24c26789 text:RichText = RichText;
textBankCard#b956812d text:RichText = RichText;
textMentionName#1a9fbfc text:RichText user_id:long = RichText;
textDate#a5b45e2b flags:# relative:flags.0?true short_time:flags.1?true long_time:flags.2?true short_date:flags.3?true long_date:flags.4?true day_of_week:flags.5?true text:RichText date:int = RichText;

pageBlockUnsupported#13567e8a = PageBlock;
pageBlockTitle#70abc3fd text:RichText = PageBlock;
pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock;
pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock;
pageBlockHeader#bfd064ec text:RichText = PageBlock;
pageBlockSubheader#f12bb6e1 text:RichText = PageBlock;
pageBlockParagraph#467a0766 text:RichText = PageBlock;
pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock;
pageBlockFooter#48870999 text:RichText = PageBlock;
pageBlockDivider#db20b188 = PageBlock;
pageBlockAnchor#ce0d37b0 name:string = PageBlock;
pageBlockList#e4e88011 items:Vector<PageListItem> = PageBlock;
pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock;
pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock;
pageBlockPhoto#1759c560 flags:# spoiler:flags.1?true photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock;
pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true spoiler:flags.2?true video_id:long caption:PageCaption = PageBlock;
pageBlockCover#39f23300 cover:PageBlock = PageBlock;
pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock;
pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector<PageBlock> caption:PageCaption = PageBlock;
pageBlockCollage#65a0fa4d items:Vector<PageBlock> caption:PageCaption = PageBlock;
pageBlockSlideshow#31f9590 items:Vector<PageBlock> caption:PageCaption = PageBlock;
pageBlockChannel#ef1751b5 channel:Chat = PageBlock;
pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock;
pageBlockKicker#1e148390 text:RichText = PageBlock;
pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector<PageTableRow> = PageBlock;
pageBlockOrderedList#1fd6f6c1 flags:# reversed:flags.2?true items:Vector<PageListOrderedItem> start:flags.0?int type:flags.1?string = PageBlock;
pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector<PageBlock> title:RichText = PageBlock;
pageBlockRelatedArticles#16115a96 title:RichText articles:Vector<PageRelatedArticle> = PageBlock;
pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock;
pageBlockHeading1#baff072f text:RichText = PageBlock;
pageBlockHeading2#96b2aec text:RichText = PageBlock;
pageBlockHeading3#67e731ad text:RichText = PageBlock;
pageBlockHeading4#b532772b text:RichText = PageBlock;
pageBlockHeading5#dbbe6c6a text:RichText = PageBlock;
pageBlockHeading6#682a41a9 text:RichText = PageBlock;
pageBlockMath#59080c20 source:string = PageBlock;
pageBlockThinking#3c29a3e2 text:RichText = PageBlock;
inputPageBlockMap#574b617f geo:InputGeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock;
pageBlockBlockquoteBlocks#e6e47c4 blocks:Vector<PageBlock> caption:RichText = PageBlock;

phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason;
phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason;
phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason;
phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason;
phoneCallDiscardReasonMigrateConferenceCall#9fbbf1f7 slug:string = PhoneCallDiscardReason;

dataJSON#7d748d04 data:string = DataJSON;

labeledPrice#cb296bf8 label:string amount:long = LabeledPrice;

invoice#49ee584 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector<LabeledPrice> max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector<long> terms_url:flags.10?string subscription_period:flags.11?int = Invoice;

paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge;

postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress;

paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo;

paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials;

webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;
webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;

inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector<DocumentAttribute> = InputWebDocument;

inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation;
inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation;
inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document:flags.0?InputDocument title:flags.1?string performer:flags.1?string = InputWebFileLocation;

upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile;

payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector<PaymentFormMethod> saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector<PaymentSavedCredentials> users:Vector<User> = payments.PaymentForm;
payments.paymentFormStars#7bf6b15c flags:# form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice users:Vector<User> = payments.PaymentForm;
payments.paymentFormStarGift#b425cfe1 form_id:long invoice:Invoice = payments.PaymentForm;

payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = payments.ValidatedRequestedInfo;

payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult;
payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult;

payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector<User> = payments.PaymentReceipt;
payments.paymentReceiptStars#dabbf83a flags:# date:int bot_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice currency:string total_amount:long transaction_id:string users:Vector<User> = payments.PaymentReceipt;

payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo;

inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials;
inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials;
inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials;
inputPaymentCredentialsGooglePay#8ac32801 payment_token:DataJSON = InputPaymentCredentials;

account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword;

shippingOption#b6213cdf id:string title:string prices:Vector<LabeledPrice> = ShippingOption;

inputStickerSetItem#32da9e9c flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords keywords:flags.1?string = InputStickerSetItem;

inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall;

phoneCallEmpty#5366c915 id:long = PhoneCall;
phoneCallWaiting#c5226f17 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall;
phoneCallRequested#14b0ed0c flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_b:bytes protocol:PhoneCallProtocol = PhoneCall;
phoneCall#30535af5 flags:# p2p_allowed:flags.5?true video:flags.6?true conference_supported:flags.8?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector<PhoneConnection> start_date:int custom_parameters:flags.7?DataJSON = PhoneCall;
phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;

phoneConnection#9cc123c7 flags:# tcp:flags.0?true id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection;
phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection;

phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector<string> = PhoneCallProtocol;

phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector<User> = phone.PhoneCall;

upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile;
upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile;

cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey;

cdnConfig#5725e40a public_keys:Vector<CdnPublicKey> = CdnConfig;

langPackString#cad181f6 key:string value:string = LangPackString;
langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString;
langPackStringDeleted#2979eeb2 key:string = LangPackString;

langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector<LangPackString> = LangPackDifference;

langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage;

channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction;
channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction;
channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction;
channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction;
channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction;
channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeLinkedChat#50c7ac8 prev_value:long new_value:long = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction;
channelAdminLogEventActionStartGroupCall#23209745 call:InputGroupCall = ChannelAdminLogEventAction;
channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantJoinByInvite#fe9fc158 flags:# via_chatlist:flags.0?true invite:ExportedChatInvite = ChannelAdminLogEventAction;
channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction;
channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction;
channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector<string> new_value:Vector<string> = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleForum#2cc6383 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction;
channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction;
channelAdminLogEventActionToggleAutotranslation#c517f77e new_value:Bool = ChannelAdminLogEventAction;
channelAdminLogEventActionParticipantEditRank#5806b4ec user_id:long prev_rank:string new_rank:string = ChannelAdminLogEventAction;

channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent;

channels.adminLogResults#ed8af74d events:Vector<ChannelAdminLogEvent> chats:Vector<Chat> users:Vector<User> = channels.AdminLogResults;

channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true edit_rank:flags.19?true = ChannelAdminLogEventsFilter;

popularContact#5ce14175 client_id:long importers:int = PopularContact;

messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers;
messages.favedStickers#2cb51097 hash:long packs:Vector<StickerPack> stickers:Vector<Document> = messages.FavedStickers;

recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl;
recentMeUrlUser#b92c09e2 url:string user_id:long = RecentMeUrl;
recentMeUrlChat#b2da71d2 url:string chat_id:long = RecentMeUrl;
recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl;
recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl;

help.recentMeUrls#e0310d7 urls:Vector<RecentMeUrl> chats:Vector<Chat> users:Vector<User> = help.RecentMeUrls;

inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector<MessageEntity> = InputSingleMedia;

webAuthorization#a6f8f452 hash:long bot_id:long domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization;

account.webAuthorizations#ed56c9fc authorizations:Vector<WebAuthorization> users:Vector<User> = account.WebAuthorizations;

inputMessageID#a676a322 id:int = InputMessage;
inputMessageReplyTo#bad88395 id:int = InputMessage;
inputMessagePinned#86872538 = InputMessage;
inputMessageCallbackQuery#acfa1a7e id:int query_id:long = InputMessage;

inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer;
inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer;

dialogPeer#e56dbf05 peer:Peer = DialogPeer;
dialogPeerFolder#514519e2 folder_id:int = DialogPeer;

messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets;
messages.foundStickerSets#8af09dd2 hash:long sets:Vector<StickerSetCovered> = messages.FoundStickerSets;

fileHash#f39b035c offset:long limit:int hash:bytes = FileHash;

inputClientProxy#75588b3f address:string port:int = InputClientProxy;

help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate;
help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate;

inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile;
inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile;

secureFileEmpty#64199744 = SecureFile;
secureFile#7d09c27e id:long access_hash:long size:long dc_id:int date:int file_hash:bytes secret:bytes = SecureFile;

secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData;

securePlainPhone#7d6099dd phone:string = SecurePlainData;
securePlainEmail#21ec5a5f email:string = SecurePlainData;

secureValueTypePersonalDetails#9d2a81e3 = SecureValueType;
secureValueTypePassport#3dac6a00 = SecureValueType;
secureValueTypeDriverLicense#6e425c4 = SecureValueType;
secureValueTypeIdentityCard#a0d0744b = SecureValueType;
secureValueTypeInternalPassport#99a48f23 = SecureValueType;
secureValueTypeAddress#cbe31e26 = SecureValueType;
secureValueTypeUtilityBill#fc36954e = SecureValueType;
secureValueTypeBankStatement#89137c0d = SecureValueType;
secureValueTypeRentalAgreement#8b883488 = SecureValueType;
secureValueTypePassportRegistration#99e3806a = SecureValueType;
secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType;
secureValueTypePhone#b320aadb = SecureValueType;
secureValueTypeEmail#8e3ca7ee = SecureValueType;

secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector<SecureFile> files:flags.4?Vector<SecureFile> plain_data:flags.5?SecurePlainData hash:bytes = SecureValue;

inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector<InputSecureFile> files:flags.4?Vector<InputSecureFile> plain_data:flags.5?SecurePlainData = InputSecureValue;

secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash;

secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError;
secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError;
secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError;
secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError;
secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError;
secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError;
secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError;
secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError;
secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector<bytes> text:string = SecureValueError;

secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted;

account.authorizationForm#ad2e1cd8 flags:# required_types:Vector<SecureRequiredType> values:Vector<SecureValue> errors:Vector<SecureValueError> users:Vector<User> privacy_policy_url:flags.0?string = account.AuthorizationForm;

account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode;

help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo;
help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector<MessageEntity> = help.DeepLinkInfo;

savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact;

account.takeout#4dba4501 id:long = account.Takeout;

passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo;
passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo;

securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo;
securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo;
securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo;

secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings;

inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP;
inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP;

secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType;
secureRequiredTypeOneOf#27477b4 types:Vector<SecureRequiredType> = SecureRequiredType;

help.passportConfigNotModified#bfb9f457 = help.PassportConfig;
help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig;

inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent;

jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue;

jsonNull#3f6d7b68 = JSONValue;
jsonBool#c7345e6a value:Bool = JSONValue;
jsonNumber#2be0dfa4 value:double = JSONValue;
jsonString#b71e767a value:string = JSONValue;
jsonArray#f7444763 value:Vector<JSONValue> = JSONValue;
jsonObject#99c1d49d value:Vector<JSONObjectValue> = JSONValue;

pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell;

pageTableRow#e0c0c5e5 cells:Vector<PageTableCell> = PageTableRow;

pageCaption#6f747657 text:RichText credit:RichText = PageCaption;

pageListItemText#2f58683c flags:# checkbox:flags.0?true checked:flags.1?true text:RichText = PageListItem;
pageListItemBlocks#63ca67aa flags:# checkbox:flags.0?true checked:flags.1?true blocks:Vector<PageBlock> = PageListItem;

pageListOrderedItemText#15031189 flags:# checkbox:flags.0?true checked:flags.1?true num:flags.2?string text:RichText value:flags.3?int type:flags.4?string = PageListOrderedItem;
pageListOrderedItemBlocks#8ff2d5f0 flags:# checkbox:flags.0?true checked:flags.1?true num:flags.2?string blocks:Vector<PageBlock> value:flags.3?int type:flags.4?string = PageListOrderedItem;

pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle;

page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> views:flags.3?int = Page;

help.supportName#8c05f1c9 name:string = help.SupportName;

help.userInfoEmpty#f3ae2eed = help.UserInfo;
help.userInfo#1eb3758 message:string entities:Vector<MessageEntity> author:string date:int = help.UserInfo;

pollAnswer#4b7d786a flags:# text:TextWithEntities option:bytes media:flags.0?MessageMedia added_by:flags.1?Peer date:flags.1?int = PollAnswer;
inputPollAnswer#199fed96 flags:# text:TextWithEntities media:flags.0?InputMedia = PollAnswer;

poll#966e2dbf id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true open_answers:flags.6?true revoting_disabled:flags.7?true shuffle_answers:flags.8?true hide_results_until_close:flags.9?true creator:flags.10?true subscribers_only:flags.11?true question:TextWithEntities answers:Vector<PollAnswer> close_period:flags.4?int close_date:flags.5?int countries_iso2:flags.12?Vector<string> hash:long = Poll;

pollAnswerVoters#3645230a flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:flags.2?int recent_voters:flags.2?Vector<Peer> = PollAnswerVoters;

pollResults#ba7bb15e flags:# min:flags.0?true has_unread_votes:flags.6?true can_view_stats:flags.7?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int recent_voters:flags.3?Vector<Peer> solution:flags.4?string solution_entities:flags.4?Vector<MessageEntity> solution_media:flags.5?MessageMedia = PollResults;

chatOnlines#f041e250 onlines:int = ChatOnlines;

statsURL#47a971e0 url:string = StatsURL;

chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true manage_direct_messages:flags.17?true manage_ranks:flags.18?true = ChatAdminRights;

chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true edit_rank:flags.26?true send_reactions:flags.27?true until_date:int = ChatBannedRights;

inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper;
inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
inputWallPaperNoFile#967a462e id:long = InputWallPaper;

account.wallPapersNotModified#1c199183 = account.WallPapers;
account.wallPapers#cdc3858c hash:long wallpapers:Vector<WallPaper> = account.WallPapers;

codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true unknown_number:flags.9?true logout_tokens:flags.6?Vector<bytes> token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings;

wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings;

autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings;

account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings;

emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector<string> = EmojiKeyword;
emojiKeywordDeleted#236df622 keyword:string emoticons:Vector<string> = EmojiKeyword;

emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector<EmojiKeyword> = EmojiKeywordsDifference;

emojiURL#a575739d url:string = EmojiURL;

emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage;

folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder;

inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer;

folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer;

messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter;

urlAuthResultRequest#3cd623ec flags:# request_write_access:flags.0?true request_phone_number:flags.1?true match_codes_first:flags.5?true is_app:flags.6?true bot:User domain:string browser:flags.2?string platform:flags.2?string ip:flags.2?string region:flags.2?string match_codes:flags.3?Vector<string> user_id_hint:flags.4?long verified_app_name:flags.7?string = UrlAuthResult;
urlAuthResultAccepted#623a8fa0 flags:# url:flags.0?string = UrlAuthResult;
urlAuthResultDefault#a9d6db1f = UrlAuthResult;

channelLocationEmpty#bfb5ad8b = ChannelLocation;
channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation;

peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated;
peerSelfLocated#f8ec284b expires:int = PeerLocated;

restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason;

inputTheme#3c5693e9 id:long access_hash:long = InputTheme;
inputThemeSlug#f5890df1 slug:string = InputTheme;

theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector<ThemeSettings> emoticon:flags.6?string installs_count:flags.4?int = Theme;

account.themesNotModified#f41eb622 = account.Themes;
account.themes#9a3d8c6d hash:long themes:Vector<Theme> = account.Themes;

auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken;
auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken;
auth.loginTokenSuccess#390d5c5e authorization:auth.Authorization = auth.LoginToken;

account.contentSettings#57e28221 flags:# sensitive_enabled:flags.0?true sensitive_can_change:flags.1?true = account.ContentSettings;

messages.inactiveChats#a927fec5 dates:Vector<int> chats:Vector<Chat> users:Vector<User> = messages.InactiveChats;

baseThemeClassic#c3a12462 = BaseTheme;
baseThemeDay#fbd81688 = BaseTheme;
baseThemeNight#b7b31ea8 = BaseTheme;
baseThemeTinted#6d5f77ee = BaseTheme;
baseThemeArctic#5b11125a = BaseTheme;

inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector<int> wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings;

themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector<int> wallpaper:flags.1?WallPaper = ThemeSettings;

webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector<Document> settings:flags.1?ThemeSettings = WebPageAttribute;
webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute;
webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector<Document> = WebPageAttribute;
webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute;
webPageAttributeStarGiftCollection#31cad303 icons:Vector<Document> = WebPageAttribute;
webPageAttributeStarGiftAuction#1c641c2 gift:StarGift end_date:int = WebPageAttribute;
webPageAttributeAiComposeTone#7781fe18 emoji_id:long = WebPageAttribute;

messages.votesList#4899484e flags:# count:int votes:Vector<MessagePeerVote> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = messages.VotesList;

bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl;

payments.bankCardData#3e24e573 title:string open_urls:Vector<BankCardOpenUrl> = payments.BankCardData;

dialogFilter#aa472651 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector<InputPeer> include_peers:Vector<InputPeer> exclude_peers:Vector<InputPeer> = DialogFilter;
dialogFilterDefault#363293ae = DialogFilter;
dialogFilterChatlist#96537bd7 flags:# has_my_invites:flags.26?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector<InputPeer> include_peers:Vector<InputPeer> = DialogFilter;

dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested;

statsDateRangeDays#b637edaf min_date:int max_date:int = StatsDateRangeDays;

statsAbsValueAndPrev#cb43acde current:double previous:double = StatsAbsValueAndPrev;

statsPercentValue#cbce2fe0 part:double total:double = StatsPercentValue;

statsGraphAsync#4a27eb2d token:string = StatsGraph;
statsGraphError#bedc9822 error:string = StatsGraph;
statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph;

stats.broadcastStats#396ca5fc period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev reactions_per_post:StatsAbsValueAndPrev views_per_story:StatsAbsValueAndPrev shares_per_story:StatsAbsValueAndPrev reactions_per_story:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph reactions_by_emotion_graph:StatsGraph story_interactions_graph:StatsGraph story_reactions_by_emotion_graph:StatsGraph recent_posts_interactions:Vector<PostInteractionCounters> = stats.BroadcastStats;

help.promoDataEmpty#98f6ac75 expires:int = help.PromoData;
help.promoData#8a4d87a flags:# proxy:flags.0?true expires:int peer:flags.3?Peer psa_type:flags.1?string psa_message:flags.2?string pending_suggestions:Vector<string> dismissed_suggestions:Vector<string> custom_pending_suggestion:flags.4?PendingSuggestion chats:Vector<Chat> users:Vector<User> = help.PromoData;

videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize;
videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector<int> = VideoSize;
videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector<int> = VideoSize;

statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster;

statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin;

statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter;

stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector<StatsGroupTopPoster> top_admins:Vector<StatsGroupTopAdmin> top_inviters:Vector<StatsGroupTopInviter> users:Vector<User> = stats.MegagroupStats;

globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings;

help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector<string> patterns:flags.1?Vector<string> = help.CountryCode;

help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector<help.CountryCode> = help.Country;

help.countriesListNotModified#93cc1f32 = help.CountriesList;
help.countriesList#87d0759e countries:Vector<help.Country> hash:int = help.CountriesList;

messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews;

messages.messageViews#b6c4f543 views:Vector<MessageViews> chats:Vector<Chat> users:Vector<User> = messages.MessageViews;

messages.discussionMessage#a6341782 flags:# messages:Vector<Message> max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector<Chat> users:Vector<User> = messages.DiscussionMessage;

messageReplyHeader#1b97dd66 flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_ephemeral:flags.13?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector<MessageEntity> quote_offset:flags.10?int todo_item_id:flags.11?int poll_option:flags.12?bytes = MessageReplyHeader;
messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader;

messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector<Peer> channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies;

peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked;

stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats;

groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall;
groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall;

inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall;
inputGroupCallSlug#fe06823f slug:string = InputGroupCall;
inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall;

groupCallParticipant#2a3dc7ac flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo paid_stars_total:flags.16?long = GroupCallParticipant;

phone.groupCall#9e727aad call:GroupCall participants:Vector<GroupCallParticipant> participants_next_offset:string chats:Vector<Chat> users:Vector<User> = phone.GroupCall;

phone.groupParticipants#f47751b6 count:int participants:Vector<GroupCallParticipant> next_offset:string chats:Vector<Chat> users:Vector<User> version:int = phone.GroupParticipants;

inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType;
inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType;
inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType;
inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType;
inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType;
inlineQueryPeerTypeBotPM#e3b2d0c = InlineQueryPeerType;

messages.historyImport#1662af0b id:long = messages.HistoryImport;

messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true title:flags.2?string = messages.HistoryImportParsed;

messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector<int> = messages.AffectedFoundMessages;

chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true via_chatlist:flags.3?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter;

messages.exportedChatInvites#bdc62dcc count:int invites:Vector<ExportedChatInvite> users:Vector<User> = messages.ExportedChatInvites;

messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector<User> = messages.ExportedChatInvite;
messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector<User> = messages.ExportedChatInvite;

messages.chatInviteImporters#81b6b00a count:int importers:Vector<ChatInviteImporter> users:Vector<User> = messages.ChatInviteImporters;

chatAdminWithInvites#f2ecef23 admin_id:long invites_count:int revoked_invites_count:int = ChatAdminWithInvites;

messages.chatAdminsWithInvites#b69b72d7 admins:Vector<ChatAdminWithInvites> users:Vector<User> = messages.ChatAdminsWithInvites;

messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer;

phone.joinAsPeers#afe5623f peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = phone.JoinAsPeers;

phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite;

groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector<int> = GroupCallParticipantVideoSourceGroup;

groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector<GroupCallParticipantVideoSourceGroup> audio_source:flags.1?int = GroupCallParticipantVideo;

stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName;

botCommandScopeDefault#2f6cb2ab = BotCommandScope;
botCommandScopeUsers#3c4f04d8 = BotCommandScope;
botCommandScopeChats#6fe1a881 = BotCommandScope;
botCommandScopeChatAdmins#b9aa606a = BotCommandScope;
botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope;
botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope;
botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope;

account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult;
account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult;
account.resetPasswordOk#e926d63e = account.ResetPasswordResult;

chatTheme#c3dffc04 emoticon:string = ChatTheme;
chatThemeUniqueGift#3458f9c8 gift:StarGift theme_settings:Vector<ThemeSettings> = ChatTheme;

account.chatThemesNotModified#e011e1c4 = account.ChatThemes;
account.chatThemes#be098173 flags:# hash:long themes:Vector<ChatTheme> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = account.ChatThemes;

sponsoredMessage#7dbf8673 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector<MessageEntity> photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string min_display_duration:flags.15?int max_display_duration:flags.15?int = SponsoredMessage;

messages.sponsoredMessages#ffda656d flags:# posts_between:flags.0?int start_delay:flags.1?int between_delay:flags.2?int messages:Vector<SponsoredMessage> chats:Vector<Chat> users:Vector<User> = messages.SponsoredMessages;
messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages;

searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod;

messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector<SearchResultsCalendarPeriod> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SearchResultsCalendar;

searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition;

messages.searchResultsPositions#53b22baf count:int positions:Vector<SearchResultsPosition> = messages.SearchResultsPositions;

channels.sendAsPeers#f496b0c6 peers:Vector<SendAsPeer> chats:Vector<Chat> users:Vector<User> = channels.SendAsPeers;

users.userFull#3b6d152e full_user:UserFull chats:Vector<Chat> users:Vector<User> = users.UserFull;

messages.peerSettings#6880b94d settings:PeerSettings chats:Vector<Chat> users:Vector<User> = messages.PeerSettings;

auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut;

reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount;

messageReactions#a339f0b flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector<ReactionCount> recent_reactions:flags.1?Vector<MessagePeerReaction> top_reactors:flags.4?Vector<MessageReactor> = MessageReactions;

messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector<MessagePeerReaction> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = messages.MessageReactionsList;

availableReaction#c077ec01 flags:# inactive:flags.0?true premium:flags.2?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction;

messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions;
messages.availableReactions#768e3aad hash:int reactions:Vector<AvailableReaction> = messages.AvailableReactions;

messagePeerReaction#8c79b63c flags:# big:flags.0?true unread:flags.1?true my:flags.2?true peer_id:Peer date:int reaction:Reaction = MessagePeerReaction;

groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel;

phone.groupCallStreamChannels#d0e482b2 channels:Vector<GroupCallStreamChannel> = phone.GroupCallStreamChannels;

phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl;

attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor;

attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector<AttachMenuBotIconColor> = AttachMenuBotIcon;

attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector<AttachMenuPeerType> icons:Vector<AttachMenuBotIcon> = AttachMenuBot;

attachMenuBotsNotModified#f1d88a5c = AttachMenuBots;
attachMenuBots#3c4301c0 hash:long bots:Vector<AttachMenuBot> users:Vector<User> = AttachMenuBots;

attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector<User> = AttachMenuBotsBot;

webViewResultUrl#4d22ff98 flags:# fullsize:flags.1?true fullscreen:flags.2?true same_origin:flags.3?true query_id:flags.0?long url:string = WebViewResult;

webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent;

botMenuButtonDefault#7533a588 = BotMenuButton;
botMenuButtonCommands#4258c205 = BotMenuButton;
botMenuButton#c7b57ce6 text:string url:string = BotMenuButton;

account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones;
account.savedRingtones#c1e92cc5 hash:long ringtones:Vector<Document> = account.SavedRingtones;

notificationSoundDefault#97e8bebe = NotificationSound;
notificationSoundNone#6f0c34df = NotificationSound;
notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound;
notificationSoundRingtone#ff6c8049 id:long = NotificationSound;

account.savedRingtone#b7263f6d = account.SavedRingtone;
account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone;

attachMenuPeerTypeSameBotPM#7d6be90e = AttachMenuPeerType;
attachMenuPeerTypeBotPM#c32bfa1a = AttachMenuPeerType;
attachMenuPeerTypePM#f146d31f = AttachMenuPeerType;
attachMenuPeerTypeChat#509113f = AttachMenuPeerType;
attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType;

inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice;
inputInvoiceSlug#c326caef slug:string = InputInvoice;
inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice;
inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice;
inputInvoiceChatInviteSubscription#34e793f1 hash:string = InputInvoice;
inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:flags.2?true peer:InputPeer gift_id:long message:flags.1?TextWithEntities = InputInvoice;
inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice;
inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice;
inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice;
inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice;
inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice;
inputInvoiceStarGiftPrepaidUpgrade#9a0b48b8 peer:InputPeer hash:string = InputInvoice;
inputInvoicePremiumAuthCode#3e77f614 purpose:InputStorePaymentPurpose = InputInvoice;
inputInvoiceStarGiftDropOriginalDetails#923d8d1 stargift:InputSavedStarGift = InputInvoice;
inputInvoiceStarGiftAuctionBid#1ecafa10 flags:# hide_name:flags.0?true update_bid:flags.2?true peer:flags.3?InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice;

payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice;

messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio;

help.premiumPromo#5334759c status_text:string status_entities:Vector<MessageEntity> video_sections:Vector<string> videos:Vector<Document> period_options:Vector<PremiumSubscriptionOption> users:Vector<User> = help.PremiumPromo;

inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose;
inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentPremiumGiftCode#fb790393 flags:# users:Vector<InputUser> boost_peer:flags.0?InputPeer currency:string amount:long message:flags.1?TextWithEntities = InputStorePaymentPurpose;
inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentStarsTopup#f9a2a6cb flags:# stars:long currency:string amount:long spend_purpose_peer:flags.0?InputPeer = InputStorePaymentPurpose;
inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose;
inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector<InputPeer> countries_iso2:flags.2?Vector<string> prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose;
inputStorePaymentAuthCode#3fc18057 flags:# restore:flags.0?true phone_number:string phone_code_hash:string premium_days:int currency:string amount:long = InputStorePaymentPurpose;

paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod;

emojiStatusEmpty#2de11aae = EmojiStatus;
emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus;
emojiStatusCollectible#7184603b flags:# collectible_id:long document_id:long title:string slug:string pattern_document_id:long center_color:int edge_color:int pattern_color:int text_color:int until:flags.0?int = EmojiStatus;
inputEmojiStatusCollectible#7141dbf flags:# collectible_id:long until:flags.0?int = EmojiStatus;

account.emojiStatusesNotModified#d08ce645 = account.EmojiStatuses;
account.emojiStatuses#90c467d1 hash:long statuses:Vector<EmojiStatus> = account.EmojiStatuses;

reactionEmpty#79f5d419 = Reaction;
reactionEmoji#1b2286b8 emoticon:string = Reaction;
reactionCustomEmoji#8935fc73 document_id:long = Reaction;
reactionPaid#523da4eb = Reaction;

chatReactionsNone#eafc32bc = ChatReactions;
chatReactionsAll#52928bca flags:# allow_custom:flags.0?true = ChatReactions;
chatReactionsSome#661d4037 reactions:Vector<Reaction> = ChatReactions;

messages.reactionsNotModified#b06fdbdf = messages.Reactions;
messages.reactions#eafdf716 hash:long reactions:Vector<Reaction> = messages.Reactions;

emailVerifyPurposeLoginSetup#4345be73 phone_number:string phone_code_hash:string = EmailVerifyPurpose;
emailVerifyPurposeLoginChange#527d22eb = EmailVerifyPurpose;
emailVerifyPurposePassport#bbf51685 = EmailVerifyPurpose;

emailVerificationCode#922e55a9 code:string = EmailVerification;
emailVerificationGoogle#db909ec2 token:string = EmailVerification;
emailVerificationApple#96d074fd token:string = EmailVerification;

account.emailVerified#2b96cd1b email:string = account.EmailVerified;
account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified;

premiumSubscriptionOption#5f2d1df2 flags:# current:flags.1?true can_purchase_upgrade:flags.2?true transaction:flags.3?string months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption;

sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer;

messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia;
messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia;

stickerKeyword#fcfeb29c document_id:long keyword:Vector<string> = StickerKeyword;

username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username;

forumTopicDeleted#23f109b id:int = ForumTopic;
forumTopic#fcdad815 flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true short:flags.5?true hidden:flags.6?true title_missing:flags.7?true id:int date:int peer:Peer title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic;

messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector<ForumTopic> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> pts:int = messages.ForumTopics;

defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL;

exportedContactToken#41bf109b url:string expires:int = ExportedContactToken;

requestPeerTypeUser#5f3b8a00 flags:# bot:flags.0?Bool premium:flags.1?Bool = RequestPeerType;
requestPeerTypeChat#c9f06e1b flags:# creator:flags.0?true bot_participant:flags.5?true has_username:flags.3?Bool forum:flags.4?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType;
requestPeerTypeBroadcast#339bef6c flags:# creator:flags.0?true has_username:flags.3?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType;
requestPeerTypeCreateBot#3e81e078 flags:# bot_managed:flags.0?true suggested_name:flags.1?string suggested_username:flags.2?string = RequestPeerType;

emojiListNotModified#481eadfa = EmojiList;
emojiList#7a1e11d1 hash:long document_id:Vector<long> = EmojiList;

emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector<string> = EmojiGroup;
emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector<string> = EmojiGroup;
emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup;

messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups;
messages.emojiGroups#881fb94b hash:int groups:Vector<EmojiGroup> = messages.EmojiGroups;

textWithEntities#751f3146 text:string entities:Vector<MessageEntity> = TextWithEntities;

messages.translateResult#33db32f8 result:Vector<TextWithEntities> = messages.TranslatedText;

autoSaveSettings#c84834ce flags:# photos:flags.0?true videos:flags.1?true video_max_size:flags.2?long = AutoSaveSettings;

autoSaveException#81602d47 peer:Peer settings:AutoSaveSettings = AutoSaveException;

account.autoSaveSettings#4c3e069d users_settings:AutoSaveSettings chats_settings:AutoSaveSettings broadcasts_settings:AutoSaveSettings exceptions:Vector<AutoSaveException> chats:Vector<Chat> users:Vector<User> = account.AutoSaveSettings;

help.appConfigNotModified#7cde641d = help.AppConfig;
help.appConfig#dd18782e hash:int config:JSONValue = help.AppConfig;

inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp;
inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp;

botAppNotModified#5da674b7 = BotApp;
botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp;

messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp;

inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView;

readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate;

inputChatlistDialogFilter#f3e0da33 filter_id:int = InputChatlist;

exportedChatlistInvite#c5181ac flags:# title:string url:string peers:Vector<Peer> = ExportedChatlistInvite;

chatlists.exportedChatlistInvite#10e6e3a6 filter:DialogFilter invite:ExportedChatlistInvite = chatlists.ExportedChatlistInvite;

chatlists.exportedInvites#10ab6dc7 invites:Vector<ExportedChatlistInvite> chats:Vector<Chat> users:Vector<User> = chatlists.ExportedInvites;

chatlists.chatlistInviteAlready#fa87f659 filter_id:int missing_peers:Vector<Peer> already_peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = chatlists.ChatlistInvite;
chatlists.chatlistInvite#f10ece2f flags:# title_noanimate:flags.1?true title:TextWithEntities emoticon:flags.0?string peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = chatlists.ChatlistInvite;

chatlists.chatlistUpdates#93bd878d missing_peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = chatlists.ChatlistUpdates;

bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo;

messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote;
messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote;
messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector<bytes> date:int = MessagePeerVote;

storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector<ReactionCount> reactions_count:flags.4?int recent_viewers:flags.0?Vector<long> = StoryViews;

storyItemDeleted#51e6ee4f id:int = StoryItem;
storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true live:flags.9?true id:int date:int expire_date:int = StoryItem;
storyItem#16a4b93c flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector<MessageEntity> media:MessageMedia media_areas:flags.14?Vector<MediaArea> privacy:flags.2?Vector<PrivacyRule> views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector<int> music:flags.20?Document = StoryItem;

stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories;
stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector<PeerStories> chats:Vector<Chat> users:Vector<User> stealth_mode:StoriesStealthMode = stories.AllStories;

stories.stories#63c3dd0a flags:# count:int stories:Vector<StoryItem> pinned_to_top:flags.0?Vector<int> chats:Vector<Chat> users:Vector<User> = stories.Stories;

storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView;
storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView;
storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView;

stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector<StoryView> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = stories.StoryViewsList;

stories.storyViews#de9eed1d views:Vector<StoryViews> users:Vector<User> = stories.StoryViews;

inputReplyToMessage#3bd4b7c2 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector<MessageEntity> quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int poll_option:flags.7?bytes = InputReplyTo;
inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo;
inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo;

exportedStoryLink#3fc9053b link:string = ExportedStoryLink;

storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode;

mediaAreaCoordinates#cfc9e002 flags:# x:double y:double w:double h:double rotation:double radius:flags.0?double = MediaAreaCoordinates;

mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MediaArea;
inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea;
mediaAreaGeoPoint#cad5452d flags:# coordinates:MediaAreaCoordinates geo:GeoPoint address:flags.0?GeoPointAddress = MediaArea;
mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea;
mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea;
inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea;
mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea;
mediaAreaWeather#49a6549c coordinates:MediaAreaCoordinates emoji:string temperature_c:double color:int = MediaArea;
mediaAreaStarGift#5787686d coordinates:MediaAreaCoordinates slug:string = MediaArea;

peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector<StoryItem> = PeerStories;

stories.peerStories#cae68768 stories:PeerStories chats:Vector<Chat> users:Vector<User> = stories.PeerStories;

messages.webPage#fd5e12bd webpage:WebPage chats:Vector<Chat> users:Vector<User> = messages.WebPage;

premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption;

payments.checkedGiftCode#eb983f8f flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int days:int used_date:flags.1?int chats:Vector<Chat> users:Vector<User> = payments.CheckedGiftCode;

payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo;
payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo;

prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway;
prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway;

boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost;

premium.boostsList#86f8613c flags:# count:int boosts:Vector<Boost> next_offset:flags.0?string users:Vector<User> = premium.BoostsList;

myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost;

premium.myBoosts#9ae228e2 my_boosts:Vector<MyBoost> chats:Vector<Chat> users:Vector<User> = premium.MyBoosts;

premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector<PrepaidGiveaway> my_boost_slots:flags.2?Vector<int> = premium.BoostsStatus;

storyFwdHeader#b826e150 flags:# modified:flags.3?true from:flags.0?Peer from_name:flags.1?string story_id:flags.2?int = StoryFwdHeader;

postInteractionCountersMessage#e7058e7f msg_id:int views:int forwards:int reactions:int = PostInteractionCounters;
postInteractionCountersStory#8a480e27 story_id:int views:int forwards:int reactions:int = PostInteractionCounters;

stats.storyStats#50cd067c views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.StoryStats;

publicForwardMessage#1f2bf4a message:Message = PublicForward;
publicForwardStory#edf3add0 peer:Peer story:StoryItem = PublicForward;

stats.publicForwards#93037e20 flags:# count:int forwards:Vector<PublicForward> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = stats.PublicForwards;

peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor;
peerColorCollectible#b9c0639a flags:# collectible_id:long gift_emoji_id:long background_emoji_id:long accent_color:int colors:Vector<int> dark_accent_color:flags.0?int dark_colors:flags.1?Vector<int> = PeerColor;
inputPeerColorCollectible#b8ea86a9 collectible_id:long = PeerColor;

help.peerColorSet#26219a58 colors:Vector<int> = help.PeerColorSet;
help.peerColorProfileSet#767d61eb palette_colors:Vector<int> bg_colors:Vector<int> story_colors:Vector<int> = help.PeerColorSet;

help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption;

help.peerColorsNotModified#2ba1f5ce = help.PeerColors;
help.peerColors#f8ed08 hash:int colors:Vector<help.PeerColorOption> = help.PeerColors;

storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction;
storyReactionPublicForward#bbab2643 message:Message = StoryReaction;
storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction;

stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector<StoryReaction> chats:Vector<Chat> users:Vector<User> next_offset:flags.0?string = stories.StoryReactionsList;

savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog;
monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true nopaid_messages_exception:flags.4?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog;

messages.savedDialogs#f83ae221 dialogs:Vector<SavedDialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SavedDialogs;
messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector<SavedDialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SavedDialogs;
messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs;

savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag;

messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags;
messages.savedReactionTags#3259950a tags:Vector<SavedReactionTag> hash:long = messages.SavedReactionTags;

outboxReadDate#3bb842ac date:int = OutboxReadDate;

smsjobs.eligibleToJoin#dc8b44cf terms_url:string monthly_sent_sms:int = smsjobs.EligibilityToJoin;

smsjobs.status#2aee9191 flags:# allow_international:flags.0?true recent_sent:int recent_since:int recent_remains:int total_sent:int total_since:int last_gift_slug:flags.1?string terms_url:string = smsjobs.Status;

smsJob#e6a1eeb8 job_id:string phone_number:string text:string = SmsJob;

businessWeeklyOpen#120b1ab9 start_minute:int end_minute:int = BusinessWeeklyOpen;

businessWorkHours#8c92b098 flags:# open_now:flags.0?true timezone_id:string weekly_open:Vector<BusinessWeeklyOpen> = BusinessWorkHours;

businessLocation#ac5c1af7 flags:# geo_point:flags.0?GeoPoint address:string = BusinessLocation;

inputBusinessRecipients#6f8b32aa flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector<InputUser> = InputBusinessRecipients;

businessRecipients#21108ff7 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector<long> = BusinessRecipients;

businessAwayMessageScheduleAlways#c9b9e2b9 = BusinessAwayMessageSchedule;
businessAwayMessageScheduleOutsideWorkHours#c3f2f501 = BusinessAwayMessageSchedule;
businessAwayMessageScheduleCustom#cc4d9ecc start_date:int end_date:int = BusinessAwayMessageSchedule;

inputBusinessGreetingMessage#194cb3b shortcut_id:int recipients:InputBusinessRecipients no_activity_days:int = InputBusinessGreetingMessage;

businessGreetingMessage#e519abab shortcut_id:int recipients:BusinessRecipients no_activity_days:int = BusinessGreetingMessage;

inputBusinessAwayMessage#832175e0 flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:InputBusinessRecipients = InputBusinessAwayMessage;

businessAwayMessage#ef156a5c flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:BusinessRecipients = BusinessAwayMessage;

timezone#ff9289f5 id:string name:string utc_offset:int = Timezone;

help.timezonesListNotModified#970708cc = help.TimezonesList;
help.timezonesList#7b74ed71 timezones:Vector<Timezone> hash:int = help.TimezonesList;

quickReply#697102b shortcut_id:int shortcut:string top_message:int count:int = QuickReply;

inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut;
inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut;

messages.quickReplies#c68d6695 quick_replies:Vector<QuickReply> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.QuickReplies;
messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies;

connectedBot#33ed001 flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights device:flags.0?string date:flags.1?int location:flags.2?string = ConnectedBot;

account.connectedBots#17d7f87b connected_bots:Vector<ConnectedBot> users:Vector<User> = account.ConnectedBots;

messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector<DialogFilter> = messages.DialogFilters;

birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday;

botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection;

inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro;

businessIntro#5a0a066d flags:# title:string description:string sticker:flags.0?Document = BusinessIntro;

messages.myStickers#faff629d count:int sets:Vector<StickerSetCovered> = messages.MyStickers;

inputCollectibleUsername#e39460a9 username:string = InputCollectible;
inputCollectiblePhone#a2e214a4 phone:string = InputCollectible;

fragment.collectibleInfo#6ebdff91 purchase_date:int currency:string amount:long crypto_currency:string crypto_amount:long url:string = fragment.CollectibleInfo;

inputBusinessBotRecipients#c4e5921e flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector<InputUser> exclude_users:flags.6?Vector<InputUser> = InputBusinessBotRecipients;

businessBotRecipients#b88cf373 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector<long> exclude_users:flags.6?Vector<long> = BusinessBotRecipients;

contactBirthday#1d998733 contact_id:long birthday:Birthday = ContactBirthday;

contacts.contactBirthdays#114ff30d contacts:Vector<ContactBirthday> users:Vector<User> = contacts.ContactBirthdays;

missingInvitee#628c9224 flags:# premium_would_allow_invite:flags.0?true premium_required_for_pm:flags.1?true user_id:long = MissingInvitee;

messages.invitedUsers#7f5defa6 updates:Updates missing_invitees:Vector<MissingInvitee> = messages.InvitedUsers;

inputBusinessChatLink#11679fa7 flags:# message:string entities:flags.0?Vector<MessageEntity> title:flags.1?string = InputBusinessChatLink;

businessChatLink#b4ae666f flags:# link:string message:string entities:flags.0?Vector<MessageEntity> title:flags.1?string views:int = BusinessChatLink;

account.businessChatLinks#ec43a2d1 links:Vector<BusinessChatLink> chats:Vector<Chat> users:Vector<User> = account.BusinessChatLinks;

account.resolvedBusinessChatLinks#9a23af21 flags:# peer:Peer message:string entities:flags.0?Vector<MessageEntity> chats:Vector<Chat> users:Vector<User> = account.ResolvedBusinessChatLinks;

requestedPeerUser#d62ff46a flags:# user_id:long first_name:flags.0?string last_name:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer;
requestedPeerChat#7307544f flags:# chat_id:long title:flags.0?string photo:flags.2?Photo = RequestedPeer;
requestedPeerChannel#8ba403e4 flags:# channel_id:long title:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer;

sponsoredMessageReportOption#430d3150 text:string option:bytes = SponsoredMessageReportOption;

channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options:Vector<SponsoredMessageReportOption> = channels.SponsoredMessageReportResult;
channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult;
channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult;

reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom;
reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom;

reactionsNotifySettings#71e4ea58 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom poll_votes_notify_from:flags.2?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings;

availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect;

messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects;
messages.availableEffects#bddb616e hash:int effects:Vector<AvailableEffect> documents:Vector<Document> = messages.AvailableEffects;

factCheck#b89bfccf flags:# need_check:flags.0?true country:flags.1?string text:flags.1?TextWithEntities hash:long = FactCheck;

starsTransactionPeerUnsupported#95f2bfe4 = StarsTransactionPeer;
starsTransactionPeerAppStore#b457b375 = StarsTransactionPeer;
starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer;
starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer;
starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer;
starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer;
starsTransactionPeerAds#60682812 = StarsTransactionPeer;
starsTransactionPeerAPI#f9677aad = StarsTransactionPeer;

starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption;

starsTransaction#13659eb0 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true posts_search:flags.24?true stargift_prepaid_upgrade:flags.25?true stargift_drop_original_details:flags.26?true phonegroup_message:flags.27?true stargift_auction_bid:flags.28?true offer:flags.29?true id:string amount:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector<MessageMedia> subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int ads_proceeds_from_date:flags.23?int ads_proceeds_to_date:flags.23?int = StarsTransaction;

payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector<StarsSubscription> subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector<StarsTransaction> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = payments.StarsStatus;

foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory;

stories.foundStories#e2de7737 flags:# count:int stories:Vector<FoundStory> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = stories.FoundStories;

geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress;

starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus;

payments.starsRevenueStats#6c207376 flags:# top_hours_graph:flags.0?StatsGraph revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats;

payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl;

payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAdsAccountUrl;

inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction;

starsGiftOption#5e0589f1 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsGiftOption;

bots.popularAppBots#1991b13b flags:# next_offset:flags.0?string users:Vector<User> = bots.PopularAppBots;

botPreviewMedia#23e91ba3 date:int media:MessageMedia = BotPreviewMedia;

bots.previewInfo#ca71d64 media:Vector<BotPreviewMedia> lang_codes:Vector<string> = bots.PreviewInfo;

starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing;

starsSubscription#2e6eab1a flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true bot_canceled:flags.7?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string title:flags.4?string photo:flags.5?WebDocument invoice_slug:flags.6?string = StarsSubscription;

messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor;

starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector<StarsGiveawayWinnersOption> = StarsGiveawayOption;

starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption;

starGift#313a9547 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true peer_color_available:flags.10?true auction:flags.11?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int locked_until_date:flags.9?int auction_slug:flags.11?string gifts_per_round:flags.11?int auction_start_date:flags.11?int upgrade_variants:flags.12?int background:flags.13?StarGiftBackground = StarGift;
starGiftUnique#85f0a9cd flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true burned:flags.14?true crafted:flags.15?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector<StarGiftAttribute> availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector<StarsAmount> released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int craft_chance_permille:flags.16?int = StarGift;

payments.starGiftsNotModified#a388a368 = payments.StarGifts;
payments.starGifts#2ed82995 hash:int gifts:Vector<StarGift> chats:Vector<Chat> users:Vector<User> = payments.StarGifts;

messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption;

reportResultChooseOption#f0e4e0b6 title:string options:Vector<MessageReportOption> = ReportResult;
reportResultAddComment#6f09ac31 flags:# optional:flags.0?true option:bytes = ReportResult;
reportResultReported#8db33c4b = ReportResult;

messages.botPreparedInlineMessage#8ecf0511 id:string expire_date:int = messages.BotPreparedInlineMessage;

messages.preparedInlineMessage#ff57708d query_id:long result:BotInlineResult peer_types:Vector<InlineQueryPeerType> cache_time:int users:Vector<User> = messages.PreparedInlineMessage;

botAppSettings#c99b1950 flags:# placeholder_path:flags.0?bytes background_color:flags.1?int background_dark_color:flags.2?int header_color:flags.3?int header_dark_color:flags.4?int = BotAppSettings;

starRefProgram#dd0c66f2 flags:# bot_id:long commission_permille:int duration_months:flags.0?int end_date:flags.1?int daily_revenue_per_user:flags.2?StarsAmount = StarRefProgram;

connectedBotStarRef#19a13f71 flags:# revoked:flags.1?true url:string date:int bot_id:long commission_permille:int duration_months:flags.0?int participants:long revenue:long = ConnectedBotStarRef;

payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector<ConnectedBotStarRef> users:Vector<User> = payments.ConnectedStarRefBots;

payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector<StarRefProgram> users:Vector<User> next_offset:flags.0?string = payments.SuggestedStarRefBots;

starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount;
starsTonAmount#74aee3e0 amount:long = StarsAmount;

messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers;
messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector<Document> = messages.FoundStickers;

botVerifierSettings#b0cd6617 flags:# can_modify_custom_description:flags.1?true icon:long company:string custom_description:flags.0?string = BotVerifierSettings;

botVerification#f93cd45c bot_id:long icon:long description:string = BotVerification;

starGiftAttributeModel#565251e2 flags:# crafted:flags.0?true name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute;
starGiftAttributePattern#4e7085ea name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute;
starGiftAttributeBackdrop#9f2504e4 name:string backdrop_id:int center_color:int edge_color:int pattern_color:int text_color:int rarity:StarGiftAttributeRarity = StarGiftAttribute;
starGiftAttributeOriginalDetails#e0bff26c flags:# sender_id:flags.0?Peer recipient_id:Peer date:int message:flags.1?TextWithEntities = StarGiftAttribute;

payments.starGiftUpgradePreview#3de1dfed sample_attributes:Vector<StarGiftAttribute> prices:Vector<StarGiftUpgradePrice> next_prices:Vector<StarGiftUpgradePrice> = payments.StarGiftUpgradePreview;

users.users#62d706b8 users:Vector<User> = users.Users;
users.usersSlice#315a4974 count:int users:Vector<User> = users.Users;

payments.uniqueStarGift#416c56e8 gift:StarGift chats:Vector<Chat> users:Vector<User> = payments.UniqueStarGift;

messages.webPagePreview#8c9a88ac media:MessageMedia chats:Vector<Chat> users:Vector<User> = messages.WebPagePreview;

savedStarGift#41df43fc flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector<int> prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int can_craft_at:flags.20?int = SavedStarGift;

payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector<SavedStarGift> next_offset:flags.0?string chats:Vector<Chat> users:Vector<User> = payments.SavedStarGifts;

inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift;
inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift;
inputSavedStarGiftSlug#2085c238 slug:string = InputSavedStarGift;

payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl;

paidReactionPrivacyDefault#206ad49e = PaidReactionPrivacy;
paidReactionPrivacyAnonymous#1f0c1ad9 = PaidReactionPrivacy;
paidReactionPrivacyPeer#dc6cfcf0 peer:InputPeer = PaidReactionPrivacy;

account.paidMessagesRevenue#1e109708 stars_amount:long = account.PaidMessagesRevenue;

requirementToContactEmpty#50a9839 = RequirementToContact;
requirementToContactPremium#e581e4e9 = RequirementToContact;
requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact;

businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights;

disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true disallow_stargifts_from_channels:flags.4?true = DisallowedGiftsSettings;

sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer;

contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers;
contacts.sponsoredPeers#eb032884 peers:Vector<SponsoredPeer> chats:Vector<Chat> users:Vector<User> = contacts.SponsoredPeers;

starGiftAttributeIdModel#48aaae3c document_id:long = StarGiftAttributeId;
starGiftAttributeIdPattern#4a162433 document_id:long = StarGiftAttributeId;
starGiftAttributeIdBackdrop#1f01c757 backdrop_id:int = StarGiftAttributeId;

starGiftAttributeCounter#2eb1b658 attribute:StarGiftAttributeId count:int = StarGiftAttributeCounter;

payments.resaleStarGifts#947a12df flags:# count:int gifts:Vector<StarGift> next_offset:flags.0?string attributes:flags.1?Vector<StarGiftAttribute> attributes_hash:flags.1?long chats:Vector<Chat> counters:flags.2?Vector<StarGiftAttributeCounter> users:Vector<User> = payments.ResaleStarGifts;

stories.canSendStoryCount#c387c04e count_remains:int = stories.CanSendStoryCount;

pendingSuggestion#e7e82e12 suggestion:string title:TextWithEntities description:TextWithEntities url:string = PendingSuggestion;

todoItem#cba9a52f id:int title:TextWithEntities = TodoItem;

todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector<TodoItem> = TodoList;

todoCompletion#221bb5e4 id:int completed_by:Peer date:int = TodoCompletion;

suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost;

starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating;

starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection;

payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections;
payments.starGiftCollections#8a2932f3 collections:Vector<StarGiftCollection> = payments.StarGiftCollections;

storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum;

stories.albumsNotModified#564edaeb = stories.Albums;
stories.albums#c3987a3a hash:long albums:Vector<StoryAlbum> = stories.Albums;

searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood;

payments.uniqueStarGiftValueInfo#512fe446 flags:# last_sale_on_fragment:flags.1?true value_is_average:flags.6?true currency:string value:long initial_sale_date:int initial_sale_stars:long initial_sale_price:long last_sale_date:flags.0?int last_sale_price:flags.0?long floor_price:flags.2?long average_price:flags.3?long listed_count:flags.4?int fragment_listed_count:flags.5?int fragment_listed_url:flags.5?string = payments.UniqueStarGiftValueInfo;

profileTabPosts#b98cd696 = ProfileTab;
profileTabGifts#4d4bd46a = ProfileTab;
profileTabMedia#72c64955 = ProfileTab;
profileTabFiles#ab339c00 = ProfileTab;
profileTabMusic#9f27d26e = ProfileTab;
profileTabVoice#e477092e = ProfileTab;
profileTabLinks#d3656499 = ProfileTab;
profileTabGifs#a2c0f695 = ProfileTab;

users.savedMusicNotModified#e3878aa4 count:int = users.SavedMusic;
users.savedMusic#34a2f297 count:int documents:Vector<Document> = users.SavedMusic;

account.savedMusicIdsNotModified#4fc81d6e = account.SavedMusicIds;
account.savedMusicIds#998d6636 ids:Vector<long> = account.SavedMusicIds;

payments.checkCanSendGiftResultOk#374fa7ad = payments.CheckCanSendGiftResult;
payments.checkCanSendGiftResultFail#d5e58274 reason:TextWithEntities = payments.CheckCanSendGiftResult;

inputChatThemeEmpty#83268483 = InputChatTheme;
inputChatTheme#c93de95c emoticon:string = InputChatTheme;
inputChatThemeUniqueGift#87e5dfe4 slug:string = InputChatTheme;

starGiftUpgradePrice#99ea331d date:int upgrade_stars:long = StarGiftUpgradePrice;

groupCallMessage#1a8afc7e flags:# from_admin:flags.1?true id:int from_id:Peer date:int message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage;

groupCallDonor#ee430c85 flags:# top:flags.0?true my:flags.1?true peer_id:flags.3?Peer stars:long = GroupCallDonor;

phone.groupCallStars#9d1dbd26 total_stars:long top_donors:Vector<GroupCallDonor> chats:Vector<Chat> users:Vector<User> = phone.GroupCallStars;

recentStory#711d692d flags:# live:flags.0?true max_id:flags.1?int = RecentStory;

auctionBidLevel#310240cc pos:int amount:long date:int = AuctionBidLevel;

starGiftAuctionStateNotModified#fe333952 = StarGiftAuctionState;
starGiftAuctionState#771a4e66 version:int start_date:int end_date:int min_bid_amount:long bid_levels:Vector<AuctionBidLevel> top_bidders:Vector<long> next_round_at:int last_gift_num:int gifts_left:int current_round:int total_rounds:int rounds:Vector<StarGiftAuctionRound> = StarGiftAuctionState;
starGiftAuctionStateFinished#972dabbf flags:# start_date:int end_date:int average_price:long listed_count:flags.0?int fragment_listed_count:flags.1?int fragment_listed_url:flags.1?string = StarGiftAuctionState;

starGiftAuctionUserState#2eeed1c4 flags:# returned:flags.1?true bid_amount:flags.0?long bid_date:flags.0?int min_bid_amount:flags.0?long bid_peer:flags.0?Peer acquired_count:int = StarGiftAuctionUserState;

payments.starGiftAuctionState#6b39f4ec gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState timeout:int users:Vector<User> chats:Vector<Chat> = payments.StarGiftAuctionState;

starGiftAuctionAcquiredGift#42b00348 flags:# name_hidden:flags.0?true peer:Peer date:int bid_amount:long round:int pos:int message:flags.1?TextWithEntities gift_num:flags.2?int = StarGiftAuctionAcquiredGift;

payments.starGiftAuctionAcquiredGifts#7d5bd1f0 gifts:Vector<StarGiftAuctionAcquiredGift> users:Vector<User> chats:Vector<Chat> = payments.StarGiftAuctionAcquiredGifts;

starGiftActiveAuctionState#d31bc45d gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState = StarGiftActiveAuctionState;

payments.starGiftActiveAuctionsNotModified#db33dad0 = payments.StarGiftActiveAuctions;
payments.starGiftActiveAuctions#aef6abbc auctions:Vector<StarGiftActiveAuctionState> users:Vector<User> chats:Vector<Chat> = payments.StarGiftActiveAuctions;

inputStarGiftAuction#2e16c98 gift_id:long = InputStarGiftAuction;
inputStarGiftAuctionSlug#7ab58308 slug:string = InputStarGiftAuction;

passkey#98613ebf flags:# id:string name:string date:int software_emoji_id:flags.0?long last_usage_date:flags.1?int = Passkey;

account.passkeys#f8e0aa1c passkeys:Vector<Passkey> = account.Passkeys;

account.passkeyRegistrationOptions#e16b5ce1 options:DataJSON = account.PasskeyRegistrationOptions;

auth.passkeyLoginOptions#e2037789 options:DataJSON = auth.PasskeyLoginOptions;

inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:bytes = InputPasskeyResponse;
inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse;

inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential;
inputPasskeyCredentialFirebasePNV#5b1ccb28 pnv_token:string = InputPasskeyCredential;

starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground;

starGiftAuctionRound#3aae0528 num:int duration:int = StarGiftAuctionRound;
starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int extend_window:int = StarGiftAuctionRound;

payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector<StarGiftAttribute> = payments.StarGiftUpgradeAttributes;

messages.emojiGameOutcome#da2ad647 seed:bytes stake_ton_amount:long ton_amount:long = messages.EmojiGameOutcome;

messages.emojiGameUnavailable#59e65335 = messages.EmojiGameInfo;
messages.emojiGameDiceInfo#44e56023 flags:# game_hash:string prev_stake:long current_streak:int params:Vector<int> plays_left:flags.0?int = messages.EmojiGameInfo;

starGiftAttributeRarity#36437737 permille:int = StarGiftAttributeRarity;
starGiftAttributeRarityUncommon#dbce6389 = StarGiftAttributeRarity;
starGiftAttributeRarityRare#f08d516b = StarGiftAttributeRarity;
starGiftAttributeRarityEpic#78fbf3a8 = StarGiftAttributeRarity;
starGiftAttributeRarityLegendary#cef7e7a8 = StarGiftAttributeRarity;

keyboardButtonStyle#4fdd3430 flags:# bg_primary:flags.0?true bg_danger:flags.1?true bg_success:flags.2?true icon:flags.3?long = KeyboardButtonStyle;

inputMessageReadMetric#402b4495 msg_id:int view_id:long time_in_view_ms:int active_time_in_view_ms:int height_to_viewport_ratio_permille:int seen_range_ratio_permille:int = InputMessageReadMetric;

bots.exportedBotToken#3c60b621 token:string = bots.ExportedBotToken;

bots.requestedButton#f13bbcd7 webapp_req_id:string = bots.RequestedButton;

messages.composedMessageWithAI#90d7adfa flags:# result_text:TextWithEntities diff_text:flags.0?TextWithEntities = messages.ComposedMessageWithAI;

stats.pollStats#2999beed votes_graph:StatsGraph = stats.PollStats;

inputAiComposeToneDefault#1fe9a9bf tone:string = InputAiComposeTone;
inputAiComposeToneID#773c080 id:long access_hash:long = InputAiComposeTone;
inputAiComposeToneSlug#1fa01357 slug:string = InputAiComposeTone;

aiComposeTone#cff63ea9 flags:# creator:flags.0?true id:long access_hash:long slug:string title:string emoji_id:flags.1?long prompt:flags.4?string installs_count:flags.2?int author_id:flags.3?long example_english:flags.5?AiComposeToneExample = AiComposeTone;
aiComposeToneDefault#9bad6414 tone:string emoji_id:long title:string = AiComposeTone;

aicompose.tonesNotModified#c1f46103 = aicompose.Tones;
aicompose.tones#6c9d0efe hash:long tones:Vector<AiComposeTone> users:Vector<User> = aicompose.Tones;

aiComposeToneExample#f1d628ec from:TextWithEntities to:TextWithEntities = AiComposeToneExample;

bots.accessSettings#dd1fbf93 flags:# restricted:flags.0?true add_users:flags.1?Vector<User> = bots.AccessSettings;

messages.chatInviteJoinResultOk#445663a7 updates:Updates = messages.ChatInviteJoinResult;
messages.chatInviteJoinResultWebView#2f51c337 bot_id:long webview:WebViewResult users:Vector<User> = messages.ChatInviteJoinResult;

joinChatBotResultApproved#ae152a69 = JoinChatBotResult;
joinChatBotResultDeclined#efa0194 = JoinChatBotResult;
joinChatBotResultQueued#98a3a840 = JoinChatBotResult;
joinChatBotResultWebView#d6e3b813 url:string = JoinChatBotResult;

webDomainException#933ca597 flags:# domain:string url:string title:string favicon:flags.0?long = WebDomainException;

account.webBrowserSettingsNotModified#c31c8f4e = account.WebBrowserSettings;
account.webBrowserSettings#79eb8cb3 flags:# open_external_browser:flags.0?true display_close_button:flags.1?true external_exceptions:Vector<WebDomainException> inapp_exceptions:Vector<WebDomainException> hash:long = account.WebBrowserSettings;

inputRichFilePhoto#9b00622b id:string photo:InputPhoto = InputRichFile;
inputRichFileDocument#83281dbd id:string document:InputDocument = InputRichFile;

inputRichMessage#e4c449fc flags:# rtl:flags.0?true noautolink:flags.1?true blocks:Vector<PageBlock> photos:flags.2?Vector<InputPhoto> documents:flags.3?Vector<InputDocument> users:flags.4?Vector<InputUser> = InputRichMessage;
inputRichMessageHTML#dacb836a flags:# rtl:flags.0?true noautolink:flags.1?true html:string files:flags.2?Vector<InputRichFile> = InputRichMessage;
inputRichMessageMarkdown#4b572c flags:# rtl:flags.0?true noautolink:flags.1?true markdown:string files:flags.2?Vector<InputRichFile> = InputRichMessage;

richMessage#baf39d8b flags:# rtl:flags.0?true part:flags.1?true blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = RichMessage;

---functions---

invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X;
initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X;
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X;
invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X;
invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X;
invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X;

auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization;
auth.signIn#8d52a951 flags:# phone_number:string phone_code_hash:string phone_code:flags.0?string email_verification:flags.1?EmailVerification = auth.Authorization;
auth.logOut#3e72ba19 = auth.LoggedOut;
auth.resetAuthorizations#9fab0d1a = Bool;
auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization;
auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool;
auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization;
auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization;
auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery;
auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization;
auth.resendCode#cae47523 flags:# phone_number:string phone_code_hash:string reason:flags.0?string = auth.SentCode;
auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector<long> = auth.LoginToken;
auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken;
auth.acceptLoginToken#e894ad4d token:bytes = Authorization;
auth.checkRecoveryPassword#d36bf79 code:string = Bool;
auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization;
auth.requestFirebaseSms#8e39261e flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string play_integrity_token:flags.2?string ios_push_secret:flags.1?string = Bool;
auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode;
auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool;
auth.checkPaidAuth#56e59f9c phone_number:string phone_code_hash:string form_id:long = auth.SentCode;
auth.initPasskeyLogin#518ad0b7 api_id:int api_hash:string = auth.PasskeyLoginOptions;
auth.finishPasskeyLogin#9857ad07 flags:# credential:InputPasskeyCredential from_dc_id:flags.0?int from_auth_key_id:flags.0?long = auth.Authorization;

account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<long> = Bool;
account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector<long> = Bool;
account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool;
account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings;
account.resetNotifySettings#db7e1747 = Bool;
account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User;
account.updateStatus#6628562c offline:Bool = Bool;
account.getWallPapers#7967d36 hash:long = account.WallPapers;
account.reportPeer#c5ba3d86 peer:InputPeer reason:ReportReason message:string = Bool;
account.checkUsername#2714d86c username:string = Bool;
account.updateUsername#3e0bdd7c username:string = User;
account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules;
account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector<InputPrivacyRule> = account.PrivacyRules;
account.deleteAccount#a2c0cf74 flags:# reason:string password:flags.0?InputCheckPasswordSRP = Bool;
account.getAccountTTL#8fc711d = AccountDaysTTL;
account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool;
account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode;
account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User;
account.updateDeviceLocked#38df3532 period:int = Bool;
account.getAuthorizations#e320c158 = account.Authorizations;
account.resetAuthorization#df77f3bc hash:long = Bool;
account.getPassword#548a30f5 = account.Password;
account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings;
account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool;
account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode;
account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool;
account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword;
account.getWebAuthorizations#182e6d6f = account.WebAuthorizations;
account.resetWebAuthorization#2d01b9ef hash:long = Bool;
account.resetWebAuthorizations#682d2594 = Bool;
account.getAllSecureValues#b288bc7d = Vector<SecureValue>;
account.getSecureValue#73665bc2 types:Vector<SecureValueType> = Vector<SecureValue>;
account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue;
account.deleteSecureValue#b880bc4b types:Vector<SecureValueType> = Bool;
account.getAuthorizationForm#a929597a bot_id:long scope:string public_key:string = account.AuthorizationForm;
account.acceptAuthorization#f3ed4c73 bot_id:long scope:string public_key:string value_hashes:Vector<SecureValueHash> credentials:SecureCredentialsEncrypted = Bool;
account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode;
account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool;
account.sendVerifyEmailCode#98e037bb purpose:EmailVerifyPurpose email:string = account.SentEmailCode;
account.verifyEmail#32da4cf purpose:EmailVerifyPurpose verification:EmailVerification = account.EmailVerified;
account.initTakeoutSession#8ef3eab0 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?long = account.Takeout;
account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool;
account.confirmPasswordEmail#8fdf1920 code:string = Bool;
account.resendPasswordEmail#7a7f2a15 = Bool;
account.cancelPasswordEmail#c1cbd5b6 = Bool;
account.getContactSignUpNotification#9f07c728 = Bool;
account.setContactSignUpNotification#cff43f61 silent:Bool = Bool;
account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true compare_stories:flags.2?true peer:flags.0?InputNotifyPeer = Updates;
account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper;
account.uploadWallPaper#e39a8f03 flags:# for_chat:flags.0?true file:InputFile mime_type:string settings:WallPaperSettings = WallPaper;
account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool;
account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool;
account.resetWallPapers#bb3b9804 = Bool;
account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings;
account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool;
account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document;
account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector<InputThemeSettings> = Theme;
account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector<InputThemeSettings> = Theme;
account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool;
account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool;
account.getTheme#3a5869ec format:string theme:InputTheme = Theme;
account.getThemes#7206e458 format:string hash:long = account.Themes;
account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool;
account.getContentSettings#8b9b4dae = account.ContentSettings;
account.getMultiWallPapers#65ad71dc wallpapers:Vector<InputWallPaper> = Vector<WallPaper>;
account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings;
account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings;
account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool;
account.resetPassword#9308ce1b = account.ResetPasswordResult;
account.declinePasswordReset#4c9409f6 = Bool;
account.getChatThemes#d638de89 hash:long = account.Themes;
account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool;
account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool;
account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones;
account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone;
account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document;
account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool;
account.getDefaultEmojiStatuses#d6753386 hash:long = account.EmojiStatuses;
account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses;
account.clearRecentEmojiStatuses#18201aae = Bool;
account.reorderUsernames#ef500eab order:Vector<string> = Bool;
account.toggleUsername#58d6b376 username:string active:Bool = Bool;
account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList;
account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList;
account.getAutoSaveSettings#adcbbcda = account.AutoSaveSettings;
account.saveAutoSaveSettings#d69b8361 flags:# users:flags.0?true chats:flags.1?true broadcasts:flags.2?true peer:flags.3?InputPeer settings:AutoSaveSettings = Bool;
account.deleteAutoSaveExceptions#53bc0020 = Bool;
account.invalidateSignInCodes#ca8ae8ba codes:Vector<string> = Bool;
account.updateColor#684d214e flags:# for_profile:flags.1?true color:flags.2?PeerColor = Bool;
account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList;
account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses;
account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList;
account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?BusinessWorkHours = Bool;
account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool;
account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool;
account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool;
account.updateConnectedBot#66a08c7e flags:# deleted:flags.1?true rights:flags.0?BusinessBotRights bot:InputUser recipients:InputBusinessBotRecipients = Updates;
account.getConnectedBots#4ea4c80f = account.ConnectedBots;
account.getBotBusinessConnection#76a86270 connection_id:string = Updates;
account.updateBusinessIntro#a614d034 flags:# intro:flags.0?InputBusinessIntro = Bool;
account.toggleConnectedBotPaused#646e1097 peer:InputPeer paused:Bool = Bool;
account.disablePeerConnectedBot#5e437ed9 peer:InputPeer = Bool;
account.updateBirthday#cc6e0c11 flags:# birthday:flags.0?Birthday = Bool;
account.createBusinessChatLink#8851e68e link:InputBusinessChatLink = BusinessChatLink;
account.editBusinessChatLink#8c3410af slug:string link:InputBusinessChatLink = BusinessChatLink;
account.deleteBusinessChatLink#60073674 slug:string = Bool;
account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks;
account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks;
account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool;
account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool;
account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings;
account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings;
account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses;
account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue;
account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool;
account.setMainProfileTab#5dee78b0 tab:ProfileTab = Bool;
account.saveMusic#b26732a9 flags:# unsave:flags.0?true id:InputDocument after_id:flags.1?InputDocument = Bool;
account.getSavedMusicIds#e09d5faf hash:long = account.SavedMusicIds;
account.getUniqueGiftChatThemes#e42ce9c9 offset:string limit:int hash:long = account.ChatThemes;
account.initPasskeyRegistration#429547e8 = account.PasskeyRegistrationOptions;
account.registerPasskey#55b41fd6 credential:InputPasskeyCredential = Passkey;
account.getPasskeys#ea1f0c52 = account.Passkeys;
account.deletePasskey#f5b5563f id:string = Bool;
account.confirmBotConnection#67ed1f68 bot_id:InputUser = Bool;
account.getWebBrowserSettings#56655768 hash:long = account.WebBrowserSettings;
account.updateWebBrowserSettings#9adf82fe flags:# open_external_browser:flags.0?true display_close_button:flags.1?true = account.WebBrowserSettings;
account.toggleWebBrowserSettingsException#60ed4229 flags:# delete:flags.1?true open_external_browser:flags.0?Bool url:string = Updates;
account.deleteWebBrowserSettingsExceptions#86a0765d = account.WebBrowserSettings;

users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector<SecureValueError> = Bool;
users.getRequirementsToContact#d89a83a3 id:Vector<InputUser> = Vector<RequirementToContact>;
users.getSavedMusic#788d7fe3 id:InputUser offset:int limit:int hash:long = users.SavedMusic;
users.getSavedMusicByID#7573a4e9 id:InputUser documents:Vector<InputDocument> = users.SavedMusic;
users.suggestBirthday#fc533372 id:InputUser birthday:Birthday = Updates;

contacts.getContactIDs#7adc669d hash:long = Vector<int>;
contacts.getStatuses#c4a353ee = Vector<ContactStatus>;
contacts.getContacts#5dd69e12 hash:long = contacts.Contacts;
contacts.importContacts#2c800be5 contacts:Vector<InputContact> = contacts.ImportedContacts;
contacts.deleteContacts#96a0e00 id:Vector<InputUser> = Updates;
contacts.deleteByPhones#1013fd9e phones:Vector<string> = Bool;
contacts.block#2e2e8734 flags:# my_stories_from:flags.0?true id:InputPeer = Bool;
contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bool;
contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked;
contacts.search#5f58d0f flags:# broadcasts:flags.0?true bots:flags.1?true q:string limit:int = contacts.Found;
contacts.resolveUsername#725afbbc flags:# username:string referer:flags.0?string = contacts.ResolvedPeer;
contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true bots_guestchat:flags.17?true offset:int limit:int hash:long = contacts.TopPeers;
contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool;
contacts.resetSaved#879537f1 = Bool;
contacts.getSaved#82f1e39f = Vector<SavedContact>;
contacts.toggleTopPeers#8514bdda enabled:Bool = Bool;
contacts.addContact#d9ba2e54 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string note:flags.1?TextWithEntities = Updates;
contacts.acceptContact#f831a20f id:InputUser = Updates;
contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates;
contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates;
contacts.resolvePhone#8af94344 phone:string = contacts.ResolvedPeer;
contacts.exportContactToken#f8654027 = ExportedContactToken;
contacts.importContactToken#13005788 token:string = User;
contacts.editCloseFriends#ba6705f0 id:Vector<long> = Bool;
contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector<InputPeer> limit:int = Bool;
contacts.getBirthdays#daeda864 = contacts.ContactBirthdays;
contacts.getSponsoredPeers#b6c8c393 q:string = contacts.SponsoredPeers;
contacts.updateContactNote#139f63fb id:InputUser note:TextWithEntities = Bool;

messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs;
messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages;
messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector<Reaction> top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages;
messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory;
messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector<int> = messages.AffectedMessages;
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool;
messages.sendMessage#fef48f62 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost rich_message:flags.23?InputRichMessage = Updates;
messages.sendMedia#330e77f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates;
messages.forwardMessages#13704a7c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates;
messages.reportSpam#cf1592db peer:InputPeer = Bool;
messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings;
messages.report#fc78af9b peer:InputPeer id:Vector<int> option:bytes message:string = ReportResult;
messages.getChats#49e9528f id:Vector<long> = messages.Chats;
messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull;
messages.editChatTitle#73783ffd chat_id:long title:string = Updates;
messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates;
messages.addChatUser#cbc6d107 chat_id:long user_id:InputUser fwd_limit:int = messages.InvitedUsers;
messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates;
messages.createChat#92ceddd4 flags:# users:Vector<InputUser> title:string ttl_period:flags.0?int = messages.InvitedUsers;
messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig;
messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat;
messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat;
messages.discardEncryption#f393aea0 flags:# delete_history:flags.0?true chat_id:int = Bool;
messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool;
messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool;
messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;
messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
messages.receivedQueue#55a5bb66 max_qts:int = Vector<long>;
messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool;
messages.readMessageContents#36a73f77 id:Vector<int> = messages.AffectedMessages;
messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers;
messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers;
messages.getWebPagePreview#570d6f6f flags:# message:string entities:flags.3?Vector<MessageEntity> = messages.WebPagePreview;
messages.exportChatInvite#a455de90 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string subscription_pricing:flags.5?StarsSubscriptionPricing = ExportedChatInvite;
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
messages.importChatInvite#de91436e hash:string = messages.ChatInviteJoinResult;
messages.getStickerSet#c8a0ec74 stickerset:InputStickerSet hash:int = messages.StickerSet;
messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult;
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates;
messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector<int> increment:Bool = messages.MessageViews;
messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool;
messages.migrateChat#a2875319 chat_id:long = Updates;
messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true groups_only:flags.2?true users_only:flags.3?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector<long> = Bool;
messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document;
messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs;
messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool;
messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults;
messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector<InputBotInlineResult> cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool;
messages.sendInlineBotResult#c0cf7646 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut allow_paid_stars:flags.21?long = Updates;
messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
messages.editMessage#b106e66c flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int schedule_repeat_period:flags.18?int quick_reply_shortcut_id:flags.17?int rich_message:flags.23?InputRichMessage = Updates;
messages.editInlineBotMessage#a423bb51 flags:# no_webpage:flags.1?true invert_media:flags.16?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> rich_message:flags.23?InputRichMessage = Bool;
messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer;
messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool;
messages.getPeerDialogs#e470bcfd peers:Vector<InputDialogPeer> = messages.PeerDialogs;
messages.saveDraft#ad0fa15c flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> media:flags.5?InputMedia effect:flags.7?long suggested_post:flags.8?SuggestedPost rich_message:flags.9?InputRichMessage = Bool;
messages.getAllDrafts#6a3f8d65 = Updates;
messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers;
messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool;
messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers;
messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool;
messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool;
messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true emojis:flags.1?true offset_id:long limit:int = messages.ArchivedStickers;
messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers;
messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector<StickerSetCovered>;
messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates;
messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool;
messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores;
messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores;
messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats;
messages.getWebPage#8d9692a3 url:string hash:int = messages.WebPage;
messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool;
messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector<InputDialogPeer> = Bool;
messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs;
messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector<ShippingOption> = Bool;
messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool;
messages.uploadMedia#14967978 flags:# business_connection_id:flags.0?string peer:InputPeer media:InputMedia = MessageMedia;
messages.sendScreenshotNotification#a1405817 peer:InputPeer reply_to:InputReplyTo random_id:long = Updates;
messages.getFavedStickers#4f1aaa9 hash:long = messages.FavedStickers;
messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool;
messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory;
messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages;
messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates;
messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets;
messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
messages.markDialogUnread#8c5006f8 flags:# unread:flags.0?true parent_peer:flags.1?InputPeer peer:InputDialogPeer = Bool;
messages.getDialogUnreadMarks#21202222 flags:# parent_peer:flags.0?InputPeer = Vector<DialogPeer>;
messages.clearAllDrafts#7e58ee9c = Bool;
messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1?true pm_oneside:flags.2?true peer:InputPeer id:int = Updates;
messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector<bytes> = Updates;
messages.getPollResults#eda3e33b peer:InputPeer msg_id:int poll_hash:long = Updates;
messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines;
messages.editChatAbout#def60797 peer:InputPeer about:string = Bool;
messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates;
messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference;
messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference;
messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector<string> = Vector<EmojiLanguage>;
messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL;
messages.getSearchCounters#1bbcf300 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.0?int filters:Vector<MessagesFilter> = Vector<messages.SearchCounter>;
messages.requestUrlAuth#894cc99c flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string in_app_origin:flags.3?string = UrlAuthResult;
messages.acceptUrlAuth#67a3f0de flags:# write_allowed:flags.0?true share_phone_number:flags.3?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string match_code:flags.4?string = UrlAuthResult;
messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool;
messages.getScheduledHistory#f516760b peer:InputPeer hash:long = messages.Messages;
messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector<int> = messages.Messages;
messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector<int> = Updates;
messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector<int> = Updates;
messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList;
messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector<InputStickerSet> = Bool;
messages.getDialogFilters#efd48c89 = messages.DialogFilters;
messages.getSuggestedDialogFilters#a29cd42c = Vector<DialogFilterSuggested>;
messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool;
messages.updateDialogFiltersOrder#c563c1e4 order:Vector<int> = Bool;
messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messages.FeaturedStickers;
messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages;
messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage;
messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool;
messages.unpinAllMessages#62dd747 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory;
messages.deleteChat#5bd0ee50 chat_id:long = Bool;
messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages;
messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed;
messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:int = messages.HistoryImport;
messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia;
messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool;
messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites;
messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite;
messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite;
messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool;
messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool;
messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites;
messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true subscription_expired:flags.3?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters;
messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates;
messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer;
messages.setChatTheme#81202c9 peer:InputPeer theme:InputChatTheme = Updates;
messages.getMessageReadParticipants#31c1c44f peer:InputPeer msg_id:int = Vector<ReadParticipantDate>;
messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar;
messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions;
messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates;
messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates;
messages.toggleNoForwards#b2081a35 flags:# peer:InputPeer enabled:Bool request_msg_id:flags.0?int = Updates;
messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool;
messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector<Reaction> = Updates;
messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector<int> = Updates;
messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList;
messages.setChatAvailableReactions#864b2581 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int paid_enabled:flags.1?Bool = Updates;
messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions;
messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool;
messages.translateText#a5eec345 flags:# peer:flags.0?InputPeer id:flags.0?Vector<int> text:flags.1?Vector<TextWithEntities> to_lang:string tone:flags.2?string = messages.TranslatedText;
messages.getUnreadReactions#bd7f90ac flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.readReactions#9ec44f93 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory;
messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages;
messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots;
messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot;
messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool;
messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult;
messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool;
messages.requestSimpleWebView#413a3e73 flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true compact:flags.7?true fullscreen:flags.8?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = WebViewResult;
messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent;
messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates;
messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio;
messages.rateTranscribedAudio#7f1d072f peer:InputPeer msg_id:int transcription_id:long good:Bool = Bool;
messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector<long> = Vector<Document>;
messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers;
messages.getFeaturedEmojiStickers#ecf6736 hash:long = messages.FeaturedStickers;
messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer = Bool;
messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions;
messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions;
messages.clearRecentReactions#9dfeefb4 = Bool;
messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector<int> = Updates;
messages.setDefaultHistoryTTL#9eb51445 period:int = Bool;
messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL;
messages.sendBotRequestedPeer#6c5cf2a7 flags:# peer:InputPeer msg_id:flags.0?int webapp_req_id:flags.1?string button_id:int requested_peers:Vector<InputPeer> = Updates;
messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups;
messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups;
messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups;
messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList;
messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool;
messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp;
messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult;
messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates;
messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets;
messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs;
messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages;
messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory;
messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs;
messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool;
messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector<InputDialogPeer> = Bool;
messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long = messages.SavedReactionTags;
messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool;
messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions;
messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate;
messages.getQuickReplies#d483f2a8 hash:long = messages.QuickReplies;
messages.reorderQuickReplies#60331907 order:Vector<int> = Bool;
messages.checkQuickReplyShortcut#f1d0fbd3 shortcut:string = Bool;
messages.editQuickReplyShortcut#5c003cef shortcut_id:int shortcut:string = Bool;
messages.deleteQuickReplyShortcut#3cc04740 shortcut_id:int = Bool;
messages.getQuickReplyMessages#94a495c3 flags:# shortcut_id:int id:flags.0?Vector<int> hash:long = messages.Messages;
messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vector<int> random_id:Vector<long> = Updates;
messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector<int> = Updates;
messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool;
messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers;
messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups;
messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects;
messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates;
messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates;
messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector<int> = Vector<FactCheck>;
messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult;
messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates;
messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool;
messages.getPaidReactionPrivacy#472455aa = Updates;
messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool;
messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool;
messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult;
messages.getSponsoredMessages#3d6ce850 flags:# peer:InputPeer msg_id:flags.0?int = messages.SponsoredMessages;
messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector<InlineQueryPeerType> = messages.BotPreparedInlineMessage;
messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage;
messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector<string> offset:int limit:int hash:long = messages.FoundStickers;
messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector<int> = Bool;
messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector<InputPeer> = messages.SavedDialogs;
messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool;
messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector<int> incompleted:Vector<int> = Updates;
messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector<TodoItem> = Updates;
messages.toggleSuggestedPostApproval#8107455c flags:# reject:flags.1?true peer:InputPeer msg_id:int schedule_date:flags.0?int reject_comment:flags.2?string = Updates;
messages.getForumTopics#3ba47bff flags:# peer:InputPeer q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics;
messages.getForumTopicsByID#af0a4a08 peer:InputPeer topics:Vector<int> = messages.ForumTopics;
messages.editForumTopic#cecc1134 flags:# peer:InputPeer topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = Updates;
messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool = Updates;
messages.reorderPinnedForumTopics#e7841f0 flags:# force:flags.0?true peer:InputPeer order:Vector<int> = Updates;
messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates;
messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory;
messages.getEmojiGameInfo#fb7e8ca7 = messages.EmojiGameInfo;
messages.summarizeText#abbbd346 flags:# peer:InputPeer id:int to_lang:flags.0?string tone:flags.2?string = TextWithEntities;
messages.editChatCreator#f743b857 peer:InputPeer user_id:InputUser password:InputCheckPasswordSRP = Updates;
messages.getFutureChatCreatorAfterLeave#3b7d0ea6 peer:InputPeer = User;
messages.editChatParticipantRank#a00f32b0 peer:InputPeer participant:InputPeer rank:string = Updates;
messages.declineUrlAuth#35436bbc url:string = Bool;
messages.checkUrlAuthMatchCode#c9a47b0b url:string match_code:string = Bool;
messages.composeMessageWithAI#daecc589 flags:# proofread:flags.0?true emojify:flags.3?true text:TextWithEntities translate_to_lang:flags.1?string tone:flags.2?InputAiComposeTone = messages.ComposedMessageWithAI;
messages.reportReadMetrics#4067c5e6 peer:InputPeer metrics:Vector<InputMessageReadMetric> = Bool;
messages.reportMusicListen#ddbcd819 id:InputDocument listened_duration:int = Bool;
messages.addPollAnswer#19bc4b6d peer:InputPeer msg_id:int answer:PollAnswer = Updates;
messages.deletePollAnswer#ac8505a5 peer:InputPeer msg_id:int option:bytes = Updates;
messages.getUnreadPollVotes#43286cf2 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
messages.readPollVotes#1720b4d8 flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory;
messages.setBotGuestChatResult#b8f106e3 query_id:long result:InputBotInlineResult = InputBotInlineMessageID;
messages.deleteParticipantReactions#a0b80cf8 peer:InputPeer participant:InputPeer = Bool;
messages.deleteParticipantReaction#e3b7f82c peer:InputPeer msg_id:int participant:InputPeer = Updates;
messages.getPersonalChannelHistory#55fb0996 user_id:InputUser limit:int max_id:int min_id:int hash:long = messages.Messages;
messages.getRichMessage#501569cf peer:InputPeer id:int = messages.Messages;

updates.getState#edd4882a = updates.State;
updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference;
updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;

photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo;
photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo;
photos.deletePhotos#87cf7f2f id:Vector<InputPhoto> = Vector<long>;
photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos;
photos.uploadContactProfilePhoto#e14c4a71 flags:# suggest:flags.3?true save:flags.4?true user_id:InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.5?VideoSize = photos.Photo;

upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File;
upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;
upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile;
upload.getCdnFile#395f69da file_token:bytes offset:long limit:int = upload.CdnFile;
upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector<FileHash>;
upload.getCdnFileHashes#91dc3f31 file_token:bytes offset:long = Vector<FileHash>;
upload.getFileHashes#9156982a location:InputFileLocation offset:long = Vector<FileHash>;

help.getConfig#c4f9186b = Config;
help.getNearestDc#1fb33026 = NearestDc;
help.getAppUpdate#522d5a7d source:string = help.AppUpdate;
help.getInviteText#4d392343 = help.InviteText;
help.getSupport#9cdf08cd = help.Support;
help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
help.getCdnConfig#52029342 = CdnConfig;
help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;
help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate;
help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo;
help.getAppConfig#61e3f854 hash:int = help.AppConfig;
help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
help.getPassportConfig#c661ad08 hash:int = help.PassportConfig;
help.getSupportName#d360e72c = help.SupportName;
help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo;
help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector<MessageEntity> = help.UserInfo;
help.getPromoData#c0977421 = help.PromoData;
help.hidePromoData#1e251c95 peer:InputPeer = Bool;
help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool;
help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList;
help.getPremiumPromo#b81b93d4 = help.PremiumPromo;
help.getPeerColors#da80f42f hash:int = help.PeerColors;
help.getPeerProfileColors#abcfa9fd hash:int = help.PeerColors;
help.getTimezonesList#49b30240 hash:int = help.TimezonesList;

channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
channels.reportSpam#f44a8315 channel:InputChannel participant:InputPeer id:Vector<int> = Bool;
channels.getMessages#ad8c9a23 channel:InputChannel id:Vector<InputMessage> = messages.Messages;
channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants;
channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant;
channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true forum:flags.5?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates;
channels.editAdmin#9a98ad68 flags:# channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:flags.0?string = Updates;
channels.editTitle#566decd0 channel:InputChannel title:string = Updates;
channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;
channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool;
channels.updateUsername#3514b3de channel:InputChannel username:string = Bool;
channels.joinChannel#7f6a1e22 channel:InputChannel = messages.ChatInviteJoinResult;
channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
channels.inviteToChannel#c9e33d54 channel:InputChannel users:Vector<InputUser> = messages.InvitedUsers;
channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink;
channels.toggleSignatures#418d549c flags:# signatures_enabled:flags.0?true profiles_enabled:flags.1?true channel:InputChannel = Updates;
channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true for_personal:flags.2?true = messages.Chats;
channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates;
channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector<InputUser> max_id:long min_id:long limit:int = channels.AdminLogResults;
channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool;
channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector<int> = Bool;
channels.deleteHistory#9baa9647 flags:# for_everyone:flags.0?true channel:InputChannel max_id:int = Updates;
channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates;
channels.getLeftChannels#8341ecc0 offset:int = messages.Chats;
channels.getGroupsForDiscussion#f5dad378 = messages.Chats;
channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool;
channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool;
channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates;
channels.getInactiveChannels#11e831ee = messages.InactiveChats;
channels.convertToGigagroup#b290c69 channel:InputChannel = Updates;
channels.getSendAs#e785a43f flags:# for_paid_reactions:flags.0?true for_live_stories:flags.1?true peer:InputPeer = channels.SendAsPeers;
channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory;
channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates;
channels.toggleJoinRequest#ecc2618 flags:# apply_to_invites:flags.1?true channel:InputChannel enabled:Bool guard_bot:flags.0?InputUser = Updates;
channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector<string> = Bool;
channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool;
channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool;
channels.toggleForum#3ff75734 channel:InputChannel enabled:Bool tabs:Bool = Updates;
channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates;
channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool;
channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates;
channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates;
channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates;
channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats;
channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates;
channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates;
channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool;
channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates;
channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages;
channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates;
channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates;
channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User;
channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood;
channels.setMainProfileTab#3583fcb1 channel:InputChannel tab:ProfileTab = Bool;

bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector<BotCommand> = Bool;
bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool;
bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector<BotCommand>;
bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool;
bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton;
bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool;
bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool;
bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool;
bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo;
bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector<string> = Bool;
bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool;
bots.canSendMessage#1359f4e6 bot:InputUser = Bool;
bots.allowSendMessage#f132e3ef bot:InputUser = Updates;
bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON;
bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots;
bots.addPreviewMedia#17aeb75a bot:InputUser lang_code:string media:InputMedia = BotPreviewMedia;
bots.editPreviewMedia#8525606f bot:InputUser lang_code:string media:InputMedia new_media:InputMedia = BotPreviewMedia;
bots.deletePreviewMedia#2d0135b3 bot:InputUser lang_code:string media:Vector<InputMedia> = Bool;
bots.reorderPreviewMedias#b627f3aa bot:InputUser lang_code:string order:Vector<InputMedia> = Bool;
bots.getPreviewInfo#423ab3ad bot:InputUser lang_code:string = bots.PreviewInfo;
bots.getPreviewMedias#a2a5594d bot:InputUser = Vector<BotPreviewMedia>;
bots.updateUserEmojiStatus#ed9f30c5 user_id:InputUser emoji_status:EmojiStatus = Bool;
bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool;
bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool;
bots.getAdminedBots#b0711d83 = Vector<User>;
bots.updateStarRefProgram#778b5ab3 flags:# bot:InputUser commission_permille:int duration_months:flags.0?int = StarRefProgram;
bots.setCustomVerification#8b89dfbd flags:# enabled:flags.1?true bot:flags.0?InputUser peer:InputPeer custom_description:flags.2?string = Bool;
bots.getBotRecommendations#a1b70815 bot:InputUser = users.Users;
bots.checkUsername#87f2219b username:string = Bool;
bots.createBot#e5b17f2b flags:# via_deeplink:flags.0?true name:string username:string manager_id:InputUser = User;
bots.exportBotToken#bd0d99eb bot:InputUser revoke:Bool = bots.ExportedBotToken;
bots.requestWebViewButton#31a2a35e user_id:InputUser button:KeyboardButton = bots.RequestedButton;
bots.getRequestedWebViewButton#bf25b7f3 bot:InputUser webapp_req_id:string = KeyboardButton;
bots.getAccessSettings#213853a3 bot:InputUser = bots.AccessSettings;
bots.editAccessSettings#31813cd8 flags:# restricted:flags.0?true bot:InputUser add_users:flags.1?Vector<InputUser> = Bool;
bots.setJoinChatResults#e71a4810 query_id:long result:JoinChatBotResult = Bool;

payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm;
payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt;
payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo;
payments.sendPaymentForm#2d03522f flags:# form_id:long invoice:InputInvoice requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult;
payments.getSavedInfo#227d824b = payments.SavedInfo;
payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool;
payments.getBankCardData#2e79d779 number:string = payments.BankCardData;
payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice;
payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates;
payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates;
payments.getPremiumGiftCodeOptions#2757ba54 flags:# boost_peer:flags.0?InputPeer = Vector<PremiumGiftCodeOption>;
payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode;
payments.applyGiftCode#f6e26854 slug:string = Updates;
payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo;
payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates;
payments.getStarsTopupOptions#c00ec7d3 = Vector<StarsTopupOption>;
payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus;
payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus;
payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult;
payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates;
payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true ton:flags.1?true peer:InputPeer = payments.StarsRevenueStats;
payments.getStarsRevenueWithdrawalUrl#2433dc92 flags:# ton:flags.0?true peer:InputPeer amount:flags.1?long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl;
payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl;
payments.getStarsTransactionsByID#2dca16b8 flags:# ton:flags.0?true peer:InputPeer id:Vector<InputStarsTransaction> = payments.StarsStatus;
payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector<StarsGiftOption>;
payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus;
payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool;
payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool;
payments.getStarsGiveawayOptions#bd1efd3e = Vector<StarsGiveawayOption>;
payments.getStarGifts#c4563590 hash:int = payments.StarGifts;
payments.saveStarGift#2a2a697c flags:# unsave:flags.0?true stargift:InputSavedStarGift = Bool;
payments.convertStarGift#74bf076b stargift:InputSavedStarGift = Bool;
payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool;
payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots;
payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots;
payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true order_by_date:flags.1?true peer:InputPeer offset:string limit:int = payments.SuggestedStarRefBots;
payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots;
payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots;
payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgradePreview;
payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates;
payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates;
payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift;
payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_unique:flags.4?true sort_by_value:flags.5?true exclude_upgradable:flags.7?true exclude_unupgradable:flags.8?true peer_color_available:flags.9?true exclude_hosted:flags.10?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts;
payments.getSavedStarGift#b455a106 stargift:Vector<InputSavedStarGift> = payments.SavedStarGifts;
payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl;
payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool;
payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector<InputSavedStarGift> = Bool;
payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool;
payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true for_craft:flags.4?true stars_only:flags.5?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector<StarGiftAttributeId> offset:string limit:int = payments.ResaleStarGifts;
payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates;
payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector<InputSavedStarGift> = StarGiftCollection;
payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector<InputSavedStarGift> add_stargift:flags.2?Vector<InputSavedStarGift> order:flags.3?Vector<InputSavedStarGift> = StarGiftCollection;
payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector<int> = Bool;
payments.deleteStarGiftCollection#ad5648e8 peer:InputPeer collection_id:int = Bool;
payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections;
payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo;
payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult;
payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState;
payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts;
payments.getStarGiftActiveAuctions#a5d0514d hash:long = payments.StarGiftActiveAuctions;
payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates;
payments.sendStarGiftOffer#8fb86b41 flags:# peer:InputPeer slug:string price:StarsAmount duration:int random_id:long allow_paid_stars:flags.0?long = Updates;
payments.getStarGiftUpgradeAttributes#6d038b58 gift_id:long = payments.StarGiftUpgradeAttributes;
payments.getCraftStarGifts#fd05dd00 gift_id:long offset:string limit:int = payments.SavedStarGifts;
payments.craftStarGift#b0f9684f stargift:Vector<InputSavedStarGift> = Updates;

stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> software:flags.3?string = messages.StickerSet;
stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet;
stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet;
stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet;
stickers.setStickerSetThumb#a76a5392 flags:# stickerset:InputStickerSet thumb:flags.0?InputDocument thumb_document_id:flags.1?long = messages.StickerSet;
stickers.checkShortName#284b3639 short_name:string = Bool;
stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName;
stickers.changeSticker#f5537ebc flags:# sticker:InputDocument emoji:flags.0?string mask_coords:flags.1?MaskCoords keywords:flags.2?string = messages.StickerSet;
stickers.renameStickerSet#124b1c00 stickerset:InputStickerSet title:string = messages.StickerSet;
stickers.deleteStickerSet#87704394 stickerset:InputStickerSet = Bool;
stickers.replaceSticker#4696459a sticker:InputDocument new_sticker:InputStickerSetItem = messages.StickerSet;

phone.getCallConfig#55451fa9 = DataJSON;
phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall;
phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool;
phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates;
phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates;
phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool;
phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool;
phone.createGroupCall#48cdc6d8 flags:# rtmp_stream:flags.2?true peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates;
phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates;
phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates;
phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector<InputUser> = Updates;
phone.discardGroupCall#7a777135 call:InputGroupCall = Updates;
phone.toggleGroupCallSettings#974392f2 flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool messages_enabled:flags.2?Bool send_paid_messages_stars:flags.3?long = Updates;
phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall;
phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector<InputPeer> sources:Vector<int> offset:string limit:int = phone.GroupParticipants;
phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector<int> = Vector<int>;
phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates;
phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates;
phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates;
phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers;
phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite;
phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates;
phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates;
phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool;
phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates;
phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates;
phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels;
phone.getGroupCallStreamRtmpUrl#5af4c73a flags:# live_story:flags.0?true peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl;
phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool;
phone.createConferenceCall#7d0444bb flags:# muted:flags.0?true video_stopped:flags.2?true join:flags.3?true random_id:int public_key:flags.3?int256 block:flags.3?bytes params:flags.3?DataJSON = Updates;
phone.deleteConferenceCallParticipants#8ca60525 flags:# only_left:flags.0?true kick:flags.1?true call:InputGroupCall ids:Vector<long> block:bytes = Updates;
phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates;
phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates;
phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates;
phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates;
phone.sendGroupCallMessage#b1d11410 flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long send_as:flags.1?InputPeer = Updates;
phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool;
phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector<int> = Updates;
phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates;
phone.getGroupCallStars#6f636302 call:InputGroupCall = phone.GroupCallStars;
phone.saveDefaultSendAs#4167add1 call:InputGroupCall send_as:InputPeer = Bool;

langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference;
langpack.getLanguages#42c6978f lang_pack:string = Vector<LangPackLanguage>;
langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage;

folders.editPeerFolders#6847d0ab folder_peers:Vector<InputFolderPeer> = Updates;

stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats;
stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats;
stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards;
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats;
stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards;
stats.getPollStats#c27dfa68 flags:# dark:flags.0?true peer:InputPeer msg_id:int = stats.PollStats;

chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector<InputPeer> = chatlists.ExportedChatlistInvite;
chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool;
chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector<InputPeer> = ExportedChatlistInvite;
chatlists.getExportedInvites#ce03da83 chatlist:InputChatlist = chatlists.ExportedInvites;
chatlists.checkChatlistInvite#41c10fff slug:string = chatlists.ChatlistInvite;
chatlists.joinChatlistInvite#a6b1e39a slug:string peers:Vector<InputPeer> = Updates;
chatlists.getChatlistUpdates#89419521 chatlist:InputChatlist = chatlists.ChatlistUpdates;
chatlists.joinChatlistUpdates#e089f8f5 chatlist:InputChatlist peers:Vector<InputPeer> = Updates;
chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool;
chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector<Peer>;
chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector<InputPeer> = Updates;

stories.canSendStory#30eb63f0 peer:InputPeer = stories.CanSendStoryCount;
stories.sendStory#8f9e6898 flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector<MediaArea> caption:flags.0?string entities:flags.1?Vector<MessageEntity> privacy_rules:Vector<InputPrivacyRule> random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int albums:flags.8?Vector<int> music:flags.9?InputDocument = Updates;
stories.editStory#2c63a72b flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector<MediaArea> caption:flags.1?string entities:flags.1?Vector<MessageEntity> privacy_rules:flags.2?Vector<InputPrivacyRule> music:flags.4?InputDocument = Updates;
stories.deleteStories#ae59db5f peer:InputPeer id:Vector<int> = Vector<int>;
stories.togglePinned#9a75a1ef peer:InputPeer id:Vector<int> pinned:Bool = Vector<int>;
stories.getAllStories#eeb0d625 flags:# next:flags.1?true hidden:flags.2?true state:flags.0?string = stories.AllStories;
stories.getPinnedStories#5821a5dc peer:InputPeer offset_id:int limit:int = stories.Stories;
stories.getStoriesArchive#b4352016 peer:InputPeer offset_id:int limit:int = stories.Stories;
stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector<int> = stories.Stories;
stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool;
stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector<int>;
stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector<int> = Bool;
stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList;
stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector<int> = stories.StoryViews;
stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink;
stories.report#19d8eb45 peer:InputPeer id:Vector<int> option:bytes message:string = ReportResult;
stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates;
stories.sendReaction#7fd736b2 flags:# add_to_recent:flags.0?true peer:InputPeer story_id:int reaction:Reaction = Updates;
stories.getPeerStories#2c4ada50 peer:InputPeer = stories.PeerStories;
stories.getAllReadPeerStories#9b5ae7f9 = Updates;
stories.getPeerMaxIDs#78499170 id:Vector<InputPeer> = Vector<RecentStory>;
stories.getChatsToSend#a56a8b60 = messages.Chats;
stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool;
stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList;
stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector<int> = Bool;
stories.searchPosts#d1810907 flags:# hashtag:flags.0?string area:flags.1?MediaArea peer:flags.2?InputPeer offset:string limit:int = stories.FoundStories;
stories.createAlbum#a36396e5 peer:InputPeer title:string stories:Vector<int> = StoryAlbum;
stories.updateAlbum#5e5259b6 flags:# peer:InputPeer album_id:int title:flags.0?string delete_stories:flags.1?Vector<int> add_stories:flags.2?Vector<int> order:flags.3?Vector<int> = StoryAlbum;
stories.reorderAlbums#8535fbd9 peer:InputPeer order:Vector<int> = Bool;
stories.deleteAlbum#8d3456d0 peer:InputPeer album_id:int = Bool;
stories.getAlbums#25b3eac7 peer:InputPeer hash:long = stories.Albums;
stories.getAlbumStories#ac806d61 peer:InputPeer album_id:int offset:int limit:int = stories.Stories;
stories.startLive#d069ccde flags:# pinned:flags.2?true noforwards:flags.4?true rtmp_stream:flags.5?true peer:InputPeer caption:flags.0?string entities:flags.1?Vector<MessageEntity> privacy_rules:Vector<InputPrivacyRule> random_id:long messages_enabled:flags.6?Bool send_paid_messages_stars:flags.7?long = Updates;

premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList;
premium.getMyBoosts#be77b4a = premium.MyBoosts;
premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector<int> peer:InputPeer = premium.MyBoosts;
premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus;
premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList;

smsjobs.isEligibleToJoin#edc39d0 = smsjobs.EligibilityToJoin;
smsjobs.join#a74ece2d = Bool;
smsjobs.leave#9898ad73 = Bool;
smsjobs.updateSettings#93fa0bf flags:# allow_international:flags.0?true = Bool;
smsjobs.getStatus#10a698e8 = smsjobs.Status;
smsjobs.getSmsJob#778d902f job_id:string = SmsJob;
smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool;

fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;

aicompose.createTone#4aa83913 flags:# display_author:flags.0?true emoji_id:long title:string prompt:string = AiComposeTone;
aicompose.updateTone#903bcf59 flags:# tone:InputAiComposeTone display_author:flags.0?Bool emoji_id:flags.1?long title:flags.2?string prompt:flags.3?string = AiComposeTone;
aicompose.saveTone#1782cbb1 tone:InputAiComposeTone unsave:Bool = Bool;
aicompose.deleteTone#dd39316a tone:InputAiComposeTone = Bool;
aicompose.getTone#b2e8ba03 tone:InputAiComposeTone = aicompose.Tones;
aicompose.getTones#abd59201 hash:long = aicompose.Tones;
aicompose.getToneExample#d1b4ab14 tone:InputAiComposeTone num:int = AiComposeToneExample;

// LAYER 227
<?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl;

use function Tak\Asyncio\File\openFile;

class Builder {
	private int $indents;
	private int $indentSize;
	private object $outStream;
	private string $text;

	public function __construct(string $filename,int $indentSize = 1){
		$this->indents = 0;
		$this->indentSize = $indentSize;
		$this->outStream = openFile($filename,'wb');
		$this->text = (string) null;
	}
	public function indent() : string {
		return str_repeat(chr(9),$this->indents * $this->indentSize);
	}
	public function addIndent(int $count = 1) : void {
		$this->indents = max($this->indents + $count,0);
	}
	public function deleteIndent(int $count = 1) : void {
		$this->indents = max($this->indents - $count,0);
	}
	public function write(string $string) : void {
		$this->text .= $string;
	}
	public function writeNewLine(? string $string = null) : void {
		$this->write(is_null($string) ? chr(10) : chr(10).$this->indent().$string);
	}
	public function writeDocComment(mixed ...$doc) : void {
		$this->writeNewLine('/**');
		foreach($doc as $name => $value):
			$this->writeNewLine(' * @'.$name.chr(32).(is_array($value) ? implode(chr(32),$value) : strval($value)));
		endforeach;
		$this->writeNewLine(' */');
	}
	public function close() : void {
		if(empty($this->text) === false):
			$this->outStream->write($this->text);
		endif;
		$this->text = (string) null;
		$this->outStream->close();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl;

use Tak\Liveproto\Utils\Tools;

use Tak\Liveproto\Parser\Tl;

use function Tak\Asyncio\File\read;

use function Tak\Asyncio\File\isFile;

use function Tak\Asyncio\File\deleteDirectory;

use function Tak\Asyncio\File\isDirectory;

use function Tak\Asyncio\File\createDirectory;

defined('TLPATH') || define('TLPATH',getenv('TLPATH') ?: ($_ENV['TLPATH'] ?? __DIR__));

define('Tak\Liveproto\Tl\PHP_TAG_START',base64_decode('PD9waHA'));

define('Tak\Liveproto\Tl\PHP_TAG_END',base64_decode('Pz4'));

abstract class Generator {
	static private function cleanFiles(string $folder) : void {
		if(isDirectory($folder)) deleteDirectory($folder);
		createDirectory($folder);
	}
	static private function create(array | string ...$tls) : void {
		self::cleanFiles(TLPATH.DIRECTORY_SEPARATOR.'Types');
		self::cleanFiles(TLPATH.DIRECTORY_SEPARATOR.'Functions');
		$filename = TLPATH.DIRECTORY_SEPARATOR.'All.php';
		$all = new Builder($filename);
		$all->write(PHP_TAG_START);
		$all->writeNewLine();
		$all->writeNewLine('declare(strict_types = 1);');
		$all->writeNewLine();
		$all->writeNewLine('namespace Tak\\Liveproto\\Tl;');
		$all->writeNewLine();
		$all->writeNewLine('final class All {');
		$all->addIndent();
		$all->writeNewLine('static public function getConstructor(int $constructorId) : object {');
		$all->addIndent();
		$all->writeNewLine('return match(intval($constructorId)){');
		$all->addIndent();
		$json = ['constructors'=>array(),'methods'=>array()];
		foreach($tls as $tl):
			$schema = is_string($tl) ? json_decode(read($tl),true) : $tl;
			$json = array_merge_recursive($json,$schema);
		endforeach;
		$result = array_reduce($json['methods'],function($carry,$item) : array {
			if(str_contains($item['method'],'.')):
				$split = explode('.',$item['method']);
				$item['space'] = ucfirst($split[false]);
				$item['name'] = ucfirst($split[true]);
			else:
				$item['space'] = 'Other';
				$item['name'] = ucfirst($item['method']);
			endif;
			$item['name'] = Tools::snakeTocamel($item['name']);
			$carry[$item['space']] []= $item;
			return $carry;
		},array());
		foreach($result as $space => $methods):
			$folder = TLPATH.DIRECTORY_SEPARATOR.('Functions').DIRECTORY_SEPARATOR.$space;
			createDirectory($folder);
			foreach($methods as $method):
				$id = '0x'.($method['id'] < 0 ? substr(dechex(intval($method['id'])),8) : dechex(intval($method['id'])));
				$function = $method['name'];
				$params = $method['params'];
				$return = $method['type'];
				$params = array_reduce($params,function($carry,$item) : array {
					$item['type'] = Tl::parseType($item['type']);
					$carry []= $item;
					return $carry;
				},array());
				$args = array_filter($params,fn($arg) => ($arg['type']['flag_indicator'] === false));
				usort($args,fn($a,$b) => $a['type']['is_flag'] <=> $b['type']['is_flag']);
				$param = array_map(fn($arg) => ($arg['type']['is_vector'] ? 'Vector<'.$arg['type']['type'].'>' : $arg['type']['type']).chr(32).$arg['name'],$args);
				$args = implode(',',array_map(fn($arg) => ($arg['type']['is_flag'] ? 'null | ' : null).self::findType($arg['type']).chr(32).chr(36).$arg['name'].($arg['type']['is_flag'] ? ' = null' : null),$args));
				$filename = $folder.DIRECTORY_SEPARATOR.$function.'.php';
				$stream = new Builder($filename);
				$stream->write(PHP_TAG_START);
				$stream->writeNewLine();
				$stream->writeNewLine('declare(strict_types = 1);');
				$stream->writeNewLine();
				$stream->writeNewLine('namespace Tak\\Liveproto\\Tl\\Functions\\'.$space.';');
				$stream->writeNewLine();
				$stream->writeNewLine('use Tak\\Liveproto\\Utils\\Binary;');
				$stream->writeNewLine();
				$stream->writeNewLine('use Tak\\Liveproto\\Utils\\Instance;');
				$stream->writeNewLine();
				$stream->writeDocComment(param : $param,return : $return);
				$stream->writeNewLine();
				$stream->writeNewLine('final class '.($function).' extends Instance {');
				$stream->addIndent();
				$stream->writeNewLine('public function request('.$args.') : Binary {');
				$stream->addIndent();
				$stream->writeNewLine('$writer = new Binary(true);');
				$stream->writeNewLine('$writer->writeInt('.$id.');');
				foreach($params as $param):
					$name = $param['name'];
					$type = $param['type'];
					self::writeRequest($stream,$params,$name,$type);
				endforeach;
				$stream->writeNewLine('return $writer;');
				$stream->deleteIndent();
				$stream->writeNewLine('}');
				$stream->writeNewLine('public function response(Binary $reader) : object {');
				$stream->addIndent();
				$stream->writeNewLine('$result = array();');
				$stream->writeNewLine('$result[\'result\'] = $reader->readObject();');
				$stream->writeNewLine('return new self($result);');
				$stream->deleteIndent();
				$stream->writeNewLine('}');
				$stream->deleteIndent();
				$stream->writeNewLine('}');
				$stream->writeNewLine();
				$stream->writeNewLine(PHP_TAG_END);
				$stream->close();
				$all->writeNewLine($id.' => new \\Tak\\Liveproto\\Tl\\Functions\\'.$space.'\\'.$function.chr(44));
			endforeach;
		endforeach;
		$result = array_reduce($json['constructors'],function($carry,$item) : array {
			if(str_contains($item['predicate'],'.')):
				$split = explode('.',$item['predicate']);
				$item['space'] = ucfirst($split[false]);
				$item['name'] = ucfirst($split[true]);
			else:
				$item['space'] = 'Other';
				$item['name'] = ucfirst($item['predicate']);
			endif;
			if(in_array($item['name'],['True','Vector','Error','Null'])):
				$item['name'] .= 'Object';
			endif;
			$item['name'] = Tools::snakeTocamel($item['name']);
			$carry[$item['space']] []= $item;
			return $carry;
		},array());
		foreach($result as $space => $constructors):
			$folder = TLPATH.DIRECTORY_SEPARATOR.('Types').DIRECTORY_SEPARATOR.$space;
			createDirectory($folder);
			foreach($constructors as $constructor):
				$id = '0x'.($constructor['id'] < 0 ? substr(dechex(intval($constructor['id'])),8) : dechex(intval($constructor['id'])));
				$predicate = $constructor['name'];
				$params = $constructor['params'];
				$return = $constructor['type'];
				$params = array_reduce($params,function($carry,$item) : array {
					$item['type'] = Tl::parseType($item['type']);
					$carry []= $item;
					return $carry;
				},array());
				$args = array_filter($params,fn($arg) => ($arg['type']['flag_indicator'] === false));
				usort($args,fn($a,$b) => $a['type']['is_flag'] <=> $b['type']['is_flag']);
				$param = array_map(fn($arg) => ($arg['type']['is_vector'] ? 'Vector<'.$arg['type']['type'].'>' : $arg['type']['type']).chr(32).$arg['name'],$args);
				$args = implode(',',array_map(fn($arg) => ($arg['type']['is_flag'] ? 'null | ' : null).self::findType($arg['type']).chr(32).chr(36).$arg['name'].($arg['type']['is_flag'] ? ' = null' : null),$args));
				$filename = $folder.DIRECTORY_SEPARATOR.$predicate.'.php';
				$stream = new Builder($filename);
				$stream->write(PHP_TAG_START);
				$stream->writeNewLine();
				$stream->writeNewLine('declare(strict_types = 1);');
				$stream->writeNewLine();
				$stream->writeNewLine('namespace Tak\\Liveproto\\Tl\\Types\\'.$space.';');
				$stream->writeNewLine();
				$stream->writeNewLine('use Tak\\Liveproto\\Utils\\Binary;');
				$stream->writeNewLine();
				$stream->writeNewLine('use Tak\\Liveproto\\Utils\\Instance;');
				$stream->writeNewLine();
				$stream->writeDocComment(param : $param,return : $return);
				$stream->writeNewLine();
				$stream->writeNewLine('final class '.($predicate).' extends Instance {');
				$stream->addIndent();
				$stream->writeNewLine('public function request('.$args.') : Binary {');
				$stream->addIndent();
				$stream->writeNewLine('$writer = new Binary(true);');
				$stream->writeNewLine('$writer->writeInt('.$id.');');
				foreach($params as $param):
					$name = $param['name'];
					$type = $param['type'];
					self::writeRequest($stream,$params,$name,$type);
				endforeach;
				$stream->writeNewLine('return $writer;');
				$stream->deleteIndent();
				$stream->writeNewLine('}');
				$stream->writeNewLine('public function response(Binary $reader) : object {');
				$stream->addIndent();
				$stream->writeNewLine('$result = array();');
				foreach($params as $param):
					$name = $param['name'];
					$type = $param['type'];
					self::writeResponse($stream,$params,$name,$type);
				endforeach;
				$stream->writeNewLine('return new self($result);');
				$stream->deleteIndent();
				$stream->writeNewLine('}');
				$stream->deleteIndent();
				$stream->writeNewLine('}');
				$stream->writeNewLine();
				$stream->writeNewLine(PHP_TAG_END);
				$stream->close();
				$all->writeNewLine($id.' => new \\Tak\\Liveproto\\Tl\\Types\\'.$space.'\\'.$predicate.chr(44));
			endforeach;
		endforeach;
		$all->writeNewLine('default => throw new \Exception(\'Constructor \'.dechex($constructorId).\' not found ( layer : '.DocBuilder::layer().' ) !\')');
		$all->deleteIndent();
		$all->writeNewLine('};');
		$all->deleteIndent();
		$all->writeNewLine('}');
		$all->deleteIndent();
		$all->writeNewLine('}');
		$all->writeNewLine();
		$all->writeNewLine(PHP_TAG_END);
		$all->close();
	}
	static private function writeRequest(Builder $stream,array $params,string $name,array $type) : void {
		if($type['is_flag'] and $type['type'] != 'true'):
			$stream->writeNewLine('if(is_null('.chr(36).$name.') === false):');
			$stream->addIndent();
		endif;
		if($type['flag_indicator']):
			$stream->writeNewLine(chr(36).$name.' = 0;');
			foreach($params as $flags):
				$flagname = $flags['name'];
				$flagtype = $flags['type'];
				if($flagtype['is_flag']):
					if(str_ends_with(strlen($name) === 0x5 ? $name.chr(49) : $name,strval($flagtype['flag_number']))):
						if($flagtype['type'] != 'true'):
							$stream->writeNewLine(chr(36).$name.' |= is_null('.chr(36).$flagname.') ? 0 : (1 << '.$flagtype['flag_index'].');');
						else:
							$stream->writeNewLine(chr(36).$name.' |= '.chr(36).$flagname.' ? (1 << '.$flagtype['flag_index'].') : 0;');
						endif;
					endif;
				endif;
			endforeach;
			$stream->writeNewLine('$writer->writeInt('.chr(36).$name.');');
		elseif($type['is_vector']):
			$stream->writeNewLine('$writer->writeVector('.chr(36).$name.','.chr(39).$type['type'].chr(39).');');
		elseif($type['type'] == 'int'):
			$stream->writeNewLine('$writer->writeInt('.chr(36).$name.');');
		elseif($type['type'] == 'int128'):
			$stream->writeNewLine('$writer->writeLargeInt('.chr(36).$name.',128);');
		elseif($type['type'] == 'int256'):
			$stream->writeNewLine('$writer->writeLargeInt('.chr(36).$name.',256);');
		elseif($type['type'] == 'int512'):
			$stream->writeNewLine('$writer->writeLargeInt('.chr(36).$name.',512);');
		elseif($type['type'] == 'long'):
			$stream->writeNewLine('$writer->writeLong('.chr(36).$name.');');
		elseif($type['type'] == 'double'):
			$stream->writeNewLine('$writer->writeDouble('.chr(36).$name.');');
		elseif($type['type'] == 'string'):
			$stream->writeNewLine('$writer->writeBytes('.chr(36).$name.');');
		elseif($type['type'] == 'bytes'):
			$stream->writeNewLine('$writer->writeBytes('.chr(36).$name.');');
		elseif($type['type'] == 'true'):
			# It's just a type of flag ! We don't need to write a single byte to it #
		elseif($type['type'] == 'bool'):
			$stream->writeNewLine('$writer->writeBool('.chr(36).$name.');');
		else:
			$stream->writeNewLine('$writer->writeObject('.chr(36).$name.');');
		endif;
		if($type['is_flag'] and $type['type'] != 'true'):
			$stream->deleteIndent();
			$stream->writeNewLine('endif;');
		endif;
	}
	static private function writeResponse(Builder $stream,array $params,string $name,array $type) : void {
		if($type['is_flag'] and $type['type'] != 'true'):
			$stream->writeNewLine('if($flags'.($type['flag_number'] === 1 ? null : $type['flag_number']).' & (1 << '.$type['flag_index'].')):');
			$stream->addIndent();
		endif;
		if($type['flag_indicator']):
			$stream->writeNewLine(chr(36).$name.' = $reader->readInt();');
		elseif($type['is_vector']):
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = $reader->readVector('.chr(39).$type['type'].chr(39).');');
		elseif($type['type'] == 'int'):
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = $reader->readInt();');
		elseif($type['type'] == 'int128'):
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = $reader->readLargeInt(128);');
		elseif($type['type'] == 'int256'):
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = $reader->readLargeInt(256);');
		elseif($type['type'] == 'int512'):
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = $reader->readLargeInt(512);');
		elseif($type['type'] == 'long'):
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = $reader->readLong();');
		elseif($type['type'] == 'double'):
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = $reader->readDouble();');
		elseif($type['type'] == 'string'):
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = $reader->readBytes();');
		elseif($type['type'] == 'bytes'):
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = $reader->readBytes();');
		elseif($type['type'] == 'true'):
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = boolval($flags'.($type['flag_number'] === 1 ? null : $type['flag_number']).' & (1 << '.$type['flag_index'].'));');
		elseif($type['type'] == 'bool'):
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = $reader->readBool();');
		else:
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = $reader->readObject();');
		endif;
		if($type['is_flag'] and $type['type'] != 'true'):
			$stream->deleteIndent();
			$stream->writeNewLine('else:');
			$stream->addIndent();
			$stream->writeNewLine('$result['.chr(39).$name.chr(39).'] = null;');
			$stream->deleteIndent();
			$stream->writeNewLine('endif;');
		endif;
	}
	static private function findType(array $type) : string {
		return $type['is_vector'] ? 'array' : match($type['type']){
			'int' => 'int',
			'int128' => 'int | string',
			'int256' => 'int | string',
			'int512' => 'int | string',
			'long' => 'int',
			'double' => 'float',
			'string' => 'string',
			'bytes' => 'string',
			'true' => 'bool',
			'bool' => 'bool',
			default => 'object'
		};
	}
	static public function start(mixed ...$tls) : void {
		$tls = array_filter($tls,fn(mixed $tl) : bool => is_string($tl) and isFile($tl));
		if(empty($tls)):
			$tls = array(__DIR__.DIRECTORY_SEPARATOR.'api.tl',__DIR__.DIRECTORY_SEPARATOR.'mtproto.tl',__DIR__.DIRECTORY_SEPARATOR.'secret.tl');
		endif;
		foreach($tls as $index => $tl):
			$type = mime_content_type($tl);
			if($type !== 'application/json'):
				$tls[$index] = Tl::parseFile($tl);
			endif;
		endforeach;
		self::create(...$tls);
		gc_collect_cycles();
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto\Tl;

use Tak\Liveproto\Utils\Tools;

use Tak\Liveproto\Utils\Helper;

use Tak\Liveproto\Parser\Tl;

use function Tak\Asyncio\File\read;

use function Tak\Asyncio\File\deleteDirectory;

use function Tak\Asyncio\File\isDirectory;

use function Tak\Asyncio\File\createDirectory;

defined('DOCPATH') || define('DOCPATH',getenv('DOCPATH') ?: ($_ENV['DOCPATH'] ?? __DIR__));

abstract class DocBuilder {
	static private function cleanFiles(string $folder) : void {
		if(isDirectory($folder)) deleteDirectory($folder);
		createDirectory($folder);
	}
	static public function mdSafe(string $string) : string {
		return htmlentities(preg_replace('/([\\\\`*_{}\[\]\(\)#\+\-\.!\|])/','\\\\$1',$string));
	}
	static public function layer(bool $secret = false) : int {
		$layer = read(__DIR__.DIRECTORY_SEPARATOR.($secret ? 'secret.tl' : 'api.tl'));
		if(preg_match('~\/\/\sLAYER\s(?<layer>\d+)~i',$layer,$match)):
			return intval($match['layer']);
		else:
			throw new \Exception('The desired layer was not found !');
		endif;
	}
	static private function extractPageInfoFromUrl(string $url) : array {
		$html = @file_get_contents($url);
		$results = ['description'=>strval(null),'params'=>array(),'errors'=>array(),'constructors'=>array(),'return'=>strval(null)];
		if(is_string($html)):
			$doc = new \DOMDocument();
			libxml_use_internal_errors(true);
			$doc->loadHTML($html);
			libxml_clear_errors();
			$xpath = new \DOMXPath($doc);
			$results['description'] = trim(strval($xpath->evaluate('string(//div[@id="dev_page_content"]/p[1])')));
			foreach($xpath->query('//h3[normalize-space(text())="Parameters"]/following-sibling::table[1]//tr') as $tr):
				$cells = $tr->getElementsByTagName('td');
				if($cells->length === 3):
					$results['params'][trim($cells->item(0)->textContent)] = [
						'type'=>trim($cells->item(1)->textContent),
						'description'=>trim($cells->item(2)->textContent)
					];
				endif;
			endforeach;
			foreach($xpath->query('//h3[normalize-space(text())="Possible errors"]/following-sibling::table[1]//tr') as $tr):
				$cells = $tr->getElementsByTagName('td');
				if($cells->length === 3):
					$results['errors'][trim($cells->item(1)->textContent)] = [
						'code'=>trim($cells->item(0)->textContent),
						'description'=>trim($cells->item(2)->textContent)
					];
				endif;
			endforeach;
			foreach($xpath->query('//h3[normalize-space(text())="Constructors"]/following-sibling::table[1]//tr') as $tr):
				$cells = $tr->getElementsByTagName('td');
				if($cells->length === 2):
					$results['constructors'][trim($cells->item(0)->textContent)] = [
						'description'=>trim($cells->item(1)->textContent)
					];
				endif;
			endforeach;
			foreach(['Result','Type'] as $return):
				$results['return'] = trim(strval($xpath->evaluate('string(//h3[normalize-space(text())="'.$return.'"]/following-sibling::*[1])')));
				if(empty($results['return']) === false) break;
			endforeach;
		endif;
		return $results;
	}
	static private function create(array $tls) : void {
		$folderTypes = DOCPATH.DIRECTORY_SEPARATOR.'type';
		self::cleanFiles($folderTypes);
		$folderConstructors = DOCPATH.DIRECTORY_SEPARATOR.'constructor';
		self::cleanFiles($folderConstructors);
		$folderMethods = DOCPATH.DIRECTORY_SEPARATOR.'method';
		self::cleanFiles($folderMethods);
		$readme = DOCPATH.DIRECTORY_SEPARATOR.'README.md';
		$all = new Builder($folderTypes.'.md');
		$all->writeNewLine('# Types');
		$types = array();
		foreach($tls as $layer => $tl):
			$types = array_reduce($tl['constructors'],function(array $carry,array $item) : array {
				$carry[$item['type']] []= $item;
				return $carry;
			},$types);
		endforeach;
		foreach($types as $items):
			$all->writeNewLine();
			$all->writeNewLine('---');
			$all->writeNewLine();
			$type = current($items)['type'];
			$all->writeNewLine('##### '.str_replace(chr(46),chr(32),$type));
			$info = self::extractPageInfoFromUrl('https://core.telegram.org/type/'.$type);
			$stream = new Builder($folderTypes.DIRECTORY_SEPARATOR.$type.'.md');
			$stream->write('# '.$type);
			if(empty($info['description']) === false):
				$stream->writeNewLine();
				$desc = self::mdSafe(trim($info['description'],chr(46)));
				$stream->writeNewLine('**Description** : *'.$desc.'*');
			else:
				$desc = 'NOTHING';
			endif;
			$all->writeNewLine();
			$all->writeNewLine(':link: [*'.$desc.'*]'.chr(40).'type'.chr(47).$type.chr(41));
			$stream->writeNewLine();
			$stream->writeNewLine('**Layer** : '.$layer);
			$stream->writeNewLine();
			$stream->writeNewLine('```tl');
			foreach($items as $item):
				$stream->writeNewLine($item['raw']);
			endforeach;
			$stream->writeNewLine('```');
			$stream->writeNewLine();
			$stream->writeNewLine('---');
			$stream->writeNewLine();
			$stream->writeNewLine('## Constructors');
			$stream->writeNewLine();
			$stream->writeNewLine('| Constructor | Description |');
			$stream->writeNewLine('| :---: | :--- |');
			foreach($items as $item):
				$constructor = $item['predicate'];
				$description = trim($info['constructors'][$constructor]['description'] ?? 'NOTHING',chr(46));
				$stream->writeNewLine('| [**'.$constructor.'**](constructor/'.$constructor.') | '.$description.' |');
			endforeach;
			$stream->close();
		endforeach;
		$all->close();
		$all = new Builder($folderConstructors.'.md');
		$all->writeNewLine('# Constructors');
		foreach($tls as $layer => $tl):
			foreach($tl['constructors'] as $item):
				$all->writeNewLine();
				$all->writeNewLine('---');
				$all->writeNewLine();
				$all->writeNewLine('##### '.str_replace(chr(46),chr(32),$item['predicate']));
				$info = self::extractPageInfoFromUrl('https://core.telegram.org/constructor/'.$item['predicate']);
				$stream = new Builder($folderConstructors.DIRECTORY_SEPARATOR.$item['predicate'].'.md');
				$stream->write('# '.$item['predicate']);
				if(empty($info['description']) === false):
					$stream->writeNewLine();
					$desc = self::mdSafe(trim($info['description'],chr(46)));
					$stream->writeNewLine('**Description** : *'.$desc.'*');
				else:
					$desc = 'NOTHING';
				endif;
				$all->writeNewLine();
				$all->writeNewLine(':link: [*'.$desc.'*]'.chr(40).'constructor'.chr(47).$item['predicate'].chr(41));
				$stream->writeNewLine();
				$stream->writeNewLine('**Layer** : '.$layer);
				$stream->writeNewLine();
				$stream->writeNewLine('```tl');
				$stream->writeNewLine($item['raw']);
				$stream->writeNewLine('```');
				if(empty($item['params']) === false):
					$stream->writeNewLine();
					$stream->writeNewLine('---');
					$stream->writeNewLine();
					$stream->writeNewLine('## Parameters');
					$stream->writeNewLine();
					$stream->writeNewLine('| Name | Type | Description |');
					$stream->writeNewLine('| :---: | :---: | :--- |');
					foreach($item['params'] as $param):
						$name = $param['name'];
						$type = $param['type'];
						$parsed = Tl::parseType($type,false);
						$description = trim($info['params'][$name]['description'] ?? 'NOTHING',chr(46));
						$stream->writeNewLine('| '.($parsed['is_flag'] ? '**'.$name.'**' : ($parsed['flag_indicator'] ? '<del style = \'opacity : 0.4\'>'.$name.'</del>' : '<mark>'.$name.'</mark>')).' | [`'.$type.'`](type/'.$parsed['type'].') | '.$description.' |');
					endforeach;
				endif;
				$stream->writeNewLine();
				$stream->writeNewLine('---');
				$stream->writeNewLine();
				$stream->writeNewLine('## Type');
				$stream->writeNewLine();
				$parsed = Tl::parseType($item['type'],false);
				$stream->writeNewLine(chr(91).$item['type'].chr(93).chr(40).'type/'.$parsed['type'].chr(41));
				$stream->writeNewLine();
				$stream->writeNewLine('---');
				$stream->writeNewLine();
				$stream->writeNewLine('## Example');
				$stream->writeNewLine();
				$stream->writeNewLine('```php');
				$stream->writeNewLine();
				$stream->write(chr(36).lcfirst(str_replace(chr(46),strval(null),$parsed['type'])).' = ');
				self::writeExample($stream,$item['params'],$item['predicate'],$types);
				$stream->write(';');
				$stream->writeNewLine('```');
				$stream->close();
			endforeach;
		endforeach;
		$all->close();
		$all = new Builder($folderMethods.'.md');
		$all->writeNewLine('# Methods');
		foreach($tls as $layer => $tl):
			foreach($tl['methods'] as $item):
				$all->writeNewLine();
				$all->writeNewLine('---');
				$all->writeNewLine();
				$all->writeNewLine('##### '.str_replace(chr(46),chr(32),$item['method']));
				$info = self::extractPageInfoFromUrl('https://core.telegram.org/method/'.$item['method']);
				$stream = new Builder($folderMethods.DIRECTORY_SEPARATOR.$item['method'].'.md');
				$stream->write('# '.$item['method']);
				if(empty($info['description']) === false):
					$stream->writeNewLine();
					$desc = self::mdSafe(trim($info['description'],chr(46)));
					$stream->writeNewLine('**Description** : *'.$desc.'*');
				else:
					$desc = 'NOTHING';
				endif;
				$all->writeNewLine();
				$all->writeNewLine(':link: [*'.$desc.'*]'.chr(40).'method'.chr(47).$item['method'].chr(41));
				$stream->writeNewLine();
				$stream->writeNewLine('**Layer** : '.$layer);
				$stream->writeNewLine();
				$stream->writeNewLine('```tl');
				$stream->writeNewLine($item['raw']);
				$stream->writeNewLine('```');
				if(empty($item['params']) === false):
					$stream->writeNewLine();
					$stream->writeNewLine('---');
					$stream->writeNewLine();
					$stream->writeNewLine('## Parameters');
					$stream->writeNewLine();
					$stream->writeNewLine('| Name | Type | Description |');
					$stream->writeNewLine('| :---: | :---: | :--- |');
					foreach($item['params'] as $param):
						$name = $param['name'];
						$type = $param['type'];
						$parsed = Tl::parseType($type,false);
						$description = trim($info['params'][$name]['description'] ?? 'NOTHING',chr(46));
						$stream->writeNewLine('| '.($parsed['is_flag'] ? '**'.$name.'**' : ($parsed['flag_indicator'] ? '<del style = \'opacity : 0.4\'>'.$name.'</del>' : '<mark>'.$name.'</mark>')).' | [`'.$type.'`](type/'.$parsed['type'].') | '.$description.' |');
					endforeach;
				endif;
				$stream->writeNewLine();
				$stream->writeNewLine('---');
				$stream->writeNewLine();
				$stream->writeNewLine('## Result');
				$stream->writeNewLine();
				$parsed = Tl::parseType($item['type'],false);
				$stream->writeNewLine(chr(91).$item['type'].chr(93).chr(40).'type/'.$parsed['type'].chr(41));
				if(empty($info['errors']) === false):
					$stream->writeNewLine();
					$stream->writeNewLine('---');
					$stream->writeNewLine();
					$stream->writeNewLine('## Possible Errors');
					$stream->writeNewLine();
					$stream->writeNewLine('| Type | Code | Description |');
					$stream->writeNewLine('| :---: | :---: | :--- |');
					foreach($info['errors'] as $type => $error):
						$code = $error['code'];
						$description = trim($error['description'],chr(46));
						$stream->writeNewLine('| **'.$type.'** | `'.$code.'` | '.$description.' |');
					endforeach;
				endif;
				$stream->writeNewLine();
				$stream->writeNewLine('---');
				$stream->writeNewLine();
				$stream->writeNewLine('## Example');
				$stream->writeNewLine();
				$stream->writeNewLine('```php');
				$stream->writeNewLine();
				$stream->write(chr(36).lcfirst(str_replace(chr(46),strval(null),$parsed['type'])).' = ');
				self::writeExample($stream,$item['params'],$item['method'],$types);
				$stream->write(';');
				$stream->writeNewLine('```');
				$stream->close();
			endforeach;
		endforeach;
		$all->close();
	}
	static private function writeExample(Builder $stream,array $params,string $name,array $types,int $depth = 0) : void {
		$stream->write('$client->'.str_replace(chr(46),chr(45).chr(62),$name).'(');
		if($depth >= 4):
			$stream->write('...)');
		elseif(empty($params) === false):
			$stream->addIndent();
			foreach($params as $param):
				$name = $param['name'];
				$type = $param['type'];
				$parsed = Tl::parseType($type,false);
				if($parsed['flag_indicator'] === false):
					$randomValue = match(strtolower($parsed['type'])){
						'int' => random_int(0,100), // random_int(-0x80000000,0x7fffffff) //
						'int128' => Helper::generateRandomLargeInt(128),
						'int256' => Helper::generateRandomLargeInt(256),
						'int512' => Helper::generateRandomLargeInt(512),
						'long' => Helper::generateRandomLong(),
						'double' => random_int(-0x80000000,0x7fffffff) / 0x400,
						'string' => Helper::generateRandomString(),
						'true' => true,
						'bool' => boolval(random_int(0,1)),
						default => null
					};
					$constValue = match(strtolower($parsed['type'])){
						'bytes' => '"\x4c\x69\x76\x65\x50\x72\x6f\x74\x6f"', // mb_convert_encoding(random_bytes(5).'LiveProto'.random_bytes(5),'UTF-8') //
						'x' => '$client->help->getConfig(raw : true)',
						'inputpeer' => '$client->get_input_peer(peer : \'@LiveProtoChat\')',
						'inputuser' => '$client->get_input_user(user : \'@TakNone\')',
						'inputchannel' => '$client->get_input_channel(channel : \'@LiveProto\')',
						'inputfile' => '$client->upload_file(path : \'file.png\')',
						'inputmedia' => '$client->get_input_media_uploaded(path : \'file.mp4\',file_type : Tak\\Liveproto\\Enums\\FileType::DOCUMENT)',
						default => null
					};
					if(is_null($randomValue) and is_null($constValue)):
						$parsed['params'] = $types[$parsed['type']] ?? array();
						if($parsed['is_vector']):
							$stream->writeNewLine($name.' : array(');
							$stream->addIndent();
							foreach($parsed['params'] as $group):
								$stream->writeNewLine();
								$stream->write($stream->indent());
								self::writeExample($stream,$group['params'],$group['predicate'],$types,$depth + 1);
								$stream->write(chr(44));
							endforeach;
							$stream->deleteIndent();
							$stream->writeNewLine(')');
						else:
							$stream->writeNewLine($name.' : ');
							self::writeExample($stream,empty($parsed['params']) ? array() : $parsed['params'][false]['params'],empty($parsed['params']) ? $parsed['type'] : $parsed['params'][false]['predicate'],$types,$depth + 1);
						endif;
					else:
						$isString = in_array($parsed['type'],['string','bytes']);
						$isInteger = in_array($parsed['type'],['int','int128','int256','int512','long']);
						$formatValue = match(true){
							str_contains($name,'md5') and $isString => md5('LiveProto'),
							str_contains($name,'url') and $isString => 'https://docs.liveproto.dev',
							str_contains($name,'email') and $isString => 'reply@liveproto.dev',
							str_contains($name,'phone') and $isString => '+1234567890',
							str_contains($name,'first_name') and $isString => 'Tak',
							str_contains($name,'last_name') and $isString => 'None',
							str_contains($name,'username') and $isString => 'TakNone',
							str_starts_with($name,'ip') and $isString => '127.0.0.1',
							str_starts_with($name,'hash') and $isInteger => 0,
							str_starts_with($name,'offset') and $isInteger => 0,
							default => $randomValue
						};
						$exported = is_null($randomValue) ? $constValue : var_export($formatValue,true);
						$stream->writeNewLine($name.' : '.($parsed['is_vector'] ? 'array('.$exported.')' : $exported));
					endif;
					$stream->write(chr(44));
				endif;
			endforeach;
			$stream->deleteIndent();
			$stream->writeNewLine(')');
		else:
			$stream->write(')');
		endif;
	}
	static public function start() : void {
		$json = array();
		$tls = array(__DIR__.DIRECTORY_SEPARATOR.'api.tl');
		foreach($tls as $tl):
			$layer = self::layer(str_contains($tl,'secret.tl'));
			$json[$layer] = Tl::parseFile($tl);
		endforeach;
		self::create($json);
	}
}

?>===8===
secret.decryptedMessage#1f814f1f random_id:long random_bytes:bytes message:string media:DecryptedMessageMedia = secret.DecryptedMessage;
secret.decryptedMessageService#aa48327d random_id:long random_bytes:bytes action:DecryptedMessageAction = secret.DecryptedMessage;
secret.decryptedMessageMediaEmpty#89f5c4a = secret.DecryptedMessageMedia;
secret.decryptedMessageMediaPhoto#32798a8c thumb:bytes thumb_w:int thumb_h:int w:int h:int size:int key:bytes iv:bytes = secret.DecryptedMessageMedia;
secret.decryptedMessageMediaVideo#4cee6ef3 thumb:bytes thumb_w:int thumb_h:int duration:int w:int h:int size:int key:bytes iv:bytes = secret.DecryptedMessageMedia;
secret.decryptedMessageMediaGeoPoint#35480a59 lat:double long:double = secret.DecryptedMessageMedia;
secret.decryptedMessageMediaContact#588a0a97 phone_number:string first_name:string last_name:string user_id:int = secret.DecryptedMessageMedia;
secret.decryptedMessageActionSetMessageTTL#a1733aec ttl_seconds:int = secret.DecryptedMessageAction;
secret.decryptedMessageMediaDocument#b095434b thumb:bytes thumb_w:int thumb_h:int file_name:string mime_type:string size:int key:bytes iv:bytes = secret.DecryptedMessageMedia;
secret.decryptedMessageMediaAudio#6080758f duration:int size:int key:bytes iv:bytes = secret.DecryptedMessageMedia;
secret.decryptedMessageActionReadMessages#c4f40be random_ids:Vector<long> = secret.DecryptedMessageAction;
secret.decryptedMessageActionDeleteMessages#65614304 random_ids:Vector<long> = secret.DecryptedMessageAction;
secret.decryptedMessageActionScreenshotMessages#8ac1f475 random_ids:Vector<long> = secret.DecryptedMessageAction;
secret.decryptedMessageActionFlushHistory#6719e45c = secret.DecryptedMessageAction;

===17===
secret.decryptedMessage#204d3878 random_id:long ttl:int message:string media:DecryptedMessageMedia = secret.DecryptedMessage;
secret.decryptedMessageService#73164160 random_id:long action:DecryptedMessageAction = secret.DecryptedMessage;
secret.decryptedMessageMediaVideo#524a415d thumb:bytes thumb_w:int thumb_h:int duration:int mime_type:string w:int h:int size:int key:bytes iv:bytes = secret.DecryptedMessageMedia;
secret.decryptedMessageMediaAudio#57e0a9cb duration:int mime_type:string size:int key:bytes iv:bytes = secret.DecryptedMessageMedia;
secret.decryptedMessageLayer#1be31789 random_bytes:bytes layer:int in_seq_no:int out_seq_no:int message:DecryptedMessage = secret.DecryptedMessageLayer;
secret.sendMessageTypingAction#16bf744e = secret.SendMessageAction;
secret.sendMessageCancelAction#fd5ec8f5 = secret.SendMessageAction;
secret.sendMessageRecordVideoAction#a187d66f = secret.SendMessageAction;
secret.sendMessageUploadVideoAction#92042ff7 = secret.SendMessageAction;
secret.sendMessageRecordAudioAction#d52f73f7 = secret.SendMessageAction;
secret.sendMessageUploadAudioAction#e6ac8a6f = secret.SendMessageAction;
secret.sendMessageUploadPhotoAction#990a3c1a = secret.SendMessageAction;
secret.sendMessageUploadDocumentAction#8faee98e = secret.SendMessageAction;
secret.sendMessageGeoLocationAction#176f8ba1 = secret.SendMessageAction;
secret.sendMessageChooseContactAction#628cbc6f = secret.SendMessageAction;
secret.decryptedMessageActionResend#511110b0 start_seq_no:int end_seq_no:int = secret.DecryptedMessageAction;
secret.decryptedMessageActionNotifyLayer#f3048883 layer:int = secret.DecryptedMessageAction;
secret.decryptedMessageActionTyping#ccb27641 action:SendMessageAction = secret.DecryptedMessageAction;

===20===
secret.decryptedMessageActionRequestKey#f3c9611b exchange_id:long g_a:bytes = secret.DecryptedMessageAction;
secret.decryptedMessageActionAcceptKey#6fe1735b exchange_id:long g_b:bytes key_fingerprint:long = secret.DecryptedMessageAction;
secret.decryptedMessageActionAbortKey#dd05ec6b exchange_id:long = secret.DecryptedMessageAction;
secret.decryptedMessageActionCommitKey#ec2e0b9b exchange_id:long key_fingerprint:long = secret.DecryptedMessageAction;
secret.decryptedMessageActionNoop#a82fdd63 = secret.DecryptedMessageAction;

===23===
secret.documentAttributeImageSize#6c37c15c w:int h:int = secret.DocumentAttribute;
secret.documentAttributeAnimated#11b58939 = secret.DocumentAttribute;
secret.documentAttributeSticker#fb0a5727 = secret.DocumentAttribute;
secret.documentAttributeVideo#5910cccb duration:int w:int h:int = secret.DocumentAttribute;
secret.documentAttributeAudio#51448e5 duration:int = secret.DocumentAttribute;
secret.documentAttributeFilename#15590068 file_name:string = secret.DocumentAttribute;
secret.photoSizeEmpty#e17e23c type:string = secret.PhotoSize;
secret.photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = secret.PhotoSize;
secret.photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = secret.PhotoSize;
secret.fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = secret.FileLocation;
secret.fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = secret.FileLocation;
secret.decryptedMessageMediaExternalDocument#fa95b0dd id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector<DocumentAttribute> = secret.DecryptedMessageMedia;

===45===
secret.decryptedMessage#36b091de flags:# random_id:long ttl:int message:string media:flags.9?DecryptedMessageMedia entities:flags.7?Vector<MessageEntity> via_bot_name:flags.11?string reply_to_random_id:flags.3?long = secret.DecryptedMessage;
secret.decryptedMessageMediaPhoto#f1fa8d78 thumb:bytes thumb_w:int thumb_h:int w:int h:int size:int key:bytes iv:bytes caption:string = secret.DecryptedMessageMedia;
secret.decryptedMessageMediaVideo#970c8c0e thumb:bytes thumb_w:int thumb_h:int duration:int mime_type:string w:int h:int size:int key:bytes iv:bytes caption:string = secret.DecryptedMessageMedia;
secret.decryptedMessageMediaDocument#7afe8ae2 thumb:bytes thumb_w:int thumb_h:int mime_type:string size:int key:bytes iv:bytes attributes:Vector<DocumentAttribute> caption:string = secret.DecryptedMessageMedia;
secret.documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = secret.DocumentAttribute;
secret.documentAttributeAudio#ded218e0 duration:int title:string performer:string = secret.DocumentAttribute;
secret.messageEntityUnknown#bb92ba95 offset:int length:int = secret.MessageEntity;
secret.messageEntityMention#fa04579d offset:int length:int = secret.MessageEntity;
secret.messageEntityHashtag#6f635b0d offset:int length:int = secret.MessageEntity;
secret.messageEntityBotCommand#6cef8ac7 offset:int length:int = secret.MessageEntity;
secret.messageEntityUrl#6ed02538 offset:int length:int = secret.MessageEntity;
secret.messageEntityEmail#64e475c2 offset:int length:int = secret.MessageEntity;
secret.messageEntityBold#bd610bc9 offset:int length:int = secret.MessageEntity;
secret.messageEntityItalic#826f8b60 offset:int length:int = secret.MessageEntity;
secret.messageEntityCode#28a20571 offset:int length:int = secret.MessageEntity;
secret.messageEntityPre#73924be0 offset:int length:int language:string = secret.MessageEntity;
secret.messageEntityTextUrl#76a6d327 offset:int length:int url:string = secret.MessageEntity;
secret.inputStickerSetShortName#861cc8a0 short_name:string = secret.InputStickerSet;
secret.inputStickerSetEmpty#ffb62b95 = secret.InputStickerSet;
secret.decryptedMessageMediaVenue#8a0df56f lat:double long:double title:string address:string provider:string venue_id:string = secret.DecryptedMessageMedia;
secret.decryptedMessageMediaWebPage#e50511d8 url:string = secret.DecryptedMessageMedia;

===46===
secret.documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = secret.DocumentAttribute;

===66===
secret.documentAttributeVideo#ef02ce6 flags:# round_message:flags.0?true duration:int w:int h:int = secret.DocumentAttribute;
secret.sendMessageRecordRoundAction#88f27fbc = secret.SendMessageAction;
secret.sendMessageUploadRoundAction#bb718624 = secret.SendMessageAction;

===73===
secret.decryptedMessage#91cc4674 flags:# no_webpage:flags.1?true silent:flags.5?true random_id:long ttl:int message:string media:flags.9?DecryptedMessageMedia entities:flags.7?Vector<MessageEntity> via_bot_name:flags.11?string reply_to_random_id:flags.3?long grouped_id:flags.17?long = secret.DecryptedMessage;

===101===
secret.messageEntityUnderline#9c4e7e8b offset:int length:int = secret.MessageEntity;
secret.messageEntityStrike#bf0693d4 offset:int length:int = secret.MessageEntity;
secret.messageEntityBlockquote#20df5d0 offset:int length:int = secret.MessageEntity;

===143===
secret.decryptedMessageMediaDocument#6abd9782 thumb:bytes thumb_w:int thumb_h:int mime_type:string size:long key:bytes iv:bytes attributes:Vector<DocumentAttribute> caption:string = secret.DecryptedMessageMedia;

===144===
secret.messageEntitySpoiler#32ca960f offset:int length:int = secret.MessageEntity;
secret.messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = secret.MessageEntity;

// LAYER 144// Core types ( no need to gen ) //

int ? = Int;
long ? = Long;
double ? = Double;
string ? = String;

vector {t:Type} # [ t ] = Vector t;

int128 4*[ int ] = Int128;
int256 8*[ int ] = Int256;
int512 16*[ int ] = Int512;

---types---

resPQ#05162463 nonce:int128 server_nonce:int128 pq:string server_public_key_fingerprints:Vector<long> = ResPQ;

p_q_inner_data#83c95aec pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 = P_Q_inner_data;
p_q_inner_data_dc#a9f55f95 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int = P_Q_inner_data;
p_q_inner_data_temp#3c6a84d4 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 expires_in:int = P_Q_inner_data;
p_q_inner_data_temp_dc#56fddf88 pq:string p:string q:string nonce:int128 server_nonce:int128 new_nonce:int256 dc:int expires_in:int = P_Q_inner_data;

bind_auth_key_inner#75a3f765 nonce:long temp_auth_key_id:long perm_auth_key_id:long temp_session_id:long expires_at:int = BindAuthKeyInner;

server_DH_params_fail#79cb045d nonce:int128 server_nonce:int128 new_nonce_hash:int128 = Server_DH_Params;
server_DH_params_ok#d0e8075c nonce:int128 server_nonce:int128 encrypted_answer:string = Server_DH_Params;

server_DH_inner_data#b5890dba nonce:int128 server_nonce:int128 g:int dh_prime:string g_a:string server_time:int = Server_DH_inner_data;

client_DH_inner_data#6643b654 nonce:int128 server_nonce:int128 retry_id:long g_b:string = Client_DH_Inner_Data;

dh_gen_ok#3bcbf734 nonce:int128 server_nonce:int128 new_nonce_hash1:int128 = Set_client_DH_params_answer;
dh_gen_retry#46dc1fb9 nonce:int128 server_nonce:int128 new_nonce_hash2:int128 = Set_client_DH_params_answer;
dh_gen_fail#a69dae02 nonce:int128 server_nonce:int128 new_nonce_hash3:int128 = Set_client_DH_params_answer;

---functions---

req_pq#60469778 nonce:int128 = ResPQ;
req_pq_multi#be7e8ef1 nonce:int128 = ResPQ;

req_DH_params#d712e4be nonce:int128 server_nonce:int128 p:string q:string public_key_fingerprint:long encrypted_data:string = Server_DH_Params;

set_client_DH_params#f5045f1f nonce:int128 server_nonce:int128 encrypted_data:string = Set_client_DH_params_answer;

---types---

msgs_ack#62d6b459 msg_ids:Vector<long> = MsgsAck;

bad_msg_notification#a7eff811 bad_msg_id:long bad_msg_seqno:int error_code:int = BadMsgNotification;
bad_server_salt#edab447b bad_msg_id:long bad_msg_seqno:int error_code:int new_server_salt:long = BadMsgNotification;

msg_resend_req#7d861a08 msg_ids:Vector<long> = MsgResendReq;
msgs_state_req#da69fb52 msg_ids:Vector<long> = MsgsStateReq;
msgs_state_info#04deb57d req_msg_id:long info:bytes = MsgsStateInfo;
msgs_all_info#8cc0d131 msg_ids:Vector<long> info:bytes = MsgsAllInfo;
msg_detailed_info#276d3ec6 msg_id:long answer_msg_id:long bytes:int status:int = MsgDetailedInfo;
msg_new_detailed_info#809db6df answer_msg_id:long bytes:int status:int = MsgDetailedInfo;

// rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; // parsed manually

// rpc_error#2144ca19 error_code:int error_message:string = RpcError; // parsed manually

rpc_answer_unknown#5e2ad36e = RpcDropAnswer;
rpc_answer_dropped_running#cd78e586 = RpcDropAnswer;
rpc_answer_dropped#a43ad8b7 msg_id:long seq_no:int bytes:int = RpcDropAnswer;

future_salt#0949d9dc valid_since:int valid_until:int salt:long = FutureSalt;
future_salts#ae500895 req_msg_id:long now:int salts:vector<future_salt> = FutureSalts;

pong#347773c5 msg_id:long ping_id:long = Pong;

destroy_session_ok#e22045fc session_id:long = DestroySessionRes;
destroy_session_none#62d350c9 session_id:long = DestroySessionRes;

new_session_created#9ec20908 first_msg_id:long unique_id:long server_salt:long = NewSession;

// message msg_id:long seqno:int bytes:int body:Object = Message; // parsed manually
// msg_container#73f1f8dc messages:vector<message> = MessageContainer; // parsed manually
// msg_copy#e06046b2 orig_message:Message = MessageCopy; // parsed manually, not used - use msg_container
// gzip_packed#3072cfa1 packed_data:string = Object; // parsed manually

http_wait#9299359f max_delay:int wait_after:int max_wait:int = HttpWait;

ipPort#d433ad73 ipv4:int port:int = IpPort;
ipPortSecret#37982646 ipv4:int port:int secret:bytes = IpPort;
accessPointRule#4679b65f phone_prefix_rules:string dc_id:int ips:vector<IpPort> = AccessPointRule;
help.configSimple#5a592a6c date:int expires:int rules:vector<AccessPointRule> = help.ConfigSimple;

destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes;
destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes;
destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes;

---functions---

rpc_drop_answer#58e4a740 req_msg_id:long = RpcDropAnswer;

get_future_salts#b921bd04 num:int = FutureSalts;

ping#7abe77ec ping_id:long = Pong;
ping_delay_disconnect#f3427b8c ping_id:long disconnect_delay:int = Pong;

destroy_session#e7512126 session_id:long = DestroySessionRes;

destroy_auth_key#d1435160 = DestroyAuthKeyRes;<?php

declare(strict_types = 1);

namespace Tak\Liveproto\Parser;

use function Tak\Asyncio\File\read;

use function Tak\Asyncio\File\write;

readonly class Tl {
	static public function parseFile(string $path,? string $json = null) : array {
		$content = read($path);
		$lines = explode(chr(10),$content);
		$type = 'constructors';
		$array = array();
		foreach($lines as $line):
			if(empty($line) === false):
				if(preg_match('~^---(?<type>\w+)---$~',$line,$match)):
					$type = ($match['type'] === 'functions') ? 'methods' : 'constructors';
				elseif(preg_match('~^(?<method>[\w.]+)\#(?<id>[0-9a-f]+)(?<args>.*)?\s=\s(?<response>[\w\d<>#.?]+);$~',$line,$match)):
					$key = ($type === 'methods') ? 'method' : 'predicate';
					$parameters = array();
					if(preg_match_all('~(?<bracketstart>\{)?(?<name>\w+):(?<type>[\w\d<>#.?!]+)(?<bracketend>\})?~',$match['args'],$args,PREG_SET_ORDER)):
						foreach($args as $arg):
							if(isset($arg['bracketstart'],$arg['bracketend']) === false):
								$parameters []= ['name'=>$arg['name'],'type'=>$arg['type']];
							endif;
						endforeach;
					endif;
					$array[$type] []= ['raw'=>$line,'id'=>strval(hexdec($match['id'])),$key=>$match['method'],'params'=>$parameters,'type'=>$match['response']];
				endif;
			endif;
		endforeach;
		if(is_null($json) === false):
			$withtab = str_replace(str_repeat(chr(32),4),chr(9),json_encode($array,JSON_PRETTY_PRINT));
			write($json,$withtab);
		endif;
		return $array;
	}
	static function parseType(string $type,bool $lowercase = true) : array {
		$data = array();
		if(preg_match('~(?:flags(?<number>\d+)?\.(?<index>\d+)\?)?(?<type>[\w.#]+(?:<(?<vector>.*)>)?)~',$type,$match)):
			$data['is_flag'] = boolval(strlen($match['index']) > 0);
			$data['flag_number'] = intval(strlen($match['number']) > 0 ? $match['number'] : $data['is_flag']);
			$data['flag_index'] = intval(strlen($match['index']) ? $match['index'] : -1);
			$data['flag_indicator'] = boolval($match['type'] === chr(35));
			$data['is_vector'] = isset($match['vector']);
			$data['type'] = strval(isset($match['vector']) ? $match['vector'] : $match['type']);
			if($lowercase):
				$data['type'] = strtolower($data['type']);
			endif;
		endif;
		return $data;
	}
	static function parseDocComment(object $class) : array {
		$reflection = new \ReflectionClass($class);
		$docComment = $reflection->getDocComment();
		$array = array();
		if(preg_match('~@return\s(?<return>.+)~',$docComment,$match)):
			$array['return'] = $match['return'];
		endif;
		if(preg_match('~@param\s(?<param>.+)~',$docComment,$match)):
			$split = explode(chr(32),$match['param']);
			for($i = 0;$i < count($split);$i += 2):
				$array['param'][$split[$i + 1]] = $split[$i];
			endfor;
		endif;
		return $array;
	}
	static function parseReturn(object $class) : string {
		$parsed = self::parseDocComment($class);
		return $parsed['return'] ?? throw new \RuntimeException('The return of object not found');
	}
	static function parseParam(object $class) : array {
		$parsed = self::parseDocComment($class);
		return $parsed['param'] ?? throw new \RuntimeException('The parameters of object not found');
	}
}

?><?php

declare(strict_types = 1);

namespace Tak\Liveproto;

use Tak\Liveproto\Tl\Generator;

use Tak\Asyncio\Loop;

use function Tak\Asyncio\File\write;

function setup(string $path) : void {
	Loop::queue(function() use($path) : void {
		$src = realpath($path).DIRECTORY_SEPARATOR.'src';
		$tlpath = $src.DIRECTORY_SEPARATOR.'Tl';
		putenv('TLPATH='.$tlpath);
		$_ENV['TLPATH'] = $tlpath;
		Generator::start();
		$errorsfile = strval($src.DIRECTORY_SEPARATOR.'Errors'.DIRECTORY_SEPARATOR.'errors.json');
		if($contents = file_get_contents('http://core.telegram.org/file/400780400470/3/OY6JMkb69K4.143326.json/3c10f72ff9ce45e8a9')){
			$errorscontent = json_decode($contents,flags : JSON_THROW_ON_ERROR);
			write($errorsfile,json_encode($errorscontent->descriptions,flags : JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT));
		}
	});
	Loop::run();
}

?>MIT License

Copyright (c) 2025 Taha

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
.github/ export-ignore
docs/ export-ignore
{
    "name": "taknone/bootstrapper",
    "homepage": "https://liveproto.dev",
    "description": "Composer plugin to set up LiveProto library requirements - runs tasks on install / update and autoload dump",
    "type": "composer-plugin",
    "license": "MIT",
    "require": {
        "php": ">=8.4",
        "taknone/asyncio": "*",
        "taknone/attributes": "*",
        "taknone/liveproto": "*",
        "composer-plugin-api": ">=2.5"
    },
    "autoload": {
        "psr-4": {
            "Tak\\Liveproto\\": "src/"
        },
        "files": [
            "src/setup.php"
        ]
    },
    "extra": {
        "class": "Tak\\Liveproto\\Plugin",
        "plugin-optional": false
    },
    "minimum-stability": "stable",
    "prefer-stable": true
}<?php

// autoload_files.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    '97de4696579fe3a611ade34a3382585d' => $vendorDir . '/taknone/asyncio/src/functions.php',
    '802e6a70936d6d4537282b1c0f55eae4' => $vendorDir . '/taknone/asyncio/src/File/functions.php',
    '084d44cdcef5a1b6b4d43af2731edea6' => $vendorDir . '/taknone/asyncio/src/Socket/functions.php',
    '83f8caf5e943c28df6b31af58ab2d745' => $vendorDir . '/taknone/asyncio/src/ByteStream/functions.php',
    'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
    '05e057cda79a37c79b97106ad803a04a' => $vendorDir . '/taknone/liveproto/src/loader.php',
    'a0a7795f4156a729eebb59aca30e0976' => $vendorDir . '/taknone/bootstrapper/src/setup.php',
);
{
    "packages": [
        {
            "name": "paragonie/constant_time_encoding",
            "version": "v3.1.3",
            "version_normalized": "3.1.3.0",
            "source": {
                "type": "git",
                "url": "https://github.com/paragonie/constant_time_encoding.git",
                "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77",
                "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77",
                "shasum": ""
            },
            "require": {
                "php": "^8"
            },
            "require-dev": {
                "infection/infection": "^0",
                "nikic/php-fuzzer": "^0",
                "phpunit/phpunit": "^9|^10|^11",
                "vimeo/psalm": "^4|^5|^6"
            },
            "time": "2025-09-24T15:06:41+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "ParagonIE\\ConstantTime\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Paragon Initiative Enterprises",
                    "email": "security@paragonie.com",
                    "homepage": "https://paragonie.com",
                    "role": "Maintainer"
                },
                {
                    "name": "Steve 'Sc00bz' Thomas",
                    "email": "steve@tobtu.com",
                    "homepage": "https://www.tobtu.com",
                    "role": "Original Developer"
                }
            ],
            "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
            "keywords": [
                "base16",
                "base32",
                "base32_decode",
                "base32_encode",
                "base64",
                "base64_decode",
                "base64_encode",
                "bin2hex",
                "encoding",
                "hex",
                "hex2bin",
                "rfc4648"
            ],
            "support": {
                "email": "info@paragonie.com",
                "issues": "https://github.com/paragonie/constant_time_encoding/issues",
                "source": "https://github.com/paragonie/constant_time_encoding"
            },
            "install-path": "../paragonie/constant_time_encoding"
        },
        {
            "name": "paragonie/random_compat",
            "version": "v9.99.100",
            "version_normalized": "9.99.100.0",
            "source": {
                "type": "git",
                "url": "https://github.com/paragonie/random_compat.git",
                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
                "shasum": ""
            },
            "require": {
                "php": ">= 7"
            },
            "require-dev": {
                "phpunit/phpunit": "4.*|5.*",
                "vimeo/psalm": "^1"
            },
            "suggest": {
                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
            },
            "time": "2020-10-15T08:29:30+00:00",
            "type": "library",
            "installation-source": "dist",
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Paragon Initiative Enterprises",
                    "email": "security@paragonie.com",
                    "homepage": "https://paragonie.com"
                }
            ],
            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
            "keywords": [
                "csprng",
                "polyfill",
                "pseudorandom",
                "random"
            ],
            "support": {
                "email": "info@paragonie.com",
                "issues": "https://github.com/paragonie/random_compat/issues",
                "source": "https://github.com/paragonie/random_compat"
            },
            "install-path": "../paragonie/random_compat"
        },
        {
            "name": "phpseclib/phpseclib",
            "version": "3.0.55",
            "version_normalized": "3.0.55.0",
            "source": {
                "type": "git",
                "url": "https://github.com/phpseclib/phpseclib.git",
                "reference": "db9744e6d47e742b1f974e965ad49bdd041105af"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/db9744e6d47e742b1f974e965ad49bdd041105af",
                "reference": "db9744e6d47e742b1f974e965ad49bdd041105af",
                "shasum": ""
            },
            "require": {
                "paragonie/constant_time_encoding": "^1|^2|^3",
                "paragonie/random_compat": "^1.4|^2.0|^9.99.99",
                "php": ">=5.6.1"
            },
            "require-dev": {
                "phpunit/phpunit": "*"
            },
            "suggest": {
                "ext-dom": "Install the DOM extension to load XML formatted public keys.",
                "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.",
                "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.",
                "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
                "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
            },
            "time": "2026-06-14T23:24:10+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "phpseclib/bootstrap.php"
                ],
                "psr-4": {
                    "phpseclib3\\": "phpseclib/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Jim Wigginton",
                    "email": "terrafrost@php.net",
                    "role": "Lead Developer"
                },
                {
                    "name": "Patrick Monnerat",
                    "email": "pm@datasphere.ch",
                    "role": "Developer"
                },
                {
                    "name": "Andreas Fischer",
                    "email": "bantu@phpbb.com",
                    "role": "Developer"
                },
                {
                    "name": "Hans-Jürgen Petrich",
                    "email": "petrich@tronic-media.com",
                    "role": "Developer"
                },
                {
                    "name": "Graham Campbell",
                    "email": "graham@alt-three.com",
                    "role": "Developer"
                }
            ],
            "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.",
            "homepage": "http://phpseclib.sourceforge.net",
            "keywords": [
                "BigInteger",
                "aes",
                "asn.1",
                "asn1",
                "blowfish",
                "crypto",
                "cryptography",
                "encryption",
                "rsa",
                "security",
                "sftp",
                "signature",
                "signing",
                "ssh",
                "twofish",
                "x.509",
                "x509"
            ],
            "support": {
                "issues": "https://github.com/phpseclib/phpseclib/issues",
                "source": "https://github.com/phpseclib/phpseclib/tree/3.0.55"
            },
            "funding": [
                {
                    "url": "https://github.com/terrafrost",
                    "type": "github"
                },
                {
                    "url": "https://www.patreon.com/phpseclib",
                    "type": "patreon"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib",
                    "type": "tidelift"
                }
            ],
            "install-path": "../phpseclib/phpseclib"
        },
        {
            "name": "revolt/event-loop",
            "version": "v1.0.9",
            "version_normalized": "1.0.9.0",
            "source": {
                "type": "git",
                "url": "https://github.com/revoltphp/event-loop.git",
                "reference": "44061cf513e53c6200372fc935ac42271566295d"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/44061cf513e53c6200372fc935ac42271566295d",
                "reference": "44061cf513e53c6200372fc935ac42271566295d",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1"
            },
            "require-dev": {
                "ext-json": "*",
                "jetbrains/phpstorm-stubs": "^2019.3",
                "phpunit/phpunit": "^9",
                "psalm/phar": "6.16.*"
            },
            "time": "2026-05-16T17:55:38+00:00",
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-main": "1.x-dev"
                }
            },
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Revolt\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Aaron Piotrowski",
                    "email": "aaron@trowski.com"
                },
                {
                    "name": "Cees-Jan Kiewiet",
                    "email": "ceesjank@gmail.com"
                },
                {
                    "name": "Christian Lück",
                    "email": "christian@clue.engineering"
                },
                {
                    "name": "Niklas Keller",
                    "email": "me@kelunik.com"
                }
            ],
            "description": "Rock-solid event loop for concurrent PHP applications.",
            "keywords": [
                "async",
                "asynchronous",
                "concurrency",
                "event",
                "event-loop",
                "non-blocking",
                "scheduler"
            ],
            "support": {
                "issues": "https://github.com/revoltphp/event-loop/issues",
                "source": "https://github.com/revoltphp/event-loop/tree/v1.0.9"
            },
            "install-path": "../revolt/event-loop"
        },
        {
            "name": "taknone/asyncio",
            "version": "v0.0.10",
            "version_normalized": "0.0.10.0",
            "source": {
                "type": "git",
                "url": "https://github.com/TakNone/Asyncio.git",
                "reference": "6935ba195f24abf0562420d54e370b85738ad4cb"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/TakNone/Asyncio/zipball/6935ba195f24abf0562420d54e370b85738ad4cb",
                "reference": "6935ba195f24abf0562420d54e370b85738ad4cb",
                "shasum": ""
            },
            "require": {
                "php": ">=8.4",
                "revolt/event-loop": "^1.0"
            },
            "suggest": {
                "ext-pcntl": "Allows for better signal handling",
                "ext-swoole": "Required for high-performance Swoole coroutine support ( > 5.0.0 )"
            },
            "time": "2026-06-16T21:45:59+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "src/functions.php",
                    "src/File/functions.php",
                    "src/Socket/functions.php",
                    "src/ByteStream/functions.php"
                ],
                "psr-4": {
                    "Tak\\Asyncio\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Tak None",
                    "email": "MrTakNone@gmail.com",
                    "role": "Developer"
                }
            ],
            "description": "A high-performance async framework for PHP supporting Swoole and Revolt loops",
            "keywords": [
                "aiodatabase",
                "aiofile",
                "aiosocket",
                "async",
                "asynchronously",
                "asyncio",
                "coroutine",
                "fiber",
                "io",
                "non-blocking",
                "non-blocking-io",
                "php",
                "revolt",
                "swoole"
            ],
            "support": {
                "issues": "https://github.com/TakNone/Asyncio/issues",
                "source": "https://github.com/TakNone/Asyncio/tree/v0.0.10"
            },
            "install-path": "../taknone/asyncio"
        },
        {
            "name": "taknone/attributes",
            "version": "v2.1.0",
            "version_normalized": "2.1.0.0",
            "source": {
                "type": "git",
                "url": "https://github.com/TakNone/Attributes.git",
                "reference": "24c5000130047f1c1c4f10bc4f86a841fd42850e"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/TakNone/Attributes/zipball/24c5000130047f1c1c4f10bc4f86a841fd42850e",
                "reference": "24c5000130047f1c1c4f10bc4f86a841fd42850e",
                "shasum": ""
            },
            "require": {
                "ext-filter": "*",
                "ext-hash": "*",
                "ext-json": "*",
                "php": ">=8.4",
                "taknone/asyncio": "*"
            },
            "time": "2026-06-03T16:22:18+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "psr-4": {
                    "Tak\\Attributes\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Tak None",
                    "email": "MrTakNone@gmail.com"
                }
            ],
            "description": "Attribute-based validation for PHP 8.4+",
            "keywords": [
                "async",
                "attribute",
                "checker",
                "filter",
                "php",
                "reflection",
                "validation"
            ],
            "support": {
                "issues": "https://github.com/TakNone/Attributes/issues",
                "source": "https://github.com/TakNone/Attributes/tree/v2.1.0"
            },
            "install-path": "../taknone/attributes"
        },
        {
            "name": "taknone/bootstrapper",
            "version": "V1.5.4",
            "version_normalized": "1.5.4.0",
            "source": {
                "type": "git",
                "url": "https://github.com/TakNone/Bootstrapper.git",
                "reference": "61c60122dc21ae1e50c13bc17a8ad373cb5079cf"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/TakNone/Bootstrapper/zipball/61c60122dc21ae1e50c13bc17a8ad373cb5079cf",
                "reference": "61c60122dc21ae1e50c13bc17a8ad373cb5079cf",
                "shasum": ""
            },
            "require": {
                "composer-plugin-api": ">=2.5",
                "php": ">=8.4",
                "taknone/asyncio": "*",
                "taknone/attributes": "*",
                "taknone/liveproto": "*"
            },
            "time": "2026-06-15T12:51:58+00:00",
            "type": "composer-plugin",
            "extra": {
                "class": "Tak\\Liveproto\\Plugin",
                "plugin-optional": false
            },
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "src/setup.php"
                ],
                "psr-4": {
                    "Tak\\Liveproto\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "description": "Composer plugin to set up LiveProto library requirements - runs tasks on install / update and autoload dump",
            "homepage": "https://liveproto.dev",
            "support": {
                "issues": "https://github.com/TakNone/Bootstrapper/issues",
                "source": "https://github.com/TakNone/Bootstrapper/tree/V1.5.4"
            },
            "install-path": "../taknone/bootstrapper"
        },
        {
            "name": "taknone/liveproto",
            "version": "v1.0.3",
            "version_normalized": "1.0.3.0",
            "source": {
                "type": "git",
                "url": "https://github.com/TakNone/LiveProto.git",
                "reference": "2c5ced249681eb9fd082417078b2fd2694c3c4d7"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/TakNone/LiveProto/zipball/2c5ced249681eb9fd082417078b2fd2694c3c4d7",
                "reference": "2c5ced249681eb9fd082417078b2fd2694c3c4d7",
                "shasum": ""
            },
            "require": {
                "ext-dom": "*",
                "ext-fileinfo": "*",
                "ext-filter": "*",
                "ext-gmp": "*",
                "ext-hash": "*",
                "ext-json": "*",
                "ext-openssl": "*",
                "ext-xml": "*",
                "ext-zlib": "*",
                "php-64bit": ">=8.4",
                "phpseclib/phpseclib": "^3.0.46",
                "taknone/asyncio": "*",
                "taknone/attributes": "*",
                "taknone/bootstrapper": "*"
            },
            "suggest": {
                "ext-pcntl": "Allows for better signal handling",
                "ext-swoole": "Required for high-performance Swoole coroutine support ( > 5.0.0 )",
                "ext-tgcrypto": "Speeds up encryption / decryption processes for Telegram MTproto"
            },
            "time": "2026-06-11T17:32:22+00:00",
            "type": "library",
            "installation-source": "dist",
            "autoload": {
                "files": [
                    "src/loader.php"
                ],
                "psr-4": {
                    "Tak\\Liveproto\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Tak None",
                    "email": "MrTakNone@gmail.com",
                    "role": "Developer"
                }
            ],
            "description": "An async , pure PHP MTProto Telegram client",
            "keywords": [
                "api",
                "async",
                "client",
                "live",
                "liveproto",
                "mtproto",
                "php",
                "proto",
                "telegram",
                "telegram-client"
            ],
            "support": {
                "issues": "https://github.com/TakNone/LiveProto/issues",
                "source": "https://github.com/TakNone/LiveProto/tree/v1.0.3"
            },
            "install-path": "../taknone/liveproto"
        }
    ],
    "dev": true,
    "dev-package-names": []
}
<?php

// autoload_namespaces.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
);

Copyright (c) Nils Adermann, Jordi Boggiano

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);
<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);

return array(
    'phpseclib3\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'),
    'Tak\\Liveproto\\' => array($vendorDir . '/taknone/bootstrapper/src', $vendorDir . '/taknone/liveproto/src'),
    'Tak\\Attributes\\' => array($vendorDir . '/taknone/attributes/src'),
    'Tak\\Asyncio\\' => array($vendorDir . '/taknone/asyncio/src'),
    'Revolt\\' => array($vendorDir . '/revolt/event-loop/src'),
    'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
);
<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInitb5db464a3f9fc316d41264b8aa61779e
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    /**
     * @return \Composer\Autoload\ClassLoader
     */
    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        require __DIR__ . '/platform_check.php';

        spl_autoload_register(array('ComposerAutoloaderInitb5db464a3f9fc316d41264b8aa61779e', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
        spl_autoload_unregister(array('ComposerAutoloaderInitb5db464a3f9fc316d41264b8aa61779e', 'loadClassLoader'));

        require __DIR__ . '/autoload_static.php';
        call_user_func(\Composer\Autoload\ComposerStaticInitb5db464a3f9fc316d41264b8aa61779e::getInitializer($loader));

        $loader->register(true);

        $filesToLoad = \Composer\Autoload\ComposerStaticInitb5db464a3f9fc316d41264b8aa61779e::$files;
        $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
            if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
                $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

                require $file;
            }
        }, null, null);
        foreach ($filesToLoad as $fileIdentifier => $file) {
            $requireFile($fileIdentifier, $file);
        }

        return $loader;
    }
}
<?php return array(
    'root' => array(
        'name' => '__root__',
        'pretty_version' => 'dev-main',
        'version' => 'dev-main',
        'reference' => '2c5ced249681eb9fd082417078b2fd2694c3c4d7',
        'type' => 'library',
        'install_path' => __DIR__ . '/../../',
        'aliases' => array(),
        'dev' => true,
    ),
    'versions' => array(
        '__root__' => array(
            'pretty_version' => 'dev-main',
            'version' => 'dev-main',
            'reference' => '2c5ced249681eb9fd082417078b2fd2694c3c4d7',
            'type' => 'library',
            'install_path' => __DIR__ . '/../../',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'paragonie/constant_time_encoding' => array(
            'pretty_version' => 'v3.1.3',
            'version' => '3.1.3.0',
            'reference' => 'd5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77',
            'type' => 'library',
            'install_path' => __DIR__ . '/../paragonie/constant_time_encoding',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'paragonie/random_compat' => array(
            'pretty_version' => 'v9.99.100',
            'version' => '9.99.100.0',
            'reference' => '996434e5492cb4c3edcb9168db6fbb1359ef965a',
            'type' => 'library',
            'install_path' => __DIR__ . '/../paragonie/random_compat',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'phpseclib/phpseclib' => array(
            'pretty_version' => '3.0.55',
            'version' => '3.0.55.0',
            'reference' => 'db9744e6d47e742b1f974e965ad49bdd041105af',
            'type' => 'library',
            'install_path' => __DIR__ . '/../phpseclib/phpseclib',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'revolt/event-loop' => array(
            'pretty_version' => 'v1.0.9',
            'version' => '1.0.9.0',
            'reference' => '44061cf513e53c6200372fc935ac42271566295d',
            'type' => 'library',
            'install_path' => __DIR__ . '/../revolt/event-loop',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'taknone/asyncio' => array(
            'pretty_version' => 'v0.0.10',
            'version' => '0.0.10.0',
            'reference' => '6935ba195f24abf0562420d54e370b85738ad4cb',
            'type' => 'library',
            'install_path' => __DIR__ . '/../taknone/asyncio',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'taknone/attributes' => array(
            'pretty_version' => 'v2.1.0',
            'version' => '2.1.0.0',
            'reference' => '24c5000130047f1c1c4f10bc4f86a841fd42850e',
            'type' => 'library',
            'install_path' => __DIR__ . '/../taknone/attributes',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'taknone/bootstrapper' => array(
            'pretty_version' => 'V1.5.4',
            'version' => '1.5.4.0',
            'reference' => '61c60122dc21ae1e50c13bc17a8ad373cb5079cf',
            'type' => 'composer-plugin',
            'install_path' => __DIR__ . '/../taknone/bootstrapper',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
        'taknone/liveproto' => array(
            'pretty_version' => 'v1.0.3',
            'version' => '1.0.3.0',
            'reference' => '2c5ced249681eb9fd082417078b2fd2694c3c4d7',
            'type' => 'library',
            'install_path' => __DIR__ . '/../taknone/liveproto',
            'aliases' => array(),
            'dev_requirement' => false,
        ),
    ),
);
<?php

// platform_check.php @generated by Composer

$issues = array();

if (!(PHP_VERSION_ID >= 80400)) {
    $issues[] = 'Your Composer dependencies require a PHP version ">= 8.4.0". You are running ' . PHP_VERSION . '.';
}

if (PHP_INT_SIZE !== 8) {
    $issues[] = 'Your Composer dependencies require a 64-bit build of PHP.';
}

if ($issues) {
    if (!headers_sent()) {
        header('HTTP/1.1 500 Internal Server Error');
    }
    if (!ini_get('display_errors')) {
        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
            fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
        } elseif (!headers_sent()) {
            echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
        }
    }
    throw new \RuntimeException(
        'Composer detected issues in your platform: ' . implode(' ', $issues)
    );
}
<?php

// autoload_static.php @generated by Composer

namespace Composer\Autoload;

class ComposerStaticInitb5db464a3f9fc316d41264b8aa61779e
{
    public static $files = array (
        '97de4696579fe3a611ade34a3382585d' => __DIR__ . '/..' . '/taknone/asyncio/src/functions.php',
        '802e6a70936d6d4537282b1c0f55eae4' => __DIR__ . '/..' . '/taknone/asyncio/src/File/functions.php',
        '084d44cdcef5a1b6b4d43af2731edea6' => __DIR__ . '/..' . '/taknone/asyncio/src/Socket/functions.php',
        '83f8caf5e943c28df6b31af58ab2d745' => __DIR__ . '/..' . '/taknone/asyncio/src/ByteStream/functions.php',
        'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
        '05e057cda79a37c79b97106ad803a04a' => __DIR__ . '/..' . '/taknone/liveproto/src/loader.php',
        'a0a7795f4156a729eebb59aca30e0976' => __DIR__ . '/..' . '/taknone/bootstrapper/src/setup.php',
    );

    public static $prefixLengthsPsr4 = array (
        'p' =>
        array (
            'phpseclib3\\' => 11,
        ),
        'T' =>
        array (
            'Tak\\Liveproto\\' => 14,
            'Tak\\Attributes\\' => 15,
            'Tak\\Asyncio\\' => 12,
        ),
        'R' =>
        array (
            'Revolt\\' => 7,
        ),
        'P' =>
        array (
            'ParagonIE\\ConstantTime\\' => 23,
        ),
    );

    public static $prefixDirsPsr4 = array (
        'phpseclib3\\' =>
        array (
            0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib',
        ),
        'Tak\\Liveproto\\' =>
        array (
            0 => __DIR__ . '/..' . '/taknone/bootstrapper/src',
            1 => __DIR__ . '/..' . '/taknone/liveproto/src',
        ),
        'Tak\\Attributes\\' =>
        array (
            0 => __DIR__ . '/..' . '/taknone/attributes/src',
        ),
        'Tak\\Asyncio\\' =>
        array (
            0 => __DIR__ . '/..' . '/taknone/asyncio/src',
        ),
        'Revolt\\' =>
        array (
            0 => __DIR__ . '/..' . '/revolt/event-loop/src',
        ),
        'ParagonIE\\ConstantTime\\' =>
        array (
            0 => __DIR__ . '/..' . '/paragonie/constant_time_encoding/src',
        ),
    );

    public static $classMap = array (
        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
    );

    public static function getInitializer(ClassLoader $loader)
    {
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInitb5db464a3f9fc316d41264b8aa61779e::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInitb5db464a3f9fc316d41264b8aa61779e::$prefixDirsPsr4;
            $loader->classMap = ComposerStaticInitb5db464a3f9fc316d41264b8aa61779e::$classMap;

        }, null, ClassLoader::class);
    }
}
<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Autoload;

/**
 * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
 *
 *     $loader = new \Composer\Autoload\ClassLoader();
 *
 *     // register classes with namespaces
 *     $loader->add('Symfony\Component', __DIR__.'/component');
 *     $loader->add('Symfony',           __DIR__.'/framework');
 *
 *     // activate the autoloader
 *     $loader->register();
 *
 *     // to enable searching the include path (eg. for PEAR packages)
 *     $loader->setUseIncludePath(true);
 *
 * In this example, if you try to use a class in the Symfony\Component
 * namespace or one of its children (Symfony\Component\Console for instance),
 * the autoloader will first look for the class under the component/
 * directory, and it will then fallback to the framework/ directory if not
 * found before giving up.
 *
 * This class is loosely based on the Symfony UniversalClassLoader.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Jordi Boggiano <j.boggiano@seld.be>
 * @see    https://www.php-fig.org/psr/psr-0/
 * @see    https://www.php-fig.org/psr/psr-4/
 */
class ClassLoader
{
    /** @var \Closure(string):void */
    private static $includeFile;

    /** @var string|null */
    private $vendorDir;

    // PSR-4
    /**
     * @var array<string, array<string, int>>
     */
    private $prefixLengthsPsr4 = array();
    /**
     * @var array<string, list<string>>
     */
    private $prefixDirsPsr4 = array();
    /**
     * @var list<string>
     */
    private $fallbackDirsPsr4 = array();

    // PSR-0
    /**
     * List of PSR-0 prefixes
     *
     * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
     *
     * @var array<string, array<string, list<string>>>
     */
    private $prefixesPsr0 = array();
    /**
     * @var list<string>
     */
    private $fallbackDirsPsr0 = array();

    /** @var bool */
    private $useIncludePath = false;

    /**
     * @var array<string, string>
     */
    private $classMap = array();

    /** @var bool */
    private $classMapAuthoritative = false;

    /**
     * @var array<string, bool>
     */
    private $missingClasses = array();

    /** @var string|null */
    private $apcuPrefix;

    /**
     * @var array<string, self>
     */
    private static $registeredLoaders = array();

    /**
     * @param string|null $vendorDir
     */
    public function __construct($vendorDir = null)
    {
        $this->vendorDir = $vendorDir;
        self::initializeIncludeClosure();
    }

    /**
     * @return array<string, list<string>>
     */
    public function getPrefixes()
    {
        if (!empty($this->prefixesPsr0)) {
            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
        }

        return array();
    }

    /**
     * @return array<string, list<string>>
     */
    public function getPrefixesPsr4()
    {
        return $this->prefixDirsPsr4;
    }

    /**
     * @return list<string>
     */
    public function getFallbackDirs()
    {
        return $this->fallbackDirsPsr0;
    }

    /**
     * @return list<string>
     */
    public function getFallbackDirsPsr4()
    {
        return $this->fallbackDirsPsr4;
    }

    /**
     * @return array<string, string> Array of classname => path
     */
    public function getClassMap()
    {
        return $this->classMap;
    }

    /**
     * @param array<string, string> $classMap Class to filename map
     *
     * @return void
     */
    public function addClassMap(array $classMap)
    {
        if ($this->classMap) {
            $this->classMap = array_merge($this->classMap, $classMap);
        } else {
            $this->classMap = $classMap;
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix, either
     * appending or prepending to the ones previously set for this prefix.
     *
     * @param string              $prefix  The prefix
     * @param list<string>|string $paths   The PSR-0 root directories
     * @param bool                $prepend Whether to prepend the directories
     *
     * @return void
     */
    public function add($prefix, $paths, $prepend = false)
    {
        $paths = (array) $paths;
        if (!$prefix) {
            if ($prepend) {
                $this->fallbackDirsPsr0 = array_merge(
                    $paths,
                    $this->fallbackDirsPsr0
                );
            } else {
                $this->fallbackDirsPsr0 = array_merge(
                    $this->fallbackDirsPsr0,
                    $paths
                );
            }

            return;
        }

        $first = $prefix[0];
        if (!isset($this->prefixesPsr0[$first][$prefix])) {
            $this->prefixesPsr0[$first][$prefix] = $paths;

            return;
        }
        if ($prepend) {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $paths,
                $this->prefixesPsr0[$first][$prefix]
            );
        } else {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $this->prefixesPsr0[$first][$prefix],
                $paths
            );
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace, either
     * appending or prepending to the ones previously set for this namespace.
     *
     * @param string              $prefix  The prefix/namespace, with trailing '\\'
     * @param list<string>|string $paths   The PSR-4 base directories
     * @param bool                $prepend Whether to prepend the directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function addPsr4($prefix, $paths, $prepend = false)
    {
        $paths = (array) $paths;
        if (!$prefix) {
            // Register directories for the root namespace.
            if ($prepend) {
                $this->fallbackDirsPsr4 = array_merge(
                    $paths,
                    $this->fallbackDirsPsr4
                );
            } else {
                $this->fallbackDirsPsr4 = array_merge(
                    $this->fallbackDirsPsr4,
                    $paths
                );
            }
        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
            // Register directories for a new namespace.
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = $paths;
        } elseif ($prepend) {
            // Prepend directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $paths,
                $this->prefixDirsPsr4[$prefix]
            );
        } else {
            // Append directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $this->prefixDirsPsr4[$prefix],
                $paths
            );
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix,
     * replacing any others previously set for this prefix.
     *
     * @param string              $prefix The prefix
     * @param list<string>|string $paths  The PSR-0 base directories
     *
     * @return void
     */
    public function set($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr0 = (array) $paths;
        } else {
            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace,
     * replacing any others previously set for this namespace.
     *
     * @param string              $prefix The prefix/namespace, with trailing '\\'
     * @param list<string>|string $paths  The PSR-4 base directories
     *
     * @throws \InvalidArgumentException
     *
     * @return void
     */
    public function setPsr4($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr4 = (array) $paths;
        } else {
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        }
    }

    /**
     * Turns on searching the include path for class files.
     *
     * @param bool $useIncludePath
     *
     * @return void
     */
    public function setUseIncludePath($useIncludePath)
    {
        $this->useIncludePath = $useIncludePath;
    }

    /**
     * Can be used to check if the autoloader uses the include path to check
     * for classes.
     *
     * @return bool
     */
    public function getUseIncludePath()
    {
        return $this->useIncludePath;
    }

    /**
     * Turns off searching the prefix and fallback directories for classes
     * that have not been registered with the class map.
     *
     * @param bool $classMapAuthoritative
     *
     * @return void
     */
    public function setClassMapAuthoritative($classMapAuthoritative)
    {
        $this->classMapAuthoritative = $classMapAuthoritative;
    }

    /**
     * Should class lookup fail if not found in the current class map?
     *
     * @return bool
     */
    public function isClassMapAuthoritative()
    {
        return $this->classMapAuthoritative;
    }

    /**
     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
     *
     * @param string|null $apcuPrefix
     *
     * @return void
     */
    public function setApcuPrefix($apcuPrefix)
    {
        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
    }

    /**
     * The APCu prefix in use, or null if APCu caching is not enabled.
     *
     * @return string|null
     */
    public function getApcuPrefix()
    {
        return $this->apcuPrefix;
    }

    /**
     * Registers this instance as an autoloader.
     *
     * @param bool $prepend Whether to prepend the autoloader or not
     *
     * @return void
     */
    public function register($prepend = false)
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend);

        if (null === $this->vendorDir) {
            return;
        }

        if ($prepend) {
            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
        } else {
            unset(self::$registeredLoaders[$this->vendorDir]);
            self::$registeredLoaders[$this->vendorDir] = $this;
        }
    }

    /**
     * Unregisters this instance as an autoloader.
     *
     * @return void
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));

        if (null !== $this->vendorDir) {
            unset(self::$registeredLoaders[$this->vendorDir]);
        }
    }

    /**
     * Loads the given class or interface.
     *
     * @param  string    $class The name of the class
     * @return true|null True if loaded, null otherwise
     */
    public function loadClass($class)
    {
        if ($file = $this->findFile($class)) {
            $includeFile = self::$includeFile;
            $includeFile($file);

            return true;
        }

        return null;
    }

    /**
     * Finds the path to the file where the class is defined.
     *
     * @param string $class The name of the class
     *
     * @return string|false The path if found, false otherwise
     */
    public function findFile($class)
    {
        // class map lookup
        if (isset($this->classMap[$class])) {
            return $this->classMap[$class];
        }
        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
            return false;
        }
        if (null !== $this->apcuPrefix) {
            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
            if ($hit) {
                return $file;
            }
        }

        $file = $this->findFileWithExtension($class, '.php');

        // Search for Hack files if we are running on HHVM
        if (false === $file && defined('HHVM_VERSION')) {
            $file = $this->findFileWithExtension($class, '.hh');
        }

        if (null !== $this->apcuPrefix) {
            apcu_add($this->apcuPrefix.$class, $file);
        }

        if (false === $file) {
            // Remember that this class does not exist.
            $this->missingClasses[$class] = true;
        }

        return $file;
    }

    /**
     * Returns the currently registered loaders keyed by their corresponding vendor directories.
     *
     * @return array<string, self>
     */
    public static function getRegisteredLoaders()
    {
        return self::$registeredLoaders;
    }

    /**
     * @param  string       $class
     * @param  string       $ext
     * @return string|false
     */
    private function findFileWithExtension($class, $ext)
    {
        // PSR-4 lookup
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

        $first = $class[0];
        if (isset($this->prefixLengthsPsr4[$first])) {
            $subPath = $class;
            while (false !== $lastPos = strrpos($subPath, '\\')) {
                $subPath = substr($subPath, 0, $lastPos);
                $search = $subPath . '\\';
                if (isset($this->prefixDirsPsr4[$search])) {
                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
                        if (file_exists($file = $dir . $pathEnd)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-4 fallback dirs
        foreach ($this->fallbackDirsPsr4 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
                return $file;
            }
        }

        // PSR-0 lookup
        if (false !== $pos = strrpos($class, '\\')) {
            // namespaced class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
        } else {
            // PEAR-like class name
            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
        }

        if (isset($this->prefixesPsr0[$first])) {
            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($dirs as $dir) {
                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-0 fallback dirs
        foreach ($this->fallbackDirsPsr0 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                return $file;
            }
        }

        // PSR-0 include paths.
        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
            return $file;
        }

        return false;
    }

    /**
     * @return void
     */
    private static function initializeIncludeClosure()
    {
        if (self::$includeFile !== null) {
            return;
        }

        /**
         * Scope isolated include.
         *
         * Prevents access to $this/self from included files.
         *
         * @param  string $file
         * @return void
         */
        self::$includeFile = \Closure::bind(static function($file) {
            include $file;
        }, null, null);
    }
}
<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer;

use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;

/**
 * This class is copied in every Composer installed project and available to all
 *
 * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
 *
 * To require its presence, you can require `composer-runtime-api ^2.0`
 *
 * @final
 */
class InstalledVersions
{
    /**
     * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
     * @internal
     */
    private static $selfDir = null;

    /**
     * @var mixed[]|null
     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
     */
    private static $installed;

    /**
     * @var bool
     */
    private static $installedIsLocalDir;

    /**
     * @var bool|null
     */
    private static $canGetVendors;

    /**
     * @var array[]
     * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    private static $installedByVendor = array();

    /**
     * Returns a list of all package names which are present, either by being installed, replaced or provided
     *
     * @return string[]
     * @psalm-return list<string>
     */
    public static function getInstalledPackages()
    {
        $packages = array();
        foreach (self::getInstalled() as $installed) {
            $packages[] = array_keys($installed['versions']);
        }

        if (1 === \count($packages)) {
            return $packages[0];
        }

        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
    }

    /**
     * Returns a list of all package names with a specific type e.g. 'library'
     *
     * @param  string   $type
     * @return string[]
     * @psalm-return list<string>
     */
    public static function getInstalledPackagesByType($type)
    {
        $packagesByType = array();

        foreach (self::getInstalled() as $installed) {
            foreach ($installed['versions'] as $name => $package) {
                if (isset($package['type']) && $package['type'] === $type) {
                    $packagesByType[] = $name;
                }
            }
        }

        return $packagesByType;
    }

    /**
     * Checks whether the given package is installed
     *
     * This also returns true if the package name is provided or replaced by another package
     *
     * @param  string $packageName
     * @param  bool   $includeDevRequirements
     * @return bool
     */
    public static function isInstalled($packageName, $includeDevRequirements = true)
    {
        foreach (self::getInstalled() as $installed) {
            if (isset($installed['versions'][$packageName])) {
                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
            }
        }

        return false;
    }

    /**
     * Checks whether the given package satisfies a version constraint
     *
     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
     *
     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
     *
     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
     * @param  string        $packageName
     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
     * @return bool
     */
    public static function satisfies(VersionParser $parser, $packageName, $constraint)
    {
        $constraint = $parser->parseConstraints((string) $constraint);
        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));

        return $provided->matches($constraint);
    }

    /**
     * Returns a version constraint representing all the range(s) which are installed for a given package
     *
     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
     * whether a given version of a package is installed, and not just whether it exists
     *
     * @param  string $packageName
     * @return string Version constraint usable with composer/semver
     */
    public static function getVersionRanges($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            $ranges = array();
            if (isset($installed['versions'][$packageName]['pretty_version'])) {
                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
            }
            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
            }
            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
            }
            if (array_key_exists('provided', $installed['versions'][$packageName])) {
                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
            }

            return implode(' || ', $ranges);
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
     */
    public static function getVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['version'])) {
                return null;
            }

            return $installed['versions'][$packageName]['version'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
     */
    public static function getPrettyVersion($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
                return null;
            }

            return $installed['versions'][$packageName]['pretty_version'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
     */
    public static function getReference($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            if (!isset($installed['versions'][$packageName]['reference'])) {
                return null;
            }

            return $installed['versions'][$packageName]['reference'];
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @param  string      $packageName
     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
     */
    public static function getInstallPath($packageName)
    {
        foreach (self::getInstalled() as $installed) {
            if (!isset($installed['versions'][$packageName])) {
                continue;
            }

            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
        }

        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
    }

    /**
     * @return array
     * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
     */
    public static function getRootPackage()
    {
        $installed = self::getInstalled();

        return $installed[0]['root'];
    }

    /**
     * Returns the raw installed.php data for custom implementations
     *
     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
     * @return array[]
     * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
     */
    public static function getRawData()
    {
        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);

        if (null === self::$installed) {
            // only require the installed.php file if this file is loaded from its dumped location,
            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
            if (substr(__DIR__, -8, 1) !== 'C') {
                self::$installed = include __DIR__ . '/installed.php';
            } else {
                self::$installed = array();
            }
        }

        return self::$installed;
    }

    /**
     * Returns the raw data of all installed.php which are currently loaded for custom implementations
     *
     * @return array[]
     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    public static function getAllRawData()
    {
        return self::getInstalled();
    }

    /**
     * Lets you reload the static array from another file
     *
     * This is only useful for complex integrations in which a project needs to use
     * this class but then also needs to execute another project's autoloader in process,
     * and wants to ensure both projects have access to their version of installed.php.
     *
     * A typical case would be PHPUnit, where it would need to make sure it reads all
     * the data it needs from this class, then call reload() with
     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
     * the project in which it runs can then also use this class safely, without
     * interference between PHPUnit's dependencies and the project's dependencies.
     *
     * @param  array[] $data A vendor/composer/installed.php data set
     * @return void
     *
     * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
     */
    public static function reload($data)
    {
        self::$installed = $data;
        self::$installedByVendor = array();

        // when using reload, we disable the duplicate protection to ensure that self::$installed data is
        // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
        // so we have to assume it does not, and that may result in duplicate data being returned when listing
        // all installed packages for example
        self::$installedIsLocalDir = false;
    }

    /**
     * @return string
     */
    private static function getSelfDir()
    {
        if (self::$selfDir === null) {
            self::$selfDir = strtr(__DIR__, '\\', '/');
        }

        return self::$selfDir;
    }

    /**
     * @return array[]
     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
     */
    private static function getInstalled()
    {
        if (null === self::$canGetVendors) {
            self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
        }

        $installed = array();
        $copiedLocalDir = false;

        if (self::$canGetVendors) {
            $selfDir = self::getSelfDir();
            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
                $vendorDir = strtr($vendorDir, '\\', '/');
                if (isset(self::$installedByVendor[$vendorDir])) {
                    $installed[] = self::$installedByVendor[$vendorDir];
                } elseif (is_file($vendorDir.'/composer/installed.php')) {
                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
                    $required = require $vendorDir.'/composer/installed.php';
                    self::$installedByVendor[$vendorDir] = $required;
                    $installed[] = $required;
                    if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
                        self::$installed = $required;
                        self::$installedIsLocalDir = true;
                    }
                }
                if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
                    $copiedLocalDir = true;
                }
            }
        }

        if (null === self::$installed) {
            // only require the installed.php file if this file is loaded from its dumped location,
            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
            if (substr(__DIR__, -8, 1) !== 'C') {
                /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
                $required = require __DIR__ . '/installed.php';
                self::$installed = $required;
            } else {
                self::$installed = array();
            }
        }

        if (self::$installed !== array() && !$copiedLocalDir) {
            $installed[] = self::$installed;
        }

        return $installed;
    }
}
<?php

declare(strict_types=1);

namespace Revolt;

use Revolt\EventLoop\CallbackType;
use Revolt\EventLoop\Driver;
use Revolt\EventLoop\DriverFactory;
use Revolt\EventLoop\Internal\AbstractDriver;
use Revolt\EventLoop\Internal\DriverCallback;
use Revolt\EventLoop\InvalidCallbackError;
use Revolt\EventLoop\Suspension;
use Revolt\EventLoop\UnsupportedFeatureException;

/**
 * Accessor to allow global access to the event loop.
 *
 * @see Driver
 */
final class EventLoop
{
    private static Driver $driver;

    /**
     * Sets the driver to be used as the event loop.
     */
    public static function setDriver(Driver $driver): void
    {
        /** @psalm-suppress RedundantPropertyInitializationCheck, RedundantCondition */
        if (isset(self::$driver) && self::$driver->isRunning()) {
            throw new \Error("Can't swap the event loop driver while the driver is running");
        }

        try {
            /** @psalm-suppress InternalClass */
            self::$driver = new class () extends AbstractDriver {
                #[\Override]
                protected function activate(array $callbacks): void
                {
                    throw new \Error("Can't activate callback during garbage collection.");
                }

                #[\Override]
                protected function dispatch(bool $blocking): void
                {
                    throw new \Error("Can't dispatch during garbage collection.");
                }

                #[\Override]
                protected function deactivate(DriverCallback $callback): void
                {
                    // do nothing
                }

                #[\Override]
                public function getHandle(): mixed
                {
                    return null;
                }

                #[\Override]
                protected function now(): float
                {
                    return (float) \hrtime(true) / 1_000_000_000;
                }
            };

            \gc_collect_cycles();
        } finally {
            self::$driver = $driver;
        }
    }

    /**
     * Queue a microtask.
     *
     * The queued callback MUST be executed immediately once the event loop gains control. Order of queueing MUST be
     * preserved when executing the callbacks. Recursive scheduling can thus result in infinite loops, use with care.
     *
     * Does NOT create an event callback, thus CAN NOT be marked as disabled or unreferenced.
     * Use {@see EventLoop::defer()} if you need these features.
     *
     * @param \Closure(...):void $closure The callback to queue.
     * @param mixed ...$args The callback arguments.
     */
    public static function queue(\Closure $closure, mixed ...$args): void
    {
        self::getDriver()->queue($closure, ...$args);
    }

    /**
     * Defer the execution of a callback.
     *
     * The deferred callback MUST be executed before any other type of callback in a tick. Order of enabling MUST be
     * preserved when executing the callbacks.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Deferred callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param \Closure(string):void $closure The callback to defer. The `$callbackId` will be
     *     invalidated before the callback invocation.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     */
    public static function defer(\Closure $closure): string
    {
        return self::getDriver()->defer($closure);
    }

    /**
     * Delay the execution of a callback.
     *
     * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which
     * timers expire first, but timers with the same expiration time MAY be executed in any order.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param float $delay The amount of time, in seconds, to delay the execution for.
     * @param \Closure(string):void $closure The callback to delay. The `$callbackId` will be invalidated
     *     before the callback invocation.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     */
    public static function delay(float $delay, \Closure $closure): string
    {
        return self::getDriver()->delay($delay, $closure);
    }

    /**
     * Repeatedly execute a callback.
     *
     * The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be
     * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order.
     * The first execution is scheduled after the first interval period.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param float $interval The time interval, in seconds, to wait between executions.
     * @param \Closure(string):void $closure The callback to repeat.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     */
    public static function repeat(float $interval, \Closure $closure): string
    {
        return self::getDriver()->repeat($interval, $closure);
    }

    /**
     * Execute a callback when a stream resource becomes readable or is closed for reading.
     *
     * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the
     * callback when closing the resource locally. Drivers MAY choose to notify the user if there are callbacks on
     * invalid resources, but are not required to, due to the high performance impact. Callbacks on closed resources are
     * therefore undefined behavior.
     *
     * Multiple callbacks on the same stream MAY be executed in any order.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param resource $stream The stream to monitor.
     * @param \Closure(string, resource):void $closure The callback to execute.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     */
    public static function onReadable(mixed $stream, \Closure $closure): string
    {
        return self::getDriver()->onReadable($stream, $closure);
    }

    /**
     * Execute a callback when a stream resource becomes writable or is closed for writing.
     *
     * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the
     * callback when closing the resource locally. Drivers MAY choose to notify the user if there are callbacks on
     * invalid resources, but are not required to, due to the high performance impact. Callbacks on closed resources are
     * therefore undefined behavior.
     *
     * Multiple callbacks on the same stream MAY be executed in any order.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param resource $stream The stream to monitor.
     * @param \Closure(string, resource):void $closure The callback to execute.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     */
    public static function onWritable(mixed $stream, \Closure $closure): string
    {
        return self::getDriver()->onWritable($stream, $closure);
    }

    /**
     * Execute a callback when a signal is received.
     *
     * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior.
     * Implementations MAY try to detect this, if possible, but are not required to. This is due to technical
     * limitations of the signals being registered globally per process.
     *
     * Multiple callbacks on the same signal MAY be executed in any order.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param int $signal The signal number to monitor.
     * @param \Closure(string, int):void $closure The callback to execute.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     *
     * @throws UnsupportedFeatureException If signal handling is not supported.
     */
    public static function onSignal(int $signal, \Closure $closure): string
    {
        return self::getDriver()->onSignal($signal, $closure);
    }

    /**
     * Enable a callback to be active starting in the next tick.
     *
     * Callbacks MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right
     * before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return string The callback identifier.
     *
     * @throws InvalidCallbackError If the callback identifier is invalid.
     */
    public static function enable(string $callbackId): string
    {
        return self::getDriver()->enable($callbackId);
    }

    /**
     * Disable a callback immediately.
     *
     * A callback MUST be disabled immediately, e.g. if a deferred callback disables another deferred callback,
     * the second deferred callback isn't executed in this tick.
     *
     * Disabling a callback MUST NOT invalidate the callback. Calling this function MUST NOT fail, even if passed an
     * invalid callback identifier.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return string The callback identifier.
     */
    public static function disable(string $callbackId): string
    {
        return self::getDriver()->disable($callbackId);
    }

    /**
     * Cancel a callback.
     *
     * This will detach the event loop from all resources that are associated to the callback. After this operation the
     * callback is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid identifier.
     *
     * @param string $callbackId The callback identifier.
     */
    public static function cancel(string $callbackId): void
    {
        self::getDriver()->cancel($callbackId);
    }

    /**
     * Reference a callback.
     *
     * This will keep the event loop alive whilst the event is still being monitored. Callbacks have this state by
     * default.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return string The callback identifier.
     *
     * @throws InvalidCallbackError If the callback identifier is invalid.
     */
    public static function reference(string $callbackId): string
    {
        return self::getDriver()->reference($callbackId);
    }

    /**
     * Unreference a callback.
     *
     * The event loop should exit the run method when only unreferenced callbacks are still being monitored. Callbacks
     * are all referenced by default.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return string The callback identifier.
     */
    public static function unreference(string $callbackId): string
    {
        return self::getDriver()->unreference($callbackId);
    }

    /**
     * Set a callback to be executed when an error occurs.
     *
     * The callback receives the error as the first and only parameter. The return value of the callback gets ignored.
     * If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation
     * MUST be thrown into the `run` loop and stop the driver.
     *
     * Subsequent calls to this method will overwrite the previous handler.
     *
     * @param null|\Closure(\Throwable):void $errorHandler The callback to execute. `null` will clear the current handler.
     */
    public static function setErrorHandler(?\Closure $errorHandler): void
    {
        self::getDriver()->setErrorHandler($errorHandler);
    }

    /**
     * Gets the error handler closure or {@code null} if none is set.
     *
     * @return null|\Closure(\Throwable):void The previous handler, `null` if there was none.
     */
    public static function getErrorHandler(): ?\Closure
    {
        return self::getDriver()->getErrorHandler();
    }

    /**
     * Returns all registered non-cancelled callback identifiers.
     *
     * @return string[] Callback identifiers.
     */
    public static function getIdentifiers(): array
    {
        return self::getDriver()->getIdentifiers();
    }

    /**
     * Returns the type of the callback identified by the given callback identifier.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return CallbackType The callback type.
     */
    public static function getType(string $callbackId): CallbackType
    {
        return self::getDriver()->getType($callbackId);
    }

    /**
     * Returns whether the callback identified by the given callback identifier is currently enabled.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return bool `true` if the callback is currently enabled, otherwise `false`.
     */
    public static function isEnabled(string $callbackId): bool
    {
        return self::getDriver()->isEnabled($callbackId);
    }

    /**
     * Returns whether the callback identified by the given callback identifier is currently referenced.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return bool `true` if the callback is currently referenced, otherwise `false`.
     */
    public static function isReferenced(string $callbackId): bool
    {
        return self::getDriver()->isReferenced($callbackId);
    }

    /**
     * Retrieve the event loop driver that is in scope.
     *
     * @return Driver
     */
    public static function getDriver(): Driver
    {
        /** @psalm-suppress RedundantPropertyInitializationCheck, RedundantCondition */
        if (!isset(self::$driver)) {
            self::setDriver((new DriverFactory())->create());
        }

        return self::$driver;
    }

    /**
     * Returns an object used to suspend and resume execution of the current fiber or {main}.
     *
     * Calls from the same fiber will return the same suspension object.
     *
     * @return Suspension
     */
    public static function getSuspension(): Suspension
    {
        return self::getDriver()->getSuspension();
    }

    /**
     * Run the event loop.
     *
     * This function may only be called from {main}, that is, not within a fiber.
     *
     * Libraries should use the {@link Suspension} API instead of calling this method.
     *
     * This method will not return until the event loop does not contain any pending, referenced callbacks anymore.
     */
    public static function run(): void
    {
        self::getDriver()->run();
    }

    /**
     * Disable construction as this is a static class.
     *
     * @psalm-suppress UnusedConstructor
     */
    private function __construct()
    {
        // intentionally left blank
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop;

use Revolt\EventLoop\Internal\ClosureHelper;

final class UncaughtThrowable extends \Error
{
    public static function throwingCallback(\Closure $closure, \Throwable $previous): self
    {
        return new self(
            "Uncaught %s thrown in event loop callback %s; use Revolt\EventLoop::setErrorHandler() to gracefully handle such exceptions%s",
            $closure,
            $previous
        );
    }

    public static function throwingErrorHandler(\Closure $closure, \Throwable $previous): self
    {
        return new self("Uncaught %s thrown in event loop error handler %s%s", $closure, $previous);
    }

    private function __construct(string $message, \Closure $closure, \Throwable $previous)
    {
        parent::__construct(\sprintf(
            $message,
            \str_replace("\0", '@', \get_class($previous)), // replace NUL-byte in anonymous class name
            ClosureHelper::getDescription($closure),
            $previous->getMessage() !== '' ? ': ' . $previous->getMessage() : ''
        ), 0, $previous);
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop;

// @codeCoverageIgnoreStart
use Revolt\EventLoop\Driver\EvDriver;
use Revolt\EventLoop\Driver\EventDriver;
use Revolt\EventLoop\Driver\StreamSelectDriver;
use Revolt\EventLoop\Driver\TracingDriver;
use Revolt\EventLoop\Driver\UvDriver;

final class DriverFactory
{
    /**
     * Creates a new loop instance and chooses the best available driver.
     *
     * @return Driver
     *
     * @throws \Error If an invalid class has been specified via REVOLT_LOOP_DRIVER
     */
    public function create(): Driver
    {
        $driver = (function () {
            if ($driver = $this->createDriverFromEnv()) {
                return $driver;
            }

            if (UvDriver::isSupported()) {
                return new UvDriver();
            }

            if (EvDriver::isSupported()) {
                return new EvDriver();
            }

            if (EventDriver::isSupported()) {
                return new EventDriver();
            }

            return new StreamSelectDriver();
        })();

        /** @psalm-suppress RiskyTruthyFalsyComparison */
        if (\getenv("REVOLT_DRIVER_DEBUG_TRACE")) {
            return new TracingDriver($driver);
        }

        return $driver;
    }

    /**
     * @return Driver|null
     */
    private function createDriverFromEnv(): ?Driver
    {
        $driver = \getenv("REVOLT_DRIVER");

        /** @psalm-suppress RiskyTruthyFalsyComparison */
        if (!$driver) {
            return null;
        }

        if (!\class_exists($driver)) {
            throw new \Error(\sprintf(
                "Driver '%s' does not exist.",
                $driver
            ));
        }

        if (!\is_subclass_of($driver, Driver::class)) {
            throw new \Error(\sprintf(
                "Driver '%s' is not a subclass of '%s'.",
                $driver,
                Driver::class
            ));
        }

        return new $driver();
    }
}
// @codeCoverageIgnoreEnd
<?php

declare(strict_types=1);

namespace Revolt\EventLoop;

enum CallbackType
{
    case Defer;
    case Delay;
    case Repeat;
    case Readable;
    case Writable;
    case Signal;
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop;

/**
 * MUST be thrown if a feature is not supported by the system.
 *
 * This might happen if ext-pcntl is missing and the loop driver doesn't support another way to dispatch signals.
 */
final class UnsupportedFeatureException extends \Exception
{
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Internal;

/** @internal */
final class ClosureHelper
{
    public static function getDescription(\Closure $closure): string
    {
        try {
            $reflection = new \ReflectionFunction($closure);

            $description = $reflection->name;

            if ($scopeClass = $reflection->getClosureScopeClass()) {
                $description = $scopeClass->name . '::' . $description;
            }

            if ($reflection->getFileName() !== false && $reflection->getStartLine()) {
                $description .= " defined in " . $reflection->getFileName() . ':' . $reflection->getStartLine();
            }

            return $description;
        } catch (\ReflectionException) {
            return '???';
        }
    }
}
<?php

/** @noinspection PhpPropertyOnlyWrittenInspection */

declare(strict_types=1);

namespace Revolt\EventLoop\Internal;

use Revolt\EventLoop\Suspension;

/**
 * @internal
 *
 * @template T
 * @implements Suspension<T>
 */
final class DriverSuspension implements Suspension
{
    /** @psalm-suppress UnusedProperty False-positive. */
    private ?\Fiber $suspendedFiber = null;

    /** @var \WeakReference<\Fiber>|null */
    private readonly ?\WeakReference $fiberRef;

    private ?\Error $error = null;

    private bool $pending = false;

    private bool $deadMain = false;

    /**
     * @param \WeakMap<object, \WeakReference<DriverSuspension>> $suspensions
     */
    public function __construct(
        private readonly \Closure $run,
        private readonly \Closure $queue,
        private readonly \Closure $interrupt,
        private readonly \WeakMap $suspensions,
    ) {
        $fiber = \Fiber::getCurrent();

        $this->fiberRef = $fiber ? \WeakReference::create($fiber) : null;
    }

    #[\Override]
    public function resume(mixed $value = null): void
    {
        // Ignore spurious resumes to old dead {main} suspension
        if ($this->deadMain) {
            return;
        }

        if (!$this->pending) {
            throw $this->error ?? new \Error('Must call suspend() before calling resume()');
        }

        $this->pending = false;

        $fiber = $this->fiberRef?->get();

        if ($fiber) {
            ($this->queue)(static function () use ($fiber, $value): void {
                // The fiber may be destroyed with suspension as part of the GC cycle collector.
                if (!$fiber->isTerminated()) {
                    $fiber->resume($value);
                }
            });
        } else {
            // Suspend event loop fiber to {main}.
            ($this->interrupt)(static fn () => $value);
        }
    }

    #[\Override]
    public function suspend(): mixed
    {
        // Throw exception when trying to use old dead {main} suspension
        if ($this->deadMain) {
            throw new \Error(
                'Suspension cannot be suspended after an uncaught exception is thrown from the event loop',
            );
        }

        if ($this->pending) {
            throw new \Error('Must call resume() or throw() before calling suspend() again');
        }

        $fiber = $this->fiberRef?->get();

        if ($fiber !== \Fiber::getCurrent()) {
            throw new \Error('Must not call suspend() from another fiber');
        }

        $this->pending = true;
        $this->error = null;

        // Awaiting from within a fiber.
        if ($fiber) {
            $this->suspendedFiber = $fiber;

            try {
                $value = \Fiber::suspend();
                $this->suspendedFiber = null;
            } catch (\FiberError $error) {
                $this->pending = false;
                $this->suspendedFiber = null;
                $this->error = $error;

                throw $error;
            }

            // Setting $this->suspendedFiber = null in finally will set the fiber to null if a fiber is destroyed
            // as part of a cycle collection, causing an error if the suspension is subsequently resumed.

            return $value;
        }

        // Awaiting from {main}.
        $result = ($this->run)();

        /** @psalm-suppress RedundantCondition $this->pending should be changed when resumed. */
        if ($this->pending) {
            // This is now a dead {main} suspension.
            $this->deadMain = true;

            // Unset suspension for {main} using queue closure.
            unset($this->suspensions[$this->queue]);

            $result && $result(); // Unwrap any uncaught exceptions from the event loop

            \gc_collect_cycles(); // Collect any circular references before dumping pending suspensions.

            $info = '';
            foreach ($this->suspensions as $suspensionRef) {
                if ($suspension = $suspensionRef->get()) {
                    \assert($suspension instanceof self);
                    $fiber = $suspension->fiberRef?->get();
                    if ($fiber === null) {
                        continue;
                    }

                    $reflectionFiber = new \ReflectionFiber($fiber);
                    $info .= "\n\n" . $this->formatStacktrace($reflectionFiber->getTrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
                }
            }

            throw new \Error('Event loop terminated without resuming the current suspension (the cause is either a fiber deadlock, or an incorrectly unreferenced/canceled watcher):' . $info);
        }

        return $result();
    }

    #[\Override]
    public function throw(\Throwable $throwable): void
    {
        // Ignore spurious resumes to old dead {main} suspension
        if ($this->deadMain) {
            return;
        }

        if (!$this->pending) {
            throw $this->error ?? new \Error('Must call suspend() before calling throw()');
        }

        $this->pending = false;

        $fiber = $this->fiberRef?->get();

        if ($fiber) {
            ($this->queue)(static function () use ($fiber, $throwable): void {
                // The fiber may be destroyed with suspension as part of the GC cycle collector.
                if (!$fiber->isTerminated()) {
                    $fiber->throw($throwable);
                }
            });
        } else {
            // Suspend event loop fiber to {main}.
            ($this->interrupt)(static fn () => throw $throwable);
        }
    }

    private function formatStacktrace(array $trace): string
    {
        return \implode("\n", \array_map(static function ($e, $i) {
            $line = "#{$i} ";

            if (isset($e["file"])) {
                $line .= "{$e['file']}:{$e['line']} ";
            }

            if (isset($e["class"], $e["type"])) {
                $line .= $e["class"] . $e["type"];
            }

            return $line . $e["function"] . "()";
        }, $trace, \array_keys($trace)));
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Internal;

use Revolt\EventLoop\CallbackType;
use Revolt\EventLoop\Driver;
use Revolt\EventLoop\FiberLocal;
use Revolt\EventLoop\InvalidCallbackError;
use Revolt\EventLoop\Suspension;
use Revolt\EventLoop\UncaughtThrowable;

/**
 * Event loop driver which implements all basic operations to allow interoperability.
 *
 * Callbacks (enabled or new callbacks) MUST immediately be marked as enabled, but only be activated (i.e. callbacks can
 * be called) right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
 *
 * @internal
 */
abstract class AbstractDriver implements Driver
{
    /** @var string Next callback identifier. */
    private string $nextId = "a";

    private \Fiber $fiber;

    private \Fiber $callbackFiber;
    private \Closure $errorCallback;

    /** @var array<string, DriverCallback> */
    private array $callbacks = [];

    /** @var array<string, DriverCallback> */
    private array $enableQueue = [];

    /** @var array<string, DriverCallback> */
    private array $enableDeferQueue = [];

    /** @var null|\Closure(\Throwable):void */
    private ?\Closure $errorHandler = null;

    /** @var null|\Closure():mixed */
    private ?\Closure $interrupt = null;

    private readonly \Closure $interruptCallback;
    private readonly \Closure $queueCallback;

    /** @var \Closure():(null|\Closure(): mixed) */
    private readonly \Closure $runCallback;

    private readonly \stdClass $internalSuspensionMarker;

    /** @var \SplQueue<array{\Closure, array}> */
    private readonly \SplQueue $microtaskQueue;

    /** @var \SplQueue<DriverCallback> */
    private readonly \SplQueue $callbackQueue;

    private bool $idle = false;
    private bool $stopped = false;

    /** @var \WeakMap<object, \WeakReference<DriverSuspension>> */
    private \WeakMap $suspensions;

    public function __construct()
    {
        if (\PHP_VERSION_ID < 80117 || \PHP_VERSION_ID >= 80200 && \PHP_VERSION_ID < 80204) {
            // PHP GC is broken on early 8.1 and 8.2 versions, see https://github.com/php/php-src/issues/10496
            /** @psalm-suppress RiskyTruthyFalsyComparison */
            if (!\getenv('REVOLT_DRIVER_SUPPRESS_ISSUE_10496')) {
                throw new \Error('Your version of PHP is affected by serious garbage collector bugs related to fibers. Please upgrade to a newer version of PHP, i.e. >= 8.1.17 or => 8.2.4');
            }
        }

        $this->suspensions = new \WeakMap();

        $this->internalSuspensionMarker = new \stdClass();
        $this->microtaskQueue = new \SplQueue();
        $this->callbackQueue = new \SplQueue();

        $this->createLoopFiber();
        $this->createCallbackFiber();
        $this->createErrorCallback();

        /** @psalm-suppress InvalidArgument */
        $this->interruptCallback = $this->setInterrupt(...);
        $this->queueCallback = $this->queue(...);
        $this->runCallback = function (): ?\Closure {
            do {
                if ($this->fiber->isTerminated()) {
                    $this->createLoopFiber();
                }

                $result = $this->fiber->isStarted() ? $this->fiber->resume() : $this->fiber->start();
                if ($result) { // Null indicates the loop fiber terminated without suspending.
                    return $result;
                }
            } while (\gc_collect_cycles() && !$this->stopped);

            return null;
        };
    }

    #[\Override]
    public function run(): void
    {
        if ($this->fiber->isRunning()) {
            throw new \Error("The event loop is already running");
        }

        if (\Fiber::getCurrent()) {
            throw new \Error(\sprintf("Can't call %s() within a fiber (i.e., outside of {main})", __METHOD__));
        }

        $lambda = ($this->runCallback)();

        if ($lambda) {
            $lambda();

            throw new \Error(
                'Interrupt from event loop must throw an exception: ' . ClosureHelper::getDescription($lambda)
            );
        }
    }

    #[\Override]
    public function stop(): void
    {
        $this->stopped = true;
    }

    #[\Override]
    public function isRunning(): bool
    {
        return $this->fiber->isRunning() || $this->fiber->isSuspended();
    }

    #[\Override]
    public function queue(\Closure $closure, mixed ...$args): void
    {
        $this->microtaskQueue->enqueue([$closure, $args]);
    }

    #[\Override]
    public function defer(\Closure $closure): string
    {
        $deferCallback = new DeferCallback($this->callbackId(), $closure);

        $this->callbacks[$deferCallback->id] = $deferCallback;
        $this->enableDeferQueue[$deferCallback->id] = $deferCallback;

        return $deferCallback->id;
    }

    #[\Override]
    public function delay(float $delay, \Closure $closure): string
    {
        if ($delay < 0) {
            throw new \Error("Delay must be greater than or equal to zero");
        }

        $timerCallback = new TimerCallback($this->callbackId(), $delay, $closure, $this->now() + $delay);

        $this->callbacks[$timerCallback->id] = $timerCallback;
        $this->enableQueue[$timerCallback->id] = $timerCallback;

        return $timerCallback->id;
    }

    #[\Override]
    public function repeat(float $interval, \Closure $closure): string
    {
        if ($interval < 0) {
            throw new \Error("Interval must be greater than or equal to zero");
        }

        $timerCallback = new TimerCallback($this->callbackId(), $interval, $closure, $this->now() + $interval, true);

        $this->callbacks[$timerCallback->id] = $timerCallback;
        $this->enableQueue[$timerCallback->id] = $timerCallback;

        return $timerCallback->id;
    }

    #[\Override]
    public function onReadable(mixed $stream, \Closure $closure): string
    {
        $streamCallback = new StreamReadableCallback($this->callbackId(), $closure, $stream);

        $this->callbacks[$streamCallback->id] = $streamCallback;
        $this->enableQueue[$streamCallback->id] = $streamCallback;

        return $streamCallback->id;
    }

    #[\Override]
    public function onWritable($stream, \Closure $closure): string
    {
        $streamCallback = new StreamWritableCallback($this->callbackId(), $closure, $stream);

        $this->callbacks[$streamCallback->id] = $streamCallback;
        $this->enableQueue[$streamCallback->id] = $streamCallback;

        return $streamCallback->id;
    }

    #[\Override]
    public function onSignal(int $signal, \Closure $closure): string
    {
        $signalCallback = new SignalCallback($this->callbackId(), $closure, $signal);

        $this->callbacks[$signalCallback->id] = $signalCallback;
        $this->enableQueue[$signalCallback->id] = $signalCallback;

        return $signalCallback->id;
    }

    #[\Override]
    public function enable(string $callbackId): string
    {
        if (!isset($this->callbacks[$callbackId])) {
            throw InvalidCallbackError::invalidIdentifier($callbackId);
        }

        $callback = $this->callbacks[$callbackId];

        if ($callback->enabled) {
            return $callbackId; // Callback already enabled.
        }

        $callback->enabled = true;

        if ($callback instanceof DeferCallback) {
            $this->enableDeferQueue[$callback->id] = $callback;
        } elseif ($callback instanceof TimerCallback) {
            $callback->expiration = $this->now() + $callback->interval;
            $this->enableQueue[$callback->id] = $callback;
        } else {
            $this->enableQueue[$callback->id] = $callback;
        }

        return $callbackId;
    }

    #[\Override]
    public function cancel(string $callbackId): void
    {
        $this->disable($callbackId);
        unset($this->callbacks[$callbackId]);
    }

    #[\Override]
    public function disable(string $callbackId): string
    {
        if (!isset($this->callbacks[$callbackId])) {
            return $callbackId;
        }

        $callback = $this->callbacks[$callbackId];

        if (!$callback->enabled) {
            return $callbackId; // Callback already disabled.
        }

        $callback->enabled = false;
        $callback->invokable = false;
        $id = $callback->id;

        if ($callback instanceof DeferCallback) {
            // Callback was only queued to be enabled.
            unset($this->enableDeferQueue[$id]);
        } elseif (isset($this->enableQueue[$id])) {
            // Callback was only queued to be enabled.
            unset($this->enableQueue[$id]);
        } else {
            $this->deactivate($callback);
        }

        return $callbackId;
    }

    #[\Override]
    public function reference(string $callbackId): string
    {
        if (!isset($this->callbacks[$callbackId])) {
            throw InvalidCallbackError::invalidIdentifier($callbackId);
        }

        $this->callbacks[$callbackId]->referenced = true;

        return $callbackId;
    }

    #[\Override]
    public function unreference(string $callbackId): string
    {
        if (!isset($this->callbacks[$callbackId])) {
            return $callbackId;
        }

        $this->callbacks[$callbackId]->referenced = false;

        return $callbackId;
    }

    #[\Override]
    public function getSuspension(): Suspension
    {
        $fiber = \Fiber::getCurrent();

        // User callbacks are always executed outside the event loop fiber, so this should always be false.
        \assert($fiber !== $this->fiber);

        // Use queue closure in case of {main}, which can be unset by DriverSuspension after an uncaught exception.
        $key = $fiber ?? $this->queueCallback;

        $suspension = ($this->suspensions[$key] ?? null)?->get();
        if ($suspension) {
            return $suspension;
        }

        $suspension = new DriverSuspension(
            $this->runCallback,
            $this->queueCallback,
            $this->interruptCallback,
            $this->suspensions,
        );

        $this->suspensions[$key] = \WeakReference::create($suspension);

        return $suspension;
    }

    #[\Override]
    public function setErrorHandler(?\Closure $errorHandler): void
    {
        $this->errorHandler = $errorHandler;
    }

    #[\Override]
    public function getErrorHandler(): ?\Closure
    {
        return $this->errorHandler;
    }

    #[\Override]
    public function __debugInfo(): array
    {
        // @codeCoverageIgnoreStart
        return \array_map(fn (DriverCallback $callback) => [
            'type' => $this->getType($callback->id),
            'enabled' => $callback->enabled,
            'referenced' => $callback->referenced,
        ], $this->callbacks);
        // @codeCoverageIgnoreEnd
    }

    #[\Override]
    public function getIdentifiers(): array
    {
        return \array_keys($this->callbacks);
    }

    #[\Override]
    public function getType(string $callbackId): CallbackType
    {
        $callback = $this->callbacks[$callbackId] ?? throw InvalidCallbackError::invalidIdentifier($callbackId);

        return match ($callback::class) {
            DeferCallback::class => CallbackType::Defer,
            TimerCallback::class => $callback->repeat ? CallbackType::Repeat : CallbackType::Delay,
            StreamReadableCallback::class => CallbackType::Readable,
            StreamWritableCallback::class => CallbackType::Writable,
            SignalCallback::class => CallbackType::Signal,
        };
    }

    #[\Override]
    public function isEnabled(string $callbackId): bool
    {
        $callback = $this->callbacks[$callbackId] ?? throw InvalidCallbackError::invalidIdentifier($callbackId);

        return $callback->enabled;
    }

    #[\Override]
    public function isReferenced(string $callbackId): bool
    {
        $callback = $this->callbacks[$callbackId] ?? throw InvalidCallbackError::invalidIdentifier($callbackId);

        return $callback->referenced;
    }

    /**
     * Activates (enables) all the given callbacks.
     */
    abstract protected function activate(array $callbacks): void;

    /**
     * Dispatches any pending read/write, timer, and signal events.
     */
    abstract protected function dispatch(bool $blocking): void;

    /**
     * Deactivates (disables) the given callback.
     */
    abstract protected function deactivate(DriverCallback $callback): void;

    final protected function enqueueCallback(DriverCallback $callback): void
    {
        $this->callbackQueue->enqueue($callback);
        $this->idle = false;
    }

    /**
     * Invokes the error handler with the given exception.
     *
     * @param \Throwable $exception The exception thrown from an event callback.
     */
    final protected function error(\Closure $closure, \Throwable $exception): void
    {
        if ($this->errorHandler === null) {
            // Explicitly override the previous interrupt if it exists in this case, hiding the exception is worse
            $this->interrupt = static fn () => $exception instanceof UncaughtThrowable
                ? throw $exception
                : throw UncaughtThrowable::throwingCallback($closure, $exception);
            return;
        }

        $fiber = new \Fiber($this->errorCallback);

        /** @noinspection PhpUnhandledExceptionInspection */
        $fiber->start($this->errorHandler, $exception);
    }

    /**
     * Returns the current event loop time in second increments.
     *
     * Note this value does not necessarily correlate to wall-clock time, rather the value returned is meant to be used
     * in relative comparisons to prior values returned by this method (intervals, expiration calculations, etc.).
     */
    abstract protected function now(): float;

    private function invokeMicrotasks(): void
    {
        while (!$this->microtaskQueue->isEmpty()) {
            [$callback, $args] = $this->microtaskQueue->dequeue();

            try {
                // Clear $args to allow garbage collection
                $callback(...$args, ...($args = []));
            } catch (\Throwable $exception) {
                $this->error($callback, $exception);
            } finally {
                FiberLocal::clear();
            }

            unset($callback, $args);

            if ($this->interrupt) {
                /** @noinspection PhpUnhandledExceptionInspection */
                \Fiber::suspend($this->internalSuspensionMarker);
            }
        }
    }

    /**
     * @return bool True if no enabled and referenced callbacks remain in the loop.
     */
    private function isEmpty(): bool
    {
        foreach ($this->callbacks as $callback) {
            if ($callback->enabled && $callback->referenced) {
                return false;
            }
        }

        return true;
    }

    /**
     * Executes a single tick of the event loop.
     */
    private function tick(bool $previousIdle): void
    {
        $this->activate($this->enableQueue);

        foreach ($this->enableQueue as $callback) {
            $callback->invokable = true;
        }

        $this->enableQueue = [];

        foreach ($this->enableDeferQueue as $callback) {
            $callback->invokable = true;
            $this->enqueueCallback($callback);
        }

        $this->enableDeferQueue = [];

        $blocking = $previousIdle
            && !$this->stopped
            && !$this->isEmpty();

        if ($blocking) {
            $this->invokeCallbacks();

            /** @psalm-suppress TypeDoesNotContainType */
            if (!empty($this->enableDeferQueue) || !empty($this->enableQueue)) {
                $blocking = false;
            }
        }

        /** @psalm-suppress RedundantCondition */
        $this->dispatch($blocking);
    }

    private function invokeCallbacks(): void
    {
        while (!$this->microtaskQueue->isEmpty() || !$this->callbackQueue->isEmpty()) {
            /** @noinspection PhpUnhandledExceptionInspection */
            if ($this->callbackFiber->isSuspended()) {
                $yielded = $this->callbackFiber->resume();
            } else {
                if ($this->callbackFiber->isTerminated()) {
                    $this->createCallbackFiber();
                }
                $yielded = $this->callbackFiber->start();
            }

            if ($yielded !== $this->internalSuspensionMarker) {
                $this->createCallbackFiber();
            }

            if ($this->interrupt) {
                $this->invokeInterrupt();
            }
        }
    }

    /**
     * @param \Closure():mixed $interrupt
     */
    private function setInterrupt(\Closure $interrupt): void
    {
        \assert($this->interrupt === null);

        $this->interrupt = $interrupt;
    }

    private function invokeInterrupt(): void
    {
        \assert($this->interrupt !== null);

        $interrupt = $this->interrupt;
        $this->interrupt = null;

        /** @noinspection PhpUnhandledExceptionInspection */
        \Fiber::suspend($interrupt);
    }

    private function createLoopFiber(): void
    {
        $this->fiber = new \Fiber(function (): void {
            $this->stopped = false;

            // Invoke microtasks if we have some
            $this->invokeCallbacks();

            /** @psalm-suppress RedundantCondition $this->stopped may be changed by $this->invokeCallbacks(). */
            while (!$this->stopped) {
                if ($this->interrupt) {
                    $this->invokeInterrupt();
                }

                if ($this->isEmpty()) {
                    return;
                }

                $previousIdle = $this->idle;
                $this->idle = true;

                $this->tick($previousIdle);
                $this->invokeCallbacks();
            }
        });
    }

    private function createCallbackFiber(): void
    {
        $this->callbackFiber = new \Fiber(function (): void {
            do {
                $this->invokeMicrotasks();

                while (!$this->callbackQueue->isEmpty()) {
                    $callback = $this->callbackQueue->dequeue();

                    if (!isset($this->callbacks[$callback->id]) || !$callback->invokable) {
                        unset($callback);

                        continue;
                    }

                    if ($callback instanceof DeferCallback) {
                        $this->cancel($callback->id);
                    } elseif ($callback instanceof TimerCallback) {
                        if (!$callback->repeat) {
                            $this->cancel($callback->id);
                        } else {
                            // Disable and re-enable, so it's not executed repeatedly in the same tick
                            // See https://github.com/amphp/amp/issues/131
                            $this->disable($callback->id);
                            $this->enable($callback->id);
                        }
                    }

                    try {
                        $result = match (true) {
                            $callback instanceof StreamCallback => ($callback->closure)(
                                $callback->id,
                                $callback->stream
                            ),
                            $callback instanceof SignalCallback => ($callback->closure)(
                                $callback->id,
                                $callback->signal
                            ),
                            default => ($callback->closure)($callback->id),
                        };

                        if ($result !== null) {
                            throw InvalidCallbackError::nonNullReturn($callback->id, $callback->closure);
                        }
                    } catch (\Throwable $exception) {
                        $this->error($callback->closure, $exception);
                    } finally {
                        FiberLocal::clear();
                    }

                    unset($callback);

                    if ($this->interrupt) {
                        /** @noinspection PhpUnhandledExceptionInspection */
                        \Fiber::suspend($this->internalSuspensionMarker);
                    }

                    $this->invokeMicrotasks();
                }

                /** @noinspection PhpUnhandledExceptionInspection */
                \Fiber::suspend($this->internalSuspensionMarker);
            } while (true);
        });
    }

    private function createErrorCallback(): void
    {
        $this->errorCallback = function (\Closure $errorHandler, \Throwable $exception): void {
            try {
                $errorHandler($exception);
            } catch (\Throwable $exception) {
                $this->interrupt = static fn () => $exception instanceof UncaughtThrowable
                    ? throw $exception
                    : throw UncaughtThrowable::throwingErrorHandler($errorHandler, $exception);
            }
        };
    }

    private function callbackId(): string
    {
        $callbackId = $this->nextId;

        if (\PHP_VERSION_ID >= 80300) {
            /** @psalm-suppress UndefinedFunction */
            $this->nextId = \str_increment($this->nextId);
        } else {
            $this->nextId++;
        }

        return $callbackId;
    }

    final public function __serialize(): never
    {
        throw new \Error(__CLASS__ . ' does not support serialization');
    }

    /**
     * @psalm-suppress UnusedParam $data param required.
     */
    final public function __unserialize(array $data): never
    {
        throw new \Error(__CLASS__ . ' does not support deserialization');
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Internal;

/** @internal */
final class TimerCallback extends DriverCallback
{
    public function __construct(
        string $id,
        public readonly float $interval,
        \Closure $callback,
        public float $expiration,
        public readonly bool $repeat = false
    ) {
        parent::__construct($id, $callback);
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Internal;

/** @internal */
final class StreamWritableCallback extends StreamCallback
{
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Internal;

/**
 * Uses a binary tree stored in an array to implement a heap.
 *
 * @internal
 */
final class TimerQueue
{
    /** @var array<int, TimerCallback> */
    private array $callbacks = [];

    /** @var array<string, int> */
    private array $pointers = [];

    /**
     * Inserts the callback into the queue.
     *
     * Time complexity: O(log(n)).
     */
    public function insert(TimerCallback $callback): void
    {
        \assert(!isset($this->pointers[$callback->id]));

        $node = \count($this->callbacks);
        $this->callbacks[$node] = $callback;
        $this->pointers[$callback->id] = $node;

        $this->heapifyUp($node);
    }

    /**
     * Removes the given callback from the queue.
     *
     * Time complexity: O(log(n)).
     */
    public function remove(TimerCallback $callback): void
    {
        $id = $callback->id;

        if (!isset($this->pointers[$id])) {
            return;
        }

        $this->removeAndRebuild($this->pointers[$id]);
    }

    /**
     * Deletes and returns the callback on top of the heap if it has expired, otherwise null is returned.
     *
     * Time complexity: O(log(n)).
     *
     * @param float $now Current event loop time.
     *
     * @return TimerCallback|null Expired callback at the top of the heap or null if the callback has not expired.
     */
    public function extract(float $now): ?TimerCallback
    {
        if (!$this->callbacks) {
            return null;
        }

        $callback = $this->callbacks[0];
        if ($callback->expiration > $now) {
            return null;
        }

        $this->removeAndRebuild(0);

        return $callback;
    }

    /**
     * Returns the expiration time value at the top of the heap.
     *
     * Time complexity: O(1).
     *
     * @return float|null Expiration time of the callback at the top of the heap or null if the heap is empty.
     */
    public function peek(): ?float
    {
        return isset($this->callbacks[0]) ? $this->callbacks[0]->expiration : null;
    }

    /**
     * @param int $node Rebuild the data array from the given node upward.
     */
    private function heapifyUp(int $node): void
    {
        $entry = $this->callbacks[$node];
        while ($node !== 0 && $entry->expiration < $this->callbacks[$parent = ($node - 1) >> 1]->expiration) {
            $this->swap($node, $parent);
            $node = $parent;
        }
    }

    /**
     * @param int $node Rebuild the data array from the given node downward.
     */
    private function heapifyDown(int $node): void
    {
        $length = \count($this->callbacks);
        while (($child = ($node << 1) + 1) < $length) {
            if ($this->callbacks[$child]->expiration < $this->callbacks[$node]->expiration
                && ($child + 1 >= $length || $this->callbacks[$child]->expiration < $this->callbacks[$child + 1]->expiration)
            ) {
                // Left child is less than parent and right child.
                $swap = $child;
            } elseif ($child + 1 < $length && $this->callbacks[$child + 1]->expiration < $this->callbacks[$node]->expiration) {
                // Right child is less than parent and left child.
                $swap = $child + 1;
            } else { // Left and right child are greater than parent.
                break;
            }

            $this->swap($node, $swap);
            $node = $swap;
        }
    }

    private function swap(int $left, int $right): void
    {
        $temp = $this->callbacks[$left];

        $this->callbacks[$left] = $this->callbacks[$right];
        $this->pointers[$this->callbacks[$right]->id] = $left;

        $this->callbacks[$right] = $temp;
        $this->pointers[$temp->id] = $right;
    }

    /**
     * @param int $node Remove the given node and then rebuild the data array.
     */
    private function removeAndRebuild(int $node): void
    {
        $length = \count($this->callbacks) - 1;
        $id = $this->callbacks[$node]->id;
        $left = $this->callbacks[$node] = $this->callbacks[$length];
        $this->pointers[$left->id] = $node;
        unset($this->callbacks[$length], $this->pointers[$id]);

        if ($node < $length) { // don't need to do anything if we removed the last element
            $parent = ($node - 1) >> 1;
            if ($parent >= 0 && $this->callbacks[$node]->expiration < $this->callbacks[$parent]->expiration) {
                $this->heapifyUp($node);
            } else {
                $this->heapifyDown($node);
            }
        }
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Internal;

/** @internal */
final class DeferCallback extends DriverCallback
{
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Internal;

/** @internal */
abstract class StreamCallback extends DriverCallback
{
    /**
     * @param resource $stream
     */
    public function __construct(
        string $id,
        \Closure $closure,
        public readonly mixed $stream
    ) {
        parent::__construct($id, $closure);
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Internal;

/** @internal */
final class StreamReadableCallback extends StreamCallback
{
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Internal;

/**
 * @internal
 */
abstract class DriverCallback
{
    public bool $invokable = false;

    public bool $enabled = true;

    public bool $referenced = true;

    public function __construct(
        public readonly string $id,
        public readonly \Closure $closure
    ) {
    }

    /**
     * @param string $property
     */
    public function __get(string $property): never
    {
        throw new \Error("Unknown property '{$property}'");
    }

    /**
     * @param string $property
     * @param mixed  $value
     */
    public function __set(string $property, mixed $value): never
    {
        throw new \Error("Unknown property '{$property}'");
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Internal;

/** @internal */
final class SignalCallback extends DriverCallback
{
    public function __construct(
        string $id,
        \Closure $closure,
        public readonly int $signal
    ) {
        parent::__construct($id, $closure);
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop;

/**
 * Fiber local storage.
 *
 * Each instance stores data separately for each fiber. Usage examples include contextual logging data.
 *
 * @template T
 */
final class FiberLocal
{
    /** @var \Fiber|null Dummy fiber for {main} */
    private static ?\Fiber $mainFiber = null;
    private static ?\WeakMap $localStorage = null;

    public static function clear(): void
    {
        if (self::$localStorage === null) {
            return;
        }

        $fiber = \Fiber::getCurrent() ?? self::$mainFiber;

        if ($fiber === null) {
            return;
        }

        unset(self::$localStorage[$fiber]);
    }

    private static function getFiberStorage(): \WeakMap
    {
        $fiber = \Fiber::getCurrent();

        if ($fiber === null) {
            $fiber = self::$mainFiber ??= new \Fiber(static function (): void {
                // dummy fiber for main, as we need some object for the WeakMap
            });
        }

        $localStorage = self::$localStorage ??= new \WeakMap();
        return $localStorage[$fiber] ??= new \WeakMap();
    }

    /**
     * @param \Closure():T $initializer
     */
    public function __construct(private readonly \Closure $initializer)
    {
    }

    /**
     * @param T $value
     */
    public function set(mixed $value): void
    {
        self::getFiberStorage()[$this] = [$value];
    }

    public function unset(): void
    {
        unset(self::getFiberStorage()[$this]);
    }

    /**
     * @return T
     */
    public function get(): mixed
    {
        $fiberStorage = self::getFiberStorage();

        if (!isset($fiberStorage[$this])) {
            $fiberStorage[$this] = [($this->initializer)()];
        }

        return $fiberStorage[$this][0];
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop;

use Revolt\EventLoop\Internal\ClosureHelper;

final class InvalidCallbackError extends \Error
{
    public const E_NONNULL_RETURN = 1;
    public const E_INVALID_IDENTIFIER = 2;

    /**
     * MUST be thrown if any callback returns a non-null value.
     */
    public static function nonNullReturn(string $callbackId, \Closure $closure): self
    {
        return new self(
            $callbackId,
            self::E_NONNULL_RETURN,
            'Non-null return value received from callback ' . ClosureHelper::getDescription($closure)
        );
    }

    /**
     * MUST be thrown if any operation (except disable() and cancel()) is attempted with an invalid callback identifier.
     *
     * An invalid callback identifier is any identifier that is not yet emitted by the driver or cancelled by the user.
     */
    public static function invalidIdentifier(string $callbackId): self
    {
        return new self($callbackId, self::E_INVALID_IDENTIFIER, 'Invalid callback identifier ' . $callbackId);
    }

    /** @var string */
    private readonly string $rawMessage;

    /** @var string */
    private readonly string $callbackId;

    /** @var array<string, string> */
    private array $info = [];

    /**
     * @param string $callbackId The callback identifier.
     * @param string $message The exception message.
     */
    private function __construct(string $callbackId, int $code, string $message)
    {
        parent::__construct($message, $code);

        $this->callbackId = $callbackId;
        $this->rawMessage = $message;
    }

    /**
     * @return string The callback identifier.
     */
    public function getCallbackId(): string
    {
        return $this->callbackId;
    }

    public function addInfo(string $key, string $message): void
    {
        $this->info[$key] = $message;

        $info = '';

        foreach ($this->info as $infoKey => $infoMessage) {
            $info .= "\r\n\r\n" . $infoKey . ': ' . $infoMessage;
        }

        $this->message = $this->rawMessage . $info;
    }
}
<?php

declare(strict_types=1);

/** @noinspection PhpComposerExtensionStubsInspection */

namespace Revolt\EventLoop\Driver;

use Revolt\EventLoop\Internal\AbstractDriver;
use Revolt\EventLoop\Internal\DriverCallback;
use Revolt\EventLoop\Internal\SignalCallback;
use Revolt\EventLoop\Internal\StreamCallback;
use Revolt\EventLoop\Internal\StreamReadableCallback;
use Revolt\EventLoop\Internal\StreamWritableCallback;
use Revolt\EventLoop\Internal\TimerCallback;

final class EventDriver extends AbstractDriver
{
    /** @var array<string, \Event>|null */
    private static ?array $activeSignals = null;

    public static function isSupported(): bool
    {
        return \extension_loaded("event");
    }

    private \EventBase $handle;
    /** @var array<string, \Event> */
    private array $events = [];
    private readonly \Closure $ioCallback;
    private readonly \Closure $timerCallback;
    private readonly \Closure $signalCallback;

    /** @var array<string, \Event> */
    private array $signals = [];

    public function __construct()
    {
        parent::__construct();

        /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */
        $this->handle = new \EventBase();

        if (self::$activeSignals === null) {
            self::$activeSignals = &$this->signals;
        }

        $this->ioCallback = function ($resource, $what, StreamCallback $callback): void {
            $this->enqueueCallback($callback);
        };

        $this->timerCallback = function ($resource, $what, TimerCallback $callback): void {
            $this->enqueueCallback($callback);
        };

        $this->signalCallback = function ($signo, $what, SignalCallback $callback): void {
            $this->enqueueCallback($callback);
        };
    }

    #[\Override]
    public function cancel(string $callbackId): void
    {
        parent::cancel($callbackId);

        if (isset($this->events[$callbackId])) {
            $this->events[$callbackId]->free();
            unset($this->events[$callbackId]);
        }
    }

    /**
     * @codeCoverageIgnore
     */
    public function __destruct()
    {
        foreach ($this->events as $event) {
            if ($event !== null) { // Events may have been nulled in extension depending on destruct order.
                $event->free();
            }
        }

        // Unset here, otherwise $event->del() fails with a warning, because __destruct order isn't defined.
        // See https://github.com/amphp/amp/issues/159.
        $this->events = [];

        // Manually free the loop handle to fully release loop resources.
        // See https://github.com/amphp/amp/issues/177.
        /** @psalm-suppress RedundantPropertyInitializationCheck */
        if (isset($this->handle)) {
            $this->handle->free();

            // Reinitialize the loop handle due to indeterminate destruct order.
            // See https://github.com/revoltphp/event-loop/issues/105
            /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */
            $this->handle = new \EventBase();
        }
    }

    #[\Override]
    public function run(): void
    {
        $active = self::$activeSignals;

        \assert($active !== null);

        foreach ($active as $event) {
            $event->del();
        }

        self::$activeSignals = &$this->signals;

        foreach ($this->signals as $event) {
            /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */
            $event->add();
        }

        try {
            parent::run();
        } finally {
            foreach ($this->signals as $event) {
                $event->del();
            }

            self::$activeSignals = &$active;

            foreach ($active as $event) {
                /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */
                $event->add();
            }
        }
    }

    #[\Override]
    public function stop(): void
    {
        $this->handle->stop();
        parent::stop();
    }

    #[\Override]
    public function getHandle(): \EventBase
    {
        return $this->handle;
    }

    #[\Override]
    protected function now(): float
    {
        return (float) \hrtime(true) / 1_000_000_000;
    }

    #[\Override]
    protected function dispatch(bool $blocking): void
    {
        $this->handle->loop($blocking ? \EventBase::LOOP_ONCE : \EventBase::LOOP_ONCE | \EventBase::LOOP_NONBLOCK);
    }

    #[\Override]
    protected function activate(array $callbacks): void
    {
        $now = $this->now();

        foreach ($callbacks as $callback) {
            if (!isset($this->events[$id = $callback->id])) {
                if ($callback instanceof StreamReadableCallback) {
                    \assert(\is_resource($callback->stream));

                    $this->events[$id] = new \Event(
                        $this->handle,
                        $callback->stream,
                        \Event::READ | \Event::PERSIST,
                        $this->ioCallback,
                        $callback
                    );
                } elseif ($callback instanceof StreamWritableCallback) {
                    \assert(\is_resource($callback->stream));

                    $this->events[$id] = new \Event(
                        $this->handle,
                        $callback->stream,
                        \Event::WRITE | \Event::PERSIST,
                        $this->ioCallback,
                        $callback
                    );
                } elseif ($callback instanceof TimerCallback) {
                    $this->events[$id] = new \Event(
                        $this->handle,
                        -1,
                        \Event::TIMEOUT,
                        $this->timerCallback,
                        $callback
                    );
                } elseif ($callback instanceof SignalCallback) {
                    $this->events[$id] = new \Event(
                        $this->handle,
                        $callback->signal,
                        \Event::SIGNAL | \Event::PERSIST,
                        $this->signalCallback,
                        $callback
                    );
                } else {
                    // @codeCoverageIgnoreStart
                    throw new \Error("Unknown callback type");
                    // @codeCoverageIgnoreEnd
                }
            }

            if ($callback instanceof TimerCallback) {
                $interval = \min(\max(0, $callback->expiration - $now), \PHP_INT_MAX / 2);
                $this->events[$id]->add($interval > 0 ? $interval : 0);
            } elseif ($callback instanceof SignalCallback) {
                $this->signals[$id] = $this->events[$id];
                /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */
                $this->events[$id]->add();
            } else {
                /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */
                $this->events[$id]->add();
            }
        }
    }

    #[\Override]
    protected function deactivate(DriverCallback $callback): void
    {
        if (isset($this->events[$id = $callback->id])) {
            $this->events[$id]->del();

            if ($callback instanceof SignalCallback) {
                unset($this->signals[$id]);
            }
        }
    }
}
<?php

declare(strict_types=1);

/** @noinspection PhpComposerExtensionStubsInspection */

namespace Revolt\EventLoop\Driver;

use Revolt\EventLoop\Internal\AbstractDriver;
use Revolt\EventLoop\Internal\DriverCallback;
use Revolt\EventLoop\Internal\SignalCallback;
use Revolt\EventLoop\Internal\StreamReadableCallback;
use Revolt\EventLoop\Internal\StreamWritableCallback;
use Revolt\EventLoop\Internal\TimerCallback;
use Revolt\EventLoop\Internal\TimerQueue;
use Revolt\EventLoop\UnsupportedFeatureException;

final class StreamSelectDriver extends AbstractDriver
{
    /** @var array<int, resource> */
    private array $readStreams = [];

    /** @var array<int, array<string, StreamReadableCallback>> */
    private array $readCallbacks = [];

    /** @var array<int, resource> */
    private array $writeStreams = [];

    /** @var array<int, array<string, StreamWritableCallback>> */
    private array $writeCallbacks = [];

    private readonly TimerQueue $timerQueue;

    /** @var array<int, array<string, SignalCallback>> */
    private array $signalCallbacks = [];

    /** @var \SplQueue<int> */
    private readonly \SplQueue $signalQueue;

    private bool $signalHandling;

    private readonly \Closure $streamSelectErrorHandler;

    private bool $streamSelectIgnoreResult = false;

    public function __construct()
    {
        parent::__construct();

        $this->signalQueue = new \SplQueue();
        $this->timerQueue = new TimerQueue();
        $this->signalHandling = \extension_loaded("pcntl")
            && \function_exists('pcntl_signal_dispatch')
            && \function_exists('pcntl_signal');

        $this->streamSelectErrorHandler = function (int $errno, string $message): void {
            // Casing changed in PHP 8 from 'unable' to 'Unable'
            if (\stripos($message, "stream_select(): unable to select [4]: ") === 0) { // EINTR
                $this->streamSelectIgnoreResult = true;

                return;
            }

            if (\str_contains($message, 'FD_SETSIZE')) {
                $message = \str_replace(["\r\n", "\n", "\r"], " ", $message);
                $pattern = '(stream_select\(\): You MUST recompile PHP with a larger value of FD_SETSIZE. It is set to (\d+), but you have descriptors numbered at least as high as (\d+)\.)';

                if (\preg_match($pattern, $message, $match)) {
                    $helpLink = 'https://revolt.run/extensions';

                    $message = 'You have reached the limits of stream_select(). It has a FD_SETSIZE of ' . $match[1]
                        . ', but you have file descriptors numbered at least as high as ' . $match[2] . '. '
                        . "You can install one of the extensions listed on {$helpLink} to support a higher number of "
                        . "concurrent file descriptors. If a large number of open file descriptors is unexpected, you "
                        . "might be leaking file descriptors that aren't closed correctly.";
                }
            }

            throw new \Exception($message, $errno);
        };
    }

    public function __destruct()
    {
        foreach ($this->signalCallbacks as $signalCallbacks) {
            foreach ($signalCallbacks as $signalCallback) {
                $this->deactivate($signalCallback);
            }
        }
    }

    /**
     * @throws UnsupportedFeatureException If the pcntl extension is not available.
     */
    #[\Override]
    public function onSignal(int $signal, \Closure $closure): string
    {
        if (!$this->signalHandling) {
            throw new UnsupportedFeatureException("Signal handling requires the pcntl extension");
        }

        return parent::onSignal($signal, $closure);
    }

    #[\Override]
    public function getHandle(): mixed
    {
        return null;
    }

    #[\Override]
    protected function now(): float
    {
        return (float) \hrtime(true) / 1_000_000_000;
    }

    /**
     * @throws \Throwable
     */
    #[\Override]
    protected function dispatch(bool $blocking): void
    {
        if ($this->signalHandling) {
            \pcntl_signal_dispatch();

            while (!$this->signalQueue->isEmpty()) {
                $signal = $this->signalQueue->dequeue();

                foreach ($this->signalCallbacks[$signal] as $callback) {
                    $this->enqueueCallback($callback);
                }

                $blocking = false;
            }
        }

        $this->selectStreams(
            $this->readStreams,
            $this->writeStreams,
            $blocking ? $this->getTimeout() : 0.0
        );

        $now = $this->now();

        while ($callback = $this->timerQueue->extract($now)) {
            $this->enqueueCallback($callback);
        }
    }

    #[\Override]
    protected function activate(array $callbacks): void
    {
        foreach ($callbacks as $callback) {
            if ($callback instanceof StreamReadableCallback) {
                \assert(\is_resource($callback->stream));

                $streamId = (int) $callback->stream;
                $this->readCallbacks[$streamId][$callback->id] = $callback;
                $this->readStreams[$streamId] = $callback->stream;
            } elseif ($callback instanceof StreamWritableCallback) {
                \assert(\is_resource($callback->stream));

                $streamId = (int) $callback->stream;
                $this->writeCallbacks[$streamId][$callback->id] = $callback;
                $this->writeStreams[$streamId] = $callback->stream;
            } elseif ($callback instanceof TimerCallback) {
                $this->timerQueue->insert($callback);
            } elseif ($callback instanceof SignalCallback) {
                if (!isset($this->signalCallbacks[$callback->signal])) {
                    \set_error_handler(static function (int $errno, string $errstr): bool {
                        throw new UnsupportedFeatureException(
                            \sprintf("Failed to register signal handler; Errno: %d; %s", $errno, $errstr)
                        );
                    });

                    // Avoid bug in Psalm handling of first-class callables by assigning to a temp variable.
                    $handler = $this->handleSignal(...);

                    try {
                        \pcntl_signal($callback->signal, $handler);
                    } finally {
                        \restore_error_handler();
                    }
                }

                $this->signalCallbacks[$callback->signal][$callback->id] = $callback;
            } else {
                // @codeCoverageIgnoreStart
                throw new \Error("Unknown callback type");
                // @codeCoverageIgnoreEnd
            }
        }
    }

    #[\Override]
    protected function deactivate(DriverCallback $callback): void
    {
        if ($callback instanceof StreamReadableCallback) {
            $streamId = (int) $callback->stream;
            unset($this->readCallbacks[$streamId][$callback->id]);
            if (empty($this->readCallbacks[$streamId])) {
                unset($this->readCallbacks[$streamId], $this->readStreams[$streamId]);
            }
        } elseif ($callback instanceof StreamWritableCallback) {
            $streamId = (int) $callback->stream;
            unset($this->writeCallbacks[$streamId][$callback->id]);
            if (empty($this->writeCallbacks[$streamId])) {
                unset($this->writeCallbacks[$streamId], $this->writeStreams[$streamId]);
            }
        } elseif ($callback instanceof TimerCallback) {
            $this->timerQueue->remove($callback);
        } elseif ($callback instanceof SignalCallback) {
            if (isset($this->signalCallbacks[$callback->signal])) {
                unset($this->signalCallbacks[$callback->signal][$callback->id]);

                if (empty($this->signalCallbacks[$callback->signal])) {
                    unset($this->signalCallbacks[$callback->signal]);
                    \set_error_handler(static fn () => true);
                    try {
                        \pcntl_signal($callback->signal, \SIG_DFL);
                    } finally {
                        \restore_error_handler();
                    }
                }
            }
        } else {
            // @codeCoverageIgnoreStart
            throw new \Error("Unknown callback type");
            // @codeCoverageIgnoreEnd
        }
    }

    /**
     * @param array<int, resource> $read
     * @param array<int, resource> $write
     */
    private function selectStreams(array $read, array $write, float $timeout): void
    {
        if (!empty($read) || !empty($write)) { // Use stream_select() if there are any streams in the loop.
            if ($timeout >= 0) {
                $seconds = (int) $timeout;
                $microseconds = (int) (($timeout - $seconds) * 1_000_000);
            } else {
                $seconds = null;
                $microseconds = null;
            }

            // Failed connection attempts are indicated via except on Windows
            // @link https://github.com/reactphp/event-loop/blob/8bd064ce23c26c4decf186c2a5a818c9a8209eb0/src/StreamSelectLoop.php#L279-L287
            // @link https://docs.microsoft.com/de-de/windows/win32/api/winsock2/nf-winsock2-select
            $except = null;
            if (\DIRECTORY_SEPARATOR === '\\') {
                $except = $write;
            }

            \set_error_handler($this->streamSelectErrorHandler);

            try {
                /** @psalm-suppress InvalidArgument */
                $result = \stream_select($read, $write, $except, $seconds, $microseconds);
            } finally {
                \restore_error_handler();
            }

            if ($this->streamSelectIgnoreResult || $result === 0) {
                $this->streamSelectIgnoreResult = false;
                return;
            }

            if (!$result) {
                throw new \Exception('Unknown error during stream_select');
            }

            foreach ($read as $stream) {
                $streamId = (int) $stream;
                if (!isset($this->readCallbacks[$streamId])) {
                    continue; // All read callbacks disabled.
                }

                foreach ($this->readCallbacks[$streamId] as $callback) {
                    $this->enqueueCallback($callback);
                }
            }

            /** @var array<int, resource>|null $except */
            if ($except !== null) {
                foreach ($except as $key => $socket) {
                    $write[$key] = $socket;
                }
            }

            foreach ($write as $stream) {
                $streamId = (int) $stream;
                if (!isset($this->writeCallbacks[$streamId])) {
                    continue; // All write callbacks disabled.
                }

                foreach ($this->writeCallbacks[$streamId] as $callback) {
                    $this->enqueueCallback($callback);
                }
            }

            return;
        }

        if ($timeout < 0) { // Only signal callbacks are enabled, so sleep indefinitely.
            /** @psalm-suppress ArgumentTypeCoercion */
            \usleep(\PHP_INT_MAX);
            return;
        }

        if ($timeout > 0) { // Sleep until next timer expires.
            /** @psalm-suppress ArgumentTypeCoercion $timeout is positive here. */
            \usleep((int) ($timeout * 1_000_000));
        }
    }

    /**
     * @return float Seconds until next timer expires or -1 if there are no pending timers.
     */
    private function getTimeout(): float
    {
        $expiration = $this->timerQueue->peek();

        if ($expiration === null) {
            return -1;
        }

        $expiration -= $this->now();

        return $expiration > 0 ? $expiration : 0.0;
    }

    private function handleSignal(int $signal): void
    {
        // Queue signals, so we don't suspend inside pcntl_signal_dispatch, which disables signals while it runs
        $this->signalQueue->enqueue($signal);
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Driver;

use Revolt\EventLoop\Internal\AbstractDriver;
use Revolt\EventLoop\Internal\DriverCallback;
use Revolt\EventLoop\Internal\SignalCallback;
use Revolt\EventLoop\Internal\StreamCallback;
use Revolt\EventLoop\Internal\StreamReadableCallback;
use Revolt\EventLoop\Internal\StreamWritableCallback;
use Revolt\EventLoop\Internal\TimerCallback;

final class UvDriver extends AbstractDriver
{
    public static function isSupported(): bool
    {
        return \extension_loaded("uv");
    }

    /** @var resource|\UVLoop A uv_loop resource created with uv_loop_new() */
    private $handle;
    /** @var array<string, resource> */
    private array $events = [];
    /** @var array<int, array<array-key, DriverCallback>> */
    private array $uvCallbacks = [];
    /** @var array<int, resource> */
    private array $streams = [];
    private readonly \Closure $ioCallback;
    private readonly \Closure $timerCallback;
    private readonly \Closure $signalCallback;

    public function __construct()
    {
        parent::__construct();

        $this->handle = \uv_loop_new();

        /** @psalm-suppress UnusedClosureParam */
        $this->ioCallback = function ($event, $status, $events, $resource): void {
            $callbacks = $this->uvCallbacks[(int) $event];

            // Invoke the callback on errors, as this matches behavior with other loop back-ends.
            // Re-enable callback as libuv disables the callback on non-zero status.
            if ($status !== 0) {
                $flags = 0;
                foreach ($callbacks as $callback) {
                    \assert($callback instanceof StreamCallback);

                    $flags |= $callback->invokable ? $this->getStreamCallbackFlags($callback) : 0;
                }
                \uv_poll_start($event, $flags, $this->ioCallback);
            }

            foreach ($callbacks as $callback) {
                \assert($callback instanceof StreamCallback);

                // $events is ORed with 4 to trigger callback if no events are indicated (0) or on UV_DISCONNECT (4).
                // http://docs.libuv.org/en/v1.x/poll.html
                if (!($this->getStreamCallbackFlags($callback) & $events || ($events | 4) === 4)) {
                    continue;
                }

                $this->enqueueCallback($callback);
            }
        };

        $this->timerCallback = function ($event): void {
            $callback = $this->uvCallbacks[(int) $event][0];

            \assert($callback instanceof TimerCallback);

            $this->enqueueCallback($callback);
        };

        $this->signalCallback = function ($event): void {
            $callback = $this->uvCallbacks[(int) $event][0];

            $this->enqueueCallback($callback);
        };
    }

    #[\Override]
    public function cancel(string $callbackId): void
    {
        parent::cancel($callbackId);

        if (!isset($this->events[$callbackId])) {
            return;
        }

        $event = $this->events[$callbackId];
        $eventId = (int) $event;

        if (isset($this->uvCallbacks[$eventId][0])) { // All except IO callbacks.
            unset($this->uvCallbacks[$eventId]);
        } elseif (isset($this->uvCallbacks[$eventId][$callbackId])) {
            $callback = $this->uvCallbacks[$eventId][$callbackId];
            unset($this->uvCallbacks[$eventId][$callbackId]);

            \assert($callback instanceof StreamCallback);

            if (empty($this->uvCallbacks[$eventId])) {
                unset($this->uvCallbacks[$eventId], $this->streams[(int) $callback->stream]);
            }
        }

        unset($this->events[$callbackId]);
    }

    public function __destruct()
    {
        $this->events = [];
        $this->uvCallbacks = [];
        $this->streams = [];

        // Reinitialize the loop handle due to indeterminate destruct order.
        // See https://github.com/revoltphp/event-loop/issues/105
        $this->handle = \uv_loop_new();
    }

    /**
     * @return \UVLoop|resource
     */
    #[\Override]
    public function getHandle(): mixed
    {
        return $this->handle;
    }

    #[\Override]
    protected function now(): float
    {
        \uv_update_time($this->handle);

        /** @psalm-suppress TooManyArguments */
        return \uv_now($this->handle) / 1000;
    }

    #[\Override]
    protected function dispatch(bool $blocking): void
    {
        /** @psalm-suppress TooManyArguments */
        \uv_run($this->handle, $blocking ? \UV::RUN_ONCE : \UV::RUN_NOWAIT);
    }

    #[\Override]
    protected function activate(array $callbacks): void
    {
        $now = $this->now();

        foreach ($callbacks as $callback) {
            $id = $callback->id;

            if ($callback instanceof StreamCallback) {
                \assert(\is_resource($callback->stream));

                $streamId = (int) $callback->stream;

                if (isset($this->streams[$streamId])) {
                    $event = $this->streams[$streamId];
                } elseif (isset($this->events[$id])) {
                    $event = $this->streams[$streamId] = $this->events[$id];
                } else {
                    /** @psalm-suppress TooManyArguments */
                    $event = $this->streams[$streamId] = \uv_poll_init_socket($this->handle, $callback->stream);
                }

                $eventId = (int) $event;
                $this->events[$id] = $event;
                $this->uvCallbacks[$eventId][$id] = $callback;

                $flags = 0;
                foreach ($this->uvCallbacks[$eventId] as $w) {
                    \assert($w instanceof StreamCallback);

                    $flags |= $w->enabled ? ($this->getStreamCallbackFlags($w)) : 0;
                }
                \uv_poll_start($event, $flags, $this->ioCallback);
            } elseif ($callback instanceof TimerCallback) {
                if (isset($this->events[$id])) {
                    $event = $this->events[$id];
                } else {
                    $event = $this->events[$id] = \uv_timer_init($this->handle);
                }

                $this->uvCallbacks[(int) $event] = [$callback];

                \uv_timer_start(
                    $event,
                    (int) \min(\max(0, \ceil(($callback->expiration - $now) * 1000)), \PHP_INT_MAX),
                    $callback->repeat ? (int) \min(\max(0, \ceil($callback->interval * 1000)), \PHP_INT_MAX) : 0,
                    $this->timerCallback
                );
            } elseif ($callback instanceof SignalCallback) {
                if (isset($this->events[$id])) {
                    $event = $this->events[$id];
                } else {
                    /** @psalm-suppress TooManyArguments */
                    $event = $this->events[$id] = \uv_signal_init($this->handle);
                }

                $this->uvCallbacks[(int) $event] = [$callback];

                /** @psalm-suppress TooManyArguments */
                \uv_signal_start($event, $this->signalCallback, $callback->signal);
            } else {
                // @codeCoverageIgnoreStart
                throw new \Error("Unknown callback type");
                // @codeCoverageIgnoreEnd
            }
        }
    }

    #[\Override]
    protected function deactivate(DriverCallback $callback): void
    {
        $id = $callback->id;

        if (!isset($this->events[$id])) {
            return;
        }

        $event = $this->events[$id];

        if (!\uv_is_active($event)) {
            return;
        }

        if ($callback instanceof StreamCallback) {
            $flags = 0;
            foreach ($this->uvCallbacks[(int) $event] as $w) {
                \assert($w instanceof StreamCallback);

                $flags |= $w->invokable ? ($this->getStreamCallbackFlags($w)) : 0;
            }

            if ($flags) {
                \uv_poll_start($event, $flags, $this->ioCallback);
            } else {
                \uv_poll_stop($event);
            }
        } elseif ($callback instanceof TimerCallback) {
            \uv_timer_stop($event);
        } elseif ($callback instanceof SignalCallback) {
            \uv_signal_stop($event);
        } else {
            // @codeCoverageIgnoreStart
            throw new \Error("Unknown callback type");
            // @codeCoverageIgnoreEnd
        }
    }

    private function getStreamCallbackFlags(StreamCallback $callback): int
    {
        if ($callback instanceof StreamWritableCallback) {
            return \UV::WRITABLE;
        }

        if ($callback instanceof StreamReadableCallback) {
            return \UV::READABLE;
        }

        throw new \Error('Invalid callback type');
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop\Driver;

use Revolt\EventLoop\CallbackType;
use Revolt\EventLoop\Driver;
use Revolt\EventLoop\InvalidCallbackError;
use Revolt\EventLoop\Suspension;

final class TracingDriver implements Driver
{
    private readonly Driver $driver;

    /** @var array<string, true> */
    private array $enabledCallbacks = [];

    /** @var array<string, true> */
    private array $unreferencedCallbacks = [];

    /** @var array<string, string> */
    private array $creationTraces = [];

    /** @var array<string, string> */
    private array $cancelTraces = [];

    public function __construct(Driver $driver)
    {
        $this->driver = $driver;
    }

    #[\Override]
    public function run(): void
    {
        $this->driver->run();
    }

    #[\Override]
    public function stop(): void
    {
        $this->driver->stop();
    }

    #[\Override]
    public function getSuspension(): Suspension
    {
        return $this->driver->getSuspension();
    }

    #[\Override]
    public function isRunning(): bool
    {
        return $this->driver->isRunning();
    }

    #[\Override]
    public function defer(\Closure $closure): string
    {
        $id = $this->driver->defer(function (...$args) use ($closure) {
            $this->cancel($args[0]);
            return $closure(...$args);
        });

        $this->creationTraces[$id] = $this->formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
        $this->enabledCallbacks[$id] = true;

        return $id;
    }

    #[\Override]
    public function delay(float $delay, \Closure $closure): string
    {
        $id = $this->driver->delay($delay, function (...$args) use ($closure) {
            $this->cancel($args[0]);
            return $closure(...$args);
        });

        $this->creationTraces[$id] = $this->formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
        $this->enabledCallbacks[$id] = true;

        return $id;
    }

    #[\Override]
    public function repeat(float $interval, \Closure $closure): string
    {
        $id = $this->driver->repeat($interval, $closure);

        $this->creationTraces[$id] = $this->formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
        $this->enabledCallbacks[$id] = true;

        return $id;
    }

    #[\Override]
    public function onReadable(mixed $stream, \Closure $closure): string
    {
        $id = $this->driver->onReadable($stream, $closure);

        $this->creationTraces[$id] = $this->formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
        $this->enabledCallbacks[$id] = true;

        return $id;
    }

    #[\Override]
    public function onWritable(mixed $stream, \Closure $closure): string
    {
        $id = $this->driver->onWritable($stream, $closure);

        $this->creationTraces[$id] = $this->formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
        $this->enabledCallbacks[$id] = true;

        return $id;
    }

    #[\Override]
    public function onSignal(int $signal, \Closure $closure): string
    {
        $id = $this->driver->onSignal($signal, $closure);

        $this->creationTraces[$id] = $this->formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
        $this->enabledCallbacks[$id] = true;

        return $id;
    }

    #[\Override]
    public function enable(string $callbackId): string
    {
        try {
            $this->driver->enable($callbackId);
            $this->enabledCallbacks[$callbackId] = true;
        } catch (InvalidCallbackError $e) {
            $e->addInfo("Creation trace", $this->getCreationTrace($callbackId));
            $e->addInfo("Cancellation trace", $this->getCancelTrace($callbackId));

            throw $e;
        }

        return $callbackId;
    }

    #[\Override]
    public function cancel(string $callbackId): void
    {
        $this->driver->cancel($callbackId);

        if (!isset($this->cancelTraces[$callbackId])) {
            $this->cancelTraces[$callbackId] = $this->formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
        }

        unset($this->enabledCallbacks[$callbackId], $this->unreferencedCallbacks[$callbackId]);
    }

    #[\Override]
    public function disable(string $callbackId): string
    {
        $this->driver->disable($callbackId);
        unset($this->enabledCallbacks[$callbackId]);

        return $callbackId;
    }

    #[\Override]
    public function reference(string $callbackId): string
    {
        try {
            $this->driver->reference($callbackId);
            unset($this->unreferencedCallbacks[$callbackId]);
        } catch (InvalidCallbackError $e) {
            $e->addInfo("Creation trace", $this->getCreationTrace($callbackId));
            $e->addInfo("Cancellation trace", $this->getCancelTrace($callbackId));

            throw $e;
        }

        return $callbackId;
    }

    #[\Override]
    public function unreference(string $callbackId): string
    {
        $this->driver->unreference($callbackId);
        $this->unreferencedCallbacks[$callbackId] = true;

        return $callbackId;
    }

    #[\Override]
    public function setErrorHandler(?\Closure $errorHandler): void
    {
        $this->driver->setErrorHandler($errorHandler);
    }

    #[\Override]
    public function getErrorHandler(): ?\Closure
    {
        return $this->driver->getErrorHandler();
    }

    /** @inheritdoc */
    #[\Override]
    public function getHandle(): mixed
    {
        return $this->driver->getHandle();
    }

    public function dump(): string
    {
        $dump = "Enabled, referenced callbacks keeping the loop running: ";

        foreach ($this->enabledCallbacks as $callbackId => $_) {
            if (isset($this->unreferencedCallbacks[$callbackId])) {
                continue;
            }

            $dump .= "Callback identifier: " . $callbackId . "\r\n";
            $dump .= $this->getCreationTrace($callbackId);
            $dump .= "\r\n\r\n";
        }

        return \rtrim($dump);
    }

    #[\Override]
    public function getIdentifiers(): array
    {
        return $this->driver->getIdentifiers();
    }

    #[\Override]
    public function getType(string $callbackId): CallbackType
    {
        return $this->driver->getType($callbackId);
    }

    #[\Override]
    public function isEnabled(string $callbackId): bool
    {
        return $this->driver->isEnabled($callbackId);
    }

    #[\Override]
    public function isReferenced(string $callbackId): bool
    {
        return $this->driver->isReferenced($callbackId);
    }

    #[\Override]
    public function __debugInfo(): array
    {
        return $this->driver->__debugInfo();
    }

    #[\Override]
    public function queue(\Closure $closure, mixed ...$args): void
    {
        $this->driver->queue($closure, ...$args);
    }

    private function getCreationTrace(string $callbackId): string
    {
        return $this->creationTraces[$callbackId] ?? 'No creation trace, yet.';
    }

    private function getCancelTrace(string $callbackId): string
    {
        return $this->cancelTraces[$callbackId] ?? 'No cancellation trace, yet.';
    }

    /**
     * Formats a stacktrace obtained via `debug_backtrace()`.
     *
     * @param list<array{
     *     args?: list<mixed>,
     *     class?: class-string,
     *     file?: string,
     *     function: string,
     *     line?: int,
     *     object?: object,
     *     type?: string
     * }> $trace Output of `debug_backtrace()`.
     *
     * @return string Formatted stacktrace.
     */
    private function formatStacktrace(array $trace): string
    {
        return \implode("\n", \array_map(static function ($e, $i) {
            $line = "#{$i} ";

            if (isset($e["file"], $e['line'])) {
                $line .= "{$e['file']}:{$e['line']} ";
            }

            if (isset($e["class"], $e["type"])) {
                $line .= $e["class"] . $e["type"];
            }

            return $line . $e["function"] . "()";
        }, $trace, \array_keys($trace)));
    }
}
<?php

declare(strict_types=1);

/** @noinspection PhpComposerExtensionStubsInspection */

namespace Revolt\EventLoop\Driver;

use Revolt\EventLoop\Internal\AbstractDriver;
use Revolt\EventLoop\Internal\DriverCallback;
use Revolt\EventLoop\Internal\SignalCallback;
use Revolt\EventLoop\Internal\StreamCallback;
use Revolt\EventLoop\Internal\StreamReadableCallback;
use Revolt\EventLoop\Internal\StreamWritableCallback;
use Revolt\EventLoop\Internal\TimerCallback;

final class EvDriver extends AbstractDriver
{
    /** @var array<string, \EvSignal>|null */
    private static ?array $activeSignals = null;

    public static function isSupported(): bool
    {
        return \extension_loaded("ev");
    }

    private \EvLoop $handle;

    /** @var array<string, \EvWatcher> */
    private array $events = [];

    private readonly \Closure $ioCallback;

    private readonly \Closure $timerCallback;

    private readonly \Closure $signalCallback;

    /** @var array<string, \EvSignal> */
    private array $signals = [];

    public function __construct()
    {
        parent::__construct();

        $this->handle = new \EvLoop();

        if (self::$activeSignals === null) {
            self::$activeSignals = &$this->signals;
        }

        $this->ioCallback = function (\EvIo $event): void {
            /** @var StreamCallback $callback */
            $callback = $event->data;

            $this->enqueueCallback($callback);
        };

        $this->timerCallback = function (\EvTimer $event): void {
            /** @var TimerCallback $callback */
            $callback = $event->data;

            $this->enqueueCallback($callback);
        };

        $this->signalCallback = function (\EvSignal $event): void {
            /** @var SignalCallback $callback */
            $callback = $event->data;

            $this->enqueueCallback($callback);
        };
    }

    #[\Override]
    public function cancel(string $callbackId): void
    {
        parent::cancel($callbackId);
        unset($this->events[$callbackId]);
    }

    public function __destruct()
    {
        foreach ($this->events as $event) {
            /** @psalm-suppress all */
            if ($event !== null) { // Events may have been nulled in extension depending on destruct order.
                $event->stop();
            }
        }

        // We need to clear all references to events manually, see
        // https://bitbucket.org/osmanov/pecl-ev/issues/31/segfault-in-ev_timer_stop
        $this->events = [];

        // Reinitialize the loop handle due to indeterminate destruct order.
        // See https://github.com/revoltphp/event-loop/issues/105
        $this->handle = new \EvLoop();
    }

    #[\Override]
    public function run(): void
    {
        $active = self::$activeSignals;

        \assert($active !== null);

        foreach ($active as $event) {
            $event->stop();
        }

        self::$activeSignals = &$this->signals;

        foreach ($this->signals as $event) {
            $event->start();
        }

        try {
            parent::run();
        } finally {
            foreach ($this->signals as $event) {
                $event->stop();
            }

            self::$activeSignals = &$active;

            foreach ($active as $event) {
                $event->start();
            }
        }
    }

    #[\Override]
    public function stop(): void
    {
        $this->handle->stop();
        parent::stop();
    }

    #[\Override]
    public function getHandle(): \EvLoop
    {
        return $this->handle;
    }

    #[\Override]
    protected function now(): float
    {
        return (float) \hrtime(true) / 1_000_000_000;
    }

    #[\Override]
    protected function dispatch(bool $blocking): void
    {
        $this->handle->run($blocking ? \Ev::RUN_ONCE : \Ev::RUN_ONCE | \Ev::RUN_NOWAIT);
    }

    #[\Override]
    protected function activate(array $callbacks): void
    {
        $this->handle->nowUpdate();
        $now = $this->now();

        foreach ($callbacks as $callback) {
            if (!isset($this->events[$id = $callback->id])) {
                if ($callback instanceof StreamReadableCallback) {
                    \assert(\is_resource($callback->stream));

                    $this->events[$id] = $this->handle->io($callback->stream, \Ev::READ, $this->ioCallback, $callback);
                } elseif ($callback instanceof StreamWritableCallback) {
                    \assert(\is_resource($callback->stream));

                    $this->events[$id] = $this->handle->io(
                        $callback->stream,
                        \Ev::WRITE,
                        $this->ioCallback,
                        $callback
                    );
                } elseif ($callback instanceof TimerCallback) {
                    $interval = $callback->interval;
                    $this->events[$id] = $this->handle->timer(
                        \max(0, ($callback->expiration - $now)),
                        $callback->repeat ? $interval : 0,
                        $this->timerCallback,
                        $callback
                    );
                } elseif ($callback instanceof SignalCallback) {
                    $this->events[$id] = $this->handle->signal($callback->signal, $this->signalCallback, $callback);
                } else {
                    // @codeCoverageIgnoreStart
                    throw new \Error("Unknown callback type: " . \get_class($callback));
                    // @codeCoverageIgnoreEnd
                }
            } else {
                $this->events[$id]->start();
            }

            if ($callback instanceof SignalCallback) {
                /** @psalm-suppress PropertyTypeCoercion */
                $this->signals[$id] = $this->events[$id];
            }
        }
    }

    #[\Override]
    protected function deactivate(DriverCallback $callback): void
    {
        if (isset($this->events[$id = $callback->id])) {
            $this->events[$id]->stop();

            if ($callback instanceof SignalCallback) {
                unset($this->signals[$id]);
            }
        }
    }
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop;

/**
 * The driver MUST run in its own fiber and execute callbacks in a separate fiber. If fibers are reused, the driver
 * needs to call {@see FiberLocal::clear()} after running the callback.
 */
interface Driver
{
    /**
     * Run the event loop.
     *
     * One iteration of the loop is called one "tick". A tick covers the following steps:
     *
     *  1. Activate callbacks created / enabled in the last tick / before `run()`.
     *  2. Execute all enabled deferred callbacks.
     *  3. Execute all due timer, pending signal and actionable stream callbacks, each only once per tick.
     *
     * The loop MUST continue to run until it is either stopped explicitly, no referenced callbacks exist anymore, or an
     * exception is thrown that cannot be handled. Exceptions that cannot be handled are exceptions thrown from an
     * error handler or exceptions that would be passed to an error handler but none exists to handle them.
     *
     * @throws \Error Thrown if the event loop is already running.
     */
    public function run(): void;

    /**
     * Stop the event loop.
     *
     * When an event loop is stopped, it continues with its current tick and exits the loop afterwards. Multiple calls
     * to stop MUST be ignored and MUST NOT raise an exception.
     */
    public function stop(): void;

    /**
     * Returns an object used to suspend and resume execution of the current fiber or {main}.
     *
     * Calls from the same fiber will return the same suspension object.
     *
     * @return Suspension
     */
    public function getSuspension(): Suspension;

    /**
     * @return bool True if the event loop is running, false if it is stopped.
     */
    public function isRunning(): bool;

    /**
     * Queue a microtask.
     *
     * The queued callback MUST be executed immediately once the event loop gains control. Order of queueing MUST be
     * preserved when executing the callbacks. Recursive scheduling can thus result in infinite loops, use with care.
     *
     * Does NOT create an event callback, thus CAN NOT be marked as disabled or unreferenced.
     * Use {@see EventLoop::defer()} if you need these features.
     *
     * @param \Closure(...):void $closure The callback to queue.
     * @param mixed ...$args The callback arguments.
     */
    public function queue(\Closure $closure, mixed ...$args): void;

    /**
     * Defer the execution of a callback.
     *
     * The deferred callback MUST be executed before any other type of callback in a tick. Order of enabling MUST be
     * preserved when executing the callbacks.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param \Closure(string):void $closure The callback to defer. The `$callbackId` will be invalidated before the
     *     callback invocation.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     */
    public function defer(\Closure $closure): string;

    /**
     * Delay the execution of a callback.
     *
     * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which
     * timers expire first, but timers with the same expiration time MAY be executed in any order.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param float $delay The amount of time, in seconds, to delay the execution for.
     * @param \Closure(string):void $closure The callback to delay. The `$callbackId` will be invalidated before the
     *     callback invocation.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     */
    public function delay(float $delay, \Closure $closure): string;

    /**
     * Repeatedly execute a callback.
     *
     * The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be
     * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order.
     * The first execution is scheduled after the first interval period.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param float $interval The time interval, in seconds, to wait between executions.
     * @param \Closure(string):void $closure The callback to repeat.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     */
    public function repeat(float $interval, \Closure $closure): string;

    /**
     * Execute a callback when a stream resource becomes readable or is closed for reading.
     *
     * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the
     * callback when closing the resource locally. Drivers MAY choose to notify the user if there are callbacks on
     * invalid resources, but are not required to, due to the high performance impact. Callbacks on closed resources are
     * therefore undefined behavior.
     *
     * Multiple callbacks on the same stream MAY be executed in any order.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param resource $stream The stream to monitor.
     * @param \Closure(string, resource):void $closure The callback to execute.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     */
    public function onReadable(mixed $stream, \Closure $closure): string;

    /**
     * Execute a callback when a stream resource becomes writable or is closed for writing.
     *
     * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the
     * callback when closing the resource locally. Drivers MAY choose to notify the user if there are callbacks on
     * invalid resources, but are not required to, due to the high performance impact. Callbacks on closed resources are
     * therefore undefined behavior.
     *
     * Multiple callbacks on the same stream MAY be executed in any order.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param resource $stream The stream to monitor.
     * @param \Closure(string, resource):void $closure The callback to execute.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     */
    public function onWritable(mixed $stream, \Closure $closure): string;

    /**
     * Execute a callback when a signal is received.
     *
     * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior.
     * Implementations MAY try to detect this, if possible, but are not required to. This is due to technical
     * limitations of the signals being registered globally per process.
     *
     * Multiple callbacks on the same signal MAY be executed in any order.
     *
     * The created callback MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
     * right before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param int $signal The signal number to monitor.
     * @param \Closure(string, int):void $closure The callback to execute.
     *
     * @return string A unique identifier that can be used to cancel, enable or disable the callback.
     *
     * @throws UnsupportedFeatureException If signal handling is not supported.
     */
    public function onSignal(int $signal, \Closure $closure): string;

    /**
     * Enable a callback to be active starting in the next tick.
     *
     * Callbacks MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right
     * before the next tick. Callbacks MUST NOT be called in the tick they were enabled.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return string The callback identifier.
     *
     * @throws InvalidCallbackError If the callback identifier is invalid.
     */
    public function enable(string $callbackId): string;

    /**
     * Cancel a callback.
     *
     * This will detach the event loop from all resources that are associated to the callback. After this operation the
     * callback is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid identifier.
     *
     * @param string $callbackId The callback identifier.
     */
    public function cancel(string $callbackId): void;

    /**
     * Disable a callback immediately.
     *
     * A callback MUST be disabled immediately, e.g. if a deferred callback disables a later deferred callback,
     * the second deferred callback isn't executed in this tick.
     *
     * Disabling a callback MUST NOT invalidate the callback. Calling this function MUST NOT fail, even if passed an
     * invalid callback identifier.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return string The callback identifier.
     */
    public function disable(string $callbackId): string;

    /**
     * Reference a callback.
     *
     * This will keep the event loop alive whilst the callback is still being monitored. Callbacks have this state by
     * default.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return string The callback identifier.
     *
     * @throws InvalidCallbackError If the callback identifier is invalid.
     */
    public function reference(string $callbackId): string;

    /**
     * Unreference a callback.
     *
     * The event loop should exit the run method when only unreferenced callbacks are still being monitored. Callbacks
     * are all referenced by default.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return string The callback identifier.
     */
    public function unreference(string $callbackId): string;

    /**
     * Set a callback to be executed when an error occurs.
     *
     * The callback receives the error as the first and only parameter. The return value of the callback gets ignored.
     * If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation
     * MUST be thrown into the `run` loop and stop the driver.
     *
     * Subsequent calls to this method will overwrite the previous handler.
     *
     * @param null|\Closure(\Throwable):void $errorHandler The callback to execute. `null` will clear the current
     *     handler.
     */
    public function setErrorHandler(?\Closure $errorHandler): void;

    /**
     * Gets the error handler closure or {@code null} if none is set.
     *
     * @return null|\Closure(\Throwable):void The previous handler, `null` if there was none.
     */
    public function getErrorHandler(): ?\Closure;

    /**
     * Get the underlying loop handle.
     *
     * Example: the `uv_loop` resource for `libuv` or the `EvLoop` object for `libev` or `null` for a stream_select
     * driver.
     *
     * Note: This function is *not* exposed in the `Loop` class. Users shall access it directly on the respective loop
     * instance.
     *
     * @return null|object|resource The loop handle the event loop operates on. `null` if there is none.
     */
    public function getHandle(): mixed;

    /**
     * Returns all registered non-cancelled callback identifiers.
     *
     * @return string[] Callback identifiers.
     */
    public function getIdentifiers(): array;

    /**
     * Returns the type of the callback identified by the given callback identifier.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return CallbackType The callback type.
     */
    public function getType(string $callbackId): CallbackType;

    /**
     * Returns whether the callback identified by the given callback identifier is currently enabled.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return bool `true` if the callback is currently enabled, otherwise `false`.
     */
    public function isEnabled(string $callbackId): bool;

    /**
     * Returns whether the callback identified by the given callback identifier is currently referenced.
     *
     * @param string $callbackId The callback identifier.
     *
     * @return bool `true` if the callback is currently referenced, otherwise `false`.
     */
    public function isReferenced(string $callbackId): bool;

    /**
     * Returns some useful information about the event loop.
     *
     * If this method isn't implemented, dumping the event loop in a busy application, even indirectly, is a pain.
     *
     * @return array
     */
    public function __debugInfo(): array;
}
<?php

declare(strict_types=1);

namespace Revolt\EventLoop;

/**
 * Should be used to run and suspend the event loop instead of directly interacting with fibers.
 *
 * **Example**
 *
 * ```php
 * $suspension = EventLoop::getSuspension();
 *
 * $promise->then(
 *     fn (mixed $value) => $suspension->resume($value),
 *     fn (Throwable $error) => $suspension->throw($error)
 * );
 *
 * $suspension->suspend();
 * ```
 *
 * @template T
 */
interface Suspension
{
    /**
     * @param T $value The value to return from the call to {@see suspend()}.
     */
    public function resume(mixed $value = null): void;

    /**
     * Returns the value provided to {@see resume()} or throws the exception provided to {@see throw()}.
     *
     * @return T
     */
    public function suspend(): mixed;

    /**
     * Throws the given exception from the call to {@see suspend()}.
     */
    public function throw(\Throwable $throwable): void;
}

The MIT License (MIT)

Copyright (c) 2021-2023 Revolt (Aaron Piotrowski, Cees-Jan Kiewiet, Christian Lück, Niklas Keller, and contributors)
Copyright (c) 2015-2021 amphp (Daniel Lowrey, Aaron Piotrowski, Niklas Keller, Bob Weinand, and contributors)
Copyright (c) 2012-2021 ReactPHP (Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden, Igor Wiedler, and contributors)
Copyright (c) 2016 PHP Asynchronous Interoperability Group

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Security Policy

## Supported Versions

| Version | Supported          |
| ------- | ------------------ |
| 1.x     | ✔️                 |
| < 1.x   | :x:                |

## Reporting a Vulnerability

If you think you've found a vulnerability, please use the [private vulnerability reporting form provided by Github](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability). 
{
    "name": "revolt/event-loop",
    "description": "Rock-solid event loop for concurrent PHP applications.",
    "keywords": [
        "async",
        "asynchronous",
        "concurrency",
        "non-blocking",
        "event",
        "event-loop",
        "scheduler"
    ],
    "license": "MIT",
    "authors": [
        {
            "name": "Aaron Piotrowski",
            "email": "aaron@trowski.com"
        },
        {
            "name": "Cees-Jan Kiewiet",
            "email": "ceesjank@gmail.com"
        },
        {
            "name": "Christian Lück",
            "email": "christian@clue.engineering"
        },
        {
            "name": "Niklas Keller",
            "email": "me@kelunik.com"
        }
    ],
    "require": {
        "php": ">=8.1"
    },
    "require-dev": {
        "ext-json": "*",
        "phpunit/phpunit": "^9",
        "jetbrains/phpstorm-stubs": "^2019.3",
        "psalm/phar": "6.16.*"
    },
    "autoload": {
        "psr-4": {
            "Revolt\\": "src"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Revolt\\EventLoop\\": "test"
        }
    },
    "support": {
        "issues": "https://github.com/revoltphp/event-loop/issues"
    },
    "extra": {
        "branch-alias": {
            "dev-main": "1.x-dev"
        }
    },
    "scripts": {
        "test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit",
        "code-style": "@php tools/php-cs-fixer/vendor/bin/php-cs-fixer fix"
    }
}
emjْd[Qt6   GBMB