浏览代码

Initial commit

YouTwitFace 5 年之前
父节点
当前提交
50f9738598

+ 19 - 0
.gitignore

@@ -0,0 +1,19 @@
+/node_modules/
+/.vscode/
+
+# Generated code
+/gramjs/tl/functions/
+/gramjs/tl/types/
+/gramjs/tl/patched/
+/gramjs/tl/alltlobjects.py
+/gramjs/errors/rpcerrorlist.py
+
+# User session
+*.session
+usermedia/
+
+# Quick tests should live in this file
+example.js
+
+# dotenv
+.env

+ 1418 - 0
gramjs_generator/data/api.tl

@@ -0,0 +1,1418 @@
+///////////////////////////////
+/////////////////// Layer cons
+///////////////////////////////
+
+//invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
+//invokeAfterMsgs#3dc4b4f0 msg_ids:Vector<long> query:!X = X;
+//invokeWithLayer1#53835315 query:!X = X;
+//invokeWithLayer2#289dd1f6 query:!X = X;
+//invokeWithLayer3#b7475268 query:!X = X;
+//invokeWithLayer4#dea0d430 query:!X = X;
+//invokeWithLayer5#417a57ae query:!X = X;
+//invokeWithLayer6#3a64d54d query:!X = X;
+//invokeWithLayer7#a5be56d3 query:!X = X;
+//invokeWithLayer8#e9abd9fd query:!X = X;
+//invokeWithLayer9#76715a63 query:!X = X;
+//invokeWithLayer10#39620c41 query:!X = X;
+//invokeWithLayer11#a6b88fdf query:!X = X;
+//invokeWithLayer12#dda60d3c query:!X = X;
+//invokeWithLayer13#427c8ea2 query:!X = X;
+//invokeWithLayer14#2b9b08fa query:!X = X;
+//invokeWithLayer15#b4418b64 query:!X = X;
+//invokeWithLayer16#cf5f0987 query:!X = X;
+//invokeWithLayer17#50858a19 query:!X = X;
+//invokeWithLayer18#1c900537 query:!X = X;
+//invokeWithLayer#da9b0d0d layer:int query:!X = X; // after 18 layer
+
+///////////////////////////////
+///////// Main application API
+///////////////////////////////
+
+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#179be863 chat_id:int = InputPeer;
+inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer;
+inputPeerChannel#20adaef8 channel_id:int access_hash:long = InputPeer;
+inputPeerUserFromMessage#17bae2e6 peer:InputPeer msg_id:int user_id:int = InputPeer;
+inputPeerChannelFromMessage#9c95f7bb peer:InputPeer msg_id:int channel_id:int = InputPeer;
+
+inputUserEmpty#b98886cf = InputUser;
+inputUserSelf#f7c1b13f = InputUser;
+inputUser#d8292816 user_id:int access_hash:long = InputUser;
+inputUserFromMessage#2d117597 peer:InputPeer msg_id:int user_id:int = InputUser;
+
+inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact;
+
+inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile;
+inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile;
+
+inputMediaEmpty#9664f57f = InputMedia;
+inputMediaUploadedPhoto#1e287d04 flags:# file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
+inputMediaPhoto#b3ba0635 flags:# id:InputPhoto ttl_seconds:flags.0?int = InputMedia;
+inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
+inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia;
+inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
+inputMediaDocument#23ab23d2 flags:# id:InputDocument ttl_seconds:flags.0?int = InputMedia;
+inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia;
+inputMediaGifExternal#4843b0fd url:string q:string = InputMedia;
+inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia;
+inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia;
+inputMediaGame#d33f43f3 id:InputGame = InputMedia;
+inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia;
+inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia;
+inputMediaPoll#6b3765b poll:Poll = InputMedia;
+
+inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
+inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
+inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto;
+
+inputGeoPointEmpty#e4c123d6 = InputGeoPoint;
+inputGeoPoint#f3b7acc9 lat:double long:double = 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;
+inputPeerPhotoFileLocation#27d69997 flags:# big:flags.0?true peer:InputPeer volume_id:long local_id:int = InputFileLocation;
+inputStickerSetThumb#dbaeae9 stickerset:InputStickerSet volume_id:long local_id:int = InputFileLocation;
+
+peerUser#9db1bc6d user_id:int = Peer;
+peerChat#bad0e5bb chat_id:int = Peer;
+peerChannel#bddde532 channel_id:int = 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#200250ba id:int = User;
+user#938458c1 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 id:int 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 = User;
+
+userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
+userProfilePhoto#ecd75d8c photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto;
+
+userStatusEmpty#9d05049 = UserStatus;
+userStatusOnline#edb93949 expires:int = UserStatus;
+userStatusOffline#8c703f was_online:int = UserStatus;
+userStatusRecently#e26f42f1 = UserStatus;
+userStatusLastWeek#7bf09fc = UserStatus;
+userStatusLastMonth#77ebc742 = UserStatus;
+
+chatEmpty#9ba2d800 id:int = Chat;
+chat#3bda1bde flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true deactivated:flags.5?true id:int 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#7328bdb id:int title:string = Chat;
+channel#d31a961e 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 id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version: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 = Chat;
+channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat;
+
+chatFull#1b7c9db3 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull;
+channelFull#2d895c74 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_view_stats:flags.12?true can_set_location:flags.16?true has_scheduled:flags.19?true id:int 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:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int 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?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int pts:int = ChatFull;
+
+chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
+chatParticipantCreator#da13538a user_id:int = ChatParticipant;
+chatParticipantAdmin#e2d6e436 user_id:int inviter_id:int date:int = ChatParticipant;
+
+chatParticipantsForbidden#fc900c2b flags:# chat_id:int self_participant:flags.0?ChatParticipant = ChatParticipants;
+chatParticipants#3f460fed chat_id:int participants:Vector<ChatParticipant> version:int = ChatParticipants;
+
+chatPhotoEmpty#37c1011c = ChatPhoto;
+chatPhoto#475cdbd5 photo_small:FileLocation photo_big:FileLocation dc_id:int = ChatPhoto;
+
+messageEmpty#83e5de54 id:int = Message;
+message#452c0e65 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 id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long restriction_reason:flags.22?Vector<RestrictionReason> = Message;
+messageService#9e19a1f6 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?int to_id:Peer reply_to_msg_id:flags.3?int date:int action:MessageAction = Message;
+
+messageMediaEmpty#3ded6320 = MessageMedia;
+messageMediaPhoto#695150d7 flags:# photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia;
+messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
+messageMediaContact#cbf24940 phone_number:string first_name:string last_name:string vcard:string user_id:int = MessageMedia;
+messageMediaUnsupported#9f84f49e = MessageMedia;
+messageMediaDocument#9cb070d7 flags:# document:flags.0?Document ttl_seconds:flags.2?int = MessageMedia;
+messageMediaWebPage#a32dd600 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#84551347 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 = MessageMedia;
+messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia;
+messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
+
+messageActionEmpty#b6aef7b0 = MessageAction;
+messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
+messageActionChatEditTitle#b5a1ce5a title:string = MessageAction;
+messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction;
+messageActionChatDeletePhoto#95e3fbef = MessageAction;
+messageActionChatAddUser#488a7337 users:Vector<int> = MessageAction;
+messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction;
+messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction;
+messageActionChannelCreate#95d2ac92 title:string = MessageAction;
+messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction;
+messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction;
+messageActionPinMessage#94bd38ed = MessageAction;
+messageActionHistoryClear#9fbab604 = MessageAction;
+messageActionGameScore#92a72876 game_id:long score:int = MessageAction;
+messageActionPaymentSentMe#8f31b327 flags:# currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge = MessageAction;
+messageActionPaymentSent#40699cd0 currency:string total_amount:long = 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#abe9affe domain:string = MessageAction;
+messageActionSecureValuesSentMe#1b287353 values:Vector<SecureValue> credentials:SecureCredentialsEncrypted = MessageAction;
+messageActionSecureValuesSent#d95c6154 types:Vector<SecureValueType> = MessageAction;
+messageActionContactSignUp#f3f25f76 = MessageAction;
+
+dialog#2c171f72 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?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#d07504a5 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> dc_id:int = Photo;
+
+photoSizeEmpty#e17e23c type:string = PhotoSize;
+photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
+photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
+photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;
+
+geoPointEmpty#1117dd5f = GeoPoint;
+geoPoint#296f104 long:double lat:double access_hash:long = 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.authorization#cd050916 flags:# tmp_sessions:flags.0?int user:User = auth.Authorization;
+auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization;
+
+auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization;
+
+inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer;
+inputNotifyUsers#193b4417 = InputNotifyPeer;
+inputNotifyChats#4a95e84e = InputNotifyPeer;
+inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer;
+
+inputPeerNotifySettings#9c3d198e flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = InputPeerNotifySettings;
+
+peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?string = PeerNotifySettings;
+
+peerSettings#818426cd 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 = 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;
+
+inputReportReasonSpam#58dbcab8 = ReportReason;
+inputReportReasonViolence#1e22c78d = ReportReason;
+inputReportReasonPornography#2e59d922 = ReportReason;
+inputReportReasonChildAbuse#adf44ee3 = ReportReason;
+inputReportReasonOther#e1746d0a text:string = ReportReason;
+inputReportReasonCopyright#9b89f93a = ReportReason;
+inputReportReasonGeoIrrelevant#dbd4feed = ReportReason;
+
+userFull#edf17c12 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 user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int = UserFull;
+
+contact#f911c994 user_id:int mutual:Bool = Contact;
+
+importedContact#d0028438 user_id:int client_id:long = ImportedContact;
+
+contactBlocked#561bc879 user_id:int date:int = ContactBlocked;
+
+contactStatus#d3680c61 user_id:int 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#1c138d15 blocked:Vector<ContactBlocked> users:Vector<User> = contacts.Blocked;
+contacts.blockedSlice#900802a1 count:int blocked:Vector<ContactBlocked> 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#8c718e87 messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
+messages.messagesSlice#c8edce1e flags:# inexact:flags.1?true count:int next_rate:flags.0?int messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.Messages;
+messages.channelMessages#99262e37 flags:# inexact:flags.1?true pts:int count:int messages:Vector<Message> 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;
+
+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#5c486927 user_id:int action:SendMessageAction = Update;
+updateChatUserTyping#9a65ea1f chat_id:int user_id:int action:SendMessageAction = Update;
+updateChatParticipants#7761198 participants:ChatParticipants = Update;
+updateUserStatus#1bfbd823 user_id:int status:UserStatus = Update;
+updateUserName#a7332b73 user_id:int first_name:string last_name:string username:string = Update;
+updateUserPhoto#95313b0c user_id:int date:int photo:UserProfilePhoto previous:Bool = 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#ea4b0e5c chat_id:int user_id:int inviter_id:int date:int version:int = Update;
+updateChatParticipantDelete#6e5f8c22 chat_id:int user_id:int version:int = Update;
+updateDcOptions#8e5e9873 dc_options:Vector<DcOption> = Update;
+updateUserBlocked#80ece81a user_id:int blocked:Bool = Update;
+updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update;
+updateServiceNotification#ebe46819 flags:# popup:flags.0?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#12b9417b user_id:int phone:string = Update;
+updateReadHistoryInbox#9c974fdf flags:# folder_id:flags.0?int peer:Peer 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#68c13933 messages:Vector<int> pts:int pts_count:int = Update;
+updateChannelTooLong#eb0467fb flags:# channel_id:int pts:flags.0?int = Update;
+updateChannel#b6d45656 channel_id:int = Update;
+updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update;
+updateReadChannelInbox#330b5424 flags:# folder_id:flags.0?int channel_id:int max_id:int still_unread_count:int pts:int = Update;
+updateDeleteChannelMessages#c37521c9 channel_id:int messages:Vector<int> pts:int pts_count:int = Update;
+updateChannelMessageViews#98a12b4b channel_id:int id:int views:int = Update;
+updateChatParticipantAdmin#b6901959 chat_id:int user_id:int is_admin:Bool version:int = Update;
+updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update;
+updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true order:Vector<long> = Update;
+updateStickerSets#43ae3dec = Update;
+updateSavedGifs#9375341e = Update;
+updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo:flags.0?GeoPoint offset:string = Update;
+updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update;
+updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update;
+updateChannelPinnedMessage#98592475 channel_id:int id:int = Update;
+updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int 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#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update;
+updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update;
+updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update;
+updateReadFeaturedStickers#571d2742 = Update;
+updateRecentStickers#9a422c20 = Update;
+updateConfig#a229dd06 = Update;
+updatePtsChanged#3354678f = Update;
+updateChannelWebPage#40771900 channel_id:int 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#e0cdc940 query_id:long user_id:int payload:bytes shipping_address:PostAddress = Update;
+updateBotPrecheckoutQuery#5d2f3aa9 flags:# query_id:long user_id:int 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#89893b45 channel_id:int messages:Vector<int> = Update;
+updateContactsReset#7084a7be = Update;
+updateChannelAvailableMessages#70db6837 channel_id:int available_min_id:int = Update;
+updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update;
+updateUserPinnedMessage#4c43da18 user_id:int id:int = Update;
+updateChatPinnedMessage#e10db349 chat_id:int id:int version:int = Update;
+updateMessagePoll#aca1657b flags:# 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#90866cee peer:Peer messages:Vector<int> = Update;
+updateTheme#8216fba3 theme:Theme = 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#914fbf11 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
+updateShortChatMessage#16812688 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = 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#11f1331c flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector<MessageEntity> = 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 id:int ip_address:string port:int secret:flags.10?bytes = DcOption;
+
+config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true ignore_phone_entities:flags.5?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true pfs_enabled:flags.13?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 saved_gifs_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int pinned_infolder_count_max: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 = Config;
+
+nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
+
+help.appUpdate#1da7158f flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector<MessageEntity> document:flags.1?Document url:flags.2?string = help.AppUpdate;
+help.noAppUpdate#c45a6536 = help.AppUpdate;
+
+help.inviteText#18cb9f78 message:string = help.InviteText;
+
+encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat;
+encryptedChatWaiting#3bf703dc id:int access_hash:long date:int admin_id:int participant_id:int = EncryptedChat;
+encryptedChatRequested#c878527e id:int access_hash:long date:int admin_id:int participant_id:int g_a:bytes = EncryptedChat;
+encryptedChat#fa56ce36 id:int access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long = EncryptedChat;
+encryptedChatDiscarded#13d6dd27 id:int = EncryptedChat;
+
+inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat;
+
+encryptedFileEmpty#c21f497e = EncryptedFile;
+encryptedFile#4a70994c id:long access_hash:long size:int 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#9ba29cc1 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector<PhotoSize> 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;
+
+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;
+
+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;
+
+privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey;
+privacyKeyChatInvite#500e6dfa = PrivacyKey;
+privacyKeyPhoneCall#3d662b7b = PrivacyKey;
+privacyKeyPhoneP2P#39491cc8 = PrivacyKey;
+privacyKeyForwards#69ec56a3 = PrivacyKey;
+privacyKeyProfilePhoto#96151fed = PrivacyKey;
+privacyKeyPhoneNumber#d19ae46d = PrivacyKey;
+privacyKeyAddedByPhone#42ffd42b = 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#4c81c1ba chats:Vector<int> = InputPrivacyRule;
+inputPrivacyValueDisallowChatParticipants#d82363af chats:Vector<int> = InputPrivacyRule;
+
+privacyValueAllowContacts#fffe1bac = PrivacyRule;
+privacyValueAllowAll#65427b82 = PrivacyRule;
+privacyValueAllowUsers#4d5bbe0c users:Vector<int> = PrivacyRule;
+privacyValueDisallowContacts#f888fa1a = PrivacyRule;
+privacyValueDisallowAll#8b73e763 = PrivacyRule;
+privacyValueDisallowUsers#c7f49b7 users:Vector<int> = PrivacyRule;
+privacyValueAllowChatParticipants#18be796b chats:Vector<int> = PrivacyRule;
+privacyValueDisallowChatParticipants#acae0690 chats:Vector<int> = 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#ef02ce6 flags:# round_message:flags.0?true supports_streaming:flags.1?true duration:int w:int h:int = 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;
+
+messages.stickersNotModified#f1749a22 = messages.Stickers;
+messages.stickers#e4599bbd hash:int stickers:Vector<Document> = messages.Stickers;
+
+stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;
+
+messages.allStickersNotModified#e86602c3 = messages.AllStickers;
+messages.allStickers#edfd405f hash:int sets:Vector<StickerSet> = messages.AllStickers;
+
+messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages;
+
+webPageEmpty#eb1477e8 id:long = WebPage;
+webPagePending#c586da1c id:long date:int = WebPage;
+webPage#fa64e172 flags:# 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 documents:flags.11?Vector<Document> cached_page:flags.10?Page = WebPage;
+webPageNotModified#85849473 = WebPage;
+
+authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?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#1250abde authorizations:Vector<Authorization> = account.Authorizations;
+
+account.password#ad2641f8 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 = 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;
+
+chatInviteEmpty#69df3769 = ExportedChatInvite;
+chatInviteExported#fc2e05bc link:string = ExportedChatInvite;
+
+chatInviteAlready#5a686d7c chat:Chat = ChatInvite;
+chatInvite#dfc2f58e flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true title:string photo:Photo participants_count:int participants:flags.4?Vector<User> = ChatInvite;
+
+inputStickerSetEmpty#ffb62b95 = InputStickerSet;
+inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
+inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
+inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
+
+stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet;
+
+messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
+
+botCommand#c27ac8c7 command:string description:string = BotCommand;
+
+botInfo#98e81d3a user_id:int description:string commands:Vector<BotCommand> = BotInfo;
+
+keyboardButton#a2fa4880 text:string = KeyboardButton;
+keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton;
+keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton;
+keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton;
+keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton;
+keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton;
+keyboardButtonGame#50f41ccf text:string = KeyboardButton;
+keyboardButtonBuy#afd93fbb text:string = KeyboardButton;
+keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton;
+inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton;
+
+keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
+
+replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup;
+replyKeyboardForceReply#f4108aa0 flags:# single_use:flags.1?true selective:flags.2?true = ReplyMarkup;
+replyKeyboardMarkup#3502758c flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true rows:Vector<KeyboardButtonRow> = 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#352dca58 offset:int length:int user_id:int = 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;
+messageEntityBlockquote#20df5d0 offset:int length:int = MessageEntity;
+
+inputChannelEmpty#ee8c1e86 = InputChannel;
+inputChannel#afeb712e channel_id:int access_hash:long = InputChannel;
+inputChannelFromMessage#2a286531 peer:InputPeer msg_id:int channel_id:int = 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#15ebac1d user_id:int date:int = ChannelParticipant;
+channelParticipantSelf#a3289a6d user_id:int inviter_id:int date:int = ChannelParticipant;
+channelParticipantCreator#808d15a4 flags:# user_id:int rank:flags.0?string = ChannelParticipant;
+channelParticipantAdmin#ccbebbaf flags:# can_edit:flags.0?true self:flags.1?true user_id:int inviter_id:flags.1?int promoted_by:int date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant;
+channelParticipantBanned#1c0facaf flags:# left:flags.0?true user_id:int kicked_by:int date:int banned_rights:ChatBannedRights = 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;
+
+channels.channelParticipants#f56ee2a8 count:int participants:Vector<ChannelParticipant> users:Vector<User> = channels.ChannelParticipants;
+channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants;
+
+channels.channelParticipant#d0d9b163 participant:ChannelParticipant 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;
+
+foundGif#162ecc1f url:string thumb_url:string content_url:string content_type:string w:int h:int = FoundGif;
+foundGifCached#9c750409 url:string photo:Photo document:Document = FoundGif;
+
+messages.foundGifs#450a1c0a next_offset:int results:Vector<FoundGif> = messages.FoundGifs;
+
+messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs;
+messages.savedGifs#2e0709a5 hash:int gifs:Vector<Document> = messages.SavedGifs;
+
+inputBotInlineMessageMediaAuto#3380c786 flags:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
+inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
+inputBotInlineMessageMediaGeo#c1b15d65 flags:# geo_point:InputGeoPoint period: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;
+
+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:# message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
+botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
+botInlineMessageMediaGeo#b722de65 flags:# geo:GeoPoint period: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;
+
+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#947ca848 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM results:Vector<BotInlineResult> cache_time:int users:Vector<User> = messages.BotResults;
+
+exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
+
+messageFwdHeader#ec338270 flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
+
+auth.codeTypeSms#72a3158c = auth.CodeType;
+auth.codeTypeCall#741cd3e3 = auth.CodeType;
+auth.codeTypeFlashCall#226ccefb = 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;
+
+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;
+
+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;
+
+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#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage;
+
+messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers;
+messages.featuredStickers#f89d88e5 hash:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;
+
+messages.recentStickersNotModified#b17f890 = messages.RecentStickers;
+messages.recentStickers#22f3afb3 hash:int 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;
+
+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#58fffcd0 pos:int user_id:int 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;
+
+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:# 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 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#9a8ae1e1 items:Vector<PageListOrderedItem> = 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;
+
+phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason;
+phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason;
+phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason;
+phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason;
+
+dataJSON#7d748d04 data:string = DataJSON;
+
+labeledPrice#cb296bf8 label:string amount:long = LabeledPrice;
+
+invoice#c30aa358 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 currency:string prices:Vector<LabeledPrice> = 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;
+
+upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile;
+
+payments.paymentForm#3f56aea3 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true bot_id:int invoice:Invoice provider_id:int url:string native_provider:flags.4?string native_params:flags.4?DataJSON saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?PaymentSavedCredentials users:Vector<User> = 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#500911e1 flags:# date:int bot_id:int invoice:Invoice provider_id:int info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption currency:string total_amount:long credentials_title: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;
+inputPaymentCredentialsAndroidPay#ca05d50e payment_token:DataJSON google_transaction_id:string = InputPaymentCredentials;
+
+account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword;
+
+shippingOption#b6213cdf id:string title:string prices:Vector<LabeledPrice> = ShippingOption;
+
+inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords = InputStickerSetItem;
+
+inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall;
+
+phoneCallEmpty#5366c915 id:long = PhoneCall;
+phoneCallWaiting#1b8f4ad1 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall;
+phoneCallRequested#87eabb53 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall;
+phoneCallAccepted#997c454a flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall;
+phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector<PhoneConnection> start_date:int = PhoneCall;
+phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.5?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall;
+
+phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection;
+
+phoneCallProtocol#a2bb35cb flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int = 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#a26f881b prev_value:int new_value:int = ChannelAdminLogEventAction;
+channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction;
+channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction;
+
+channelAdminLogEvent#3b5a3e40 id:long date:int user_id:int 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 = ChannelAdminLogEventsFilter;
+
+popularContact#5ce14175 client_id:long importers:int = PopularContact;
+
+messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers;
+messages.favedStickers#f37f2f16 hash:int packs:Vector<StickerPack> stickers:Vector<Document> = messages.FavedStickers;
+
+recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl;
+recentMeUrlUser#8dbc3336 url:string user_id:int = RecentMeUrl;
+recentMeUrlChat#a01b22f9 url:string chat_id:int = 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#cac943f2 hash:long bot_id:int 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;
+
+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#5108d648 hash:int sets:Vector<StickerSetCovered> = messages.FoundStickerSets;
+
+fileHash#6242c773 offset:int limit:int hash:bytes = FileHash;
+
+inputClientProxy#75588b3f address:string port:int = InputClientProxy;
+
+help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData;
+help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector<Chat> users:Vector<User> = help.ProxyData;
+
+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#e0277a62 id:long access_hash:long size:int 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#b92fb6cd text:RichText = PageListItem;
+pageListItemBlocks#25e073fc blocks:Vector<PageBlock> = PageListItem;
+
+pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem;
+pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector<PageBlock> = 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#ae891bec flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector<PageBlock> photos:Vector<Photo> documents:Vector<Document> = 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#6ca9c2e9 text:string option:bytes = PollAnswer;
+
+poll#d5529d06 id:long flags:# closed:flags.0?true question:string answers:Vector<PollAnswer> = Poll;
+
+pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true option:bytes voters:int = PollAnswerVoters;
+
+pollResults#5755785a flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int = 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 = 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 until_date:int = ChatBannedRights;
+
+inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper;
+inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
+
+account.wallPapersNotModified#1c199183 = account.WallPapers;
+account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers;
+
+codeSettings#debebe83 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true = CodeSettings;
+
+wallPaperSettings#a12f40b8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int intensity:flags.3?int = WallPaperSettings;
+
+autoDownloadSettings#d246fd47 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true photo_size_max:int video_size_max:int file_size_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;
+
+fileLocationToBeDeprecated#bc7fc6cd volume_id:long local_id:int = FileLocation;
+
+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#92d33a0e flags:# request_write_access:flags.0?true bot:User domain:string = UrlAuthResult;
+urlAuthResultAccepted#8f8c0e4e url: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;
+
+restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason;
+
+inputTheme#3c5693e9 id:long access_hash:long = InputTheme;
+inputThemeSlug#f5890df1 slug:string = InputTheme;
+
+themeDocumentNotModified#483d270c = Theme;
+theme#f7d90ce0 flags:# creator:flags.0?true default:flags.1?true id:long access_hash:long slug:string title:string document:flags.2?Document installs_count:int = Theme;
+
+account.themesNotModified#f41eb622 = account.Themes;
+account.themes#7f676421 hash:int themes:Vector<Theme> = account.Themes;
+
+---functions---
+
+invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
+invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X;
+initConnection#785188b8 {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 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;
+
+auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
+auth.signUp#80eee427 phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization;
+auth.signIn#bcd51581 phone_number:string phone_code_hash:string phone_code:string = auth.Authorization;
+auth.logOut#5717da40 = Bool;
+auth.resetAuthorizations#9fab0d1a = Bool;
+auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization;
+auth.importAuthorization#e3ef9613 id:int 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#4ea56e92 code:string = auth.Authorization;
+auth.resendCode#3ef1a9bf phone_number:string phone_code_hash:string = auth.SentCode;
+auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool;
+auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector<long> = Bool;
+
+account.registerDevice#68976c6f flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector<int> = Bool;
+account.unregisterDevice#3076c4bf token_type:int token:string other_uids:Vector<int> = 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#aabb1763 hash:int = account.WallPapers;
+account.reportPeer#ae189d5f peer:InputPeer reason:ReportReason = 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#418d4e0b reason:string = 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#b86ba8e1 bot_id:int scope:string public_key:string = account.AuthorizationForm;
+account.acceptAuthorization#e7027c94 bot_id:int 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#7011509f email:string = account.SentEmailCode;
+account.verifyEmail#ecba39db email:string code:string = Bool;
+account.initTakeoutSession#f05b4804 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?int = 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 peer:flags.0?InputNotifyPeer = Updates;
+account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper;
+account.uploadWallPaper#dd853661 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#2b7ffd7f slug:string title:string document:InputDocument = Theme;
+account.updateTheme#3b8ea202 flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument = Theme;
+account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool;
+account.installTheme#7ae43737 flags:# dark:flags.0?true format:flags.1?string theme:flags.1?InputTheme = Bool;
+account.getTheme#8d9d742b format:string theme:InputTheme document_id:long = Theme;
+account.getThemes#285946f8 format:string hash:int = account.Themes;
+
+users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
+users.getFullUser#ca30a5b1 id:InputUser = UserFull;
+users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector<SecureValueError> = Bool;
+
+contacts.getContactIDs#2caa4a42 hash:int = Vector<int>;
+contacts.getStatuses#c4a353ee = Vector<ContactStatus>;
+contacts.getContacts#c023849f hash:int = 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#332b49fc id:InputUser = Bool;
+contacts.unblock#e54100bd id:InputUser = Bool;
+contacts.getBlocked#f57c350f offset:int limit:int = contacts.Blocked;
+contacts.search#11f812d8 q:string limit:int = contacts.Found;
+contacts.resolveUsername#f93ccba3 username:string = contacts.ResolvedPeer;
+contacts.getTopPeers#d4982db5 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 offset:int limit:int hash:int = 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#e8f463d0 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string = Updates;
+contacts.acceptContact#f831a20f id:InputUser = Updates;
+contacts.getLocated#a356056 geo_point:InputGeoPoint = Updates;
+
+messages.getMessages#63c66506 id:Vector<InputMessage> = messages.Messages;
+messages.getDialogs#a0ee3b73 flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:int = messages.Dialogs;
+messages.getHistory#dcbb8260 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
+messages.search#8614ef68 flags:# peer:InputPeer q:string from_id:flags.0?InputUser filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:int = messages.Messages;
+messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
+messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id: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#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
+messages.sendMessage#520c3870 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
+messages.sendMedia#3491eba9 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int = Updates;
+messages.forwardMessages#d9fee60e flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true grouped:flags.9?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer schedule_date:flags.10?int = Updates;
+messages.reportSpam#cf1592db peer:InputPeer = Bool;
+messages.getPeerSettings#3672e09c peer:InputPeer = PeerSettings;
+messages.report#bd82b658 peer:InputPeer id:Vector<int> reason:ReportReason = Bool;
+messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
+messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
+messages.editChatTitle#dc452855 chat_id:int title:string = Updates;
+messages.editChatPhoto#ca4c79d8 chat_id:int photo:InputChatPhoto = Updates;
+messages.addChatUser#f9a0aa09 chat_id:int user_id:InputUser fwd_limit:int = Updates;
+messages.deleteChatUser#e0611f16 chat_id:int user_id:InputUser = Updates;
+messages.createChat#9cb126e users:Vector<InputUser> title:string = Updates;
+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#edd923c5 chat_id:int = Bool;
+messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool;
+messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool;
+messages.sendEncrypted#a9776773 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage;
+messages.sendEncryptedFile#9a901b66 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#43d4f2c emoticon:string hash:int = messages.Stickers;
+messages.getAllStickers#1c9618b1 hash:int = messages.AllStickers;
+messages.getWebPagePreview#8b68b0cc flags:# message:string entities:flags.3?Vector<MessageEntity> = MessageMedia;
+messages.exportChatInvite#df7534c peer:InputPeer = ExportedChatInvite;
+messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
+messages.importChatInvite#6c50051c hash:string = Updates;
+messages.getStickerSet#2619a90e stickerset:InputStickerSet = 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#c4c8a55d peer:InputPeer id:Vector<int> increment:Bool = Vector<int>;
+messages.editChatAdmin#a9e69f2e chat_id:int user_id:InputUser is_admin:Bool = Bool;
+messages.migrateChat#15a3b8e3 chat_id:int = Updates;
+messages.searchGlobal#bf7225a4 flags:# folder_id:flags.0?int q:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
+messages.reorderStickerSets#78337739 flags:# masks:flags.0?true order:Vector<long> = Bool;
+messages.getDocumentByHash#338e2464 sha256:bytes size:int mime_type:string = Document;
+messages.searchGifs#bf9a776b q:string offset:int = messages.FoundGifs;
+messages.getSavedGifs#83bf3d52 hash:int = 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#eb5ea206 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 = Bool;
+messages.sendInlineBotResult#220815b0 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to_msg_id:flags.0?int random_id:long query_id:long id:string schedule_date:flags.10?int = Updates;
+messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
+messages.editMessage#48f71778 flags:# no_webpage:flags.1?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 = Updates;
+messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
+messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = 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#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
+messages.getAllDrafts#6a3f8d65 = Updates;
+messages.getFeaturedStickers#2dacca4f hash:int = messages.FeaturedStickers;
+messages.readFeaturedStickers#5b118126 id:Vector<long> = Bool;
+messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = 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 offset_id:long limit:int = messages.ArchivedStickers;
+messages.getMaskStickers#65b8c79f hash:int = 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#d0a48c4 user_id:InputUser max_id:int limit:int = messages.Chats;
+messages.getAllChats#eba80ff0 except_ids:Vector<int> = messages.Chats;
+messages.getWebPage#32ca8f91 url:string hash:int = 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#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia;
+messages.sendScreenshotNotification#c97df020 peer:InputPeer reply_to_msg_id:int random_id:long = Updates;
+messages.getFavedStickers#21ce0b0e hash:int = messages.FavedStickers;
+messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool;
+messages.getUnreadMentions#46578472 peer:InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
+messages.readMentions#f0189d3 peer:InputPeer = messages.AffectedHistory;
+messages.getRecentLocations#bbc45b09 peer:InputPeer limit:int hash:int = messages.Messages;
+messages.sendMultiMedia#cc0110cb flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int = Updates;
+messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile;
+messages.searchStickerSets#c2b7d08b flags:# exclude_featured:flags.0?true q:string hash:int = messages.FoundStickerSets;
+messages.getSplitRanges#1cff7e08 = Vector<MessageRange>;
+messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool;
+messages.getDialogUnreadMarks#22e24e22 = Vector<DialogPeer>;
+messages.clearAllDrafts#7e58ee9c = Bool;
+messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true peer:InputPeer id:int = Updates;
+messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector<bytes> = Updates;
+messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates;
+messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines;
+messages.getStatsURL#812c2ae6 flags:# dark:flags.0?true peer:InputPeer params:string = StatsURL;
+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#732eef00 peer:InputPeer filters:Vector<MessagesFilter> = Vector<messages.SearchCounter>;
+messages.requestUrlAuth#e33f5613 peer:InputPeer msg_id:int button_id:int = UrlAuthResult;
+messages.acceptUrlAuth#f729ea98 flags:# write_allowed:flags.0?true peer:InputPeer msg_id:int button_id:int = UrlAuthResult;
+messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool;
+messages.getScheduledHistory#e2c2685b peer:InputPeer hash:int = 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;
+
+updates.getState#edd4882a = updates.State;
+updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
+updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference;
+
+photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto;
+photos.uploadProfilePhoto#4f32c098 file:InputFile = 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;
+
+upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool;
+upload.getFile#b15a9afc flags:# precise:flags.0?true location:InputFileLocation offset:int 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#2000bcc3 file_token:bytes offset:int limit:int = upload.CdnFile;
+upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector<FileHash>;
+upload.getCdnFileHashes#4da54231 file_token:bytes offset:int = Vector<FileHash>;
+upload.getFileHashes#c7025931 location:InputFileLocation offset:int = 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.getAppChangelog#9010ef6f prev_app_version:string = Updates;
+help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
+help.getCdnConfig#52029342 = CdnConfig;
+help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;
+help.getProxyData#3d7758e1 = help.ProxyData;
+help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate;
+help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
+help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo;
+help.getAppConfig#98914110 = JSONValue;
+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;
+
+channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
+channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
+channels.deleteUserHistory#d10dd71b channel:InputChannel user_id:InputUser = messages.AffectedHistory;
+channels.reportSpam#fe087810 channel:InputChannel user_id:InputUser id:Vector<int> = Bool;
+channels.getMessages#ad8c9a23 channel:InputChannel id:Vector<InputMessage> = messages.Messages;
+channels.getParticipants#123e05e9 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:int = channels.ChannelParticipants;
+channels.getParticipant#546dd7a6 channel:InputChannel user_id:InputUser = channels.ChannelParticipant;
+channels.getChannels#a7f6bbb id:Vector<InputChannel> = messages.Chats;
+channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull;
+channels.createChannel#3d5fb10f flags:# broadcast:flags.0?true megagroup:flags.1?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string = Updates;
+channels.editAdmin#d33c8902 channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank: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#24b524c5 channel:InputChannel = Updates;
+channels.leaveChannel#f836aa95 channel:InputChannel = Updates;
+channels.inviteToChannel#199f3a6c channel:InputChannel users:Vector<InputUser> = Updates;
+channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
+channels.exportMessageLink#ceb77163 channel:InputChannel id:int grouped:Bool = ExportedMessageLink;
+channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
+channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true = messages.Chats;
+channels.editBanned#72796912 channel:InputChannel user_id:InputUser 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#af369d42 channel:InputChannel max_id:int = Bool;
+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.editCreator#8f38cd1f channel:InputChannel user_id:InputUser password:InputCheckPasswordSRP = Updates;
+channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool;
+channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates;
+
+bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
+bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
+
+payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm;
+payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt;
+payments.validateRequestedInfo#770a8e74 flags:# save:flags.0?true msg_id:int info:PaymentRequestedInfo = payments.ValidatedRequestedInfo;
+payments.sendPaymentForm#2b8879b3 flags:# msg_id:int requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials = payments.PaymentResult;
+payments.getSavedInfo#227d824b = payments.SavedInfo;
+payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool;
+
+stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector<InputStickerSetItem> = 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;
+
+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;
+
+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;
+folders.deleteFolder#1c295881 folder_id:int = Updates;
+
+// LAYER 105

+ 288 - 0
gramjs_generator/data/errors.csv

@@ -0,0 +1,288 @@
+name,codes,description
+ABOUT_TOO_LONG,400,The provided bio is too long
+ACCESS_TOKEN_EXPIRED,400,Bot token expired
+ACCESS_TOKEN_INVALID,400,The provided token is not valid
+ACTIVE_USER_REQUIRED,401,The method is only available to already activated users
+ADMINS_TOO_MUCH,400,Too many admins
+ADMIN_RANK_EMOJI_NOT_ALLOWED,400,Emoji are not allowed in admin titles or ranks
+ADMIN_RANK_INVALID,400,The given admin title or rank was invalid (possibly larger than 16 characters)
+API_ID_INVALID,400,The api_id/api_hash combination is invalid
+API_ID_PUBLISHED_FLOOD,400,"This API id was published somewhere, you can't use it now"
+ARTICLE_TITLE_EMPTY,400,The title of the article is empty
+AUTH_BYTES_INVALID,400,The provided authorization is invalid
+AUTH_KEY_DUPLICATED,406,"The authorization key (session file) was used under two different IP addresses simultaneously, and can no longer be used. Use the same session exclusively, or use different sessions"
+AUTH_KEY_INVALID,401,The key is invalid
+AUTH_KEY_PERM_EMPTY,401,"The method is unavailable for temporary authorization key, not bound to permanent"
+AUTH_KEY_UNREGISTERED,401,The key is not registered in the system
+AUTH_RESTART,500,Restart the authorization process
+BANNED_RIGHTS_INVALID,400,"You cannot use that set of permissions in this request, i.e. restricting view_messages as a default"
+BOTS_TOO_MUCH,400,There are too many bots in this chat/channel
+BOT_CHANNELS_NA,400,Bots can't edit admin privileges
+BOT_GROUPS_BLOCKED,400,This bot can't be added to groups
+BOT_INLINE_DISABLED,400,This bot can't be used in inline mode
+BOT_INVALID,400,This is not a valid bot
+BOT_METHOD_INVALID,400,The API access for bot users is restricted. The method you tried to invoke cannot be executed as a bot
+BOT_MISSING,400,This method can only be run by a bot
+BOT_PAYMENTS_DISABLED,400,This method can only be run by a bot
+BOT_POLLS_DISABLED,400,You cannot create polls under a bot account
+BROADCAST_ID_INVALID,400,The channel is invalid
+BUTTON_DATA_INVALID,400,The provided button data is invalid
+BUTTON_TYPE_INVALID,400,The type of one of the buttons you provided is invalid
+BUTTON_URL_INVALID,400,Button URL invalid
+CALL_ALREADY_ACCEPTED,400,The call was already accepted
+CALL_ALREADY_DECLINED,400,The call was already declined
+CALL_OCCUPY_FAILED,500,The call failed because the user is already making another call
+CALL_PEER_INVALID,400,The provided call peer object is invalid
+CALL_PROTOCOL_FLAGS_INVALID,400,Call protocol flags invalid
+CDN_METHOD_INVALID,400,This method cannot be invoked on a CDN server. Refer to https://core.telegram.org/cdn#schema for available methods
+CHANNELS_ADMIN_PUBLIC_TOO_MUCH,400,"You're admin of too many public channels, make some channels private to change the username of this channel"
+CHANNELS_TOO_MUCH,400,You have joined too many channels/supergroups
+CHANNEL_INVALID,400,"Invalid channel object. Make sure to pass the right types, for instance making sure that the request is designed for channels or otherwise look for a different one more suited"
+CHANNEL_PRIVATE,400,The channel specified is private and you lack permission to access it. Another reason may be that you were banned from it
+CHANNEL_PUBLIC_GROUP_NA,403,channel/supergroup not available
+CHAT_ABOUT_NOT_MODIFIED,400,About text has not changed
+CHAT_ABOUT_TOO_LONG,400,Chat about too long
+CHAT_ADMIN_INVITE_REQUIRED,403,You do not have the rights to do this
+CHAT_ADMIN_REQUIRED,400 403,"Chat admin privileges are required to do that in the specified chat (for example, to send a message in a channel which is not yours), or invalid permissions used for the channel or group"
+CHAT_FORBIDDEN,,You cannot write in this chat
+CHAT_ID_EMPTY,400,The provided chat ID is empty
+CHAT_ID_INVALID,400,"Invalid object ID for a chat. Make sure to pass the right types, for instance making sure that the request is designed for chats (not channels/megagroups) or otherwise look for a different one more suited\nAn example working with a megagroup and AddChatUserRequest, it will fail because megagroups are channels. Use InviteToChannelRequest instead"
+CHAT_INVALID,400,The chat is invalid for this request
+CHAT_LINK_EXISTS,400,The chat is linked to a channel and cannot be used in that request
+CHAT_NOT_MODIFIED,400,"The chat or channel wasn't modified (title, invites, username, admins, etc. are the same)"
+CHAT_RESTRICTED,400,The chat is restricted and cannot be used in that request
+CHAT_SEND_GIFS_FORBIDDEN,403,You can't send gifs in this chat
+CHAT_SEND_INLINE_FORBIDDEN,400,You cannot send inline results in this chat
+CHAT_SEND_MEDIA_FORBIDDEN,403,You can't send media in this chat
+CHAT_SEND_STICKERS_FORBIDDEN,403,You can't send stickers in this chat
+CHAT_TITLE_EMPTY,400,No chat title provided
+CHAT_WRITE_FORBIDDEN,403,You can't write in this chat
+CODE_EMPTY,400,The provided code is empty
+CODE_HASH_INVALID,400,Code hash invalid
+CODE_INVALID,400,Code invalid (i.e. from email)
+CONNECTION_API_ID_INVALID,400,The provided API id is invalid
+CONNECTION_DEVICE_MODEL_EMPTY,400,Device model empty
+CONNECTION_LANG_PACK_INVALID,400,"The specified language pack is not valid. This is meant to be used by official applications only so far, leave it empty"
+CONNECTION_LAYER_INVALID,400,The very first request must always be InvokeWithLayerRequest
+CONNECTION_NOT_INITED,400,Connection not initialized
+CONNECTION_SYSTEM_EMPTY,400,Connection system empty
+CONTACT_ID_INVALID,400,The provided contact ID is invalid
+DATA_INVALID,400,Encrypted data invalid
+DATA_JSON_INVALID,400,The provided JSON data is invalid
+DATE_EMPTY,400,Date empty
+DC_ID_INVALID,400,This occurs when an authorization is tried to be exported for the same data center one is currently connected to
+DH_G_A_INVALID,400,g_a invalid
+EMAIL_HASH_EXPIRED,400,The email hash expired and cannot be used to verify it
+EMAIL_INVALID,400,The given email is invalid
+EMAIL_UNCONFIRMED_X,400,"Email unconfirmed, the length of the code must be {code_length}"
+EMOTICON_EMPTY,400,The emoticon field cannot be empty
+ENCRYPTED_MESSAGE_INVALID,400,Encrypted message invalid
+ENCRYPTION_ALREADY_ACCEPTED,400,Secret chat already accepted
+ENCRYPTION_ALREADY_DECLINED,400,The secret chat was already declined
+ENCRYPTION_DECLINED,400,The secret chat was declined
+ENCRYPTION_ID_INVALID,400,The provided secret chat ID is invalid
+ENCRYPTION_OCCUPY_FAILED,500,TDLib developer claimed it is not an error while accepting secret chats and 500 is used instead of 420
+ENTITIES_TOO_LONG,400,It is no longer possible to send such long data inside entity tags (for example inline text URLs)
+ENTITY_MENTION_USER_INVALID,400,You can't use this entity
+ERROR_TEXT_EMPTY,400,The provided error message is empty
+EXPORT_CARD_INVALID,400,Provided card is invalid
+EXTERNAL_URL_INVALID,400,External URL invalid
+FIELD_NAME_EMPTY,,The field with the name FIELD_NAME is missing
+FIELD_NAME_INVALID,,The field with the name FIELD_NAME is invalid
+FILE_ID_INVALID,400,The provided file id is invalid
+FILE_MIGRATE_X,303,The file to be accessed is currently stored in DC {new_dc}
+FILE_PARTS_INVALID,400,The number of file parts is invalid
+FILE_PART_0_MISSING,,File part 0 missing
+FILE_PART_EMPTY,400,The provided file part is empty
+FILE_PART_INVALID,400,The file part number is invalid
+FILE_PART_LENGTH_INVALID,400,The length of a file part is invalid
+FILE_PART_SIZE_INVALID,400,The provided file part size is invalid
+FILE_PART_X_MISSING,400,Part {which} of the file is missing from storage
+FILEREF_UPGRADE_NEEDED,406,The file reference needs to be refreshed before being used again
+FIRSTNAME_INVALID,400,The first name is invalid
+FLOOD_TEST_PHONE_WAIT_X,420,A wait of {seconds} seconds is required in the test servers
+FLOOD_WAIT_X,420,A wait of {seconds} seconds is required
+FOLDER_ID_EMPTY,400,The folder you tried to delete was already empty
+FOLDER_ID_INVALID,400,The folder you tried to use was not valid
+FRESH_RESET_AUTHORISATION_FORBIDDEN,406,The current session is too new and cannot be used to reset other authorisations yet
+GIF_ID_INVALID,400,The provided GIF ID is invalid
+GROUPED_MEDIA_INVALID,400,Invalid grouped media
+HASH_INVALID,400,The provided hash is invalid
+HISTORY_GET_FAILED,500,Fetching of history failed
+IMAGE_PROCESS_FAILED,400,Failure while processing image
+INLINE_RESULT_EXPIRED,400,The inline query expired
+INPUT_CONSTRUCTOR_INVALID,400,The provided constructor is invalid
+INPUT_FETCH_ERROR,,An error occurred while deserializing TL parameters
+INPUT_FETCH_FAIL,400,Failed deserializing TL payload
+INPUT_LAYER_INVALID,400,The provided layer is invalid
+INPUT_METHOD_INVALID,,The invoked method does not exist anymore or has never existed
+INPUT_REQUEST_TOO_LONG,400,The input request was too long. This may be a bug in the library as it can occur when serializing more bytes than it should (like appending the vector constructor code at the end of a message)
+INPUT_USER_DEACTIVATED,400,The specified user was deleted
+INTERDC_X_CALL_ERROR,,An error occurred while communicating with DC {dc}
+INTERDC_X_CALL_RICH_ERROR,,A rich error occurred while communicating with DC {dc}
+INVITE_HASH_EMPTY,400,The invite hash is empty
+INVITE_HASH_EXPIRED,400,The chat the user tried to join has expired and is not valid anymore
+INVITE_HASH_INVALID,400,The invite hash is invalid
+LANG_PACK_INVALID,400,The provided language pack is invalid
+LASTNAME_INVALID,,The last name is invalid
+LIMIT_INVALID,400,An invalid limit was provided. See https://core.telegram.org/api/files#downloading-files
+LINK_NOT_MODIFIED,400,The channel is already linked to this group
+LOCATION_INVALID,400,The location given for a file was invalid. See https://core.telegram.org/api/files#downloading-files
+MAX_ID_INVALID,400,The provided max ID is invalid
+MAX_QTS_INVALID,400,The provided QTS were invalid
+MD5_CHECKSUM_INVALID,,The MD5 check-sums do not match
+MEDIA_CAPTION_TOO_LONG,400,The caption is too long
+MEDIA_EMPTY,400,The provided media object is invalid
+MEDIA_INVALID,400,Media invalid
+MEDIA_NEW_INVALID,400,The new media to edit the message with is invalid (such as stickers or voice notes)
+MEDIA_PREV_INVALID,400,The old media cannot be edited with anything else (such as stickers or voice notes)
+MEGAGROUP_ID_INVALID,400,The group is invalid
+MEGAGROUP_PREHISTORY_HIDDEN,400,You can't set this discussion group because it's history is hidden
+MEMBER_NO_LOCATION,500,An internal failure occurred while fetching user info (couldn't find location)
+MEMBER_OCCUPY_PRIMARY_LOC_FAILED,500,Occupation of primary member location failed
+MESSAGE_AUTHOR_REQUIRED,403,Message author required
+MESSAGE_DELETE_FORBIDDEN,403,"You can't delete one of the messages you tried to delete, most likely because it is a service message."
+MESSAGE_EDIT_TIME_EXPIRED,400,"You can't edit this message anymore, too much time has passed since its creation."
+MESSAGE_EMPTY,400,Empty or invalid UTF-8 message was sent
+MESSAGE_IDS_EMPTY,400,No message ids were provided
+MESSAGE_ID_INVALID,400,"The specified message ID is invalid or you can't do that operation on such message"
+MESSAGE_NOT_MODIFIED,400,Content of the message was not modified
+MESSAGE_TOO_LONG,400,Message was too long. Current maximum length is 4096 UTF-8 characters
+MSG_WAIT_FAILED,400,A waiting call returned an error
+MT_SEND_QUEUE_TOO_LONG,500,
+NEED_CHAT_INVALID,500,The provided chat is invalid
+NEED_MEMBER_INVALID,500,The provided member is invalid or does not exist (for example a thumb size)
+NETWORK_MIGRATE_X,303,The source IP address is associated with DC {new_dc}
+NEW_SALT_INVALID,400,The new salt is invalid
+NEW_SETTINGS_INVALID,400,The new settings are invalid
+OFFSET_INVALID,400,"The given offset was invalid, it must be divisible by 1KB. See https://core.telegram.org/api/files#downloading-files"
+OFFSET_PEER_ID_INVALID,400,The provided offset peer is invalid
+OPTIONS_TOO_MUCH,400,You defined too many options for the poll
+PACK_SHORT_NAME_INVALID,400,"Invalid sticker pack name. It must begin with a letter, can't contain consecutive underscores and must end in ""_by_<bot username>""."
+PACK_SHORT_NAME_OCCUPIED,400,A stickerpack with this name already exists
+PARTICIPANTS_TOO_FEW,400,Not enough participants
+PARTICIPANT_CALL_FAILED,500,Failure while making call
+PARTICIPANT_VERSION_OUTDATED,400,The other participant does not use an up to date telegram client with support for calls
+PASSWORD_EMPTY,400,The provided password is empty
+PASSWORD_HASH_INVALID,400,The password (and thus its hash value) you entered is invalid
+PASSWORD_REQUIRED,400,The account must have 2-factor authentication enabled (a password) before this method can be used
+PAYMENT_PROVIDER_INVALID,400,The payment provider was not recognised or its token was invalid
+PEER_FLOOD,,Too many requests
+PEER_ID_INVALID,400,An invalid Peer was used. Make sure to pass the right peer type
+PEER_ID_NOT_SUPPORTED,400,The provided peer ID is not supported
+PERSISTENT_TIMESTAMP_EMPTY,400,Persistent timestamp empty
+PERSISTENT_TIMESTAMP_INVALID,400,Persistent timestamp invalid
+PERSISTENT_TIMESTAMP_OUTDATED,500,Persistent timestamp outdated
+PHONE_CODE_EMPTY,400,The phone code is missing
+PHONE_CODE_EXPIRED,400,The confirmation code has expired
+PHONE_CODE_HASH_EMPTY,,The phone code hash is missing
+PHONE_CODE_INVALID,400,The phone code entered was invalid
+PHONE_MIGRATE_X,303,The phone number a user is trying to use for authorization is associated with DC {new_dc}
+PHONE_NUMBER_APP_SIGNUP_FORBIDDEN,400,
+PHONE_NUMBER_BANNED,400,The used phone number has been banned from Telegram and cannot be used anymore. Maybe check https://www.telegram.org/faq_spam
+PHONE_NUMBER_FLOOD,400,You asked for the code too many times.
+PHONE_NUMBER_INVALID,400 406,The phone number is invalid
+PHONE_NUMBER_OCCUPIED,400,The phone number is already in use
+PHONE_NUMBER_UNOCCUPIED,400,The phone number is not yet being used
+PHONE_PASSWORD_FLOOD,406,You have tried logging in too many times
+PHONE_PASSWORD_PROTECTED,400,This phone is password protected
+PHOTO_CONTENT_URL_EMPTY,400,The content from the URL used as a photo appears to be empty or has caused another HTTP error
+PHOTO_CROP_SIZE_SMALL,400,Photo is too small
+PHOTO_EXT_INVALID,400,The extension of the photo is invalid
+PHOTO_INVALID,400,Photo invalid
+PHOTO_INVALID_DIMENSIONS,400,The photo dimensions are invalid (hint: `pip install pillow` for `send_file` to resize images)
+PHOTO_SAVE_FILE_INVALID,400,The photo you tried to send cannot be saved by Telegram. A reason may be that it exceeds 10MB. Try resizing it locally
+PHOTO_THUMB_URL_EMPTY,400,The URL used as a thumbnail appears to be empty or has caused another HTTP error
+PIN_RESTRICTED,400,You can't pin messages in private chats with other people
+POLL_OPTION_DUPLICATE,400,A duplicate option was sent in the same poll
+POLL_UNSUPPORTED,400,This layer does not support polls in the issued method
+PRIVACY_KEY_INVALID,400,The privacy key is invalid
+PTS_CHANGE_EMPTY,500,No PTS change
+QUERY_ID_EMPTY,400,The query ID is empty
+QUERY_ID_INVALID,400,The query ID is invalid
+QUERY_TOO_SHORT,400,The query string is too short
+RANDOM_ID_DUPLICATE,500,You provided a random ID that was already used
+RANDOM_ID_INVALID,400,A provided random ID is invalid
+RANDOM_LENGTH_INVALID,400,Random length invalid
+RANGES_INVALID,400,Invalid range provided
+REACTION_INVALID,400,Invalid reaction provided (only emoji are allowed)
+REG_ID_GENERATE_FAILED,500,Failure while generating registration ID
+REPLY_MARKUP_INVALID,400,The provided reply markup is invalid
+REPLY_MARKUP_TOO_LONG,400,The data embedded in the reply markup buttons was too much
+RESULT_ID_DUPLICATE,400,Duplicated IDs on the sent results. Make sure to use unique IDs.
+RESULT_TYPE_INVALID,400,Result type invalid
+RESULTS_TOO_MUCH,400,You sent too many results. See https://core.telegram.org/bots/api#answerinlinequery for the current limit.
+RIGHT_FORBIDDEN,403,Either your admin rights do not allow you to do this or you passed the wrong rights combination (some rights only apply to channels and vice versa)
+RPC_CALL_FAIL,,"Telegram is having internal issues, please try again later."
+RPC_MCGET_FAIL,,"Telegram is having internal issues, please try again later."
+RSA_DECRYPT_FAILED,400,Internal RSA decryption failed
+SCHEDULE_DATE_TOO_LATE,400,The date you tried to schedule is too far in the future (several years long)
+SCHEDULE_TOO_MUCH,400,You cannot schedule more messages in this chat (last known limit of 100 per chat)
+SEARCH_QUERY_EMPTY,400,The search query is empty
+SECONDS_INVALID,400,"Slow mode only supports certain values (e.g. 0, 10s, 30s, 1m, 5m, 15m and 1h)"
+SEND_MESSAGE_MEDIA_INVALID,400,The message media was invalid or not specified
+SEND_MESSAGE_TYPE_INVALID,400,The message type is invalid
+SESSION_EXPIRED,401,The authorization has expired
+SESSION_PASSWORD_NEEDED,401,Two-steps verification is enabled and a password is required
+SESSION_REVOKED,401,"The authorization has been invalidated, because of the user terminating all sessions"
+SHA256_HASH_INVALID,400,The provided SHA256 hash is invalid
+SHORTNAME_OCCUPY_FAILED,400,An error occurred when trying to register the short-name used for the sticker pack. Try a different name
+START_PARAM_EMPTY,400,The start parameter is empty
+START_PARAM_INVALID,400,Start parameter invalid
+STICKERSET_INVALID,400,The provided sticker set is invalid
+STICKERS_EMPTY,400,No sticker provided
+STICKER_EMOJI_INVALID,400,Sticker emoji invalid
+STICKER_FILE_INVALID,400,Sticker file invalid
+STICKER_ID_INVALID,400,The provided sticker ID is invalid
+STICKER_INVALID,400,The provided sticker is invalid
+STICKER_PNG_DIMENSIONS,400,Sticker png dimensions invalid
+STORAGE_CHECK_FAILED,500,Server storage check failed
+STORE_INVALID_SCALAR_TYPE,500,
+TAKEOUT_INIT_DELAY_X,420,A wait of {seconds} seconds is required before being able to initiate the takeout
+TAKEOUT_INVALID,400,The takeout session has been invalidated by another data export session
+TAKEOUT_REQUIRED,400,You must initialize a takeout request first
+TEMP_AUTH_KEY_EMPTY,400,No temporary auth key provided
+Timeout,-503,A timeout occurred while fetching data from the bot
+TMP_PASSWORD_DISABLED,400,The temporary password is disabled
+TOKEN_INVALID,400,The provided token is invalid
+TTL_DAYS_INVALID,400,The provided TTL is invalid
+TYPES_EMPTY,400,The types field is empty
+TYPE_CONSTRUCTOR_INVALID,,The type constructor is invalid
+UNKNOWN_METHOD,500,The method you tried to call cannot be called on non-CDN DCs
+UNTIL_DATE_INVALID,400,That date cannot be specified in this request (try using None)
+URL_INVALID,400,The URL used was invalid (e.g. when answering a callback with an URL that's not t.me/yourbot or your game's URL)
+USERNAME_INVALID,400,"Nobody is using this username, or the username is unacceptable. If the latter, it must match r""[a-zA-Z][\w\d]{3,30}[a-zA-Z\d]"""
+USERNAME_NOT_MODIFIED,400,The username is not different from the current username
+USERNAME_NOT_OCCUPIED,400,The username is not in use by anyone else yet
+USERNAME_OCCUPIED,400,The username is already taken
+USERS_TOO_FEW,400,"Not enough users (to create a chat, for example)"
+USERS_TOO_MUCH,400,"The maximum number of users has been exceeded (to create a chat, for example)"
+USER_ADMIN_INVALID,400,Either you're not an admin or you tried to ban an admin that you didn't promote
+USER_ALREADY_PARTICIPANT,400,The authenticated user is already a participant of the chat
+USER_BANNED_IN_CHANNEL,400,You're banned from sending messages in supergroups/channels
+USER_BLOCKED,400,User blocked
+USER_BOT,400,Bots can only be admins in channels.
+USER_BOT_INVALID,400 403,This method can only be called by a bot
+USER_BOT_REQUIRED,400,This method can only be called by a bot
+USER_CHANNELS_TOO_MUCH,403,One of the users you tried to add is already in too many channels/supergroups
+USER_CREATOR,400,"You can't leave this channel, because you're its creator"
+USER_DEACTIVATED,401,The user has been deleted/deactivated
+USER_DEACTIVATED_BAN,401,The user has been deleted/deactivated
+USER_ID_INVALID,400,"Invalid object ID for a user. Make sure to pass the right types, for instance making sure that the request is designed for users or otherwise look for a different one more suited"
+USER_INVALID,400,The given user was invalid
+USER_IS_BLOCKED,400 403,User is blocked
+USER_IS_BOT,400,Bots can't send messages to other bots
+USER_KICKED,400,This user was kicked from this supergroup/channel
+USER_MIGRATE_X,303,The user whose identity is being used to execute queries is associated with DC {new_dc}
+USER_NOT_MUTUAL_CONTACT,400 403,The provided user is not a mutual contact
+USER_NOT_PARTICIPANT,400,The target user is not a member of the specified megagroup or channel
+USER_PRIVACY_RESTRICTED,403,The user's privacy settings do not allow you to do this
+USER_RESTRICTED,403,"You're spamreported, you can't create channels or chats."
+VIDEO_CONTENT_TYPE_INVALID,400,The video content type is not supported with the given parameters (i.e. supports_streaming)
+WALLPAPER_FILE_INVALID,400,The given file cannot be used as a wallpaper
+WALLPAPER_INVALID,400,The input wallpaper was not valid
+WC_CONVERT_URL_INVALID,400,WC convert URL invalid
+WEBPAGE_CURL_FAILED,400,Failure while fetching the webpage with cURL
+WEBPAGE_MEDIA_EMPTY,400,Webpage media empty
+WORKER_BUSY_TOO_LONG_RETRY,500,Telegram workers are too busy to respond immediately
+YOU_BLOCKED_USER,400,You blocked this user

+ 27 - 0
gramjs_generator/data/friendly.csv

@@ -0,0 +1,27 @@
+ns,friendly,raw
+account.AccountMethods,takeout,invokeWithTakeout account.initTakeoutSession account.finishTakeoutSession
+auth.AuthMethods,sign_in,auth.signIn auth.importBotAuthorization
+auth.AuthMethods,sign_up,auth.signUp
+auth.AuthMethods,send_code_request,auth.sendCode auth.resendCode
+auth.AuthMethods,log_out,auth.logOut
+auth.AuthMethods,edit_2fa,account.updatePasswordSettings
+bots.BotMethods,inline_query,messages.getInlineBotResults
+chats.ChatMethods,action,messages.setTyping
+chats.ChatMethods,edit_admin,channels.editAdmin messages.editChatAdmin
+chats.ChatMethods,edit_permissions,channels.editBanned messages.editChatDefaultBannedRights
+chats.ChatMethods,iter_participants,channels.getParticipants
+chats.ChatMethods,iter_admin_log,channels.getAdminLog
+dialogs.DialogMethods,iter_dialogs,messages.getDialogs
+dialogs.DialogMethods,iter_drafts,messages.getAllDrafts
+dialogs.DialogMethods,edit_folder,folders.deleteFolder folders.editPeerFolders
+downloads.DownloadMethods,download_media,upload.getFile
+messages.MessageMethods,iter_messages,messages.searchGlobal messages.search messages.getHistory channels.getMessages messages.getMessages
+messages.MessageMethods,send_message,messages.sendMessage
+messages.MessageMethods,forward_messages,messages.forwardMessages
+messages.MessageMethods,edit_message,messages.editInlineBotMessage messages.editMessage
+messages.MessageMethods,delete_messages,channels.deleteMessages messages.deleteMessages
+messages.MessageMethods,send_read_acknowledge,messages.readMentions channels.readHistory messages.readHistory
+updates.UpdateMethods,catch_up,updates.getDifference updates.getChannelDifference
+uploads.UploadMethods,send_file,messages.sendMedia messages.sendMultiMedia messages.uploadMedia
+uploads.UploadMethods,upload_file,upload.saveFilePart upload.saveBigFilePart
+users.UserMethods,get_entity,users.getUsers messages.getChats channels.getChannels contacts.resolveUsername

+ 300 - 0
gramjs_generator/data/methods.csv

@@ -0,0 +1,300 @@
+method,usability,errors
+account.acceptAuthorization,user,
+account.cancelPasswordEmail,user,
+account.changePhone,user,PHONE_NUMBER_INVALID
+account.checkUsername,user,USERNAME_INVALID
+account.confirmPasswordEmail,user,
+account.confirmPhone,user,CODE_HASH_INVALID PHONE_CODE_EMPTY
+account.deleteSecureValue,user,
+account.finishTakeoutSession,user,
+account.getAccountTTL,user,
+account.getAllSecureValues,user,
+account.getAuthorizationForm,user,
+account.getAuthorizations,user,
+account.getContactSignUpNotification,user,
+account.getNotifyExceptions,user,
+account.getNotifySettings,user,PEER_ID_INVALID
+account.getPassword,user,
+account.getPasswordSettings,user,PASSWORD_HASH_INVALID
+account.getPrivacy,user,PRIVACY_KEY_INVALID
+account.getSecureValue,user,
+account.getTmpPassword,user,PASSWORD_HASH_INVALID TMP_PASSWORD_DISABLED
+account.getWallPaper,user,WALLPAPER_INVALID
+account.getWallPapers,user,
+account.getWebAuthorizations,user,
+account.initTakeoutSession,user,
+account.installWallPaper,user,WALLPAPER_INVALID
+account.registerDevice,user,TOKEN_INVALID
+account.reportPeer,user,PEER_ID_INVALID
+account.resendPasswordEmail,user,
+account.resetAuthorization,user,HASH_INVALID
+account.resetNotifySettings,user,
+account.resetWallPapers,user,
+account.resetWebAuthorization,user,
+account.resetWebAuthorizations,user,
+account.saveSecureValue,user,PASSWORD_REQUIRED
+account.saveWallPaper,user,WALLPAPER_INVALID
+account.sendChangePhoneCode,user,PHONE_NUMBER_INVALID
+account.sendConfirmPhoneCode,user,HASH_INVALID
+account.sendVerifyEmailCode,user,EMAIL_INVALID
+account.sendVerifyPhoneCode,user,
+account.setAccountTTL,user,TTL_DAYS_INVALID
+account.setContactSignUpNotification,user,
+account.setPrivacy,user,PRIVACY_KEY_INVALID
+account.unregisterDevice,user,TOKEN_INVALID
+account.updateDeviceLocked,user,
+account.updateNotifySettings,user,PEER_ID_INVALID
+account.updatePasswordSettings,user,EMAIL_UNCONFIRMED_X NEW_SALT_INVALID NEW_SETTINGS_INVALID PASSWORD_HASH_INVALID
+account.updateProfile,user,ABOUT_TOO_LONG FIRSTNAME_INVALID
+account.updateStatus,user,SESSION_PASSWORD_NEEDED
+account.updateUsername,user,USERNAME_INVALID USERNAME_NOT_MODIFIED USERNAME_OCCUPIED
+account.uploadWallPaper,user,WALLPAPER_FILE_INVALID
+account.verifyEmail,user,EMAIL_INVALID
+account.verifyPhone,user,
+auth.bindTempAuthKey,both,ENCRYPTED_MESSAGE_INVALID INPUT_REQUEST_TOO_LONG TEMP_AUTH_KEY_EMPTY Timeout
+auth.cancelCode,user,PHONE_NUMBER_INVALID
+auth.checkPassword,user,PASSWORD_HASH_INVALID
+auth.dropTempAuthKeys,both,
+auth.exportAuthorization,both,DC_ID_INVALID
+auth.importAuthorization,both,AUTH_BYTES_INVALID USER_ID_INVALID
+auth.importBotAuthorization,both,ACCESS_TOKEN_EXPIRED ACCESS_TOKEN_INVALID API_ID_INVALID
+auth.logOut,both,
+auth.recoverPassword,user,CODE_EMPTY
+auth.requestPasswordRecovery,user,PASSWORD_EMPTY
+auth.resendCode,user,PHONE_NUMBER_INVALID
+auth.resetAuthorizations,user,Timeout
+auth.sendCode,user,API_ID_INVALID API_ID_PUBLISHED_FLOOD AUTH_RESTART INPUT_REQUEST_TOO_LONG PHONE_NUMBER_APP_SIGNUP_FORBIDDEN PHONE_NUMBER_BANNED PHONE_NUMBER_FLOOD PHONE_NUMBER_INVALID PHONE_PASSWORD_FLOOD PHONE_PASSWORD_PROTECTED
+auth.signIn,user,PHONE_CODE_EMPTY PHONE_CODE_EXPIRED PHONE_CODE_INVALID PHONE_NUMBER_INVALID PHONE_NUMBER_UNOCCUPIED SESSION_PASSWORD_NEEDED
+auth.signUp,user,FIRSTNAME_INVALID MEMBER_OCCUPY_PRIMARY_LOC_FAILED PHONE_CODE_EMPTY PHONE_CODE_EXPIRED PHONE_CODE_INVALID PHONE_NUMBER_FLOOD PHONE_NUMBER_INVALID PHONE_NUMBER_OCCUPIED REG_ID_GENERATE_FAILED
+bots.answerWebhookJSONQuery,bot,QUERY_ID_INVALID USER_BOT_INVALID
+bots.sendCustomRequest,bot,USER_BOT_INVALID
+channels.checkUsername,user,CHANNEL_INVALID CHAT_ID_INVALID USERNAME_INVALID
+channels.createChannel,user,CHAT_TITLE_EMPTY USER_RESTRICTED
+channels.deleteChannel,user,CHANNEL_INVALID CHANNEL_PRIVATE
+channels.deleteHistory,user,
+channels.deleteMessages,both,CHANNEL_INVALID CHANNEL_PRIVATE MESSAGE_DELETE_FORBIDDEN
+channels.deleteUserHistory,user,CHANNEL_INVALID CHAT_ADMIN_REQUIRED
+channels.editAdmin,both,ADMINS_TOO_MUCH ADMIN_RANK_EMOJI_NOT_ALLOWED ADMIN_RANK_INVALID BOT_CHANNELS_NA CHANNEL_INVALID CHAT_ADMIN_INVITE_REQUIRED CHAT_ADMIN_REQUIRED RIGHT_FORBIDDEN USER_CREATOR USER_ID_INVALID USER_NOT_MUTUAL_CONTACT USER_PRIVACY_RESTRICTED
+channels.editBanned,both,CHANNEL_INVALID CHANNEL_PRIVATE CHAT_ADMIN_REQUIRED USER_ADMIN_INVALID USER_ID_INVALID
+channels.editPhoto,both,CHANNEL_INVALID CHAT_ADMIN_REQUIRED PHOTO_INVALID
+channels.editTitle,both,CHANNEL_INVALID CHAT_ADMIN_REQUIRED CHAT_NOT_MODIFIED
+channels.exportMessageLink,user,CHANNEL_INVALID
+channels.getAdminLog,user,CHANNEL_INVALID CHANNEL_PRIVATE CHAT_ADMIN_REQUIRED
+channels.getAdminedPublicChannels,user,
+channels.getChannels,both,CHANNEL_INVALID CHANNEL_PRIVATE NEED_CHAT_INVALID
+channels.getFullChannel,both,CHANNEL_INVALID CHANNEL_PRIVATE CHANNEL_PUBLIC_GROUP_NA Timeout
+channels.getLeftChannels,user,
+channels.getMessages,both,CHANNEL_INVALID CHANNEL_PRIVATE MESSAGE_IDS_EMPTY
+channels.getParticipant,both,CHANNEL_INVALID CHANNEL_PRIVATE CHAT_ADMIN_REQUIRED USER_ID_INVALID USER_NOT_PARTICIPANT
+channels.getParticipants,both,CHANNEL_INVALID CHANNEL_PRIVATE CHAT_ADMIN_REQUIRED INPUT_CONSTRUCTOR_INVALID Timeout
+channels.inviteToChannel,user,BOTS_TOO_MUCH BOT_GROUPS_BLOCKED CHANNEL_INVALID CHANNEL_PRIVATE CHAT_ADMIN_REQUIRED CHAT_INVALID CHAT_WRITE_FORBIDDEN INPUT_USER_DEACTIVATED USERS_TOO_MUCH USER_BANNED_IN_CHANNEL USER_BLOCKED USER_BOT USER_CHANNELS_TOO_MUCH USER_ID_INVALID USER_KICKED USER_NOT_MUTUAL_CONTACT USER_PRIVACY_RESTRICTED
+channels.joinChannel,user,CHANNELS_TOO_MUCH CHANNEL_INVALID CHANNEL_PRIVATE
+channels.leaveChannel,both,CHANNEL_INVALID CHANNEL_PRIVATE CHANNEL_PUBLIC_GROUP_NA USER_CREATOR USER_NOT_PARTICIPANT
+channels.readHistory,user,CHANNEL_INVALID CHANNEL_PRIVATE
+channels.readMessageContents,user,CHANNEL_INVALID CHANNEL_PRIVATE
+channels.reportSpam,user,CHANNEL_INVALID INPUT_USER_DEACTIVATED
+channels.setDiscussionGroup,user,BROADCAST_ID_INVALID LINK_NOT_MODIFIED MEGAGROUP_ID_INVALID MEGAGROUP_PREHISTORY_HIDDEN
+channels.setStickers,both,CHANNEL_INVALID PARTICIPANTS_TOO_FEW
+channels.togglePreHistoryHidden,user,CHAT_LINK_EXISTS
+channels.toggleSignatures,user,CHANNEL_INVALID
+channels.toggleSlowMode,user,SECONDS_INVALID
+channels.updateUsername,user,CHANNELS_ADMIN_PUBLIC_TOO_MUCH CHANNEL_INVALID CHAT_ADMIN_REQUIRED USERNAME_INVALID USERNAME_OCCUPIED
+contacts.block,user,CONTACT_ID_INVALID
+contacts.deleteByPhones,user,
+contacts.deleteContact,user,CONTACT_ID_INVALID
+contacts.deleteContacts,user,NEED_MEMBER_INVALID Timeout
+contacts.getBlocked,user,
+contacts.getContactIDs,user,
+contacts.getContacts,user,
+contacts.getSaved,user,TAKEOUT_REQUIRED
+contacts.getStatuses,user,
+contacts.getTopPeers,user,TYPES_EMPTY
+contacts.importContacts,user,
+contacts.resetSaved,user,
+contacts.resetTopPeerRating,user,PEER_ID_INVALID
+contacts.resolveUsername,both,AUTH_KEY_PERM_EMPTY SESSION_PASSWORD_NEEDED USERNAME_INVALID USERNAME_NOT_OCCUPIED
+contacts.search,user,QUERY_TOO_SHORT SEARCH_QUERY_EMPTY Timeout
+contacts.toggleTopPeers,user,
+contacts.unblock,user,CONTACT_ID_INVALID
+contest.saveDeveloperInfo,both,
+folders.deleteFolder,user,FOLDER_ID_EMPTY
+folders.editPeerFolders,user,FOLDER_ID_INVALID
+help.acceptTermsOfService,user,
+help.editUserInfo,user,USER_INVALID
+help.getAppChangelog,user,
+help.getAppConfig,user,
+help.getAppUpdate,user,
+help.getCdnConfig,both,AUTH_KEY_PERM_EMPTY Timeout
+help.getConfig,both,AUTH_KEY_DUPLICATED Timeout
+help.getDeepLinkInfo,user,
+help.getInviteText,user,
+help.getNearestDc,user,
+help.getPassportConfig,user,
+help.getProxyData,user,
+help.getRecentMeUrls,user,
+help.getSupport,user,
+help.getSupportName,user,USER_INVALID
+help.getTermsOfServiceUpdate,user,
+help.getUserInfo,user,USER_INVALID
+help.saveAppLog,user,
+help.setBotUpdatesStatus,both,
+initConnection,both,CONNECTION_LAYER_INVALID INPUT_FETCH_FAIL
+invokeAfterMsg,both,
+invokeAfterMsgs,both,
+invokeWithLayer,both,AUTH_BYTES_INVALID AUTH_KEY_DUPLICATED CDN_METHOD_INVALID CHAT_WRITE_FORBIDDEN CONNECTION_API_ID_INVALID CONNECTION_DEVICE_MODEL_EMPTY CONNECTION_LANG_PACK_INVALID CONNECTION_NOT_INITED CONNECTION_SYSTEM_EMPTY INPUT_LAYER_INVALID INVITE_HASH_EXPIRED NEED_MEMBER_INVALID Timeout
+invokeWithMessagesRange,both,
+invokeWithTakeout,both,
+invokeWithoutUpdates,both,
+langpack.getDifference,user,LANG_PACK_INVALID
+langpack.getLangPack,user,LANG_PACK_INVALID
+langpack.getLanguage,user,
+langpack.getLanguages,user,LANG_PACK_INVALID
+langpack.getStrings,user,LANG_PACK_INVALID
+messages.acceptEncryption,user,CHAT_ID_INVALID ENCRYPTION_ALREADY_ACCEPTED ENCRYPTION_ALREADY_DECLINED ENCRYPTION_OCCUPY_FAILED
+messages.addChatUser,user,CHAT_ADMIN_REQUIRED CHAT_ID_INVALID INPUT_USER_DEACTIVATED PEER_ID_INVALID USERS_TOO_MUCH USER_ALREADY_PARTICIPANT USER_ID_INVALID USER_NOT_MUTUAL_CONTACT USER_PRIVACY_RESTRICTED
+messages.checkChatInvite,user,INVITE_HASH_EMPTY INVITE_HASH_EXPIRED INVITE_HASH_INVALID
+messages.clearAllDrafts,user,
+messages.clearRecentStickers,user,
+messages.createChat,user,USERS_TOO_FEW USER_RESTRICTED
+messages.deleteChatUser,both,CHAT_ID_INVALID PEER_ID_INVALID USER_NOT_PARTICIPANT
+messages.deleteHistory,user,PEER_ID_INVALID
+messages.deleteMessages,both,MESSAGE_DELETE_FORBIDDEN
+messages.discardEncryption,user,CHAT_ID_EMPTY ENCRYPTION_ALREADY_DECLINED ENCRYPTION_ID_INVALID
+messages.editChatAbout,both,
+messages.editChatAdmin,user,CHAT_ID_INVALID
+messages.editChatDefaultBannedRights,both,BANNED_RIGHTS_INVALID
+messages.editChatPhoto,both,CHAT_ID_INVALID INPUT_CONSTRUCTOR_INVALID INPUT_FETCH_FAIL PEER_ID_INVALID PHOTO_EXT_INVALID
+messages.editChatTitle,both,CHAT_ID_INVALID NEED_CHAT_INVALID
+messages.editInlineBotMessage,both,MESSAGE_ID_INVALID MESSAGE_NOT_MODIFIED
+messages.editMessage,both,CHANNEL_INVALID CHANNEL_PRIVATE CHAT_WRITE_FORBIDDEN INPUT_USER_DEACTIVATED MEDIA_NEW_INVALID MEDIA_PREV_INVALID MESSAGE_AUTHOR_REQUIRED MESSAGE_EDIT_TIME_EXPIRED MESSAGE_EMPTY MESSAGE_ID_INVALID MESSAGE_NOT_MODIFIED PEER_ID_INVALID
+messages.exportChatInvite,user,CHAT_ID_INVALID
+messages.faveSticker,user,STICKER_ID_INVALID
+messages.forwardMessages,both,CHANNEL_INVALID CHANNEL_PRIVATE CHAT_ADMIN_REQUIRED CHAT_ID_INVALID CHAT_SEND_GIFS_FORBIDDEN CHAT_SEND_MEDIA_FORBIDDEN CHAT_SEND_STICKERS_FORBIDDEN CHAT_WRITE_FORBIDDEN GROUPED_MEDIA_INVALID INPUT_USER_DEACTIVATED MEDIA_EMPTY MESSAGE_IDS_EMPTY MESSAGE_ID_INVALID PEER_ID_INVALID PTS_CHANGE_EMPTY RANDOM_ID_DUPLICATE RANDOM_ID_INVALID SCHEDULE_DATE_TOO_LATE SCHEDULE_TOO_MUCH Timeout USER_BANNED_IN_CHANNEL USER_IS_BLOCKED USER_IS_BOT YOU_BLOCKED_USER
+messages.getAllChats,user,
+messages.getAllDrafts,user,
+messages.getAllStickers,user,
+messages.getArchivedStickers,user,
+messages.getAttachedStickers,user,
+messages.getBotCallbackAnswer,user,CHANNEL_INVALID DATA_INVALID MESSAGE_ID_INVALID PEER_ID_INVALID Timeout
+messages.getChats,both,CHAT_ID_INVALID PEER_ID_INVALID
+messages.getCommonChats,user,USER_ID_INVALID
+messages.getDhConfig,user,RANDOM_LENGTH_INVALID
+messages.getDialogUnreadMarks,user,
+messages.getDialogs,user,INPUT_CONSTRUCTOR_INVALID OFFSET_PEER_ID_INVALID SESSION_PASSWORD_NEEDED Timeout
+messages.getDocumentByHash,both,SHA256_HASH_INVALID
+messages.getFavedStickers,user,
+messages.getFeaturedStickers,user,
+messages.getFullChat,both,CHAT_ID_INVALID PEER_ID_INVALID
+messages.getGameHighScores,bot,PEER_ID_INVALID USER_BOT_REQUIRED
+messages.getHistory,user,AUTH_KEY_DUPLICATED AUTH_KEY_PERM_EMPTY CHANNEL_INVALID CHANNEL_PRIVATE CHAT_ID_INVALID PEER_ID_INVALID Timeout
+messages.getInlineBotResults,user,BOT_INLINE_DISABLED BOT_INVALID CHANNEL_PRIVATE Timeout
+messages.getInlineGameHighScores,bot,MESSAGE_ID_INVALID USER_BOT_REQUIRED
+messages.getMaskStickers,user,
+messages.getMessageEditData,user,MESSAGE_AUTHOR_REQUIRED PEER_ID_INVALID
+messages.getMessages,both,
+messages.getMessagesViews,user,CHANNEL_PRIVATE CHAT_ID_INVALID PEER_ID_INVALID
+messages.getOnlines,user,
+messages.getPeerDialogs,user,CHANNEL_PRIVATE PEER_ID_INVALID
+messages.getPeerSettings,user,CHANNEL_INVALID PEER_ID_INVALID
+messages.getPinnedDialogs,user,
+messages.getPollResults,user,
+messages.getRecentLocations,user,
+messages.getRecentStickers,user,
+messages.getSavedGifs,user,
+messages.getSplitRanges,user,
+messages.getStatsURL,user,
+messages.getStickerSet,both,STICKERSET_INVALID
+messages.getStickers,user,EMOTICON_EMPTY
+messages.getUnreadMentions,user,PEER_ID_INVALID
+messages.getWebPage,user,WC_CONVERT_URL_INVALID
+messages.getWebPagePreview,user,
+messages.hideReportSpam,user,PEER_ID_INVALID
+messages.importChatInvite,user,CHANNELS_TOO_MUCH INVITE_HASH_EMPTY INVITE_HASH_EXPIRED INVITE_HASH_INVALID SESSION_PASSWORD_NEEDED USERS_TOO_MUCH USER_ALREADY_PARTICIPANT
+messages.installStickerSet,user,STICKERSET_INVALID
+messages.markDialogUnread,user,
+messages.migrateChat,user,CHAT_ADMIN_REQUIRED CHAT_ID_INVALID PEER_ID_INVALID
+messages.readEncryptedHistory,user,MSG_WAIT_FAILED
+messages.readFeaturedStickers,user,
+messages.readHistory,user,PEER_ID_INVALID Timeout
+messages.readMentions,user,
+messages.readMessageContents,user,
+messages.receivedMessages,user,
+messages.receivedQueue,user,MSG_WAIT_FAILED MAX_QTS_INVALID
+messages.reorderPinnedDialogs,user,PEER_ID_INVALID
+messages.reorderStickerSets,user,
+messages.report,user,
+messages.reportEncryptedSpam,user,CHAT_ID_INVALID
+messages.reportSpam,user,PEER_ID_INVALID
+messages.requestEncryption,user,DH_G_A_INVALID USER_ID_INVALID
+messages.saveDraft,user,PEER_ID_INVALID
+messages.saveGif,user,GIF_ID_INVALID
+messages.saveRecentSticker,user,STICKER_ID_INVALID
+messages.search,user,CHAT_ADMIN_REQUIRED INPUT_CONSTRUCTOR_INVALID INPUT_USER_DEACTIVATED PEER_ID_INVALID PEER_ID_NOT_SUPPORTED SEARCH_QUERY_EMPTY USER_ID_INVALID
+messages.searchGifs,user,SEARCH_QUERY_EMPTY
+messages.searchGlobal,user,SEARCH_QUERY_EMPTY
+messages.searchStickerSets,user,
+messages.sendEncrypted,user,CHAT_ID_INVALID DATA_INVALID ENCRYPTION_DECLINED MSG_WAIT_FAILED
+messages.sendEncryptedFile,user,MSG_WAIT_FAILED
+messages.sendEncryptedService,user,DATA_INVALID ENCRYPTION_DECLINED MSG_WAIT_FAILED USER_IS_BLOCKED
+messages.sendInlineBotResult,user,CHAT_SEND_INLINE_FORBIDDEN CHAT_WRITE_FORBIDDEN INLINE_RESULT_EXPIRED PEER_ID_INVALID QUERY_ID_EMPTY SCHEDULE_DATE_TOO_LATE SCHEDULE_TOO_MUCH WEBPAGE_CURL_FAILED WEBPAGE_MEDIA_EMPTY
+messages.sendMedia,both,BOT_PAYMENTS_DISABLED BOT_POLLS_DISABLED CHANNEL_INVALID CHANNEL_PRIVATE CHAT_ADMIN_REQUIRED CHAT_SEND_MEDIA_FORBIDDEN CHAT_WRITE_FORBIDDEN EXTERNAL_URL_INVALID FILE_PARTS_INVALID FILE_PART_LENGTH_INVALID INPUT_USER_DEACTIVATED MEDIA_CAPTION_TOO_LONG MEDIA_EMPTY PAYMENT_PROVIDER_INVALID PEER_ID_INVALID PHOTO_EXT_INVALID PHOTO_INVALID_DIMENSIONS PHOTO_SAVE_FILE_INVALID POLL_OPTION_DUPLICATE RANDOM_ID_DUPLICATE SCHEDULE_DATE_TOO_LATE SCHEDULE_TOO_MUCH STORAGE_CHECK_FAILED Timeout USER_BANNED_IN_CHANNEL USER_IS_BLOCKED USER_IS_BOT VIDEO_CONTENT_TYPE_INVALID WEBPAGE_CURL_FAILED WEBPAGE_MEDIA_EMPTY
+messages.sendMessage,both,AUTH_KEY_DUPLICATED BUTTON_DATA_INVALID BUTTON_TYPE_INVALID BUTTON_URL_INVALID CHANNEL_INVALID CHANNEL_PRIVATE CHAT_ADMIN_REQUIRED CHAT_ID_INVALID CHAT_RESTRICTED CHAT_WRITE_FORBIDDEN ENTITIES_TOO_LONG ENTITY_MENTION_USER_INVALID INPUT_USER_DEACTIVATED MESSAGE_EMPTY MESSAGE_TOO_LONG PEER_ID_INVALID RANDOM_ID_DUPLICATE REPLY_MARKUP_INVALID REPLY_MARKUP_TOO_LONG SCHEDULE_DATE_TOO_LATE SCHEDULE_TOO_MUCH Timeout USER_BANNED_IN_CHANNEL USER_IS_BLOCKED USER_IS_BOT YOU_BLOCKED_USER
+messages.sendMultiMedia,both,SCHEDULE_DATE_TOO_LATE SCHEDULE_TOO_MUCH
+messages.sendReaction,User,REACTION_INVALID
+messages.sendVote,user,
+messages.setBotCallbackAnswer,both,QUERY_ID_INVALID URL_INVALID
+messages.setBotPrecheckoutResults,both,ERROR_TEXT_EMPTY
+messages.setBotShippingResults,both,QUERY_ID_INVALID
+messages.setEncryptedTyping,user,CHAT_ID_INVALID
+messages.setGameScore,bot,PEER_ID_INVALID USER_BOT_REQUIRED
+messages.setInlineBotResults,bot,ARTICLE_TITLE_EMPTY BUTTON_DATA_INVALID BUTTON_TYPE_INVALID BUTTON_URL_INVALID MESSAGE_EMPTY PHOTO_CONTENT_URL_EMPTY PHOTO_THUMB_URL_EMPTY QUERY_ID_INVALID REPLY_MARKUP_INVALID RESULT_TYPE_INVALID SEND_MESSAGE_MEDIA_INVALID SEND_MESSAGE_TYPE_INVALID START_PARAM_INVALID USER_BOT_INVALID
+messages.setInlineGameScore,bot,MESSAGE_ID_INVALID USER_BOT_REQUIRED
+messages.setTyping,both,CHANNEL_INVALID CHANNEL_PRIVATE CHAT_ID_INVALID CHAT_WRITE_FORBIDDEN PEER_ID_INVALID USER_BANNED_IN_CHANNEL USER_IS_BLOCKED USER_IS_BOT
+messages.startBot,user,BOT_INVALID PEER_ID_INVALID START_PARAM_EMPTY START_PARAM_INVALID
+messages.toggleDialogPin,user,PEER_ID_INVALID
+messages.uninstallStickerSet,user,STICKERSET_INVALID
+messages.updatePinnedMessage,both,
+messages.uploadEncryptedFile,user,
+messages.uploadMedia,both,BOT_MISSING MEDIA_INVALID PEER_ID_INVALID
+payments.clearSavedInfo,user,
+payments.getPaymentForm,user,MESSAGE_ID_INVALID
+payments.getPaymentReceipt,user,MESSAGE_ID_INVALID
+payments.getSavedInfo,user,
+payments.sendPaymentForm,user,MESSAGE_ID_INVALID
+payments.validateRequestedInfo,user,MESSAGE_ID_INVALID
+phone.acceptCall,user,CALL_ALREADY_ACCEPTED CALL_ALREADY_DECLINED CALL_OCCUPY_FAILED CALL_PEER_INVALID CALL_PROTOCOL_FLAGS_INVALID
+phone.confirmCall,user,CALL_ALREADY_DECLINED CALL_PEER_INVALID
+phone.discardCall,user,CALL_ALREADY_ACCEPTED CALL_PEER_INVALID
+phone.getCallConfig,user,
+phone.receivedCall,user,CALL_ALREADY_DECLINED CALL_PEER_INVALID
+phone.requestCall,user,CALL_PROTOCOL_FLAGS_INVALID PARTICIPANT_CALL_FAILED PARTICIPANT_VERSION_OUTDATED USER_ID_INVALID USER_IS_BLOCKED USER_PRIVACY_RESTRICTED
+phone.saveCallDebug,user,CALL_PEER_INVALID DATA_JSON_INVALID
+phone.setCallRating,user,CALL_PEER_INVALID
+photos.deletePhotos,user,
+photos.getUserPhotos,both,MAX_ID_INVALID USER_ID_INVALID
+photos.updateProfilePhoto,user,
+photos.uploadProfilePhoto,user,FILE_PARTS_INVALID IMAGE_PROCESS_FAILED PHOTO_CROP_SIZE_SMALL PHOTO_EXT_INVALID
+ping,both,
+reqDHParams,both,
+reqPq,both,
+reqPqMulti,both,
+rpcDropAnswer,both,
+setClientDHParams,both,
+stickers.addStickerToSet,bot,BOT_MISSING STICKERSET_INVALID
+stickers.changeStickerPosition,bot,BOT_MISSING STICKER_INVALID
+stickers.createStickerSet,bot,BOT_MISSING PACK_SHORT_NAME_INVALID PACK_SHORT_NAME_OCCUPIED PEER_ID_INVALID SHORTNAME_OCCUPY_FAILED STICKERS_EMPTY STICKER_EMOJI_INVALID STICKER_FILE_INVALID STICKER_PNG_DIMENSIONS USER_ID_INVALID
+stickers.removeStickerFromSet,bot,BOT_MISSING STICKER_INVALID
+updates.getChannelDifference,both,CHANNEL_INVALID CHANNEL_PRIVATE CHANNEL_PUBLIC_GROUP_NA HISTORY_GET_FAILED PERSISTENT_TIMESTAMP_EMPTY PERSISTENT_TIMESTAMP_INVALID PERSISTENT_TIMESTAMP_OUTDATED RANGES_INVALID Timeout
+updates.getDifference,both,AUTH_KEY_PERM_EMPTY CDN_METHOD_INVALID DATE_EMPTY NEED_MEMBER_INVALID PERSISTENT_TIMESTAMP_EMPTY PERSISTENT_TIMESTAMP_INVALID SESSION_PASSWORD_NEEDED STORE_INVALID_SCALAR_TYPE Timeout
+updates.getState,both,AUTH_KEY_DUPLICATED SESSION_PASSWORD_NEEDED Timeout
+upload.getCdnFile,user,UNKNOWN_METHOD
+upload.getCdnFileHashes,both,CDN_METHOD_INVALID RSA_DECRYPT_FAILED
+upload.getFile,both,AUTH_KEY_PERM_EMPTY FILE_ID_INVALID INPUT_FETCH_FAIL LIMIT_INVALID LOCATION_INVALID OFFSET_INVALID Timeout
+upload.getFileHashes,both,
+upload.getWebFile,user,LOCATION_INVALID
+upload.reuploadCdnFile,both,RSA_DECRYPT_FAILED
+upload.saveBigFilePart,both,FILE_PARTS_INVALID FILE_PART_EMPTY FILE_PART_INVALID FILE_PART_SIZE_INVALID Timeout
+upload.saveFilePart,both,FILE_PART_EMPTY FILE_PART_INVALID INPUT_FETCH_FAIL SESSION_PASSWORD_NEEDED
+users.getFullUser,both,Timeout USER_ID_INVALID
+users.getUsers,both,AUTH_KEY_PERM_EMPTY MEMBER_NO_LOCATION NEED_MEMBER_INVALID SESSION_PASSWORD_NEEDED Timeout
+users.setSecureValueErrors,bot,

+ 113 - 0
gramjs_generator/data/mtproto.tl

@@ -0,0 +1,113 @@
+// Core types (no need to gen)
+
+//vector#1cb5c415 {t:Type} # [ t ] = Vector t;
+
+///////////////////////////////
+/// Authorization key creation
+///////////////////////////////
+
+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;
+
+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;
+
+destroy_auth_key_ok#f660e1d4 = DestroyAuthKeyRes;
+destroy_auth_key_none#0a9f2259 = DestroyAuthKeyRes;
+destroy_auth_key_fail#ea109b13 = DestroyAuthKeyRes;
+
+---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;
+
+destroy_auth_key#d1435160 = DestroyAuthKeyRes;
+
+///////////////////////////////
+////////////// System messages
+///////////////////////////////
+
+---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;
+
+msgs_state_req#da69fb52 msg_ids:Vector<long> = MsgsStateReq;
+msgs_state_info#04deb57d req_msg_id:long info:string = MsgsStateInfo;
+msgs_all_info#8cc0d131 msg_ids:Vector<long> info:string = 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;
+
+msg_resend_req#7d861a08 msg_ids:Vector<long> = MsgResendReq;
+
+//rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult; // parsed manually
+
+rpc_error#2144ca19 error_code:int error_message:string = RpcError;
+
+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 ipv4:int port:int = IpPort;
+//help.configSimple#d997c3c5 date:int expires:int dc_id:int ip_port_list:Vector<ipPort> = help.ConfigSimple;
+
+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;
+
+tlsClientHello blocks:vector<TlsBlock> = TlsClientHello;
+
+tlsBlockString data:string = TlsBlock;
+tlsBlockRandom length:int = TlsBlock;
+tlsBlockZero length:int = TlsBlock;
+tlsBlockDomain = TlsBlock;
+tlsBlockGrease seed:int = TlsBlock;
+tlsBlockScope entries:Vector<TlsBlock> = TlsBlock;
+
+---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;

+ 1 - 0
gramjs_generator/generators/docs.js

@@ -0,0 +1 @@
+// TODO

+ 87 - 0
gramjs_generator/generators/errors.js

@@ -0,0 +1,87 @@
+const generateErrors = (errors, f) => {
+    // Exact/regex match to create {CODE: ErrorClassName}
+    const exactMatch = [];
+    const regexMatch = [];
+
+    // Find out what subclasses to import and which to create
+    const importBase = new Set();
+    const createBase = {};
+
+    for (const error of errors) {
+        if (error.subclassExists) {
+            importBase.add(error.subclass);
+        } else {
+            createBase[error.subclass] = error.intCode;
+        }
+
+        if (error.hasCaptures) {
+            regexMatch.push(error);
+        } else {
+            exactMatch.push(error);
+        }
+    }
+
+    // Imports and new subclass creation
+    f.write(
+        `const { RPCError, ${[...importBase.values()].join(
+            ', '
+        )} } = require('./rpcbaseerrors');`
+    );
+
+    f.write("\nconst format = require('string-format');");
+
+    for (const [cls, intCode] of Object.entries(createBase)) {
+        f.write(
+            `\n\nclass ${cls} extends RPCError {\n    constructor() {\n        this.code = ${intCode};\n    }\n}`
+        );
+    }
+
+    // Error classes generation
+    for (const error of errors) {
+        f.write(
+            `\n\nclass ${error.name} extends ${error.subclass} {\n    constructor(args) {\n        `
+        );
+
+        if (error.hasCaptures) {
+            f.write(
+                `const ${error.captureName} = Number(args.capture || 0);\n        `
+            );
+        }
+
+        const capture = error.description.replace(/'/g, "\\'");
+
+        if (error.hasCaptures) {
+            f.write(`super(format('${capture}', {${error.captureName}})`);
+        } else {
+            f.write(`super('${capture}'`);
+        }
+
+        f.write(' + this._fmtRequest(args.request));\n');
+
+        if (error.hasCaptures) {
+            f.write(
+                `        this.${error.captureName} = ${error.captureName};\n`
+            );
+        }
+
+        f.write('    }\n}\n');
+    }
+
+    f.write('\n\nconst rpcErrorsDict = {\n');
+
+    for (const error of exactMatch) {
+        f.write(`    ${error.pattern}: ${error.name},\n`);
+    }
+
+    f.write('};\n\nconst rpcErrorRe = [\n');
+
+    for (const error of regexMatch) {
+        f.write(`    [/${error.pattern}/, ${error.name}],\n`);
+    }
+
+    f.write('];');
+};
+
+module.exports = {
+    generateErrors,
+};

+ 10 - 0
gramjs_generator/generators/index.js

@@ -0,0 +1,10 @@
+const { generateErrors } = require('./errors');
+const { generateTlobjects, cleanTlobjects } = require('./tlobject');
+// const { generateDocs } = require('./docs');
+
+module.exports = {
+    generateErrors,
+    generateTlobjects,
+    cleanTlobjects,
+    // generateDocs,
+};

+ 779 - 0
gramjs_generator/generators/tlobject.js

@@ -0,0 +1,779 @@
+const fs = require('fs');
+const util = require('util');
+const { crc32 } = require('crc');
+const SourceBuilder = require('../sourcebuilder');
+
+const AUTO_GEN_NOTICE =
+    "/*! File generated by TLObjects' generator. All changes will be ERASED !*/";
+
+const AUTO_CASTS = {
+    InputPeer: 'utils.get_input_peer(await client.get_input_entity(%s))',
+    InputChannel: 'utils.get_input_channel(await client.get_input_entity(%s))',
+    InputUser: 'utils.get_input_user(await client.get_input_entity(%s))',
+    InputDialogPeer: 'await client._get_input_dialog(%s)',
+    InputNotifyPeer: 'await client._get_input_notify(%s)',
+    InputMedia: 'utils.get_input_media(%s)',
+    InputPhoto: 'utils.get_input_photo(%s)',
+    InputMessage: 'utils.get_input_message(%s)',
+    InputDocument: 'utils.get_input_document(%s)',
+    InputChatPhoto: 'utils.get_input_chat_photo(%s)',
+};
+
+const NAMED_AUTO_CASTS = {
+    'chat_id,int': 'await client.get_peer_id(%s, add_mark=False)',
+};
+
+// Secret chats have a chat_id which may be negative.
+// With the named auto-cast above, we would break it.
+// However there are plenty of other legit requests
+// with `chat_id:int` where it is useful.
+//
+// NOTE: This works because the auto-cast is not recursive.
+//       There are plenty of types that would break if we
+//       did recurse into them to resolve them.
+const NAMED_BLACKLIST = new Set(['messages.discardEncryption']);
+
+const BASE_TYPES = [
+    'string',
+    'bytes',
+    'int',
+    'long',
+    'int128',
+    'int256',
+    'double',
+    'Bool',
+    'true',
+];
+
+// Patched types {fullname: custom.ns.Name}
+const PATCHED_TYPES = {
+    messageEmpty: 'message.Message',
+    message: 'message.Message',
+    messageService: 'message.Message',
+};
+
+const writeModules = (
+    outDir,
+    depth,
+    kind,
+    namespaceTlobjects,
+    typeConstructors
+) => {
+    // namespace_tlobjects: {'namespace', [TLObject]}
+    fs.mkdirSync(outDir, { recursive: true });
+
+    for (const [ns, tlobjects] of Object.entries(namespaceTlobjects)) {
+        const file = `${outDir}/${ns === 'null' ? 'index' : ns}.js`;
+        const stream = fs.createWriteStream(file);
+        const builder = new SourceBuilder(stream);
+        const dotDepth = '.'.repeat(depth || 1);
+
+        builder.writeln(AUTO_GEN_NOTICE);
+        builder.writeln(
+            `const { TLObject } = require('${dotDepth}/tlobject');`
+        );
+
+        if (kind !== 'TLObject') {
+            builder.writeln(
+                `const { ${kind} } = require('${dotDepth}/tlobject');`
+            );
+        }
+
+        // Add the relative imports to the namespaces,
+        // unless we already are in a namespace.
+        if (!ns) {
+            const imports = Object.keys(namespaceTlobjects)
+                .filter(Boolean)
+                .join(`, `);
+
+            builder.writeln(`const { ${imports} } = require('.');`);
+        }
+
+        // Import struct for the .__bytes__(self) serialization
+        builder.writeln("const struct = require('python-struct');");
+
+        const typeNames = new Set();
+        const typeDefs = [];
+
+        // Find all the types in this file and generate type definitions
+        // based on the types. The type definitions are written to the
+        // file at the end.
+        for (const t of tlobjects) {
+            if (!t.isFunction) {
+                let typeName = t.result;
+
+                if (typeName.includes('.')) {
+                    typeName = typeName.slice(typeName.lastIndexOf('.'));
+                }
+
+                if (typeNames.has(typeName)) {
+                    continue;
+                }
+
+                typeNames.add(typeName);
+
+                const constructors = typeConstructors[typeName];
+
+                if (!constructors) {
+                } else if (constructors.length === 1) {
+                    typeDefs.push(
+                        `Type${typeName} = ${constructors[0].className}`
+                    );
+                } else {
+                    typeDefs.push(
+                        `Type${typeName} = Union[${constructors
+                            .map(x => constructors.className)
+                            .join(',')}]`
+                    );
+                }
+            }
+        }
+
+        const imports = {};
+        const primitives = new Set([
+            'int',
+            'long',
+            'int128',
+            'int256',
+            'double',
+            'string',
+            'bytes',
+            'Bool',
+            'true',
+        ]);
+
+        // Find all the types in other files that are used in this file
+        // and generate the information required to import those types.
+        for (const t of tlobjects) {
+            for (const arg of t.args) {
+                let name = arg.type;
+
+                if (!name || primitives.has(name)) {
+                    continue;
+                }
+
+                let importSpace = `${dotDepth}/tl/types`;
+
+                if (name.includes('.')) {
+                    const [namespace] = name.split('.');
+                    name = name.split('.');
+                    importSpace += `/${namespace}`;
+                }
+
+                if (!typeNames.has(name)) {
+                    typeNames.add(name);
+
+                    if (name === 'date') {
+                        imports.datetime = ['datetime'];
+                        continue;
+                    } else if (!(importSpace in imports)) {
+                        imports[importSpace] = new Set();
+                    }
+
+                    imports[importSpace].add(`Type${name}`);
+                }
+            }
+        }
+
+        // Add imports required for type checking
+        if (imports) {
+            builder.writeln('if (false) { // TYPE_CHECKING {');
+
+            for (const [namespace, names] of Object.entries(imports)) {
+                builder.writeln(
+                    `const { ${[...names.values()].join(
+                        ', '
+                    )} } =  require('${namespace}');`
+                );
+            }
+
+            builder.endBlock();
+        }
+
+        // Generate the class for every TLObject
+        for (const t of tlobjects) {
+            if (t.fullname in PATCHED_TYPES) {
+                builder.writeln(`const ${t.className} = null; // Patched`);
+            } else {
+                writeSourceCode(t, kind, builder, typeConstructors);
+                builder.currentIndent = 0;
+            }
+        }
+
+        // Write the type definitions generated earlier.
+        builder.writeln();
+
+        for (const line of typeDefs) {
+            builder.writeln(line);
+        }
+
+        writeModuleExports(tlobjects, builder);
+    }
+};
+
+/**
+ * Writes the source code corresponding to the given TLObject
+ * by making use of the ``builder`` `SourceBuilder`.
+ *
+ * Additional information such as file path depth and
+ * the ``Type: [Constructors]`` must be given for proper
+ * importing and documentation strings.
+ */
+const writeSourceCode = (tlobject, kind, builder, typeConstructors) => {
+    writeClassConstructor(tlobject, kind, typeConstructors, builder);
+    writeResolve(tlobject, builder);
+    writeToJson(tlobject, builder);
+    writeToBytes(tlobject, builder);
+    builder.currentIndent--;
+    builder.writeln('}');
+    // writeFromReader(tlobject, builder);
+    // writeReadResult(tlobject, builder);
+};
+
+const writeClassConstructor = (tlobject, kind, typeConstructors, builder) => {
+    builder.writeln();
+    builder.writeln();
+    builder.writeln(`class ${tlobject.className} extends ${kind} {`);
+
+    // Convert the args to string parameters, flags having =None
+    const args = tlobject.realArgs.map(
+        a =>
+            `${a.name}: ${a.typeHint()}${
+                a.isFlag || a.canBeInferred ? `=None` : ''
+            }`
+    );
+
+    // Write the __init__ function if it has any argument
+    if (!tlobject.realArgs.length) {
+        return;
+    }
+
+    builder.writeln('/**');
+
+    if (tlobject.isFunction) {
+        builder.write(`:returns ${tlobject.result}: `);
+    } else {
+        builder.write(`Constructor for ${tlobject.result}: `);
+    }
+
+    const constructors = typeConstructors[tlobject.result];
+
+    if (!constructors) {
+        builder.writeln('This type has no constructors.');
+    } else if (constructors.length === 1) {
+        builder.writeln(`Instance of ${constructors[0].className}`);
+    } else {
+        builder.writeln(
+            `Instance of either ${constructors
+                .map(c => c.className)
+                .join(', ')}`
+        );
+    }
+
+    builder.writeln('*/');
+    builder.writeln(`constructor(args) {`);
+    builder.writeln(`super();`);
+
+    // Class-level variable to store its Telegram's constructor ID
+    builder.writeln(
+        `this.CONSTRUCTOR_ID = 0x${tlobject.id.toString(16).padStart(8, '0')};`
+    );
+    builder.writeln(`this.SUBCLASS_OF_ID = 0x${crc32(tlobject.result)};`);
+    builder.writeln();
+
+    // Set the arguments
+    for (const arg of tlobject.realArgs) {
+        if (!arg.canBeInferred) {
+            builder.writeln(`this.${arg.name} = args.${arg.name};`);
+        }
+
+        // Currently the only argument that can be
+        // inferred are those called 'random_id'
+        else if (arg.name === 'random_id') {
+            // Endianness doesn't really matter, and 'big' is shorter
+            let code = `int.from_bytes(os.urandom(${
+                arg.type === 'long' ? 8 : 4
+            }), 'big', signed=True)`;
+
+            if (arg.isVector) {
+                // Currently for the case of "messages.forwardMessages"
+                // Ensure we can infer the length from id:Vector<>
+                if (!tlobject.realArgs.find(a => a.name === 'id').isVector) {
+                    throw new Error(
+                        `Cannot infer list of random ids for ${tlobject}`
+                    );
+                }
+
+                code = `new Array(id.length).fill().map(_ => ${code})`;
+            }
+
+            builder.writeln(
+                `this.random_id = random_id !== null ? random_id : ${code}`
+            );
+        } else {
+            throw new Error(`Cannot infer a value for ${arg}`);
+        }
+    }
+
+    builder.endBlock();
+};
+
+const writeResolve = (tlobject, builder) => {
+    if (
+        tlobject.isFunction &&
+        tlobject.realArgs.some(
+            arg =>
+                arg.type in AUTO_CASTS ||
+                (`${arg.name},${arg.type}` in NAMED_AUTO_CASTS &&
+                    !NAMED_BLACKLIST.has(tlobject.fullname))
+        )
+    ) {
+        builder.writeln('async resolve(client, utils) {');
+
+        for (const arg of tlobject.realArgs) {
+            let ac = AUTO_CASTS[arg.type];
+
+            if (!ac) {
+                ac = NAMED_AUTO_CASTS[`${arg.name},${arg.type}`];
+
+                if (!ac) {
+                    continue;
+                }
+            }
+
+            if (arg.isFlag) {
+                builder.writeln(`if (this.${arg.name}) {`);
+            }
+
+            if (arg.isVector) {
+                builder.write(`const _tmp = [];`);
+                builder.writeln(`for (const _x of this.${arg.name}) {`);
+                builder.writeln(`_tmp.push(%s);`, util.format(ac, '_x'));
+                builder.endBlock();
+                builder.writeln(`this.${arg.name} = _tmp;`);
+            } else {
+                builder.writeln(
+                    `this.${arg.name} = %s`,
+                    util.format(ac, `this.${arg.name}`)
+                );
+            }
+
+            if (arg.isFlag) {
+                builder.currentIndent--;
+                builder.writeln('}');
+            }
+        }
+
+        builder.endBlock();
+    }
+};
+
+const writeToJson = (tlobject, builder) => {
+    builder.writeln('toJson() {');
+    builder.writeln('return {');
+
+    builder.write("_: '%s'", tlobject.className);
+
+    for (const arg of tlobject.realArgs) {
+        builder.writeln(',');
+        builder.write('%s: ', arg.name);
+
+        if (BASE_TYPES.includes(arg.type)) {
+            if (arg.isVector) {
+                builder.write(
+                    'this.%s === null ? [] : this.%s.slice()',
+                    arg.name,
+                    arg.name
+                );
+            } else {
+                builder.write('this.%s', arg.name);
+            }
+        } else {
+            if (arg.isVector) {
+                builder.write(
+                    'this.%s === null ? [] : this.%s.map(x => x instanceof TLObject ? x.toJson() : x)',
+                    arg.name,
+                    arg.name
+                );
+            } else {
+                builder.write(
+                    'this.%s instanceof TLObject ? this.%s.toJson() : this.%s',
+                    arg.name,
+                    arg.name,
+                    arg.name
+                );
+            }
+        }
+    }
+
+    builder.writeln();
+    builder.endBlock();
+    builder.currentIndent--;
+    builder.writeln('}');
+};
+
+const writeToBytes = (tlobject, builder) => {
+    builder.writeln('get bytes() {');
+
+    // Some objects require more than one flag parameter to be set
+    // at the same time. In this case, add an assertion.
+    const repeatedArgs = {};
+
+    for (const arg of tlobject.args) {
+        if (arg.isFlag) {
+            if (!repeatedArgs[arg.flagIndex]) {
+                repeatedArgs[arg.flagIndex] = [];
+            }
+
+            repeatedArgs[arg.flagIndex].push(arg);
+        }
+    }
+
+    for (const ra of Object.values(repeatedArgs)) {
+        if (ra.length > 1) {
+            const cnd1 = ra.map(
+                a => `(this.${a.name} || this.${a.name} !== null)`
+            );
+            const cnd2 = ra.map(
+                a => `(this.${a.name} === null || this.${a.name} === false)`
+            );
+
+            builder.writeln(
+                'if (!(%s || %s)) {',
+                cnd1.join(' && '),
+                cnd2.join(' && ')
+            );
+
+            builder.writeln(
+                "throw new Error('%s parameters must all be false-y (like null) or all me true-y');",
+                ra.map(a => a.name).join(', ')
+            );
+
+            builder.endBlock();
+        }
+    }
+
+    const bytes = Buffer.from(
+        parseInt(tlobject.id)
+            .toString(16)
+            .padStart(8, `0`),
+        `hex`
+    )
+        .readUInt32LE()
+        .toString(16)
+        .padStart(8, `0`);
+
+    builder.writeln('return parseInt([');
+    builder.currentIndent++;
+    builder.writeln("'%s',", bytes);
+
+    for (const arg of tlobject.args) {
+        if (writeArgToBytes(builder, arg, tlobject.args)) {
+            builder.writeln(',');
+        }
+    }
+
+    builder.currentIndent--;
+    builder.writeln(']);');
+    builder.endBlock();
+};
+
+// writeFromReader
+// writeReadResult
+
+/**
+ * Writes the .__bytes__() code for the given argument
+ * :param builder: The source code builder
+ * :param arg: The argument to write
+ * :param args: All the other arguments in TLObject same __bytes__.
+ *              This is required to determine the flags value
+ * :param name: The name of the argument. Defaults to "self.argname"
+ *              This argument is an option because it's required when
+ *              writing Vectors<>
+ */
+const writeArgToBytes = (builder, arg, args, name = null) => {
+    if (arg.genericDefinition) {
+        return; // Do nothing, this only specifies a later type
+    }
+
+    if (name === null) {
+        name = `this.${arg.name}`;
+    }
+
+    // The argument may be a flag, only write if it's not None AND
+    // if it's not a True type.
+    // True types are not actually sent, but instead only used to
+    // determine the flags.
+    if (arg.isFlag) {
+        if (arg.type === 'true') {
+            return; // Exit, since true type is never written
+        } else if (arg.isVector) {
+            // Vector flags are special since they consist of 3 values,
+            // so we need an extra join here. Note that empty vector flags
+            // should NOT be sent either!
+            builder.write(
+                "%s === null || %s === false ? b'' : b''.join([",
+                name,
+                name
+            );
+        } else {
+            builder.write("%s === null || %s === false ? b'' : [", name, name);
+        }
+    }
+
+    if (arg.isVector) {
+        if (arg.useVectorId) {
+            builder.write("'15c4b51c',");
+        }
+
+        builder.write("struct.pack('<i', %s.length),", name);
+
+        // Cannot unpack the values for the outer tuple through *[(
+        // since that's a Python >3.5 feature, so add another join.
+        builder.write('Buffer.concat(%s.map(x => ', name);
+
+        // Temporary disable .is_vector, not to enter this if again
+        // Also disable .is_flag since it's not needed per element
+        const oldFlag = arg.isFlag;
+        arg.isVector = arg.isFlag = false;
+        writeArgToBytes(builder, arg, args, 'x');
+        arg.isVector = true;
+        arg.isFlag = oldFlag;
+
+        builder.write('))', name);
+    } else if (arg.flagIndicator) {
+        // Calculate the flags with those items which are not None
+        if (!args.some(f => f.isFlag)) {
+            // There's a flag indicator, but no flag arguments so it's 0
+            builder.write('Buffer.alloc(4)');
+        } else {
+            builder.write("struct.pack('<I', ");
+            builder.write(
+                args
+                    .filter(flag => flag.isFlag)
+                    .map(
+                        flag =>
+                            `(this.${flag.name} === null || this.${
+                                flag.name
+                            } === false ? 0 : ${1 << flag.flagIndex})`
+                    )
+                    .join(' | ')
+            );
+            builder.write(')');
+        }
+    } else if (arg.type === 'int') {
+        builder.write("struct.pack('<i', %s)", name);
+    } else if (arg.type === 'long') {
+        builder.write("struct.pack('<q', %s)", name);
+    } else if (arg.type === 'int128') {
+        builder.write("%s.to_bytes(16, 'little', signed=True)", name);
+    } else if (arg.type === 'int256') {
+        builder.write("%s.to_bytes(32, 'little', signed=True)", name);
+    } else if (arg.type === 'double') {
+        builder.write("struct.pack('<d', %s)", name);
+    } else if (arg.type === 'string') {
+        builder.write('this.serializeBytes(%s)', name);
+    } else if (arg.type === 'Bool') {
+        builder.write('%s ? 0xb5757299 : 0x379779bc', name);
+    } else if (arg.type === 'true') {
+        // These are actually NOT written! Only used for flags
+    } else if (arg.type === 'bytes') {
+        builder.write('this.serializeBytes(%s)', name);
+    } else if (arg.type === 'date') {
+        builder.write('this.serializeDatetime(%s)', name);
+    } else {
+        // Else it may be a custom type
+        builder.write('bytes(%s)', name);
+
+        // If the type is not boxed (i.e. starts with lowercase) we should
+        // not serialize the constructor ID (so remove its first 4 bytes).
+        let boxed = arg.type.charAt(arg.type.indexOf('.') + 1);
+        boxed = boxed === boxed.toUpperCase();
+
+        if (!boxed) {
+            builder.write('.slice(4)');
+        }
+    }
+
+    if (arg.isFlag) {
+        builder.write(']');
+
+        if (arg.isVector) {
+            builder.write(']');
+        }
+    }
+
+    return true;
+};
+
+const writePatched = (outDir, namespaceTlobjects) => {
+    fs.mkdirSync(outDir, { recursive: true });
+
+    for (const [ns, tlobjects] of Object.entries(namespaceTlobjects)) {
+        const file = `${outDir}/${ns === 'null' ? 'index' : ns}.js`;
+        const stream = fs.createWriteStream(file);
+        const builder = new SourceBuilder(stream);
+
+        builder.writeln(AUTO_GEN_NOTICE);
+        builder.writeln("const struct = require('python-struct');");
+        builder.writeln(`const { TLObject, types, custom } = require('..');`);
+        builder.writeln();
+
+        for (const t of tlobjects) {
+            builder.writeln(
+                'class %s extends custom.%s {',
+                t.className,
+                PATCHED_TYPES[t.fullname]
+            );
+
+            builder.writeln('constructor() {');
+            builder.writeln('super();');
+            builder.writeln(`this.CONSTRUCTOR_ID = 0x${t.id.toString(16)}`);
+            builder.writeln(`this.SUBCLASS_OF_ID = 0x${crc32(t.result)}`);
+            builder.endBlock();
+
+            writeToJson(t, builder);
+            writeToBytes(t, builder);
+            // writeFromReader(t, builder);
+
+            builder.writeln();
+            builder.writeln(
+                'types.%s%s = %s',
+                t.namespace ? `${t.namespace}.` : '',
+                t.className,
+                t.className
+            );
+            builder.writeln();
+        }
+    }
+};
+
+const writeAllTlobjects = (tlobjects, layer, builder = new SourceBuilder()) => {
+    builder.writeln(AUTO_GEN_NOTICE);
+    builder.writeln();
+
+    builder.writeln("const { types, functions, patched } = require('.');");
+    builder.writeln();
+
+    // Create a constant variable to indicate which layer this is
+    builder.writeln(`const LAYER = %s;`, layer);
+    builder.writeln();
+
+    // Then create the dictionary containing constructor_id: class
+    builder.writeln('const tlobjects = {');
+
+    // Fill the dictionary (0x1a2b3c4f: tl.full.type.path.Class)
+    for (const tlobject of tlobjects) {
+        builder.write('0x0%s: ', tlobject.id.toString(16).padStart(8, '0'));
+
+        if (tlobject.fullname in PATCHED_TYPES) {
+            builder.write('patched');
+        } else {
+            builder.write(tlobject.isFunction ? 'functions' : 'types');
+        }
+
+        if (tlobject.namespace) {
+            builder.write('.%s', tlobject.namespace);
+        }
+
+        builder.writeln('.%s,', tlobject.className);
+    }
+
+    builder.endBlock(true);
+    builder.writeln('');
+    builder.writeln('module.exports = {');
+    builder.writeln('layer,');
+    builder.writeln('tlobjects');
+    builder.endBlock(true);
+};
+
+const generateTlobjects = (tlobjects, layer, importDepth, outputDir) => {
+    const namespaceFunctions = {};
+    const namespaceTypes = {};
+    const namespacePatched = {};
+
+    const typeConstructors = {};
+
+    for (const tlobject of tlobjects) {
+        if (tlobject.isFunction) {
+            if (!namespaceFunctions[tlobject.namespace]) {
+                namespaceFunctions[tlobject.namespace] = [];
+            }
+
+            namespaceFunctions[tlobject.namespace].push(tlobject);
+        } else {
+            if (!namespaceTypes[tlobject.namespace]) {
+                namespaceTypes[tlobject.namespace] = [];
+            }
+
+            if (!typeConstructors[tlobject.result]) {
+                typeConstructors[tlobject.result] = [];
+            }
+
+            namespaceTypes[tlobject.namespace].push(tlobject);
+            typeConstructors[tlobject.result].push(tlobject);
+
+            if (tlobject.fullname in PATCHED_TYPES) {
+                if (!namespacePatched[tlobject.namespace]) {
+                    namespacePatched[tlobject.namespace] = [];
+                }
+
+                namespacePatched[tlobject.namespace].push(tlobject);
+            }
+        }
+    }
+
+    writeModules(
+        `${outputDir}/functions`,
+        importDepth,
+        'TLRequest',
+        namespaceFunctions,
+        typeConstructors
+    );
+    writeModules(
+        `${outputDir}/types`,
+        importDepth,
+        'TLObject',
+        namespaceTypes,
+        typeConstructors
+    );
+    writePatched(`${outputDir}/pathced`, namespacePatched);
+
+    const filename = `${outputDir}/alltlobjects.js`;
+    const stream = fs.createWriteStream(filename);
+    const builder = new SourceBuilder(stream);
+
+    writeAllTlobjects(tlobjects, layer, builder);
+};
+
+const cleanTlobjects = outputDir => {
+    for (let d in ['functions', 'types', 'patched']) {
+        d = `${outputDir}/d`;
+
+        if (fs.statSync(d).isDirectory()) {
+            fs.rmdirSync(d);
+        }
+    }
+
+    const tl = `${outputDir}/alltlobjects.js`;
+
+    if (fs.statSync(tl).isFile()) {
+        fs.unlinkSync(tl);
+    }
+};
+
+const writeModuleExports = (tlobjects, builder) => {
+    builder.writeln('module.exports = {');
+
+    for (const t of tlobjects) {
+        builder.writeln(`${t.className},`);
+    }
+
+    builder.currentIndent--;
+    builder.writeln('};');
+};
+
+module.exports = {
+    generateTlobjects,
+    cleanTlobjects,
+};

+ 100 - 0
gramjs_generator/parsers/errors.js

@@ -0,0 +1,100 @@
+const fs = require('fs');
+const csvParse = require('csv-parse/lib/sync');
+const { snakeToCamelCase } = require('../utils');
+
+const KNOWN_BASE_CLASSES = {
+    303: 'InvalidDCError',
+    400: 'BadRequestError',
+    401: 'UnauthorizedError',
+    403: 'ForbiddenError',
+    404: 'NotFoundError',
+    406: 'AuthKeyError',
+    420: 'FloodError',
+    500: 'ServerError',
+    503: 'TimedOutError',
+};
+
+/**
+ * Gets the corresponding class name for the given error code,
+ * this either being an integer (thus base error name) or str.
+ */
+const getClassName = errorCode => {
+    if (typeof errorCode === 'number') {
+        return (
+            KNOWN_BASE_CLASSES[Math.abs(errorCode)] ||
+            'RPCError' + errorCode.toString().replace('-', 'Neg')
+        );
+    }
+
+    return snakeToCamelCase(
+        errorCode.replace('FIRSTNAME', 'FIRST_NAME').toLowerCase(),
+        'Error'
+    );
+};
+
+class TelegramError {
+    constructor(codes, name, description) {
+        // TODO Some errors have the same name but different integer codes
+        // Should these be split into different files or doesn't really matter?
+        // Telegram isn't exactly consistent with returned errors anyway.
+        this.intCode = codes[0];
+        this.stringCode = name;
+        this.subclass = getClassName(codes[0]);
+        this.subclassExists = Math.abs(codes[0]) in KNOWN_BASE_CLASSES;
+        this.description = description;
+
+        this.hasCaptures = name.includes('_X');
+
+        if (this.hasCaptures) {
+            this.name = getClassName(name.replace('_X', ''));
+            this.pattern = name.replace('_X', '_(\\d+)');
+            this.captureName = description.match(/{(\w+)}/)[1];
+        } else {
+            this.name = getClassName(name);
+            this.pattern = name;
+            this.captureName = null;
+        }
+    }
+}
+
+/**
+ * Parses the input CSV file with columns (name, error codes, description)
+ * and yields `Error` instances as a result.
+ */
+const parseErrors = function*(csvFile) {
+    const f = csvParse(fs.readFileSync(csvFile, { encoding: 'utf-8' })).slice(
+        1
+    );
+
+    for (let line = 0; line < f.length; line++) {
+        if (f[line].length !== 3) {
+            throw new Error(
+                `Columns count mismatch, unquoted comma in desc? (line ${line +
+                    2})`
+            );
+        }
+
+        let [name, codes, description] = f[line];
+
+        codes =
+            codes === ''
+                ? [400]
+                : codes.split(' ').map(x => {
+                      if (isNaN(x)) {
+                          throw new Error(
+                              `Not all codes are integers (line ${line + 2})`
+                          );
+                      }
+
+                      return Number(x);
+                  });
+
+        yield new TelegramError(codes, name, description);
+    }
+};
+
+module.exports = {
+    KNOWN_BASE_CLASSES,
+    TelegramError,
+    parseErrors,
+};

+ 14 - 0
gramjs_generator/parsers/index.js

@@ -0,0 +1,14 @@
+const { TelegramError, parseErrors } = require('./errors');
+const { MethodInfo, Usability, parseMethods } = require('./methods');
+const { TLObject, parseTl, findLayer } = require('./tlobject');
+
+module.exports = {
+    TelegramError,
+    parseErrors,
+    MethodInfo,
+    Usability,
+    parseMethods,
+    TLObject,
+    parseTl,
+    findLayer,
+};

+ 70 - 0
gramjs_generator/parsers/methods.js

@@ -0,0 +1,70 @@
+const fs = require('fs');
+const csvParse = require('csv-parse/lib/sync');
+
+const Usability = {
+    UNKNOWN: 0,
+    USER: 1,
+    BOT: 2,
+    BOTH: 4,
+};
+
+class MethodInfo {
+    constructor(name, usability, errors, friendly) {
+        this.name = name;
+        this.errors = errors;
+        this.friendly = friendly;
+
+        if (usability.toUpperCase() in Usability) {
+            this.usability = Usability[usability.toUpperCase()];
+        } else {
+            throw new Error(
+                `Usability must be either user, bot, both or unknown, not ${usability}`
+            );
+        }
+    }
+}
+
+/**
+ * Parses the input CSV file with columns (method, usability, errors)
+ * and yields `MethodInfo` instances as a result.
+ */
+const parseMethods = function*(csvFile, friendlyCsvFile, errorsDict) {
+    const rawToFriendly = {};
+    const f1 = csvParse(
+        fs.readFileSync(friendlyCsvFile, { encoding: 'utf-8' })
+    );
+
+    for (const [ns, friendly, rawList] of f1.slice(1)) {
+        for (const raw of rawList.split(' ')) {
+            rawToFriendly[raw] = [ns, friendly];
+        }
+    }
+
+    const f2 = csvParse(fs.readFileSync(csvFile, { encoding: 'utf-8' })).slice(
+        1
+    );
+
+    for (let line = 0; line < f2.length; line++) {
+        let [method, usability, errors] = f2[line];
+
+        errors = errors.split(' ').map(x => {
+            if (x && !(x in errorsDict)) {
+                throw new Error(
+                    `Method ${method} references unknown errors ${errors}`
+                );
+            }
+
+            return errorsDict[x];
+        });
+
+        const friendly = rawToFriendly[method];
+        delete rawToFriendly[method];
+        yield new MethodInfo(method, usability, errors, friendly);
+    }
+};
+
+module.exports = {
+    Usability,
+    MethodInfo,
+    parseMethods,
+};

+ 10 - 0
gramjs_generator/parsers/tlobject/index.js

@@ -0,0 +1,10 @@
+const { TLArg } = require('./tlarg');
+const { TLObject } = require('./tlobject');
+const { parseTl, findLayer } = require('./parser');
+
+module.exports = {
+    TLArg,
+    TLObject,
+    parseTl,
+    findLayer,
+};

+ 199 - 0
gramjs_generator/parsers/tlobject/parser.js

@@ -0,0 +1,199 @@
+const fs = require('fs');
+const { TLArg } = require('./tlarg');
+const { TLObject } = require('./tlobject');
+const { Usability } = require('../methods');
+
+const CORE_TYPES = new Set([
+    0xbc799737, // boolFalse#bc799737 = Bool;
+    0x997275b5, // boolTrue#997275b5 = Bool;
+    0x3fedd339, // true#3fedd339 = True;
+    0xc4b9f9bb, // error#c4b9f9bb code:int text:string = Error;
+    0x56730bcc, // null#56730bcc = Null;
+]);
+
+// Telegram Desktop (C++) doesn't care about string/bytes, and the .tl files
+// don't either. However in Python we *do*, and we want to deal with bytes
+// for the authorization key process, not UTF-8 strings (they won't be).
+//
+// Every type with an ID that's in here should get their attribute types
+// with string being replaced with bytes.
+const AUTH_KEY_TYPES = new Set([
+    0x05162463, // resPQ,
+    0x83c95aec, // p_q_inner_data
+    0xa9f55f95, // p_q_inner_data_dc
+    0x3c6a84d4, // p_q_inner_data_temp
+    0x56fddf88, // p_q_inner_data_temp_dc
+    0xd0e8075c, // server_DH_params_ok
+    0xb5890dba, // server_DH_inner_data
+    0x6643b654, // client_DH_inner_data
+    0xd712e4be, // req_DH_params
+    0xf5045f1f, // set_client_DH_params
+    0x3072cfa1, // gzip_packed
+]);
+
+const findall = (regex, str, matches) => {
+    if (!matches) {
+        matches = [];
+    }
+
+    if (!regex.flags.includes(`g`)) {
+        regex = new RegExp(regex.source, `g`);
+    }
+
+    const res = regex.exec(str);
+
+    if (res) {
+        matches.push(res.slice(1));
+        findall(regex, str, matches);
+    }
+
+    return matches;
+};
+
+const fromLine = (line, isFunction, methodInfo, layer) => {
+    const match = line.match(
+        /([\w.]+)(?:#([0-9a-fA-F]+))?(?:\s{?\w+:[\w\d<>#.?!]+}?)*\s=\s([\w\d<>#.?]+);$/
+    );
+
+    if (!match) {
+        // Probably "vector#1cb5c415 {t:Type} # [ t ] = Vector t;"
+        throw new Error(`Cannot parse TLObject ${line}`);
+    }
+
+    const argsMatch = findall(/({)?(\w+):([\w\d<>#.?!]+)}?/, line);
+    const [, name] = match;
+    methodInfo = methodInfo[name];
+
+    let usability, friendly;
+
+    if (methodInfo) {
+        usability = methodInfo.usability;
+        friendly = methodInfo.friendly;
+    } else {
+        usability = Usability.UNKNOWN;
+        friendly = null;
+    }
+
+    return new TLObject(
+        name,
+        match[2],
+        argsMatch.map(
+            ([brace, name, argType]) =>
+                new TLArg(name, argType, brace !== undefined)
+        ),
+        match[3],
+        isFunction,
+        usability,
+        friendly,
+        layer
+    );
+};
+
+/**
+ * This method yields TLObjects from a given .tl file.
+ *
+ * Note that the file is parsed completely before the function yields
+ * because references to other objects may appear later in the file.
+ */
+const parseTl = function*(filePath, layer, methods, ignoreIds = CORE_TYPES) {
+    const methodInfo = (methods || []).reduce(
+        (o, m) => ({ ...o, [m.name]: m }),
+        {}
+    );
+    const objAll = [];
+    const objByName = {};
+    const objByType = {};
+
+    const file = fs.readFileSync(filePath, { encoding: 'utf-8' });
+
+    let isFunction = false;
+
+    for (let line of file.split('\n')) {
+        const commentIndex = line.indexOf('//');
+
+        if (commentIndex !== -1) {
+            line = line.slice(0, commentIndex);
+        }
+
+        line = line.trim();
+
+        if (!line) {
+            continue;
+        }
+
+        const match = line.match(/---(\w+)---/);
+
+        if (match) {
+            const [, followingTypes] = match;
+            isFunction = followingTypes === 'functions';
+            continue;
+        }
+
+        try {
+            const result = fromLine(line, isFunction, methodInfo, layer);
+
+            if (ignoreIds.has(result.id)) {
+                continue;
+            }
+
+            objAll.push(result);
+
+            if (!result.isFunction) {
+                if (!objByType[result.result]) {
+                    objByType[result.result] = [];
+                }
+
+                objByName[result.fullname] = result;
+                objByType[result.result].push(result);
+            }
+        } catch (e) {
+            if (!e.toString().includes('vector#1cb5c415')) {
+                throw e;
+            }
+        }
+    }
+
+    // Once all objects have been parsed, replace the
+    // string type from the arguments with references
+    for (const obj of objAll) {
+        if (AUTH_KEY_TYPES.has(obj.id)) {
+            for (const arg of obj.args) {
+                if (arg.type === 'string') {
+                    arg.type = 'bytes';
+                }
+            }
+        }
+
+        for (const arg of obj.args) {
+            arg.cls =
+                objByType[arg.type] ||
+                (arg.type in objByName ? [objByName[arg.type]] : []);
+        }
+    }
+
+    for (const obj of objAll) {
+        yield obj;
+    }
+};
+
+/**
+ * Finds the layer used on the specified scheme.tl file.
+ */
+const findLayer = filePath => {
+    const layerRegex = /^\/\/\s*LAYER\s*(\d+)$/;
+
+    const file = fs.readFileSync(filePath, { encoding: 'utf-8' });
+
+    for (const line of file.split('\n')) {
+        const match = line.match(layerRegex);
+
+        if (match) {
+            return Number(match[1]);
+        }
+    }
+};
+
+module.exports = {
+    parseTl,
+    findLayer,
+};

+ 293 - 0
gramjs_generator/parsers/tlobject/tlarg.js

@@ -0,0 +1,293 @@
+const fmtStrings = (...objects) => {
+    for (const object of objects) {
+        for (const [k, v] of Object.entries(object)) {
+            if (['null', 'true', 'false'].includes(v)) {
+                object[k] = `<strong>${v}</strong>`;
+            } else {
+                object[k] = v.replace(
+                    /((['"]).*\2)/,
+                    (_, g) => `<em>${g}</em>`
+                );
+            }
+        }
+    }
+};
+
+const KNOWN_NAMED_EXAMPLES = {
+    'message,string': "'Hello there!'",
+    'expires_at,date': 'datetime.timedelta(minutes=5)',
+    'until_date,date': 'datetime.timedelta(days=14)',
+    'view_messages,true': 'None',
+    'send_messages,true': 'None',
+    'limit,int': '100',
+    'hash,int': '0',
+    'hash,string': "'A4LmkR23G0IGxBE71zZfo1'",
+    'min_id,int': '0',
+    'max_id,int': '0',
+    'min_id,long': '0',
+    'max_id,long': '0',
+    'add_offset,int': '0',
+    'title,string': "'My awesome title'",
+    'device_model,string': "'ASUS Laptop'",
+    'system_version,string': "'Arch Linux'",
+    'app_version,string': "'1.0'",
+    'system_lang_code,string': "'en'",
+    'lang_pack,string': "''",
+    'lang_code,string': "'en'",
+    'chat_id,int': '478614198',
+    'client_id,long': 'random.randrange(-2**63, 2**63)',
+};
+
+const KNOWN_TYPED_EXAMPLES = {
+    int128: "int.from_bytes(crypto.randomBytes(16), 'big')",
+    bytes: "b'arbitrary\\x7f data \\xfa here'",
+    long: '-12398745604826',
+    string: "'some string here'",
+    int: '42',
+    date: 'datetime.datetime(2018, 6, 25)',
+    double: '7.13',
+    Bool: 'False',
+    true: 'True',
+    InputChatPhoto: "client.upload_file('/path/to/photo.jpg')",
+    InputFile: "client.upload_file('/path/to/file.jpg')",
+    InputPeer: "'username'",
+};
+
+fmtStrings(KNOWN_NAMED_EXAMPLES, KNOWN_TYPED_EXAMPLES);
+
+const SYNONYMS = {
+    InputUser: 'InputPeer',
+    InputChannel: 'InputPeer',
+    InputDialogPeer: 'InputPeer',
+    InputNotifyPeer: 'InputPeer',
+    InputMessage: 'int',
+};
+
+// These are flags that are cleaner to leave off
+const OMITTED_EXAMPLES = [
+    'silent',
+    'background',
+    'clear_draft',
+    'reply_to_msg_id',
+    'random_id',
+    'reply_markup',
+    'entities',
+    'embed_links',
+    'hash',
+    'min_id',
+    'max_id',
+    'add_offset',
+    'grouped',
+    'broadcast',
+    'admins',
+    'edit',
+    'delete',
+];
+
+/**
+ * Initializes a new .tl argument
+ * :param name: The name of the .tl argument
+ * :param argType: The type of the .tl argument
+ * :param genericDefinition: Is the argument a generic definition?
+ *                           (i.e. {X:Type})
+ */
+class TLArg {
+    constructor(name, argType, genericDefinition) {
+        this.name = name === 'self' ? 'is_self' : name;
+
+        // Default values
+        this.isVector = false;
+        this.isFlag = false;
+        this.skipConstructorId = false;
+        this.flagIndex = -1;
+        this.cls = null;
+
+        // Special case: some types can be inferred, which makes it
+        // less annoying to type. Currently the only type that can
+        // be inferred is if the name is 'random_id', to which a
+        // random ID will be assigned if left as None (the default)
+        this.canBeInferred = name === 'random_id';
+
+        // The type can be an indicator that other arguments will be flags
+        if (argType === '#') {
+            this.flagIndicator = true;
+            this.type = null;
+            this.isGeneric = false;
+        } else {
+            this.flagIndicator = false;
+            this.isGeneric = argType.startsWith('!');
+            // Strip the exclamation mark always to have only the name
+            this.type = argType.replace(/^!+/, '');
+
+            // The type may be a flag (flags.IDX?REAL_TYPE)
+            // Note that 'flags' is NOT the flags name; this
+            // is determined by a previous argument
+            // However, we assume that the argument will always be called 'flags'
+            const flagMatch = this.type.match(/flags.(\d+)\?([\w<>.]+)/);
+
+            if (flagMatch) {
+                this.isFlag = true;
+                this.flagIndex = Number(flagMatch[1]);
+                // Update the type to match the exact type, not the "flagged" one
+                this.type = flagMatch[2];
+            }
+
+            // Then check if the type is a Vector<REAL_TYPE>
+            const vectorMatch = this.type.match(/[Vv]ector<([\w\d.]+)>/);
+
+            if (vectorMatch) {
+                this.isVector = true;
+
+                // If the type's first letter is not uppercase, then
+                // it is a constructor and we use (read/write) its ID.
+                this.useVectorId = this.type.charAt(0) === 'V';
+
+                // Update the type to match the one inside the vector
+                this.type = vectorMatch[1];
+            }
+
+            // See use_vector_id. An example of such case is ipPort in
+            // help.configSpecial
+            if (
+                /^[a-z]$/.test(
+                    this.type
+                        .split('.')
+                        .pop()
+                        .charAt(0)
+                )
+            ) {
+                this.skipConstructorId = true;
+            }
+
+            // The name may contain "date" in it, if this is the case and
+            // the type is "int", we can safely assume that this should be
+            // treated as a "date" object. Note that this is not a valid
+            // Telegram object, but it's easier to work with
+            // if (
+            //     this.type === 'int' &&
+            //     (/(\b|_)([dr]ate|until|since)(\b|_)/.test(name) ||
+            //         ['expires', 'expires_at', 'was_online'].includes(name))
+            // ) {
+            //     this.type = 'date';
+            // }
+        }
+
+        this.genericDefinition = genericDefinition;
+    }
+
+    typeHint() {
+        let cls = this.type;
+
+        if (cls.includes('.')) {
+            cls = cls.split('.')[1];
+        }
+
+        let result = {
+            int: 'int',
+            long: 'int',
+            int128: 'int',
+            int256: 'int',
+            double: 'float',
+            string: 'str',
+            date: 'Optional[datetime]', // None date = 0 timestamp
+            bytes: 'bytes',
+            Bool: 'bool',
+            true: 'bool',
+        };
+
+        result = result[cls] || `'Type${cls}'`;
+
+        if (this.isVector) {
+            result = `List[${result}]`;
+        }
+
+        if (this.isFlag && cls !== 'date') {
+            result = `Optional[${result}]`;
+        }
+
+        return result;
+    }
+
+    realType() {
+        // Find the real type representation by updating it as required
+        let realType = this.flagIndicator ? '#' : this.type;
+
+        if (this.isVector) {
+            if (this.useVectorId) {
+                realType = `Vector<${realType}>`;
+            } else {
+                realType = `vector<${realType}>`;
+            }
+        }
+
+        if (this.isGeneric) {
+            realType = `!${realType}`;
+        }
+
+        if (this.isFlag) {
+            realType = `flags.${this.flagIndex}?${realType}`;
+        }
+
+        return realType;
+    }
+
+    toString() {
+        if (this.genericDefinition) {
+            return `{${this.name}:${this.realType()}}`;
+        } else {
+            return `${this.name}:${this.realType()}`;
+        }
+    }
+
+    toJson() {
+        return {
+            name: this.name.replace('is_self', 'self'),
+            type: this.realType().replace(/\bdate$/, 'int'),
+        };
+    }
+
+    asExample(f, indent) {
+        if (this.isGeneric) {
+            f.write('other_request');
+            return;
+        }
+
+        let known =
+            KNOWN_NAMED_EXAMPLES[`${this.name},${this.type}`] ||
+            KNOWN_TYPED_EXAMPLES[this.type] ||
+            KNOWN_TYPED_EXAMPLES[SYNONYMS[this.type]];
+
+        if (known) {
+            f.write(known);
+            return;
+        }
+
+        // assert self.omit_example() or self.cls, 'TODO handle ' + str(self)
+
+        // Pick an interesting example if any
+        for (const cls of this.cls) {
+            if (cls.isGoodExample()) {
+                cls.asExample(f, indent || 0);
+                return;
+            }
+        }
+
+        // If no example is good, just pick the first
+        this.cls[0].asExample(f, indent || 0);
+    }
+
+    omitExample() {
+        return (
+            this.isFlag ||
+            (this.canBeInferred && OMITTED_EXAMPLES.includes(this.name))
+        );
+    }
+}
+
+module.exports = {
+    KNOWN_NAMED_EXAMPLES,
+    KNOWN_TYPED_EXAMPLES,
+    SYNONYMS,
+    OMITTED_EXAMPLES,
+    TLArg,
+};

+ 204 - 0
gramjs_generator/parsers/tlobject/tlobject.js

@@ -0,0 +1,204 @@
+const { crc32 } = require('crc');
+const struct = require('python-struct');
+const { snakeToCamelCase } = require('../../utils');
+
+// https://github.com/telegramdesktop/tdesktop/blob/4bf66cb6e93f3965b40084771b595e93d0b11bcd/Telegram/SourceFiles/codegen/scheme/codegen_scheme.py#L57-L62
+const WHITELISTED_MISMATCHING_IDS = {
+    // 0 represents any layer
+    0: new Set([
+        'channel', // Since layer 77, there seems to be no going back...
+        'ipPortSecret',
+        'accessPointRule',
+        'help.configSimple',
+    ]),
+};
+
+/**
+ * Initializes a new TLObject, given its properties.
+ *
+ * :param fullname: The fullname of the TL object (namespace.name)
+ *                  The namespace can be omitted.
+ * :param object_id: The hexadecimal string representing the object ID
+ * :param args: The arguments, if any, of the TL object
+ * :param result: The result type of the TL object
+ * :param is_function: Is the object a function or a type?
+ * :param usability: The usability for this method.
+ * :param friendly: A tuple (namespace, friendly method name) if known.
+ * :param layer: The layer this TLObject belongs to.
+ */
+class TLObject {
+    constructor(
+        fullname,
+        objectId,
+        args,
+        result,
+        isFunction,
+        usability,
+        friendly,
+        layer
+    ) {
+        // The name can or not have a namespace
+        this.fullname = fullname;
+
+        if (fullname.includes('.')) {
+            [this.namespace, this.name] = fullname.split(/\.(.+)/);
+            // console.log(fullname.split(/\.(.+)/));
+            // const [namespace, ...name] = fullname.split('.');
+            // this.namespace = namespace;
+            // this.name = name.join('.');
+        } else {
+            this.namespace = null;
+            this.name = fullname;
+        }
+
+        this.args = args;
+        this.result = result;
+        this.isFunction = isFunction;
+        this.usability = usability;
+        this.friendly = friendly;
+        this.id = null;
+
+        if (!objectId) {
+            this.id = this.inferId();
+        } else {
+            this.id = parseInt(objectId, 16);
+
+            const whitelist = new Set([
+                ...WHITELISTED_MISMATCHING_IDS[0],
+                ...(WHITELISTED_MISMATCHING_IDS[layer] || []),
+            ]);
+
+            if (!whitelist.has(this.fullname)) {
+                if (this.id !== this.inferId()) {
+                    throw new Error(`Invalid inferred ID for ${this.repr()}`);
+                }
+            }
+        }
+
+        this.className = snakeToCamelCase(
+            this.name,
+            this.isFunction ? 'Request' : ''
+        );
+
+        this.realArgs = this.sortedArgs().filter(
+            a => !(a.flagIndicator || a.genericDefinition)
+        );
+    }
+
+    get innermostResult() {
+        const index = this.result.indexOf('<');
+        return index === -1 ? this.result : this.result.slice(index + 1, -1);
+    }
+
+    /**
+     * Returns the arguments properly sorted and ready to plug-in
+     * into a Python's method header (i.e., flags and those which
+     * can be inferred will go last so they can default =None)
+     */
+    sortedArgs() {
+        return this.args.sort(x => x.isFlag || x.canBeInferred);
+    }
+
+    repr(ignoreId) {
+        let hexId, args;
+
+        if (this.id === null || ignoreId) {
+            hexId = '';
+        } else {
+            hexId = `#${this.id.toString(16).padStart(8, '0')}`;
+        }
+
+        if (this.args.length) {
+            args = ` ${this.args.map(arg => arg.toString()).join(' ')}`;
+        } else {
+            args = '';
+        }
+
+        return `${this.fullname}${hexId}${args} = ${this.result}`;
+    }
+
+    inferId() {
+        const representation = this.repr(true)
+            .replace(/(:|\?)bytes /g, '$1string ')
+            .replace(/</g, ' ')
+            .replace(/>|{|}/g, '')
+            .replace(/ \w+:flags\.\d+\?true/g, '');
+
+        if (this.fullname === 'inputMediaInvoice') {
+            if (this.fullname === 'inputMediaInvoice') {
+            }
+        }
+
+        return crc32(Buffer.from(representation, 'utf8'));
+    }
+
+    toJson() {
+        return {
+            id: struct.unpack('i', struct.pack('I', this.id))[0].toString(),
+            [this.isFunction ? 'method' : 'predicate']: this.fullname,
+            param: this.args
+                .filter(x => !x.genericDefinition)
+                .map(x => x.toJson()),
+            type: this.result,
+        };
+    }
+
+    isGoodExample() {
+        return !this.className.endsWith('Empty');
+    }
+
+    asExample(f, indent) {
+        f.write(this.isFunction ? 'functions' : 'types');
+
+        if (this.namespace) {
+            f.write('.');
+            f.write(this.namespace);
+        }
+
+        f.write('.');
+        f.write(this.className);
+        f.write('(');
+
+        const args = this.realArgs.filter(arg => !arg.omitExample());
+
+        if (!args.length) {
+            f.write(')');
+            return;
+        }
+
+        f.write('\n');
+        indent++;
+        let remaining = args.length;
+
+        for (const arg of args) {
+            remaining--;
+            f.write('    '.repeat(indent));
+            f.write(arg.name);
+            f.write('=');
+
+            if (arg.isVector) {
+                f.write('[');
+            }
+
+            arg.asExample(f, indent || 0);
+
+            if (arg.isVector) {
+                f.write(']');
+            }
+
+            if (remaining) {
+                f.write(',');
+            }
+
+            f.write('\n');
+        }
+
+        indent--;
+        f.write('    '.repeat(indent));
+        f.write(')');
+    }
+}
+
+module.exports = {
+    TLObject,
+};

+ 77 - 0
gramjs_generator/sourcebuilder.js

@@ -0,0 +1,77 @@
+const util = require('util');
+
+/**
+ * This class should be used to build .py source files
+ */
+class SourceBuilder {
+    constructor(stream, indentSize) {
+        this.currentIndent = 0;
+        this.onNewLine = false;
+        this.indentSize = indentSize || 4;
+        this.stream = stream;
+
+        // Was a new line added automatically before? If so, avoid it
+        this.autoAddedLine = false;
+    }
+
+    /**
+     * Indents the current source code line
+     * by the current indentation level
+     */
+    indent() {
+        this.write(' '.repeat(this.currentIndent * this.indentSize));
+    }
+
+    /**
+     * Writes a string into the source code,
+     * applying indentation if required
+     */
+    write(string, ...args) {
+        if (this.onNewLine) {
+            this.onNewLine = false; // We're not on a new line anymore
+
+            // If the string was not empty, indent; Else probably a new line
+            if (string.trim()) {
+                this.indent();
+            }
+        }
+
+        if (args.length) {
+            this.stream.write(util.format(string, ...args));
+        } else {
+            this.stream.write(string);
+        }
+    }
+
+    /**
+     * Writes a string into the source code _and_ appends a new line,
+     * applying indentation if required
+     */
+    writeln(string, ...args) {
+        this.write(`${string || ''}\n`, ...args);
+        this.onNewLine = true;
+
+        // If we're writing a block, increment indent for the next time
+        if (string && string.endsWith('{')) {
+            this.currentIndent++;
+        }
+
+        // Clear state after the user adds a new line
+        this.autoAddedLine = false;
+    }
+
+    /**
+     * Ends an indentation block, leaving an empty line afterwards
+     */
+    endBlock(semiColon = false) {
+        this.currentIndent--;
+
+        // If we did not add a new line automatically yet, now it's the time!
+        if (!this.autoAddedLine) {
+            this.writeln('}%s', semiColon ? ';' : '');
+            this.autoAddedLine = true;
+        }
+    }
+}
+
+module.exports = SourceBuilder;

+ 8 - 0
gramjs_generator/utils.js

@@ -0,0 +1,8 @@
+const snakeToCamelCase = (name, suffix) => {
+    const result = name.replace(/(?:^|_)([a-z])/g, (_, g) => g.toUpperCase());
+    return result.replace(/_/g, '') + (suffix || '');
+};
+
+module.exports = {
+    snakeToCamelCase,
+};

+ 162 - 0
index.js

@@ -0,0 +1,162 @@
+const fs = require('fs');
+const glob = require('glob');
+
+const GENERATOR_DIR = './gramjs_generator';
+const LIBRARY_DIR = './gramjs';
+
+const ERRORS_IN = `${GENERATOR_DIR}/data/errors.csv`;
+const ERRORS_OUT = `${LIBRARY_DIR}/errors/rpcerrorlist.js`;
+
+const METHODS_IN = `${GENERATOR_DIR}/data/methods.csv`;
+
+// Which raw API methods are covered by *friendly* methods in the client?
+const FRIENDLY_IN = `${GENERATOR_DIR}/data/friendly.csv`;
+
+const TLOBJECT_IN_TLS = glob.sync(`${GENERATOR_DIR}/data/*.tl`);
+const TLOBJECT_OUT = `${LIBRARY_DIR}/tl`;
+const IMPORT_DEPTH = 2;
+
+const DOCS_IN_RES = `${GENERATOR_DIR}/data/html`;
+const DOCS_OUT = `./docs`;
+
+const generate = (which, action = 'gen') => {
+    const {
+        parseErrors,
+        parseMethods,
+        parseTl,
+        findLayer,
+    } = require('./gramjs_generator/parsers');
+
+    const {
+        generateErrors,
+        generateTlobjects,
+        // generateDocs,
+        cleanTlobjects,
+    } = require('./gramjs_generator/generators');
+
+    const [layer] = TLOBJECT_IN_TLS.map(findLayer).filter(Boolean);
+    const errors = [...parseErrors(ERRORS_IN)];
+    const methods = [
+        ...parseMethods(
+            METHODS_IN,
+            FRIENDLY_IN,
+            errors.reduce((errors, error) => {
+                errors[error.stringCode] = error;
+                return errors;
+            }, {})
+        ),
+    ];
+
+    const [tlobjects] = TLOBJECT_IN_TLS.map(file => [
+        ...parseTl(file, layer, methods),
+    ]);
+
+    if (!which || which.length === 0) {
+        which.push('tl', 'errors');
+    }
+
+    const clean = action === 'clean';
+    action = clean ? 'Cleaning' : 'Generating';
+
+    if (which.includes('all')) {
+        which.splice(which.indexOf('all'), 1);
+
+        for (const x of ['tl', 'errors', 'docs']) {
+            if (!which.includes(x)) {
+                which.push(x);
+            }
+        }
+    }
+
+    if (which.includes('tl')) {
+        which.splice(which.indexOf('tl'), 1);
+        console.log(action, 'TLObjects...');
+
+        if (clean) {
+            cleanTlobjects(TLOBJECT_OUT);
+        } else {
+            generateTlobjects(tlobjects, layer, IMPORT_DEPTH, TLOBJECT_OUT);
+        }
+    }
+
+    if (which.includes('errors')) {
+        which.splice(which.indexOf('errors'), 1);
+        console.log(action, 'RPCErrors...');
+
+        if (clean) {
+            if (fs.statSync(ERRORS_OUT).isFile()) {
+                fs.unlinkSync(ERRORS_OUT);
+            }
+        } else {
+            const file = fs.createWriteStream(ERRORS_OUT);
+            generateErrors(errors, file);
+        }
+    }
+
+    if (which.includes('docs')) {
+        which.splice(which.indexOf('docs'), 1);
+        // console.log(action, 'documentation...');
+        console.log('TODO: documentation...');
+
+        if (clean) {
+            if (fs.statSync(DOCS_OUT)) {
+                fs.rmdirSync(DOCS_OUT);
+            }
+        } else {
+            // TODO
+        }
+    }
+
+    if (which.includes('json')) {
+        which.splice(which.indexOf('json'), 1);
+        console.log(action, 'JSON schema...');
+
+        const jsonFiles = TLOBJECT_IN_TLS.map(
+            x => x.slice(0, x.lastIndexOf('.')) + '.json'
+        );
+
+        if (clean) {
+            for (const file of jsonFiles) {
+                if (fs.statSync(file).isFile()) {
+                    fs.unlinkSync(file);
+                }
+            }
+        } else {
+            const genJson = (fin, fout) => {
+                const meths = [];
+                const constructors = [];
+
+                for (const tl of parseTl(fin, layer)) {
+                    if (tl.isFunction) {
+                        meths.push(tl.toJson());
+                    } else {
+                        constructors.push(tl.toJson());
+                    }
+                }
+
+                const what = { constructors, methods };
+                fs.writeFileSync(fout, JSON.stringify(what, null, 2));
+            };
+
+            for (let i = 0; i < TLOBJECT_IN_TLS.length; i++) {
+                const fin = TLOBJECT_IN_TLS[i];
+                const fout = jsonFiles[i];
+                genJson(fin, fout);
+            }
+        }
+    }
+
+    if (which.length) {
+        console.log('The following items were not understood:', which);
+        console.log('  Consider using only "tl", "errors" and/or "docs".');
+        console.log(
+            '  Using only "clean" will clean them. "all" to act on all.'
+        );
+        console.log('  For instance "gen tl errors".');
+    }
+};
+
+const { argv } = process;
+if (argv.length > 2 && argv[2] === 'gen') {
+    generate(argv.slice(3));
+}

+ 1306 - 0
package-lock.json

@@ -0,0 +1,1306 @@
+{
+  "name": "gramjs",
+  "version": "0.1.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "@babel/code-frame": {
+      "version": "7.5.5",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz",
+      "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==",
+      "requires": {
+        "@babel/highlight": "^7.0.0"
+      }
+    },
+    "@babel/highlight": {
+      "version": "7.5.0",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz",
+      "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==",
+      "requires": {
+        "chalk": "^2.0.0",
+        "esutils": "^2.0.2",
+        "js-tokens": "^4.0.0"
+      }
+    },
+    "@types/lodash": {
+      "version": "4.14.138",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.138.tgz",
+      "integrity": "sha512-A4uJgHz4hakwNBdHNPdxOTkYmXNgmUAKLbXZ7PKGslgeV0Mb8P3BlbYfPovExek1qnod4pDfRbxuzcVs3dlFLg=="
+    },
+    "@types/node": {
+      "version": "12.7.5",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz",
+      "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w=="
+    },
+    "@types/normalize-package-data": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+      "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA=="
+    },
+    "acorn": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz",
+      "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ=="
+    },
+    "acorn-jsx": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz",
+      "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw=="
+    },
+    "ajv": {
+      "version": "6.10.2",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+      "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+      "requires": {
+        "fast-deep-equal": "^2.0.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      }
+    },
+    "ansi-escapes": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
+      "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ=="
+    },
+    "ansi-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+      "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+    },
+    "ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "requires": {
+        "color-convert": "^1.9.0"
+      }
+    },
+    "argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "requires": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "astral-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+      "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg=="
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+    },
+    "base64-js": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
+      "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "buffer": {
+      "version": "5.4.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz",
+      "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==",
+      "requires": {
+        "base64-js": "^1.0.2",
+        "ieee754": "^1.1.4"
+      }
+    },
+    "caller-callsite": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
+      "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
+      "requires": {
+        "callsites": "^2.0.0"
+      },
+      "dependencies": {
+        "callsites": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+          "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA="
+        }
+      }
+    },
+    "caller-path": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
+      "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
+      "requires": {
+        "caller-callsite": "^2.0.0"
+      }
+    },
+    "callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
+    },
+    "chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "requires": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      }
+    },
+    "chardet": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
+    },
+    "ci-info": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+      "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
+    },
+    "cli-cursor": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+      "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+      "requires": {
+        "restore-cursor": "^2.0.0"
+      }
+    },
+    "cli-width": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+      "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
+    },
+    "color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "requires": {
+        "color-name": "1.1.3"
+      }
+    },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+    },
+    "cosmiconfig": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+      "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+      "requires": {
+        "import-fresh": "^2.0.0",
+        "is-directory": "^0.3.1",
+        "js-yaml": "^3.13.1",
+        "parse-json": "^4.0.0"
+      },
+      "dependencies": {
+        "import-fresh": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+          "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
+          "requires": {
+            "caller-path": "^2.0.0",
+            "resolve-from": "^3.0.0"
+          }
+        },
+        "resolve-from": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+          "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
+        }
+      }
+    },
+    "crc": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz",
+      "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==",
+      "requires": {
+        "buffer": "^5.1.0"
+      }
+    },
+    "cross-spawn": {
+      "version": "6.0.5",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+      "requires": {
+        "nice-try": "^1.0.4",
+        "path-key": "^2.0.1",
+        "semver": "^5.5.0",
+        "shebang-command": "^1.2.0",
+        "which": "^1.2.9"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+        }
+      }
+    },
+    "csv-parse": {
+      "version": "4.4.6",
+      "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.4.6.tgz",
+      "integrity": "sha512-VisC5TBBhOF+70zjrF9FOiqI2LZOhXK/vAWlOrqyqz3lLa+P8jzJ7L/sg90MHmkSY/brAXWwrmGSZR0tM5yi4g=="
+    },
+    "debug": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+      "requires": {
+        "ms": "^2.1.1"
+      }
+    },
+    "deep-is": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+    },
+    "doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "requires": {
+        "esutils": "^2.0.2"
+      }
+    },
+    "emoji-regex": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
+    },
+    "end-of-stream": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+      "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+      "requires": {
+        "once": "^1.4.0"
+      }
+    },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+    },
+    "eslint": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.4.0.tgz",
+      "integrity": "sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA==",
+      "requires": {
+        "@babel/code-frame": "^7.0.0",
+        "ajv": "^6.10.0",
+        "chalk": "^2.1.0",
+        "cross-spawn": "^6.0.5",
+        "debug": "^4.0.1",
+        "doctrine": "^3.0.0",
+        "eslint-scope": "^5.0.0",
+        "eslint-utils": "^1.4.2",
+        "eslint-visitor-keys": "^1.1.0",
+        "espree": "^6.1.1",
+        "esquery": "^1.0.1",
+        "esutils": "^2.0.2",
+        "file-entry-cache": "^5.0.1",
+        "functional-red-black-tree": "^1.0.1",
+        "glob-parent": "^5.0.0",
+        "globals": "^11.7.0",
+        "ignore": "^4.0.6",
+        "import-fresh": "^3.0.0",
+        "imurmurhash": "^0.1.4",
+        "inquirer": "^6.4.1",
+        "is-glob": "^4.0.0",
+        "js-yaml": "^3.13.1",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.3.0",
+        "lodash": "^4.17.14",
+        "minimatch": "^3.0.4",
+        "mkdirp": "^0.5.1",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.8.2",
+        "progress": "^2.0.0",
+        "regexpp": "^2.0.1",
+        "semver": "^6.1.2",
+        "strip-ansi": "^5.2.0",
+        "strip-json-comments": "^3.0.1",
+        "table": "^5.2.3",
+        "text-table": "^0.2.0",
+        "v8-compile-cache": "^2.0.3"
+      }
+    },
+    "eslint-scope": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
+      "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
+      "requires": {
+        "esrecurse": "^4.1.0",
+        "estraverse": "^4.1.1"
+      }
+    },
+    "eslint-utils": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz",
+      "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==",
+      "requires": {
+        "eslint-visitor-keys": "^1.0.0"
+      }
+    },
+    "eslint-visitor-keys": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz",
+      "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A=="
+    },
+    "espree": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz",
+      "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==",
+      "requires": {
+        "acorn": "^7.0.0",
+        "acorn-jsx": "^5.0.2",
+        "eslint-visitor-keys": "^1.1.0"
+      }
+    },
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+    },
+    "esquery": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
+      "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
+      "requires": {
+        "estraverse": "^4.0.0"
+      }
+    },
+    "esrecurse": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+      "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+      "requires": {
+        "estraverse": "^4.1.0"
+      }
+    },
+    "estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
+    },
+    "esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
+    },
+    "execa": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+      "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+      "requires": {
+        "cross-spawn": "^6.0.0",
+        "get-stream": "^4.0.0",
+        "is-stream": "^1.1.0",
+        "npm-run-path": "^2.0.0",
+        "p-finally": "^1.0.0",
+        "signal-exit": "^3.0.0",
+        "strip-eof": "^1.0.0"
+      }
+    },
+    "external-editor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+      "requires": {
+        "chardet": "^0.7.0",
+        "iconv-lite": "^0.4.24",
+        "tmp": "^0.0.33"
+      }
+    },
+    "fast-csv": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-3.4.0.tgz",
+      "integrity": "sha512-/vPTDJc/l6VLOLIqcrMjuhyi8ZVTipTNl2GkVvaYiHlyh16oQMYPUkUVfREurT3MYE9j3mLQDk2Q8kPq30qQCg==",
+      "requires": {
+        "@types/lodash": "^4.14.132",
+        "@types/node": "^12.0.2",
+        "lodash": "^4.17.13"
+      }
+    },
+    "fast-deep-equal": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+      "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+    },
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+    },
+    "figures": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+      "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+      "requires": {
+        "escape-string-regexp": "^1.0.5"
+      }
+    },
+    "file-entry-cache": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
+      "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
+      "requires": {
+        "flat-cache": "^2.0.1"
+      }
+    },
+    "find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "requires": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      }
+    },
+    "flat-cache": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+      "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+      "requires": {
+        "flatted": "^2.0.0",
+        "rimraf": "2.6.3",
+        "write": "1.0.3"
+      }
+    },
+    "flatted": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz",
+      "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg=="
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+    },
+    "functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
+    },
+    "get-stdin": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz",
+      "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ=="
+    },
+    "get-stream": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+      "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+      "requires": {
+        "pump": "^3.0.0"
+      }
+    },
+    "glob": {
+      "version": "7.1.4",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
+      "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "glob-parent": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz",
+      "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==",
+      "requires": {
+        "is-glob": "^4.0.1"
+      }
+    },
+    "globals": {
+      "version": "11.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+    },
+    "hosted-git-info": {
+      "version": "2.8.4",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz",
+      "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ=="
+    },
+    "husky": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.5.tgz",
+      "integrity": "sha512-cKd09Jy9cDyNIvAdN2QQAP/oA21sle4FWXjIMDttailpLAYZuBE7WaPmhrkj+afS8Sj9isghAtFvWSQ0JiwOHg==",
+      "requires": {
+        "chalk": "^2.4.2",
+        "cosmiconfig": "^5.2.1",
+        "execa": "^1.0.0",
+        "get-stdin": "^7.0.0",
+        "is-ci": "^2.0.0",
+        "opencollective-postinstall": "^2.0.2",
+        "pkg-dir": "^4.2.0",
+        "please-upgrade-node": "^3.2.0",
+        "read-pkg": "^5.1.1",
+        "run-node": "^1.0.0",
+        "slash": "^3.0.0"
+      }
+    },
+    "iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "requires": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      }
+    },
+    "ieee754": {
+      "version": "1.1.13",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+      "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
+    },
+    "ignore": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+      "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
+    },
+    "import-fresh": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz",
+      "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==",
+      "requires": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      }
+    },
+    "imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "inquirer": {
+      "version": "6.5.2",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz",
+      "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==",
+      "requires": {
+        "ansi-escapes": "^3.2.0",
+        "chalk": "^2.4.2",
+        "cli-cursor": "^2.1.0",
+        "cli-width": "^2.0.0",
+        "external-editor": "^3.0.3",
+        "figures": "^2.0.0",
+        "lodash": "^4.17.12",
+        "mute-stream": "0.0.7",
+        "run-async": "^2.2.0",
+        "rxjs": "^6.4.0",
+        "string-width": "^2.1.0",
+        "strip-ansi": "^5.1.0",
+        "through": "^2.3.6"
+      }
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
+    },
+    "is-ci": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+      "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+      "requires": {
+        "ci-info": "^2.0.0"
+      }
+    },
+    "is-directory": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+      "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
+    },
+    "is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+    },
+    "is-fullwidth-code-point": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+    },
+    "is-glob": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+      "requires": {
+        "is-extglob": "^2.1.1"
+      }
+    },
+    "is-promise": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
+    },
+    "is-stream": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+      "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+    },
+    "js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+    },
+    "js-yaml": {
+      "version": "3.13.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+      "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+      "requires": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      }
+    },
+    "json-parse-better-errors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
+    },
+    "json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+    },
+    "json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
+    },
+    "levn": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+      "requires": {
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2"
+      }
+    },
+    "lines-and-columns": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
+      "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA="
+    },
+    "locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "requires": {
+        "p-locate": "^4.1.0"
+      }
+    },
+    "lodash": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
+    },
+    "long": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
+      "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
+    },
+    "mimic-fn": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+      "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+    },
+    "mkdirp": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "requires": {
+        "minimist": "0.0.8"
+      }
+    },
+    "ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+    },
+    "mute-stream": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+      "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
+    },
+    "natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
+    },
+    "nice-try": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
+    },
+    "normalize-package-data": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "requires": {
+        "hosted-git-info": "^2.1.4",
+        "resolve": "^1.10.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+        }
+      }
+    },
+    "npm-run-path": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+      "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+      "requires": {
+        "path-key": "^2.0.0"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "onetime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "requires": {
+        "mimic-fn": "^1.0.0"
+      }
+    },
+    "opencollective-postinstall": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz",
+      "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw=="
+    },
+    "optionator": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+      "requires": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.4",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "wordwrap": "~1.0.0"
+      }
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+    },
+    "p-finally": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+      "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
+    },
+    "p-limit": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
+      "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
+      "requires": {
+        "p-try": "^2.0.0"
+      }
+    },
+    "p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "requires": {
+        "p-limit": "^2.2.0"
+      }
+    },
+    "p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+    },
+    "parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "requires": {
+        "callsites": "^3.0.0"
+      }
+    },
+    "parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+      "requires": {
+        "error-ex": "^1.3.1",
+        "json-parse-better-errors": "^1.0.1"
+      }
+    },
+    "path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+    },
+    "path-key": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+    },
+    "path-parse": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
+    },
+    "pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+      "requires": {
+        "find-up": "^4.0.0"
+      }
+    },
+    "please-upgrade-node": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+      "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
+      "requires": {
+        "semver-compare": "^1.0.0"
+      }
+    },
+    "prelude-ls": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+    },
+    "progress": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
+    },
+    "pump": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "punycode": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+    },
+    "python-struct": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/python-struct/-/python-struct-1.1.1.tgz",
+      "integrity": "sha512-s581PmdO3nooRRO+NZmwY+C7P1tY3ZWSIEpbLY/yp8FLrmC0AFxiY6mPzvzfULyT3eYkYx2dTBtV2cbi7HZxqg==",
+      "requires": {
+        "eslint": "^6.2.2",
+        "husky": "^3.0.4",
+        "long": "^4.0.0"
+      }
+    },
+    "read-pkg": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+      "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+      "requires": {
+        "@types/normalize-package-data": "^2.4.0",
+        "normalize-package-data": "^2.5.0",
+        "parse-json": "^5.0.0",
+        "type-fest": "^0.6.0"
+      },
+      "dependencies": {
+        "parse-json": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
+          "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
+          "requires": {
+            "@babel/code-frame": "^7.0.0",
+            "error-ex": "^1.3.1",
+            "json-parse-better-errors": "^1.0.1",
+            "lines-and-columns": "^1.1.6"
+          }
+        }
+      }
+    },
+    "regexpp": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+      "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw=="
+    },
+    "resolve": {
+      "version": "1.12.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
+      "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
+      "requires": {
+        "path-parse": "^1.0.6"
+      }
+    },
+    "resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
+    },
+    "restore-cursor": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+      "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+      "requires": {
+        "onetime": "^2.0.0",
+        "signal-exit": "^3.0.2"
+      }
+    },
+    "rimraf": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+      "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+      "requires": {
+        "glob": "^7.1.3"
+      }
+    },
+    "run-async": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+      "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+      "requires": {
+        "is-promise": "^2.1.0"
+      }
+    },
+    "run-node": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz",
+      "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A=="
+    },
+    "rxjs": {
+      "version": "6.5.3",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz",
+      "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==",
+      "requires": {
+        "tslib": "^1.9.0"
+      }
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+    },
+    "semver-compare": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+      "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w="
+    },
+    "shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "requires": {
+        "shebang-regex": "^1.0.0"
+      }
+    },
+    "shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+    },
+    "slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
+    },
+    "slice-ansi": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+      "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+      "requires": {
+        "ansi-styles": "^3.2.0",
+        "astral-regex": "^1.0.0",
+        "is-fullwidth-code-point": "^2.0.0"
+      }
+    },
+    "spdx-correct": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+      "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+      "requires": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+      "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA=="
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+      "requires": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+      "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q=="
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+    },
+    "string-format": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz",
+      "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA=="
+    },
+    "string-width": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+      "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+      "requires": {
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^4.0.0"
+      },
+      "dependencies": {
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        }
+      }
+    },
+    "strip-ansi": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+      "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+      "requires": {
+        "ansi-regex": "^4.1.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
+        }
+      }
+    },
+    "strip-eof": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+      "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
+    },
+    "strip-json-comments": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
+      "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw=="
+    },
+    "supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "requires": {
+        "has-flag": "^3.0.0"
+      }
+    },
+    "table": {
+      "version": "5.4.6",
+      "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
+      "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
+      "requires": {
+        "ajv": "^6.10.2",
+        "lodash": "^4.17.14",
+        "slice-ansi": "^2.1.0",
+        "string-width": "^3.0.0"
+      },
+      "dependencies": {
+        "string-width": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "requires": {
+            "emoji-regex": "^7.0.1",
+            "is-fullwidth-code-point": "^2.0.0",
+            "strip-ansi": "^5.1.0"
+          }
+        }
+      }
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+    },
+    "tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "requires": {
+        "os-tmpdir": "~1.0.2"
+      }
+    },
+    "tslib": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
+      "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ=="
+    },
+    "type-check": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "requires": {
+        "prelude-ls": "~1.1.2"
+      }
+    },
+    "type-fest": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+      "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="
+    },
+    "uri-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+      "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "requires": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "v8-compile-cache": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
+      "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g=="
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "requires": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "requires": {
+        "isexe": "^2.0.0"
+      }
+    },
+    "wordwrap": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+    },
+    "write": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
+      "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
+      "requires": {
+        "mkdirp": "^0.5.1"
+      }
+    }
+  }
+}

+ 23 - 0
package.json

@@ -0,0 +1,23 @@
+{
+  "name": "gramjs",
+  "version": "0.1.0",
+  "description": "NodeJS MTProto API Telegram client library,",
+  "main": "index.js",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/gram-js/gramjs.git"
+  },
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/gram-js/gramjs/issues"
+  },
+  "homepage": "https://github.com/gram-js/gramjs#readme",
+  "dependencies": {
+    "crc": "^3.8.0",
+    "csv-parse": "^4.4.6",
+    "fast-csv": "^3.4.0",
+    "glob": "^7.1.4",
+    "python-struct": "^1.1.1",
+    "string-format": "^2.0.0"
+  }
+}