[
  {
    "path": ".babelrc",
    "content": "{\n  \"plugins\": [\n    \"transform-strict-mode\",\n    \"transform-object-rest-spread\",\n    \"transform-class-properties\"\n  ],\n  \"presets\": [\n    \"babel-preset-es2015\"\n  ]\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".eslintignore",
    "content": "bin\n*.md\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"extends\": \"airbnb/base\",\n  \"parser\": \"babel-eslint\",\n  \"rules\": {\n    \"new-cap\": 0,\n    \"prefer-arrow-callback\": 0,\n    \"no-param-reassign\": [2,{\"props\":false}],\n    \"max-len\": [2, 200],\n    \"arrow-body-style\": 0,\n    \"comma-dangle\": 0,\n    \"indent\": [\"error\", 2]\n  },\n  \"plugins\": [\n    \"mocha\"\n  ],\n  \"env\": {\n    \"mocha\": true\n  }\n}"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "<!--\nThis template includes three sections:\n1. Bug reporting\n2. Feature request\n3. Question\n\nPlease remove sections that do not apply to your issue\n-->\n\n\n\n<!--********************************************************************\nReporting a Bug.\n*********************************************************************-->\n\n> Bug Report\n\nI have read:\n\n* [Usage information](https://github.com/yagop/node-telegram-bot-api/tree/master/doc/usage.md)\n* [Help information](https://github.com/yagop/node-telegram-bot-api/tree/master/doc/help.md)\n\nI am using the latest version of the library.\n\n### Expected Behavior\n\n<!-- Explain what you are trying to achieve -->\n\n### Actual Behavior\n\n<!-- Explain what happens, contrary to what you expected -->\n\n### Steps to reproduce the Behavior\n\n<!-- Explain how we can reproduce the bug -->\n\n\n\n<!--********************************************************************\nFeature Request.\n*********************************************************************-->\n\n> Feature Request\n\nI have:\n\n* searched for such a feature request (https://github.com/yagop/node-telegram-bot-api/labels/enhancement) and found none\n\n### Introduction\n\n<!-- Describe what value this feature would add, and in which use case,\nor scenario -->\n\n### Example\n\n<!-- A code snippet of how this feature would work, were it already\nimplemented -->\n\n\n\n<!--********************************************************************\nQuestion.\n*********************************************************************-->\n\n> Question\n\n<!-- Ask your question here. Please be precise, adding as much detail\nas necessary. Also, add a code snippet(s) if possible. -->\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "<!--\nMark whichever option below applies to this PR.\nFor example, if your PR passes all tests, you would mark the option as so:\n- [x] All tests pass\nNote the 'x' in between the square brackets '[]'\n-->\n- [ ] All tests pass\n- [ ] I have run `npm run doc`\n\n### Description\n\n<!-- Explain what you are trying to achieve with this PR -->\n\n### References\n\n<!--\nAdd references to other documents/pages that are relevant to this\nPR, such as related issues, documentation, etc.\n\nFor example,\n* Issue #1: https://github.com/yagop/node-telegram-bot-api/issues/1\n* Telegram Bot API - Getting updates: https://core.telegram.org/bots/api#getting-updates\n-->\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\ncoverage/\nnpm-debug.log\n.package.json\npackage-lock.json\noutput.md\noutput/\nlib/\nlib-doc/\n.DS_Store"
  },
  {
    "path": ".npmignore",
    "content": "# lcov\ncoverage/\n*.log\n.package.json\n\n# artifacts & source\nREADME.hbs\noutput.md\noutput/\ntest/\nexamples/\nlib-doc/\n\n# dotfiles\n.travis.yml\n.eslintrc\n.eslintignore\n.editorconfig\n.babelrc\n.gitignore\n.git\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - \"12\"\n  - \"10\"\n  - \"8\"\n  - \"6\"\n#\n# create required bash scripts to run builds on pull requests in the future\n#\n#script:\n#   - 'if [ \"$TRAVIS_PULL_REQUEST\" != \"false\" ]; then bash ./travis/run_on_pull_requests; fi'\n#   - 'if [ \"$TRAVIS_PULL_REQUEST\" = \"false\" ]; then bash ./travis/run_on_non_pull_requests; fi'\nafter_success:\n  - bash <(curl -s https://codecov.io/bash)\ncache:\n  directories:\n    - node_modules\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nThis project adheres to [Semantic Versioning](http://semver.org/).\n\n## [Unreleased][Unreleased]\n\n## [0.68.0][0.68.0] - 2026-03-15\n\nAdded:\n\n1. Support Telegram Bot API v9.3 (by @danielperez9430)\n   * `#getUserGifts`\n   * `#getChatGifts`\n   * `#sendMessageDraft` (by @xjx0106)\n   * `#repostStory`\n\n2. Fixed method:\n   * `unpinAllGeneralForumTopicMessages`\n   * `replaceStickerInSet`\n\n3. Support Telegram Bot API v9.5 (by @danielperez9430)\n   * `setChatMemberTag`\n\n4. Support Telegram Bot API v9.6 (by @danielperez9430)\n   * setMyProfilePhoto\n   * removeMyProfilePhoto\n\n5. Added missing methods (by @danielperez9430)\n   * getUserProfileAudios\n   * approveSuggestedPost\n   * declineSuggestedPost\n\n6. Added more test\n\n## [0.67.0][0.67.0] - 2025-12-13\n\nAdded:\n\n1. Support Telegram Bot API v7.4 (by @danielperez9430)\n   * `#refundStarPayment`\n6. Support Telegram Bot API 7.6 (@danielperez9430)\n   * `#sendPaidMedia`\n1. Support Telegram Bot API v7.9 (by @danielperez9430)\n1. Support Telegram Bot API v7.10 (by @danielperez9430)\n   * Update: `purchased_paid_media`\n1. Support Telegram Bot API v8.0 and v8.1\n   * `#savePreparedInlineMessage` (@IsmailBinMujeeb)\n   * `#setUserEmojiStatus` (@danielperez9430)\n   * `#editUserStarSubscription` (@danielperez9430)\n   * `#getAvailableGifts` (@danielperez9430)\n   * `#sendGift` (@danielperez9430)\n1. Support Telegram Bot API v8.2, v8.3 (@danielperez9430)\n   * `#verifyUser`\n   * `#verifyChat`\n   * `#removeUserVerification`\n   * `#removeChatVerification`\n1. Support Telegram Bot API v8.3 (by @danielperez9430)\n1. Support Telegram Bot API v9.0 (by @danielperez9430)\n   * `#readBusinessMessage`\n   * `#deleteBusinessMessages`\n   * `#setBusinessAccountName`\n   * `#setBusinessAccountUsername`\n   * `#setBusinessAccountBio`\n   * `#setBusinessAccountProfilePhoto`\n   * `#removeBusinessAccountProfilePhoto`\n   * `#setBusinessAccountGiftSettings`\n   * `#getBusinessAccountStarBalance`\n   * `#transferBusinessAccountStars`\n   * `#getBusinessAccountGifts`\n   * `#convertGiftToStars`\n   * `#upgradeGift`\n   * `#transferGift`\n   * `#postStory`\n   * `#editStory`\n   * `#deleteStory`\n   * `#giftPremiumSubscription`\n1. Support Telegram Bot API v9.1 (by @danielperez9430)\n   * `#sendChecklist`\n   * `#editMessageChecklist`\n   * `#getMyStarBalance`\n\nFixed:\n\n1. Reference causing error in `FatalError` (by @ivanjh)\n1. Stringify `scope` field in `#deleteMyCommands` (by @XC-Zhang)\n1. Stringify `allowed_updates` field in `#getUpdates` (by @alfanzain)\n1. Stringify `message_ids` in `#forwardMessages` (by @qiaoshouzi)\n1. Rename parameter `thumb` to `thumbnail` (by @0x114514BB)\n1. Remove travis badge (by @melroy89)\n1. Improve documentation on events (by @programminghoch10)\n1. Fix Telegram invite group link (by @melroy89)\n\n  \n## [0.66.0][0.66.0] - 2024-05-03\n\n1. Support Telegram Bot API 7.2 & 7.3 (@danielperez9430)\n  * getBusinessConnection\n  * replaceStickerInSet\n\n2. Support for updates: (@danielperez9430)\n  * business_connection\n  * business_message\n  * edited_business_message\n  * deleted_business_messages\n\n3. Minor fixes: (@danielperez9430)\n  * getUserChatBoosts\n\n## [0.65.1][0.65.1] - 2024-03-09\n\n1. Support for updates (@danielperez9430)\n  * message_reaction\n  * message_reaction_count\n  * chat_boost\n  * removed_chat_boost\n\n## [0.65.0][0.65.0] - 2024-02-20\n\n1. Support Telegram Bot API v7.1\n  * deleteMessages (@Sp3ricka)\n  * copyMessages (@xjx0106 & @Sp3ricka)\n  * setMessageReaction (@Sp3ricka)\n  * forwardMessages (@danielperez9430)\n  * getUserChatBoosts (@danielperez9430)\n\n2. Minor changes: (@danielperez9430)\n  * Refactor methods order\n  * Fix copyMessages & setMessageReaction methods\n  * Added missing tests \n  * Fix tests for methods copyMessages & getMyDefaulAdministratorRights\n\n## [0.64.0][0.64.0] - 2023-10-25\n\n1. Replace `request` with a maintained version (@danielperez9430)\n * Change `request` to `@cypress/request`\n * Change `request-promise` to `@cypress/request-promise`\n\n## [0.63.0][0.63.0] - 2023-08-23\n\n1. Support Telegram Bot API v6.8 (@danielperez9430)\n * unpinAllGeneralForumTopicMessages\n\n## [0.62.0][0.62.0] - 2023-03-19\n\n1. Support Telegram Bot API v6.6 & v6.7 (@danielperez9430)\n * setMyDescription\n * getMyDescription\n * setMyShortDescription\n * getMyShortDescription\n * setCustomEmojiStickerSetThumbnail\n * setStickerSetTitle\n * deleteStickerSet \n * setStickerEmojiList \n * setStickerKeywords \n * setStickerMaskPosition \n\n## [0.61.0][0.61.0] - 2022-12-30\n\n1. Support Telegram Bot API v6.4 (@danielperez9430)\n * editGeneralForumTopic\n * closeGeneralForumTopic\n * reopenGeneralForumTopic\n * hideGeneralForumTopic\n * unhideGeneralForumTopic\n\n2. Minor changes: (@danielperez9430)\n * The parameters `name` and `icon_custom_emoji_id` of the method `editForumTopic` are now optional.\n * Fix add thumb in sendAudio, sendVideo and sendVideoNote\n * Fix getMyCommands and setMyCommands\n * Suggested tip amounts stringify in sendInvoice\n\n## [0.60.0][0.60.0] - 2022-10-06\n\n1. Support Telegram Bot API v6.3 (@danielperez9430)\n * createForumTopic\n * closeForumTopic\n * reopenForumTopic\n * deleteForumTopic\n * unpinAllForumTopicMessages\n * getForumTopicIconStickers\n\n2. Fix test getMyDefaultAdministratorRights (@danielperez9430)\n\n3. Fix parse entities - (@toniop99)\n\n## [0.59.0][0.59.0] - 2022-08-15\n\n1. Support Telegram Bot API v6.2 (@danielperez9430)\n * getCustomEmojiStickers\n\n2. Support test enviroment (@tinsaeDev & @kamikazechaser)\n\n3. Remove dependencies: (@danielperez9430)\n   * Remove *bluebird* => Use NodeJS Native Promises\n   * Remove *depd* => Use node native deprecate util for warnings\n   * Remove contributor dev dependency and add list of contributors in the readme\n\n4. Remove legacy methods: (@danielperez9430)\n  * getChatMembersCount\n  * kickChatMember\n\n5. Docs: (@danielperez9430)\n * Update the docs of the methods\n * Order methods follow the Telegram bot API docs in src/telegram.js\n * Update README\n\n6. Fix: (@danielperez9430)\n * addStickerToSet() -> Allow to send tgs_sticker + webm_sticker\n * Remove mandatory param “start_parameter” from sendInvoice, because in the docs is a optional param\n * getStickerSet test fix deprecated response value \"contains_masks\" change to \"sticker_type\"\n * Fix some other tests\n\n7. New Test: (@danielperez9430)\n * deleteStickerFromSet\n * setStickerPositionInSet\n * getCustomEmojiStickers\n\n## [0.58.0][0.58.0] - 2022-06-22\n\n1. Support Bot API v6.1: (@danielperez9430)\n   * Add method *createInvoiceLink()*\n\n2. Support for setStickerSetThumb (@elihaidv)\n\n3. Add new test (@danielperez9430)\n   * createInvoiceLink\n\n4. Test fixes (@danielperez9430)\n   * sendVideoNote\n   * createNewStickerSet\n   * setStickerSetThumb\n   * getChatMenuButton\n   * setWebHook\n\n5. Bug fixes (@danielperez9430)\n   * answerWebAppQuery\n   * Support for send thumb in sendAudio \n\n## [0.57.0][0.57.0] - 2022-04-23\n\nAdded:\n\n1. Support Bot API v6: (@danielperez9430)\n\n   * Add method *setChatMenuButton()*\n   * Add method *getChatMenuButton()*\n   * Add method *setMyDefaultAdministratorRights()*\n   * Add method *getMyDefaultAdministratorRights()*\n   * Add method *answerWebAppQuery()*\n   * Renamed the fields voice_chat_scheduled, voice_chat_started, voice_chat_ended, and voice_chat_participants_invited to video_chat_scheduled, video_chat_started, video_chat_ended, and video_chat_participants_invited \n\n\n   Tests:\n\n   * answerWebAppQuery\n   * setChatMenuButton\n   * getChatMenuButton\n   * setMyDefaultAdministratorRights\n   * getMyDefaultAdministratorRights\n\n## [0.56.0][0.56.0] - 2021-12-07\n\nAdded:\n\n1. Support Bot API v5.5: (@danielperez9430)\n\n   * Add method *banChatSenderChat()*\n   * Add method *unbanChatSenderChat()*\n\n   Fixes:\n\n   * Tests for support with new invite link format\n\n## [0.55.0][0.55.0] - 2021-11-06\n\nAdded:\n\n1. Support Bot API v5.4: (@danielperez9430)\n\n   * Add method *approveChatJoinRequest()*\n   * Add method *declineChatJoinRequest()*\n   * Add support for new updates:\n     * *chat_join_request*\n   \n   Fixes:\n\n   * Method *editMessageMedia*: Now you can send a local file (`\"attach://\" + filePatch`)\n\n## [0.54.0][0.54.0] - 2021-06-29\n\nAdded:\n\n1. Support Bot API v5.3: (@danielperez9430)\n\n   * Add method *deleteMyCommands()*\n   * Add method *banChatMember()*\n   * Add method *getChatMemberCount()*\n\n   New Test:\n   \n   * deleteMyCommands\n   * banChatMember\n   * getChatMemberCount\n\n   Deprecated:\n   * Method *kickChatMember()*\n   * Method *getChatMembersCount()*\n\n## [0.53.0][0.53.0] - 2021-04-26\n\nAdded:\n\n1. Support Bot API v5.2:(@danielperez9430)\n\n   * Add support for new messageTypes:\n     * *voice_chat_scheduled*\n\n## [0.52.0][0.52.0] - 2021-03-20\n\nAdded:\n\n1. Support Bot API v5.1: (by @danielperez9430)\n   \n   * Add method *createChatInviteLink()*\n   * Add method *editChatInviteLink()*\n   * Add method *revokeChatInviteLink()*\n   * Add support for new messageTypes:\n     * *voice_chat_started*\n     * *voice_chat_ended*\n     * *voice_chat_participants_invited*\n     * *message_auto_delete_timer_changed*\n     * *chat_invite_link*\n     * *chat_member_updated*\n   * Add support for new updates:\n     * *my_chat_member*\n     * *chat_member*\n   \n   New Test: (by @danielperez9430)\n   \n   * createChatInviteLink\n   * editChatInviteLink\n   * revokeChatInviteLink\n\n## [0.51.0][0.51.0] - 2020-11-04\n\nAdded:\n\n1. Support Bot API v5.0: (by @danielperez9430)\n   \n   * Add method *copyMessage()*\n   * Add method *unpinAllChatMessages()*\n   * Add method *close()*\n   * Add method *logOut()*\n   \n   Changed: (by @danielperez9430)\n   \n   * Remove trailing-spaces\n   * Fix Bugs in Test\n   \n   New Test: (by @danielperez9430)\n   \n   * copyMessage\n   * unpinAllChatMessages\n\n## [0.50.0][0.50.0] - 2020-05-2020\n\nAdded:\n\n1. Support Bot API v4.8: (by @danielperez9430)\n   * Add methods: *sendDice()*\n2. Support Bot API v4.7: (by @danielperez9430)\n   * Add methods: *getMyCommands()*,*setMyCommands()*\n3. Support Bot API v4.5: (by @danielperez9430)\n   * Add methods: *setChatAdministratorCustomTitle()*\n4. Support Bot API v4.4: (by @danielperez9430)\n   * Add methods: *setChatPermissions()*\n5. Support for poll_answer (by @JieJiSS)\n6. Add request options in file stream (by @zhangpanyi )\n\nChanged: (by @danielperez9430)\n\n* New message type: *dice*\n* Fix Bugs in tests\n* Fix regex compare (by @ledamint)\n* Fix listening for error events when downloading files (by @Kraigo)\n\nNew Test: (by @danielperez9430)\n\n* sendDice\n* getMyCommands\n* setMyCommands\n* setChatAdministratorCustomTitle\n* setChatPermissions\n\n## [0.40.0][0.40.0] - 2019-05-04\n\nAdded:\n\n1. Support Bot API v4.2: (by @kamikazechaser)\n   * Add methods: *TelegramBot#sendPoll()*, *TelegramBot#stopPoll()*\n   * Support events: *poll*\n2. Support Bot API v4.0: (by @kamikazechaser)\n   * Add methods: *TelegramBot#editMessageMedia()*, *TelegramBot#sendAnimation()*\n   * Support new message types: *passport_data*, *animation*\n\n* * *\n\n## [0.30.0][0.30.0] - 2017-12-21\n\nAdded:\n\n1. Support Bot API v3.5: (by @GochoMugo)\n   * Allow `provider_data` parameter in *TelegramBot#sendInvoice*\n   * Add method *TelegramBot#sendMediaGroup()*\n2. Support Bot API v3.4: (by @kamikazechaser)\n   * Add methods *TelegramBot#editMessageLiveLocation*, *TelegramBot#stopMessageLiveLocation* (#439)\n   * Add methods *TelegramBot#setChatStickerSet*, *TelegramBot#deleteChatStickerSet* (#440)\n3. Add methods:\n   * *TelegramBot#getFileStream* (#442) (by @GochoMugo, requested-by @Xaqron)\n4. Add options to *TelegramBot#stopPolling()* (by @GochoMugo)\n5. Add `metadata` argument in `message` event (and friends e.g. `text`, `audio`, etc.) (#409) (by @jlsjonas, @GochoMugo)\n6. Add forward-compatibility i.e. support future additional Telegram options (by @GochoMugo)\n7. Add support for Node.js v9 (by @GochoMugo)\n8. Document *TelegramBot.errors*, *TelegramBot.messageTypes* (by @GochoMugo)\n\nChanged:\n\n1. Update *TelegramBot#answerCallbackQuery()* signature (by @GochoMugo)\n2. Improve default error logging of `polling_error` and `webhook_error` (#377)\n3. Update dependencies\n\nDeprecated:\n\n1. Sending files: *(See [usage guide][usage-sending-files])* (by @hufan-akari, @GochoMugo)\n   * Error will **not** be thrown if `Buffer` is used and file-type could **not** be detected.\n   * Filename will **not** be set to `data.${ext}` if `Buffer` is used\n   * Content type will **not** default to `null` or `undefined`\n\nFixed:\n\n1. Fix the offset infinite loop bug (#265, #36) (by @GochoMugo)\n2. Fix game example (#449, #418) (by @MCSH)\n\n* * *\n\n## [0.29.0][0.29.0] - 2017-10-22\n\nAdded:\n\n1. Add Bot API v3.2 methods:\n   * (#429) *TelegramBot#getStickerSet* (by @CapacitorSet, @LibertyLocked)\n   * (#430) *TelegramBot#uploadStickerFile* (by @CapacitorSet)\n   * *TelegramBot#createNewStickerSet*, *TelegramBot#addStickerToSet*, *TelegramBot#setStickerPositionInSet*, *TelegramBot#deleteStickerFromSet* (by @GochoMugo)\n2. Supports API v3.3\n\nDeprecated:\n\n1. Auto-enabling Promise cancellation (#319) (by @GochoMugo)\n\n* * *\n\n## [0.28.0][0.28.0] - 2017-08-06\n\nAdded:\n\n1. (#361) Support Bot API v3.1 (by @Lord-Protector, @kamikazechaser)\n2. (#332) Support Bot API v3.0 (by @kamikazechaser, @GochoMugo)\n3. Add *TelegramBot#removeTextListener()* (by @GochoMugo)\n4. (#342) Add game example (by @MCSH)\n5. (#315) List 'bot-brother' project in community section in README (by @saeedhei)\n\nChanged:\n\n1. (#367) Update *TelegramBot#answerCallbackQuery()* signature (by @mnb3000)\n\nFixed:\n\n1. (#325) Fix global regexp state reset (by @Sirius-A)\n2. (#363) Fix download file path on windows (by @kucherenkovova)\n3. (#346) Fix anchor webhook link in docs (by @Coac)\n\n* * *\n\n## [0.27.1][0.27.1] - 2017-04-07\n\nAdded:\n\n1. (#287) Add Express WebHook example (by @kamikazechaser)\n\nFixed:\n\n1. (#291) Improve docs (by @preco21)\n2. (#298) Fix running on Node v5 (by @jehy)\n3. (#307) Fix badge links in README (by @JaakkoLipsanen)\n4. Fix defaulting value of `options.polling.params.timeout` (by @GochoMugo)\n5. Fix typos in Github issue template (by @GochoMugo, requested-by @GingerPlusPlus)\n\n* * *\n\n## [0.27.0][0.27.0] - 2017-02-10\n\nAdded:\n\n1. Add constructor options:\n   * (#243) `options.polling.params` (by @GochoMugo, requested-by @sidelux)\n2. Add methods:\n   * (#74) *TelegramBot#removeReplyListener()* (by @githugger)\n3. (#283) Add proper error handling (by @GochoMugo)\n4. (#272) Add health-check endpoint (by @mironov)\n   * `options.webHook.healthEndpoint`\n5. (#152) Add test for TelegramBot#sendDocument() using 'fileOpts'\n   param (by @evolun)\n6. Document `options.webHook.host` (by @GochoMugo)\n7. (#264) Add Bot API version to README (by @kamikazechaser)\n8. Add examples:\n   - (#271) WebHook on Heroku (by @TheBeastOfCaerbannog)\n   - (#274) WebHook on Zeit Now (by @Ferrari)\n\nChanged:\n\n1. (#147) Use *String#indexOf()*, instead of *RegExp#test()*, to\n   find token in webhook request (by @AVVS)\n\nFixed:\n\n* Fix bug:\n  - (#275, #280) fix es6 syntax error on Node.js v4.x (by @crazyabdul)\n  - (#276) promise.warning from `request-promise` (by @GochoMugo,\n    reported-by @preco21)\n  - (#281) fix handling error during polling (by @GochoMugo,\n    reported-by @dimawebmaker)\n  - (#284) fix error during deletion of already-set webhook, during\n    polling (by @GochoMugo, reported-by @dcparga)\n1. Fix links in documentation (by @Ni2c2k)\n\n* * *\n\n## [0.26.0][0.26.0] - 2017-01-20\n\nAdded:\n\n1. Add *TelegramBot* constructor options:\n   * `options.https`\n   * `options.baseApiUrl`\n   * `options.filepath`\n2. Add methods:\n   * *TelegramBot#stopPolling()*\n   * *TelegramBot#isPolling()*\n   * *TelegramBot#openWebHook()*\n   * *TelegramBot#closeWebHook()*\n   * *TelegramBot#hasOpenWebHook()*\n   * *TelegramBot#deleteWebHook()*\n   * *TelegramBot#getWebHookInfo()*\n\nChanged:\n\n1. Use POST requests by default\n2. Ensure all relevant methods return Promises\n3. Document auto-deletion of webhook during polling\n4. Deprecate support for Node.js v0.12\n5. Fix consistency of methods signatures\n6. Rename *TelegramBot#initPolling()* to *TelegramBot#startPolling()*\n   * Deprecate *TelegramBot#initPolling()*\n\nFixed:\n\n1. Handle error during formatting `formData`\n2. Fix ES6 syntax\n\n*Credits/Blames: Unless explicitly stated otherwise, above work was\ndone by @GochoMugo*\n\n* * *\n\n## [0.25.0][0.25.0] - 2016-12-21\n\nAdded:\n\n1. Supports the API v2.3 updates (by @kamikazechaser)\n2. Add *TelegramBot* constructor option:\n   * `options.request`: proxy extra request options (by @tarmolov)\n   * `options.onlyFirstMatch` (by @GingerPlusPlus)\n3. Add methods:\n   * *TelegramBot#sendVenue()* (by Tketa)\n   * *TelegramBot#sendContact()* (by @GochoMugo)\n   * *TelegramBot#getGameHighScores()* (by @jishnu7)\n\nFixed:\n\n1. Fix request performance issue (by @preco21)\n2. Fix typos (by oflisback)\n\n[usage-sending-files]:https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files-options\n\n[0.25.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.25.0\n[0.26.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.26.0\n[0.27.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.27.0\n[0.27.1]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.27.1\n[0.28.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.28.0\n[0.29.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.29.0\n[0.30.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.30.0\n[0.63.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.63.0\n[0.64.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.64.0\n[0.65.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.65.0\n[0.65.1]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.65.1\n[0.66.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.66.0\n[0.67.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.67.0\n[0.68.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.68.0\n[Unreleased]:https://github.com/yagop/node-telegram-bot-api/compare/v0.68.0...master\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as\ncontributors and maintainers pledge to making participation in our project and\nour community a harassment-free experience for everyone, regardless of age, body\nsize, disability, ethnicity, gender identity and expression, level of experience,\nnationality, personal appearance, race, religion, or sexual identity and\norientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment\ninclude:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or\nadvances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic\n  address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable\nbehavior and are expected to take appropriate and fair corrective action in\nresponse to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community. Examples of\nrepresenting a project or community include using an official project e-mail\naddress, posting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event. Representation of a project may be\nfurther defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting the project team at mugo@forfuture.co.ke. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. The project team is\nobligated to maintain confidentiality with regard to the reporter of an incident.\nFurther details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good\nfaith may face temporary or permanent repercussions as determined by other\nmembers of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,\navailable at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\n> If you are willing to contribute, first you should know that\n> I will love you and so will the Telegram Bot community.\n\nBefore proceeding any further, read the following documents:\n\n1. [Code of Conduct][coc]\n1. [License][license]\n\n## General Information\n\n### Creating a Github issue:\n\n1. Ensure that your issue does **not** already exist. [Do a search](https://github.com/yagop/node-telegram-bot-api/issues).\n2. Browse through [StackOverflow](https://stackoverflow.com/search?q=telegram+nodejs) and other similar platforms.\n3. Should you open your issue, ensure you use the English language for\n   the wider target audience.\n4. Be patient please.\n\n\n### Updating API Reference i.e. generating `doc/api.md`\n\nRun:\n\n```bash\n$ npm run doc\n```\n\n\n### Running tests\n\nPlease read `test/README.md` for more information.\n\n\n### Transpiling ES2015 for older Node.js versions\n\nWe use babel to transpile the code:\n\n```bash\n$ npm run build\n```\n\n[coc]:https://github.com/yagop/node-telegram-bot-api/blob/master/CODE_OF_CONDUCT.md\n[license]:https://github.com/yagop/node-telegram-bot-api/blob/master/LICENSE.md\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2019 Yago\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">Node.js Telegram Bot API</h1>\n\n<div align=\"center\">\n\nNode.js module to interact with the official [Telegram Bot API](https://core.telegram.org/bots/api).\n\n\n[![Bot API](https://img.shields.io/badge/Bot%20API-v.9.6-00aced.svg?style=flat-square&logo=telegram)](https://core.telegram.org/bots/api)\n[![npm package](https://img.shields.io/npm/v/node-telegram-bot-api?logo=npm&style=flat-square)](https://www.npmjs.org/package/node-telegram-bot-api)\n[![Coverage Status](https://img.shields.io/codecov/c/github/yagop/node-telegram-bot-api?style=flat-square&logo=codecov)](https://codecov.io/gh/yagop/node-telegram-bot-api)\n\n[![https://telegram.me/node_telegram_bot_api](https://img.shields.io/badge/💬%20Telegram-Channel-blue.svg?style=flat-square)](https://telegram.me/node_telegram_bot_api)\n[![https://t.me/+_IC8j_b1wSFlZTVk](https://img.shields.io/badge/💬%20Telegram-Group-blue.svg?style=flat-square)](https://t.me/+_IC8j_b1wSFlZTVk)\n[![https://telegram.me/Yago_Perez](https://img.shields.io/badge/💬%20Telegram-Yago_Perez-blue.svg?style=flat-square)](https://telegram.me/Yago_Perez)\n\n</div>\n\n## 📦 Install\n\n```sh\nnpm i node-telegram-bot-api\n```\n\n<br/>\n\n> ✍️ **Note:** If you use Typescript you can install this package that contains type definitions for this library\n>```sh\n>npm install --save-dev @types/node-telegram-bot-api\n>```\n\n## 🚀 Usage\n\n```js\nconst TelegramBot = require('node-telegram-bot-api');\n\n// replace the value below with the Telegram token you receive from @BotFather\nconst token = 'YOUR_TELEGRAM_BOT_TOKEN';\n\n// Create a bot that uses 'polling' to fetch new updates\nconst bot = new TelegramBot(token, {polling: true});\n\n// Matches \"/echo [whatever]\"\nbot.onText(/\\/echo (.+)/, (msg, match) => {\n  // 'msg' is the received Message from Telegram\n  // 'match' is the result of executing the regexp above on the text content\n  // of the message\n\n  const chatId = msg.chat.id;\n  const resp = match[1]; // the captured \"whatever\"\n\n  // send back the matched \"whatever\" to the chat\n  bot.sendMessage(chatId, resp);\n});\n\n// Listen for any kind of message. There are different kinds of\n// messages.\nbot.on('message', (msg) => {\n  const chatId = msg.chat.id;\n\n  // send a message to the chat acknowledging receipt of their message\n  bot.sendMessage(chatId, 'Received your message');\n});\n```\n\n## 📚 Documentation\n\n* [Usage][usage]\n* [Examples][examples]\n* [Tutorials][tutorials]\n* [Help Information][help]\n* API Reference: ([api-release](../master/doc/api.md) / [development][api-dev] / [experimental][api-experimental])\n* [Contributing to the Project][contributing]\n* [Experimental Features][experimental]\n\n_**Note**: Development is done against the **development** branch.\nCode for the latest release resides on the **master** branch.\nExperimental features reside on the **experimental** branch._\n\n\n## 💭 Community\n\nWe thank all the developers in the Open-Source community who continuously\ntake their time and effort in advancing this project.\nSee our [list of contributors][contributors].\n\nWe have a [Telegram channel][tg-channel] where we post updates on\nthe Project. Head over and subscribe!\n\nWe also have a [Telegram  group][tg-group] to discuss issues related to this library.\n\nSome things built using this library that might interest you:\n\n* [tgfancy](https://github.com/GochoMugo/tgfancy): A fancy, higher-level wrapper for Telegram Bot API\n* [node-telegram-bot-api-middleware](https://github.com/idchlife/node-telegram-bot-api-middleware): Middleware for node-telegram-bot-api\n* [teleirc](https://github.com/FruitieX/teleirc): A simple Telegram ↔ IRC gateway\n* [bot-brother](https://github.com/SerjoPepper/bot-brother): Node.js library to help you easily create telegram bots\n* [redbot](https://github.com/guidone/node-red-contrib-chatbot): A Node-RED plugin to create telegram bots visually\n* [node-telegram-keyboard-wrapper](https://github.com/alexandercerutti/node-telegram-keyboard-wrapper): A wrapper to improve keyboards structures creation through a more easy-to-see way (supports Inline Keyboards, Reply Keyboard, Remove Keyboard and Force Reply)\n* [beetube-bot](https://github.com/kodjunkie/beetube-bot): A telegram bot for music, videos, movies, EDM tracks, torrent downloads, files and more.\n* [telegram-inline-calendar](https://github.com/VDS13/telegram-inline-calendar): Date and time picker and inline calendar for Node.js telegram bots.\n* [telegram-captcha](https://github.com/VDS13/telegram-captcha): Telegram bot to protect Telegram groups from automatic bots.\n\n\n## 👥 Contributors\n\n<p align=\"center\">\n  <a href=\"https://github.com/yagop/node-telegram-bot-api/graphs/contributors\">\n    <img src=\"https://contrib.rocks/image?repo=yagop/node-telegram-bot-api\" />\n  </a>\n</p>\n\n## License\n\n**The MIT License (MIT)**\n\nCopyright © 2019 Yago\n\n[usage]:https://github.com/yagop/node-telegram-bot-api/tree/master/doc/usage.md\n[examples]:https://github.com/yagop/node-telegram-bot-api/tree/master/examples\n[help]:https://github.com/yagop/node-telegram-bot-api/tree/master/doc/help.md\n[tutorials]:https://github.com/yagop/node-telegram-bot-api/tree/master/doc/tutorials.md\n[api-dev]:https://github.com/yagop/node-telegram-bot-api/tree/master/doc/api.md\n[api-release]:https://github.com/yagop/node-telegram-bot-api/tree/release/doc/api.md\n[api-experimental]:https://github.com/yagop/node-telegram-bot-api/tree/experimental/doc/api.md\n[contributing]:https://github.com/yagop/node-telegram-bot-api/tree/master/CONTRIBUTING.md\n[contributors]:https://github.com/yagop/node-telegram-bot-api/graphs/contributors\n[experimental]:https://github.com/yagop/node-telegram-bot-api/tree/master/doc/experimental.md\n[tg-channel]:https://telegram.me/node_telegram_bot_api\n[tg-group]:https://t.me/+UTbprHdcw0JdZdbL\n"
  },
  {
    "path": "doc/api.hbs",
    "content": "# API Reference\n\n**Note:** If you are looking for available [events](usage.md#events) or usage of api, please refer [`usage.md`](usage.md).\n\n{{#class name=\"TelegramBot\"~}}\n{{>header~}}\n{{>body~}}\n{{>member-index~}}\n{{>members~}}\n{{/class}}\n* * *\n\n\n[usage-sending-files-performance]:https://github.com/yagop/node-telegram-bot-api/tree/master/doc/usage.md#sending-files-performance\n[setWebHook-v0.25.0]:https://github.com/yagop/node-telegram-bot-api/tree/4e5a493cadfaad5589a8d79e55d9e0d103000ce4#telegrambotsetwebhookurl-cert\n[getUpdates-v0.25.0]:https://github.com/yagop/node-telegram-bot-api/tree/4e5a493cadfaad5589a8d79e55d9e0d103000ce4#TelegramBot+getUpdates\n[getUserProfilePhotos-v0.25.0]:https://github.com/yagop/node-telegram-bot-api/tree/4e5a493cadfaad5589a8d79e55d9e0d103000ce4#TelegramBot+getUserProfilePhotos\n[answerCallbackQuery-v0.27.1]:https://github.com/yagop/node-telegram-bot-api/blob/v0.27.1/doc/api.md#TelegramBot+answerCallbackQuery\n[answerCallbackQuery-v0.29.0]:https://github.com/yagop/node-telegram-bot-api/blob/v0.29.0/doc/api.md#TelegramBot+answerCallbackQuery\n"
  },
  {
    "path": "doc/api.md",
    "content": "# API Reference\n\n**Note:** If you are looking for available [events](usage.md#events) or usage of api, please refer [`usage.md`](usage.md).\n\n<a name=\"TelegramBot\"></a>\n\n## TelegramBot\nTelegramBot\n\n**Kind**: global class  \n**See**: https://core.telegram.org/bots/api  \n\n* [TelegramBot](#TelegramBot)\n    * [new TelegramBot(token, [options])](#new_TelegramBot_new)\n    * _instance_\n        * [.on(event, listener)](#TelegramBot+on)\n        * [.startPolling([options])](#TelegramBot+startPolling) ⇒ <code>Promise</code>\n        * ~~[.initPolling([options])](#TelegramBot+initPolling) ⇒ <code>Promise</code>~~\n        * [.stopPolling([options])](#TelegramBot+stopPolling) ⇒ <code>Promise</code>\n        * [.getFileLink(fileId, [options])](#TelegramBot+getFileLink) ⇒ <code>Promise</code>\n        * [.getFileStream(fileId, [options])](#TelegramBot+getFileStream) ⇒ <code>stream.Readable</code>\n        * [.downloadFile(fileId, downloadDir, [options])](#TelegramBot+downloadFile) ⇒ <code>Promise</code>\n        * [.onText(regexpRexecuted, callback)](#TelegramBot+onText)\n        * [.removeTextListener(regexp)](#TelegramBot+removeTextListener) ⇒ <code>Object</code>\n        * [.clearTextListeners()](#TelegramBot+clearTextListeners)\n        * [.onReplyToMessage(chatId, messageId, callback)](#TelegramBot+onReplyToMessage) ⇒ <code>Number</code>\n        * [.removeReplyListener(replyListenerId)](#TelegramBot+removeReplyListener) ⇒ <code>Object</code>\n        * [.clearReplyListeners()](#TelegramBot+clearReplyListeners) ⇒ <code>Array</code>\n        * [.isPolling()](#TelegramBot+isPolling) ⇒ <code>Boolean</code>\n        * [.openWebHook()](#TelegramBot+openWebHook) ⇒ <code>Promise</code>\n        * [.closeWebHook()](#TelegramBot+closeWebHook) ⇒ <code>Promise</code>\n        * [.hasOpenWebHook()](#TelegramBot+hasOpenWebHook) ⇒ <code>Boolean</code>\n        * [.processUpdate(update)](#TelegramBot+processUpdate)\n        * [.getUpdates([options])](#TelegramBot+getUpdates) ⇒ <code>Promise</code>\n        * [.setWebHook(url, [options], [fileOptions])](#TelegramBot+setWebHook) ⇒ <code>Promise</code>\n        * [.deleteWebHook([options])](#TelegramBot+deleteWebHook) ⇒ <code>Promise</code>\n        * [.getWebHookInfo([options])](#TelegramBot+getWebHookInfo) ⇒ <code>Promise</code>\n        * [.getMe([options])](#TelegramBot+getMe) ⇒ <code>Promise</code>\n        * [.logOut([options])](#TelegramBot+logOut) ⇒ <code>Promise</code>\n        * [.close([options])](#TelegramBot+close) ⇒ <code>Promise</code>\n        * [.sendMessage(chatId, text, [options])](#TelegramBot+sendMessage) ⇒ <code>Promise</code>\n        * [.forwardMessage(chatId, fromChatId, messageId, [options])](#TelegramBot+forwardMessage) ⇒ <code>Promise</code>\n        * [.forwardMessages(chatId, fromChatId, messageIds, [options])](#TelegramBot+forwardMessages) ⇒ <code>Promise</code>\n        * [.copyMessage(chatId, fromChatId, messageId, [options])](#TelegramBot+copyMessage) ⇒ <code>Promise</code>\n        * [.copyMessages(chatId, fromChatId, messageIds, [options])](#TelegramBot+copyMessages) ⇒ <code>Promise</code>\n        * [.sendPhoto(chatId, photo, [options], [fileOptions])](#TelegramBot+sendPhoto) ⇒ <code>Promise</code>\n        * [.sendAudio(chatId, audio, [options], [fileOptions])](#TelegramBot+sendAudio) ⇒ <code>Promise</code>\n        * [.sendDocument(chatId, doc, [options], [fileOptions])](#TelegramBot+sendDocument) ⇒ <code>Promise</code>\n        * [.sendVideo(chatId, video, [options], [fileOptions])](#TelegramBot+sendVideo) ⇒ <code>Promise</code>\n        * [.sendAnimation(chatId, animation, [options], [fileOptions])](#TelegramBot+sendAnimation) ⇒ <code>Promise</code>\n        * [.sendVoice(chatId, voice, [options], [fileOptions])](#TelegramBot+sendVoice) ⇒ <code>Promise</code>\n        * [.sendVideoNote(chatId, videoNote, [options], [fileOptions])](#TelegramBot+sendVideoNote) ⇒ <code>Promise</code>\n        * [.sendPaidMedia(chatId, starCount, media, [options])](#TelegramBot+sendPaidMedia) ⇒ <code>Promise</code>\n        * [.sendMediaGroup(chatId, media, [options])](#TelegramBot+sendMediaGroup) ⇒ <code>Promise</code>\n        * [.sendLocation(chatId, latitude, longitude, [options])](#TelegramBot+sendLocation) ⇒ <code>Promise</code>\n        * [.editMessageLiveLocation(latitude, longitude, [options])](#TelegramBot+editMessageLiveLocation) ⇒ <code>Promise</code>\n        * [.stopMessageLiveLocation([options])](#TelegramBot+stopMessageLiveLocation) ⇒ <code>Promise</code>\n        * [.sendVenue(chatId, latitude, longitude, title, address, [options])](#TelegramBot+sendVenue) ⇒ <code>Promise</code>\n        * [.sendContact(chatId, phoneNumber, firstName, [options])](#TelegramBot+sendContact) ⇒ <code>Promise</code>\n        * [.sendPoll(chatId, question, pollOptions, [options])](#TelegramBot+sendPoll) ⇒ <code>Promise</code>\n        * [.sendChecklist(businessConnectionId, chatId, checklist, [options])](#TelegramBot+sendChecklist) ⇒ <code>Promise</code>\n        * [.sendDice(chatId, [options])](#TelegramBot+sendDice) ⇒ <code>Promise</code>\n        * [.sendMessageDraft(chatId, draftId, text, [options])](#TelegramBot+sendMessageDraft) ⇒ <code>Promise</code>\n        * [.sendChatAction(chatId, action, [options])](#TelegramBot+sendChatAction) ⇒ <code>Promise</code>\n        * [.setMessageReaction(chatId, messageId, [options])](#TelegramBot+setMessageReaction) ⇒ <code>Promise.&lt;Boolean&gt;</code>\n        * [.getUserProfilePhotos(userId, [options])](#TelegramBot+getUserProfilePhotos) ⇒ <code>Promise</code>\n        * [.getUserProfileAudios(userId, [options])](#TelegramBot+getUserProfileAudios) ⇒ <code>Promise</code>\n        * [.setUserEmojiStatus(userId, [options])](#TelegramBot+setUserEmojiStatus) ⇒ <code>Promise</code>\n        * [.getFile(fileId, [options])](#TelegramBot+getFile) ⇒ <code>Promise</code>\n        * [.banChatMember(chatId, userId, [options])](#TelegramBot+banChatMember) ⇒ <code>Promise</code>\n        * [.unbanChatMember(chatId, userId, [options])](#TelegramBot+unbanChatMember) ⇒ <code>Promise</code>\n        * [.restrictChatMember(chatId, userId, [options])](#TelegramBot+restrictChatMember) ⇒ <code>Promise</code>\n        * [.promoteChatMember(chatId, userId, [options])](#TelegramBot+promoteChatMember) ⇒ <code>Promise</code>\n        * [.setChatAdministratorCustomTitle(chatId, userId, customTitle, [options])](#TelegramBot+setChatAdministratorCustomTitle) ⇒ <code>Promise</code>\n        * [.setChatMemberTag(chatId, userId, [options])](#TelegramBot+setChatMemberTag) ⇒ <code>Promise</code>\n        * [.banChatSenderChat(chatId, senderChatId, [options])](#TelegramBot+banChatSenderChat) ⇒ <code>Promise</code>\n        * [.unbanChatSenderChat(chatId, senderChatId, [options])](#TelegramBot+unbanChatSenderChat) ⇒ <code>Promise</code>\n        * [.setChatPermissions(chatId, chatPermissions, [options])](#TelegramBot+setChatPermissions) ⇒ <code>Promise</code>\n        * [.exportChatInviteLink(chatId, [options])](#TelegramBot+exportChatInviteLink) ⇒ <code>Promise</code>\n        * [.createChatInviteLink(chatId, [options])](#TelegramBot+createChatInviteLink) ⇒ <code>Object</code>\n        * [.editChatInviteLink(chatId, inviteLink, [options])](#TelegramBot+editChatInviteLink) ⇒ <code>Promise</code>\n        * [.createChatSubscriptionInviteLink(chatId, subscriptionPeriod, subscriptionPrice, [options])](#TelegramBot+createChatSubscriptionInviteLink) ⇒ <code>Promise</code>\n        * [.editChatSubscriptionInviteLink(chatId, inviteLink, [options])](#TelegramBot+editChatSubscriptionInviteLink) ⇒ <code>Promise</code>\n        * [.revokeChatInviteLink(chatId, inviteLink, [options])](#TelegramBot+revokeChatInviteLink) ⇒ <code>Promise</code>\n        * [.approveChatJoinRequest(chatId, userId, [options])](#TelegramBot+approveChatJoinRequest) ⇒ <code>Promise</code>\n        * [.declineChatJoinRequest(chatId, userId, [options])](#TelegramBot+declineChatJoinRequest) ⇒ <code>Promise</code>\n        * [.setChatPhoto(chatId, photo, [options], [fileOptions])](#TelegramBot+setChatPhoto) ⇒ <code>Promise</code>\n        * [.deleteChatPhoto(chatId, [options])](#TelegramBot+deleteChatPhoto) ⇒ <code>Promise</code>\n        * [.setChatTitle(chatId, title, [options])](#TelegramBot+setChatTitle) ⇒ <code>Promise</code>\n        * [.setChatDescription(chatId, description, [options])](#TelegramBot+setChatDescription) ⇒ <code>Promise</code>\n        * [.pinChatMessage(chatId, messageId, [options])](#TelegramBot+pinChatMessage) ⇒ <code>Promise</code>\n        * [.unpinChatMessage(chatId, [options])](#TelegramBot+unpinChatMessage) ⇒ <code>Promise</code>\n        * [.unpinAllChatMessages(chatId, [options])](#TelegramBot+unpinAllChatMessages) ⇒ <code>Promise</code>\n        * [.leaveChat(chatId, [options])](#TelegramBot+leaveChat) ⇒ <code>Promise</code>\n        * [.getChat(chatId, [options])](#TelegramBot+getChat) ⇒ <code>Promise</code>\n        * [.getChatAdministrators(chatId, [options])](#TelegramBot+getChatAdministrators) ⇒ <code>Promise</code>\n        * [.getChatMemberCount(chatId, [options])](#TelegramBot+getChatMemberCount) ⇒ <code>Promise</code>\n        * [.getChatMember(chatId, userId, [options])](#TelegramBot+getChatMember) ⇒ <code>Promise</code>\n        * [.setChatStickerSet(chatId, stickerSetName, [options])](#TelegramBot+setChatStickerSet) ⇒ <code>Promise</code>\n        * [.deleteChatStickerSet(chatId, [options])](#TelegramBot+deleteChatStickerSet) ⇒ <code>Promise</code>\n        * [.getForumTopicIconStickers(chatId, [options])](#TelegramBot+getForumTopicIconStickers) ⇒ <code>Promise</code>\n        * [.createForumTopic(chatId, name, [options])](#TelegramBot+createForumTopic)\n        * [.editForumTopic(chatId, messageThreadId, [options])](#TelegramBot+editForumTopic) ⇒ <code>Promise</code>\n        * [.closeForumTopic(chatId, messageThreadId, [options])](#TelegramBot+closeForumTopic) ⇒ <code>Promise</code>\n        * [.reopenForumTopic(chatId, messageThreadId, [options])](#TelegramBot+reopenForumTopic) ⇒ <code>Promise</code>\n        * [.deleteForumTopic(chatId, messageThreadId, [options])](#TelegramBot+deleteForumTopic) ⇒ <code>Promise</code>\n        * [.unpinAllForumTopicMessages(chatId, messageThreadId, [options])](#TelegramBot+unpinAllForumTopicMessages) ⇒ <code>Promise</code>\n        * [.editGeneralForumTopic(chatId, name, [options])](#TelegramBot+editGeneralForumTopic) ⇒ <code>Promise</code>\n        * [.closeGeneralForumTopic(chatId, [options])](#TelegramBot+closeGeneralForumTopic) ⇒ <code>Promise</code>\n        * [.reopenGeneralForumTopic(chatId, [options])](#TelegramBot+reopenGeneralForumTopic) ⇒ <code>Promise</code>\n        * [.hideGeneralForumTopic(chatId, [options])](#TelegramBot+hideGeneralForumTopic) ⇒ <code>Promise</code>\n        * [.unhideGeneralForumTopic(chatId, [options])](#TelegramBot+unhideGeneralForumTopic) ⇒ <code>Promise</code>\n        * [.unpinAllGeneralForumTopicMessages(chatId, [options])](#TelegramBot+unpinAllGeneralForumTopicMessages) ⇒ <code>Promise</code>\n        * [.answerCallbackQuery(callbackQueryId, [options])](#TelegramBot+answerCallbackQuery) ⇒ <code>Promise</code>\n        * [.savePreparedInlineMessage(userId, result, [options])](#TelegramBot+savePreparedInlineMessage) ⇒ <code>Promise</code>\n        * [.getUserChatBoosts(chatId, userId, [options])](#TelegramBot+getUserChatBoosts) ⇒ <code>Promise</code>\n        * [.getBusinessConnection(businessConnectionId, [options])](#TelegramBot+getBusinessConnection) ⇒ <code>Promise</code>\n        * [.setMyCommands(commands, [options])](#TelegramBot+setMyCommands) ⇒ <code>Promise</code>\n        * [.deleteMyCommands([options])](#TelegramBot+deleteMyCommands) ⇒ <code>Promise</code>\n        * [.getMyCommands([options])](#TelegramBot+getMyCommands) ⇒ <code>Promise</code>\n        * [.setMyName([options])](#TelegramBot+setMyName) ⇒ <code>Promise</code>\n        * [.getMyName([options])](#TelegramBot+getMyName) ⇒ <code>Promise</code>\n        * [.setMyDescription([options])](#TelegramBot+setMyDescription) ⇒ <code>Promise</code>\n        * [.getMyDescription([options])](#TelegramBot+getMyDescription) ⇒ <code>Promise</code>\n        * [.setMyShortDescription([options])](#TelegramBot+setMyShortDescription) ⇒ <code>Promise</code>\n        * [.getMyShortDescription([options])](#TelegramBot+getMyShortDescription) ⇒ <code>Promise</code>\n        * [.setMyProfilePhoto(photo, [options])](#TelegramBot+setMyProfilePhoto) ⇒ <code>Promise</code>\n        * [.removeMyProfilePhoto([options])](#TelegramBot+removeMyProfilePhoto) ⇒ <code>Promise</code>\n        * [.setChatMenuButton([options])](#TelegramBot+setChatMenuButton) ⇒ <code>Promise</code>\n        * [.getChatMenuButton([options])](#TelegramBot+getChatMenuButton) ⇒ <code>Promise</code>\n        * [.setMyDefaultAdministratorRights([options])](#TelegramBot+setMyDefaultAdministratorRights) ⇒ <code>Promise</code>\n        * [.getMyDefaultAdministratorRights([options])](#TelegramBot+getMyDefaultAdministratorRights) ⇒ <code>Promise</code>\n        * [.editMessageText(text, [options])](#TelegramBot+editMessageText) ⇒ <code>Promise</code>\n        * [.editMessageCaption(caption, [options])](#TelegramBot+editMessageCaption) ⇒ <code>Promise</code>\n        * [.editMessageMedia(media, [options])](#TelegramBot+editMessageMedia) ⇒ <code>Promise</code>\n        * [.editMessageChecklist(businessConnectionId, chatId, messageId, checklist, [options])](#TelegramBot+editMessageChecklist) ⇒ <code>Promise</code>\n        * [.editMessageReplyMarkup(replyMarkup, [options])](#TelegramBot+editMessageReplyMarkup) ⇒ <code>Promise</code>\n        * [.stopPoll(chatId, pollId, [options])](#TelegramBot+stopPoll) ⇒ <code>Promise</code>\n        * [.approveSuggestedPost(chatId, messageId, [options])](#TelegramBot+approveSuggestedPost) ⇒ <code>Promise</code>\n        * [.declineSuggestedPost(chatId, messageId, [options])](#TelegramBot+declineSuggestedPost) ⇒ <code>Promise</code>\n        * [.sendSticker(chatId, sticker, [options], [fileOptions])](#TelegramBot+sendSticker) ⇒ <code>Promise</code>\n        * [.getStickerSet(name, [options])](#TelegramBot+getStickerSet) ⇒ <code>Promise</code>\n        * [.getCustomEmojiStickers(custom_emoji_ids, [options])](#TelegramBot+getCustomEmojiStickers) ⇒ <code>Promise</code>\n        * [.uploadStickerFile(userId, sticker, stickerFormat, [options], [fileOptions])](#TelegramBot+uploadStickerFile) ⇒ <code>Promise</code>\n        * [.createNewStickerSet(userId, name, title, pngSticker, emojis, [options], [fileOptions])](#TelegramBot+createNewStickerSet) ⇒ <code>Promise</code>\n        * [.addStickerToSet(userId, name, sticker, emojis, stickerType, [options], [fileOptions])](#TelegramBot+addStickerToSet) ⇒ <code>Promise</code>\n        * [.setStickerPositionInSet(sticker, position, [options])](#TelegramBot+setStickerPositionInSet) ⇒ <code>Promise</code>\n        * [.deleteStickerFromSet(sticker, [options])](#TelegramBot+deleteStickerFromSet) ⇒ <code>Promise</code>\n        * [.replaceStickerInSet(userId, name, sticker, [options])](#TelegramBot+replaceStickerInSet) ⇒ <code>Promise</code>\n        * [.setStickerEmojiList(sticker, emojiList, [options])](#TelegramBot+setStickerEmojiList) ⇒ <code>Promise</code>\n        * [.setStickerKeywords(sticker, [options])](#TelegramBot+setStickerKeywords) ⇒ <code>Promise</code>\n        * [.setStickerMaskPosition(sticker, [options])](#TelegramBot+setStickerMaskPosition) ⇒ <code>Promise</code>\n        * [.setStickerSetTitle(name, title, [options])](#TelegramBot+setStickerSetTitle) ⇒ <code>Promise</code>\n        * [.setStickerSetThumbnail(userId, name, thumbnail, [options], [fileOptions])](#TelegramBot+setStickerSetThumbnail) ⇒ <code>Promise</code>\n        * [.setCustomEmojiStickerSetThumbnail(name, [options])](#TelegramBot+setCustomEmojiStickerSetThumbnail) ⇒ <code>Promise</code>\n        * [.deleteStickerSet(name, [options])](#TelegramBot+deleteStickerSet) ⇒ <code>Promise</code>\n        * [.answerInlineQuery(inlineQueryId, results, [options])](#TelegramBot+answerInlineQuery) ⇒ <code>Promise</code>\n        * [.answerWebAppQuery(webAppQueryId, result, [options])](#TelegramBot+answerWebAppQuery) ⇒ <code>Promise</code>\n        * [.sendInvoice(chatId, title, description, payload, providerToken, currency, prices, [options])](#TelegramBot+sendInvoice) ⇒ <code>Promise</code>\n        * [.createInvoiceLink(title, description, payload, providerToken, currency, prices, [options])](#TelegramBot+createInvoiceLink) ⇒ <code>Promise</code>\n        * [.answerShippingQuery(shippingQueryId, ok, [options])](#TelegramBot+answerShippingQuery) ⇒ <code>Promise</code>\n        * [.answerPreCheckoutQuery(preCheckoutQueryId, ok, [options])](#TelegramBot+answerPreCheckoutQuery) ⇒ <code>Promise</code>\n        * [.getMyStarBalance([options])](#TelegramBot+getMyStarBalance) ⇒ <code>Promise</code>\n        * [.getStarTransactions([options])](#TelegramBot+getStarTransactions) ⇒ <code>Promise</code>\n        * [.refundStarPayment(userId, telegramPaymentChargeId, [options])](#TelegramBot+refundStarPayment) ⇒ <code>Promise</code>\n        * [.editUserStarSubscription(userId, telegramPaymentChargeId, isCanceled, [options])](#TelegramBot+editUserStarSubscription) ⇒ <code>Promise</code>\n        * [.sendGame(chatId, gameShortName, [options])](#TelegramBot+sendGame) ⇒ <code>Promise</code>\n        * [.setGameScore(userId, score, [options])](#TelegramBot+setGameScore) ⇒ <code>Promise</code>\n        * [.getGameHighScores(userId, [options])](#TelegramBot+getGameHighScores) ⇒ <code>Promise</code>\n        * [.deleteMessage(chatId, messageId, [options])](#TelegramBot+deleteMessage) ⇒ <code>Promise</code>\n        * [.deleteMessages(chatId, messageIds, [options])](#TelegramBot+deleteMessages) ⇒ <code>Promise.&lt;Boolean&gt;</code>\n        * [.getAvailableGifts([options])](#TelegramBot+getAvailableGifts) ⇒ <code>Promise</code>\n        * [.sendGift(giftId, [options])](#TelegramBot+sendGift) ⇒ <code>Promise</code>\n        * [.giftPremiumSubscription(userId, monthCount, starCount, [options])](#TelegramBot+giftPremiumSubscription) ⇒ <code>Promise</code>\n        * [.verifyUser(userId, [options])](#TelegramBot+verifyUser) ⇒ <code>Promise</code>\n        * [.verifyChat(chatId, [options])](#TelegramBot+verifyChat) ⇒ <code>Promise</code>\n        * [.removeUserVerification(userId, [options])](#TelegramBot+removeUserVerification) ⇒ <code>Promise</code>\n        * [.removeChatVerification(chatId, [options])](#TelegramBot+removeChatVerification) ⇒ <code>Promise</code>\n        * [.readBusinessMessage(businessConnectionId, chatId, messageId, [options])](#TelegramBot+readBusinessMessage) ⇒ <code>Promise</code>\n        * [.deleteBusinessMessages(businessConnectionId, messageIds, [options])](#TelegramBot+deleteBusinessMessages) ⇒ <code>Promise</code>\n        * [.setBusinessAccountName(businessConnectionId, firstName, [options])](#TelegramBot+setBusinessAccountName) ⇒ <code>Promise</code>\n        * [.setBusinessAccountUsername(businessConnectionId, [options])](#TelegramBot+setBusinessAccountUsername) ⇒ <code>Promise</code>\n        * [.setBusinessAccountBio(businessConnectionId, [options])](#TelegramBot+setBusinessAccountBio) ⇒ <code>Promise</code>\n        * [.setBusinessAccountProfilePhoto(businessConnectionId, photo, [options])](#TelegramBot+setBusinessAccountProfilePhoto) ⇒ <code>Promise</code>\n        * [.removeBusinessAccountProfilePhoto(businessConnectionId, [options])](#TelegramBot+removeBusinessAccountProfilePhoto) ⇒ <code>Promise</code>\n        * [.setBusinessAccountGiftSettings(businessConnectionId, showGiftButton, acceptedGiftTypes, [options])](#TelegramBot+setBusinessAccountGiftSettings) ⇒ <code>Promise</code>\n        * [.getBusinessAccountStarBalance(businessConnectionId, [options])](#TelegramBot+getBusinessAccountStarBalance) ⇒ <code>Promise</code>\n        * [.transferBusinessAccountStars(businessConnectionId, starCount, [options])](#TelegramBot+transferBusinessAccountStars) ⇒ <code>Promise</code>\n        * [.getBusinessAccountGifts(businessConnectionId, [options])](#TelegramBot+getBusinessAccountGifts) ⇒ <code>Promise</code>\n        * [.getUserGifts(userId, [options])](#TelegramBot+getUserGifts) ⇒ <code>Promise</code>\n        * [.getChatGifts(chatId, [options])](#TelegramBot+getChatGifts) ⇒ <code>Promise</code>\n        * [.convertGiftToStars(businessConnectionId, ownedGiftId, [options])](#TelegramBot+convertGiftToStars) ⇒ <code>Promise</code>\n        * [.upgradeGift(businessConnectionId, ownedGiftId, [options])](#TelegramBot+upgradeGift) ⇒ <code>Promise</code>\n        * [.transferGift(businessConnectionId, ownedGiftId, newOwnerChatId, [options])](#TelegramBot+transferGift) ⇒ <code>Promise</code>\n        * [.postStory(businessConnectionId, content, activePeriod, [options])](#TelegramBot+postStory) ⇒ <code>Promise</code>\n        * [.repostStory(businessConnectionId, fromChatId, fromStoryId, activePeriod, [options])](#TelegramBot+repostStory) ⇒ <code>Promise</code>\n        * [.editStory(businessConnectionId, storyId, content, [options])](#TelegramBot+editStory) ⇒ <code>Promise</code>\n        * [.deleteStory(businessConnectionId, storyId, [options])](#TelegramBot+deleteStory) ⇒ <code>Promise</code>\n    * _static_\n        * [.errors](#TelegramBot.errors) : <code>Object</code>\n        * [.messageTypes](#TelegramBot.messageTypes) : <code>Array.&lt;String&gt;</code>\n\n<a name=\"new_TelegramBot_new\"></a>\n\n### new TelegramBot(token, [options])\nBoth request method to obtain messages are implemented. To use standard polling, set `polling: true`\non `options`. Notice that [webHook](https://core.telegram.org/bots/api#setwebhook) will need a SSL certificate.\nEmits `message` when a message arrives.\n\n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| token | <code>String</code> |  | Bot Token |\n| [options] | <code>Object</code> |  |  |\n| [options.polling] | <code>Boolean</code> \\| <code>Object</code> | <code>false</code> | Set true to enable polling or set options.  If a WebHook has been set, it will be deleted automatically. |\n| [options.polling.timeout] | <code>String</code> \\| <code>Number</code> | <code>10</code> | *Deprecated. Use `options.polling.params` instead*.  Timeout in seconds for long polling. |\n| [options.testEnvironment] | <code>Boolean</code> | <code>false</code> | Set true to  work with test enviroment. When working with the test environment, you may use HTTP links without TLS to test your Web App. |\n| [options.polling.interval] | <code>String</code> \\| <code>Number</code> | <code>300</code> | Interval between requests in miliseconds |\n| [options.polling.autoStart] | <code>Boolean</code> | <code>true</code> | Start polling immediately |\n| [options.polling.params] | <code>Object</code> |  | Parameters to be used in polling API requests.  See https://core.telegram.org/bots/api#getupdates for more information. |\n| [options.polling.params.timeout] | <code>Number</code> | <code>10</code> | Timeout in seconds for long polling. |\n| [options.polling.params.allowed_updates] | <code>Array.&lt;String&gt;</code> \\| <code>String</code> |  | A JSON-serialized list of the update types you want your bot to receive.  For example, specify [\"message\", \"edited_channel_post\", \"callback_query\"] to only receive updates of these types. |\n| [options.webHook] | <code>Boolean</code> \\| <code>Object</code> | <code>false</code> | Set true to enable WebHook or set options |\n| [options.webHook.host] | <code>String</code> | <code>&quot;0.0.0.0&quot;</code> | Host to bind to |\n| [options.webHook.port] | <code>Number</code> | <code>8443</code> | Port to bind to |\n| [options.webHook.key] | <code>String</code> |  | Path to file with PEM private key for webHook server.  The file is read **synchronously**! |\n| [options.webHook.cert] | <code>String</code> |  | Path to file with PEM certificate (public) for webHook server.  The file is read **synchronously**! |\n| [options.webHook.pfx] | <code>String</code> |  | Path to file with PFX private key and certificate chain for webHook server.  The file is read **synchronously**! |\n| [options.webHook.autoOpen] | <code>Boolean</code> | <code>true</code> | Open webHook immediately |\n| [options.webHook.https] | <code>Object</code> |  | Options to be passed to `https.createServer()`.  Note that `options.webHook.key`, `options.webHook.cert` and `options.webHook.pfx`, if provided, will be  used to override `key`, `cert` and `pfx` in this object, respectively.  See https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener for more information. |\n| [options.webHook.healthEndpoint] | <code>String</code> | <code>&quot;/healthz&quot;</code> | An endpoint for health checks that always responds with 200 OK |\n| [options.onlyFirstMatch] | <code>Boolean</code> | <code>false</code> | Set to true to stop after first match. Otherwise, all regexps are executed |\n| [options.request] | <code>Object</code> |  | Options which will be added for all requests to telegram api.  See https://github.com/request/request#requestoptions-callback for more information. |\n| [options.baseApiUrl] | <code>String</code> | <code>&quot;https://api.telegram.org&quot;</code> | API Base URl; useful for proxying and testing |\n| [options.filepath] | <code>Boolean</code> | <code>true</code> | Allow passing file-paths as arguments when sending files,  such as photos using `TelegramBot#sendPhoto()`. See [usage information][usage-sending-files-performance]  for more information on this option and its consequences. |\n| [options.badRejection] | <code>Boolean</code> | <code>false</code> | Set to `true`  **if and only if** the Node.js version you're using terminates the  process on unhandled rejections. This option is only for  *forward-compatibility purposes*. |\n\n<a name=\"TelegramBot+on\"></a>\n\n### telegramBot.on(event, listener)\nAdd listener for the specified [event](https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#events).\nThis is the usual `emitter.on()` method.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**See**\n\n- [Available events](https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#events)\n- https://nodejs.org/api/events.html#events_emitter_on_eventname_listener\n\n\n| Param | Type |\n| --- | --- |\n| event | <code>String</code> | \n| listener | <code>function</code> | \n\n<a name=\"TelegramBot+startPolling\"></a>\n\n### telegramBot.startPolling([options]) ⇒ <code>Promise</code>\nStart polling.\nRejects returned promise if a WebHook is being used by this instance.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| [options] | <code>Object</code> |  |  |\n| [options.restart] | <code>Boolean</code> | <code>true</code> | Consecutive calls to this method causes polling to be restarted |\n\n<a name=\"TelegramBot+initPolling\"></a>\n\n### ~~telegramBot.initPolling([options]) ⇒ <code>Promise</code>~~\n***Deprecated***\n\nAlias of `TelegramBot#startPolling()`. This is **deprecated**.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n\n| Param | Type |\n| --- | --- |\n| [options] | <code>Object</code> | \n\n<a name=\"TelegramBot+stopPolling\"></a>\n\n### telegramBot.stopPolling([options]) ⇒ <code>Promise</code>\nStops polling after the last polling request resolves.\nMultiple invocations do nothing if polling is already stopped.\nReturning the promise of the last polling request is **deprecated**.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Options |\n| [options.cancel] | <code>Boolean</code> | Cancel current request |\n| [options.reason] | <code>String</code> | Reason for stopping polling |\n\n<a name=\"TelegramBot+getFileLink\"></a>\n\n### telegramBot.getFileLink(fileId, [options]) ⇒ <code>Promise</code>\nGet link for file.\nUse this method to get link for file for subsequent use.\nAttention: link will be valid for 1 hour.\n\nThis method is a sugar extension of the (getFile)[#getfilefileid] method,\nwhich returns just path to file on remote server (you will have to manually build full uri after that).\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Promise which will have  *fileURI* in resolve callback  \n**See**: https://core.telegram.org/bots/api#getfile  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| fileId | <code>String</code> | File identifier to get info about |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getFileStream\"></a>\n\n### telegramBot.getFileStream(fileId, [options]) ⇒ <code>stream.Readable</code>\nReturn a readable stream for file.\n\n`fileStream.path` is the specified file ID i.e. `fileId`.\n`fileStream` emits event `info` passing a single argument i.e.\n`info` with the interface `{ uri }` where `uri` is the URI of the\nfile on Telegram servers.\n\nThis method is a sugar extension of the [getFileLink](#TelegramBot+getFileLink) method,\nwhich returns the full URI to the file on remote server.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>stream.Readable</code> - fileStream  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| fileId | <code>String</code> | File identifier to get info about |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+downloadFile\"></a>\n\n### telegramBot.downloadFile(fileId, downloadDir, [options]) ⇒ <code>Promise</code>\nDownloads file in the specified folder.\n\nThis method is a sugar extension of the [getFileStream](#TelegramBot+getFileStream) method,\nwhich returns a readable file stream.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Promise, which will have *filePath* of downloaded file in resolve callback  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| fileId | <code>String</code> | File identifier to get info about |\n| downloadDir | <code>String</code> | Absolute path to the folder in which file will be saved |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+onText\"></a>\n\n### telegramBot.onText(regexpRexecuted, callback)\nRegister a RegExp to test against an incomming text message.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| regexpRexecuted | <code>RegExp</code> | with `exec`. |\n| callback | <code>function</code> | Callback will be called with 2 parameters, the `msg` and the result of executing `regexp.exec` on message text. |\n\n<a name=\"TelegramBot+removeTextListener\"></a>\n\n### telegramBot.removeTextListener(regexp) ⇒ <code>Object</code>\nRemove a listener registered with `onText()`.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Object</code> - deletedListener The removed reply listener if\n  found. This object has `regexp` and `callback`\n  properties. If not found, returns `null`.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| regexp | <code>RegExp</code> | RegExp used previously in `onText()` |\n\n<a name=\"TelegramBot+clearTextListeners\"></a>\n\n### telegramBot.clearTextListeners()\nRemove all listeners registered with `onText()`.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n<a name=\"TelegramBot+onReplyToMessage\"></a>\n\n### telegramBot.onReplyToMessage(chatId, messageId, callback) ⇒ <code>Number</code>\nRegister a reply to wait for a message response.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Number</code> - id The ID of the inserted reply listener.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | The chat id where the message cames from. |\n| messageId | <code>Number</code> \\| <code>String</code> | The message id to be replied. |\n| callback | <code>function</code> | Callback will be called with the reply  message. |\n\n<a name=\"TelegramBot+removeReplyListener\"></a>\n\n### telegramBot.removeReplyListener(replyListenerId) ⇒ <code>Object</code>\nRemoves a reply that has been prev. registered for a message response.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Object</code> - deletedListener The removed reply listener if\n  found. This object has `id`, `chatId`, `messageId` and `callback`\n  properties. If not found, returns `null`.  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| replyListenerId | <code>Number</code> | The ID of the reply listener. |\n\n<a name=\"TelegramBot+clearReplyListeners\"></a>\n\n### telegramBot.clearReplyListeners() ⇒ <code>Array</code>\nRemoves all replies that have been prev. registered for a message response.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Array</code> - deletedListeners An array of removed listeners.  \n<a name=\"TelegramBot+isPolling\"></a>\n\n### telegramBot.isPolling() ⇒ <code>Boolean</code>\nReturn true if polling. Otherwise, false.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n<a name=\"TelegramBot+openWebHook\"></a>\n\n### telegramBot.openWebHook() ⇒ <code>Promise</code>\nOpen webhook.\nMultiple invocations do nothing if webhook is already open.\nRejects returned promise if Polling is being used by this instance.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n<a name=\"TelegramBot+closeWebHook\"></a>\n\n### telegramBot.closeWebHook() ⇒ <code>Promise</code>\nClose webhook after closing all current connections.\nMultiple invocations do nothing if webhook is already closed.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Promise  \n<a name=\"TelegramBot+hasOpenWebHook\"></a>\n\n### telegramBot.hasOpenWebHook() ⇒ <code>Boolean</code>\nReturn true if using webhook and it is open i.e. accepts connections.\nOtherwise, false.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n<a name=\"TelegramBot+processUpdate\"></a>\n\n### telegramBot.processUpdate(update)\nProcess an update; emitting the proper events and executing regexp\ncallbacks. This method is useful should you be using a different\nway to fetch updates, other than those provided by TelegramBot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**See**: https://core.telegram.org/bots/api#update  \n\n| Param | Type |\n| --- | --- |\n| update | <code>Object</code> | \n\n<a name=\"TelegramBot+getUpdates\"></a>\n\n### telegramBot.getUpdates([options]) ⇒ <code>Promise</code>\nUse this method to receive incoming updates using long polling.\nThis method has an [older, compatible signature][getUpdates-v0.25.0]\nthat is being deprecated.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**See**: https://core.telegram.org/bots/api#getupdates  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setWebHook\"></a>\n\n### telegramBot.setWebHook(url, [options], [fileOptions]) ⇒ <code>Promise</code>\nSpecify an url to receive incoming updates via an outgoing webHook.\nThis method has an [older, compatible signature][setWebHook-v0.25.0]\nthat is being deprecated.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**See**\n\n- https://core.telegram.org/bots/api#setwebhook\n- https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| url | <code>String</code> | URL where Telegram will make HTTP Post. Leave empty to delete webHook. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [options.certificate] | <code>String</code> \\| <code>stream.Stream</code> | PEM certificate key (public). |\n| [options.secret_token] | <code>String</code> | Optional secret token to be sent in a header `X-Telegram-Bot-Api-Secret-Token` in every webhook request. |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+deleteWebHook\"></a>\n\n### telegramBot.deleteWebHook([options]) ⇒ <code>Promise</code>\nUse this method to remove webhook integration if you decide to\nswitch back to getUpdates. Returns True on success.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**See**: https://core.telegram.org/bots/api#deletewebhook  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getWebHookInfo\"></a>\n\n### telegramBot.getWebHookInfo([options]) ⇒ <code>Promise</code>\nUse this method to get current webhook status.\nOn success, returns a [WebhookInfo](https://core.telegram.org/bots/api#webhookinfo) object.\nIf the bot is using getUpdates, will return an object with the\nurl field empty.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**See**: https://core.telegram.org/bots/api#getwebhookinfo  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getMe\"></a>\n\n### telegramBot.getMe([options]) ⇒ <code>Promise</code>\nA simple method for testing your bot's authentication token. Requires no parameters.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - basic information about the bot in form of a [User](https://core.telegram.org/bots/api#user) object.  \n**See**: https://core.telegram.org/bots/api#getme  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+logOut\"></a>\n\n### telegramBot.logOut([options]) ⇒ <code>Promise</code>\nThis method log out your bot from the cloud Bot API server before launching the bot locally.\nYou must log out the bot before running it locally, otherwise there is no guarantee that the bot will receive updates.\nAfter a successful call, you will not be able to log in again using the same token for 10 minutes.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#logout  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+close\"></a>\n\n### telegramBot.close([options]) ⇒ <code>Promise</code>\nThis method close the bot instance before moving it from one local server to another.\nThis method will return error 429 in the first 10 minutes after the bot is launched.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#close  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendMessage\"></a>\n\n### telegramBot.sendMessage(chatId, text, [options]) ⇒ <code>Promise</code>\nSend text message.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**: https://core.telegram.org/bots/api#sendmessage  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| text | <code>String</code> | Text of the message to be sent |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+forwardMessage\"></a>\n\n### telegramBot.forwardMessage(chatId, fromChatId, messageId, [options]) ⇒ <code>Promise</code>\nForward messages of any kind.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**See**: https://core.telegram.org/bots/api#forwardmessage  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) or username of the target channel (in the format `@channelusername`) |\n| fromChatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the chat where the original message was sent (or channel username in the format `@channelusername`) |\n| messageId | <code>Number</code> \\| <code>String</code> | Unique message identifier in the chat specified in fromChatId |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+forwardMessages\"></a>\n\n### telegramBot.forwardMessages(chatId, fromChatId, messageIds, [options]) ⇒ <code>Promise</code>\nUse this method to forward multiple messages of any kind.\nIf some of the specified messages can't be found or forwarded, they are skipped.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - An array of MessageId of the sent messages on success  \n**See**: https://core.telegram.org/bots/api#forwardmessages  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) or username of the target channel (in the format `@channelusername`) |\n| fromChatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the chat where the original message was sent (or channel username in the format `@channelusername`) |\n| messageIds | <code>Array.&lt;(Number\\|String)&gt;</code> | Identifiers of 1-100 messages in the chat from_chat_id to forward. The identifiers must be specified in a strictly increasing order. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+copyMessage\"></a>\n\n### telegramBot.copyMessage(chatId, fromChatId, messageId, [options]) ⇒ <code>Promise</code>\nCopy messages of any kind. **Service messages and invoice messages can't be copied.**\nThe method is analogous to the method forwardMessages, but the copied message doesn't\nhave a link to the original message.\nReturns the MessageId of the sent message on success.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - The [MessageId](https://core.telegram.org/bots/api#messageid) of the sent message on success  \n**See**: https://core.telegram.org/bots/api#copymessage  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| fromChatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the chat where the original message was sent |\n| messageId | <code>Number</code> \\| <code>String</code> | Unique message identifier |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+copyMessages\"></a>\n\n### telegramBot.copyMessages(chatId, fromChatId, messageIds, [options]) ⇒ <code>Promise</code>\nUse this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped.\nService messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied.\nReturns the MessageId of the sent message on success.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - An array of MessageId of the sent messages  \n**See**: https://core.telegram.org/bots/api#copymessages  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat |\n| fromChatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the chat where the original message was sent |\n| messageIds | <code>Array</code> | Identifiers of 1-100 messages in the chat from_chat_id to copy. The identifiers must be specified in a strictly increasing order. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendPhoto\"></a>\n\n### telegramBot.sendPhoto(chatId, photo, [options], [fileOptions]) ⇒ <code>Promise</code>\nSend photo\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**\n\n- https://core.telegram.org/bots/api#sendphoto\n- https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| photo | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | A file path or a Stream. Can also be a `file_id` previously uploaded |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+sendAudio\"></a>\n\n### telegramBot.sendAudio(chatId, audio, [options], [fileOptions]) ⇒ <code>Promise</code>\nSend audio\n\n**Your audio must be in the .MP3 or .M4A format.**\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**\n\n- https://core.telegram.org/bots/api#sendaudio\n- https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| audio | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | A file path, Stream or Buffer. Can also be a `file_id` previously uploaded. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+sendDocument\"></a>\n\n### telegramBot.sendDocument(chatId, doc, [options], [fileOptions]) ⇒ <code>Promise</code>\nSend Document\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**\n\n- https://core.telegram.org/bots/api#sendDocument\n- https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| doc | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | A file path, Stream or Buffer. Can also be a `file_id` previously uploaded. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+sendVideo\"></a>\n\n### telegramBot.sendVideo(chatId, video, [options], [fileOptions]) ⇒ <code>Promise</code>\nUse this method to send video files, **Telegram clients support mp4 videos** (other formats may be sent as Document).\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**\n\n- https://core.telegram.org/bots/api#sendvideo\n- https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| video | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | A file path or Stream. Can also be a `file_id` previously uploaded. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+sendAnimation\"></a>\n\n### telegramBot.sendAnimation(chatId, animation, [options], [fileOptions]) ⇒ <code>Promise</code>\nUse this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound).\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**\n\n- https://core.telegram.org/bots/api#sendanimation\n- https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| animation | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | A file path, Stream or Buffer. Can also be a `file_id` previously uploaded. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+sendVoice\"></a>\n\n### telegramBot.sendVoice(chatId, voice, [options], [fileOptions]) ⇒ <code>Promise</code>\nSend voice\n\n**Your audio must be in an .OGG file encoded with OPUS**, or in .MP3 format, or in .M4A format (other formats may be sent as Audio or Document)\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**\n\n- https://core.telegram.org/bots/api#sendvoice\n- https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| voice | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | A file path, Stream or Buffer. Can also be a `file_id` previously uploaded. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+sendVideoNote\"></a>\n\n### telegramBot.sendVideoNote(chatId, videoNote, [options], [fileOptions]) ⇒ <code>Promise</code>\nUse this method to send video messages\nTelegram clients support **rounded square MPEG4 videos** of up to 1 minute long.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**Info**: The length parameter is actually optional. However, the API (at time of writing) requires you to always provide it until it is fixed.  \n**See**\n\n- https://core.telegram.org/bots/api#sendvideonote\n- https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| videoNote | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | A file path or Stream. Can also be a `file_id` previously uploaded. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+sendPaidMedia\"></a>\n\n### telegramBot.sendPaidMedia(chatId, starCount, media, [options]) ⇒ <code>Promise</code>\nUse this method to send paid media.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**: https://core.telegram.org/bots/api#sendpaidmedia  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| starCount | <code>Number</code> | The number of Telegram Stars that must be paid to buy access to the media; 1-10000 |\n| media | <code>Array</code> | Array of [InputPaidMedia](https://core.telegram.org/bots/api#inputpaidmedia). The media property can bea String, Stream or Buffer. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendMediaGroup\"></a>\n\n### telegramBot.sendMediaGroup(chatId, media, [options]) ⇒ <code>Promise</code>\nUse this method to send a group of photos or videos as an album.\n\n**Documents and audio files can be only grouped in an album with messages of the same type**\n\nIf you wish to [specify file options](https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files),\nadd a `fileOptions` property to the target input in `media`.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, an array of the sent [Messages](https://core.telegram.org/bots/api#message)\nis returned.  \n**See**\n\n- https://core.telegram.org/bots/api#sendmediagroup\n- https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| media | <code>Array</code> | A JSON-serialized array describing photos and videos to be sent, must include 2–10 items |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendLocation\"></a>\n\n### telegramBot.sendLocation(chatId, latitude, longitude, [options]) ⇒ <code>Promise</code>\nSend location.\nUse this method to send point on the map.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**: https://core.telegram.org/bots/api#sendlocation  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| latitude | <code>Float</code> | Latitude of location |\n| longitude | <code>Float</code> | Longitude of location |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+editMessageLiveLocation\"></a>\n\n### telegramBot.editMessageLiveLocation(latitude, longitude, [options]) ⇒ <code>Promise</code>\nUse this method to edit live location messages sent by\nthe bot or via the bot (for inline bots).\n\n A location **can be edited until its live_period expires or editing is explicitly disabled by a call to [stopMessageLiveLocation](https://core.telegram.org/bots/api#stopmessagelivelocation)**\n\nNote that you must provide one of chat_id, message_id, or\ninline_message_id in your request.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned.  \n**See**: https://core.telegram.org/bots/api#editmessagelivelocation  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| latitude | <code>Float</code> | Latitude of location |\n| longitude | <code>Float</code> | Longitude of location |\n| [options] | <code>Object</code> | Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) |\n\n<a name=\"TelegramBot+stopMessageLiveLocation\"></a>\n\n### telegramBot.stopMessageLiveLocation([options]) ⇒ <code>Promise</code>\nUse this method to stop updating a live location message sent by\nthe bot or via the bot (for inline bots) before live_period expires.\n\nNote that you must provide one of chat_id, message_id, or\ninline_message_id in your request.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned.  \n**See**: https://core.telegram.org/bots/api#stopmessagelivelocation  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) |\n\n<a name=\"TelegramBot+sendVenue\"></a>\n\n### telegramBot.sendVenue(chatId, latitude, longitude, title, address, [options]) ⇒ <code>Promise</code>\nSend venue.\nUse this method to send information about a venue.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned.  \n**See**: https://core.telegram.org/bots/api#sendvenue  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| latitude | <code>Float</code> | Latitude of location |\n| longitude | <code>Float</code> | Longitude of location |\n| title | <code>String</code> | Name of the venue |\n| address | <code>String</code> | Address of the venue |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendContact\"></a>\n\n### telegramBot.sendContact(chatId, phoneNumber, firstName, [options]) ⇒ <code>Promise</code>\nSend contact.\nUse this method to send phone contacts.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**: https://core.telegram.org/bots/api#sendcontact  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| phoneNumber | <code>String</code> | Contact's phone number |\n| firstName | <code>String</code> | Contact's first name |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendPoll\"></a>\n\n### telegramBot.sendPoll(chatId, question, pollOptions, [options]) ⇒ <code>Promise</code>\nSend poll.\nUse this method to send a native poll.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**: https://core.telegram.org/bots/api#sendpoll  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the group/channel |\n| question | <code>String</code> | Poll question, 1-300 characters |\n| pollOptions | <code>Array</code> | Poll options, between 2-10 options (only 1-100 characters each) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendChecklist\"></a>\n\n### telegramBot.sendChecklist(businessConnectionId, chatId, checklist, [options]) ⇒ <code>Promise</code>\nSend sendChecklist.\nUse this method to send a checklist on behalf of a connected business account.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**: https://core.telegram.org/bots/api#sendchecklist  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>Number</code> \\| <code>String</code> | Unique identifier for the business connection |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the group/channel |\n| checklist | <code>Object</code> | A JSON-serialized object for the checklist to send |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendDice\"></a>\n\n### telegramBot.sendDice(chatId, [options]) ⇒ <code>Promise</code>\nSend Dice\nUse this method to send an animated emoji that will display a random value.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned  \n**See**: https://core.telegram.org/bots/api#senddice  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendMessageDraft\"></a>\n\n### telegramBot.sendMessageDraft(chatId, draftId, text, [options]) ⇒ <code>Promise</code>\nSend Message Draft\nUse this method to stream a partial message to a user while the message is being generated; supported only for bots with forum topic mode enabled. Returns True on success.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, return true  \n**See**: https://core.telegram.org/bots/api#sendmessagedraft  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target private chat |\n| draftId | <code>Number</code> | Unique identifier of the message draft; must be non-zero. Changes of drafts with the same identifier are animated |\n| text | <code>String</code> | Text of the message to be sent, 1-4096 characters after entities parsing |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendChatAction\"></a>\n\n### telegramBot.sendChatAction(chatId, action, [options]) ⇒ <code>Promise</code>\nSend chat action.\n\nUse this method when you need to tell the user that something is happening on the bot's side.\n**The status is set for 5 seconds or less** (when a message arrives from your bot, Telegram clients clear its typing status).\n\n Action `typing` for [text messages](https://core.telegram.org/bots/api#sendmessage),\n`upload_photo` for [photos](https://core.telegram.org/bots/api#sendphoto), `record_video` or `upload_video` for [videos](https://core.telegram.org/bots/api#sendvideo),\n`record_voice` or `upload_voice` for [voice notes](https://core.telegram.org/bots/api#sendvoice), `upload_document` for [general files](https://core.telegram.org/bots/api#senddocument),\n`choose_sticker` for [stickers](https://core.telegram.org/bots/api#sendsticker), `find_location` for [location data](https://core.telegram.org/bots/api#sendlocation),\n`record_video_note` or `upload_video_note` for [video notes](https://core.telegram.org/bots/api#sendvideonote).\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#sendchataction  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| action | <code>String</code> | Type of action to broadcast. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setMessageReaction\"></a>\n\n### telegramBot.setMessageReaction(chatId, messageId, [options]) ⇒ <code>Promise.&lt;Boolean&gt;</code>\nUse this method to change the chosen reactions on a message.\n- Service messages can't be reacted to.\n- Automatically forwarded messages from a channel to its discussion group have the same available reactions as messages in the channel.\n- In albums, bots must react to the first message.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise.&lt;Boolean&gt;</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setmessagereaction  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format @channelusername) |\n| messageId | <code>Number</code> | Unique identifier of the target message |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getUserProfilePhotos\"></a>\n\n### telegramBot.getUserProfilePhotos(userId, [options]) ⇒ <code>Promise</code>\nUse this method to get a list of profile pictures for a user.\nReturns a [UserProfilePhotos](https://core.telegram.org/bots/api#userprofilephotos) object.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Returns a [UserProfilePhotos](https://core.telegram.org/bots/api#userprofilephotos) object  \n**See**: https://core.telegram.org/bots/api#getuserprofilephotos  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getUserProfileAudios\"></a>\n\n### telegramBot.getUserProfileAudios(userId, [options]) ⇒ <code>Promise</code>\nUse this method to get a list of profile audios for a user.\nReturns a [UserProfileAudios](https://core.telegram.org/bots/api#userprofileaudios) object.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Returns a [UserProfileAudios](https://core.telegram.org/bots/api#userprofileaudios) object  \n**See**: https://core.telegram.org/bots/api#getuserprofileaudios  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setUserEmojiStatus\"></a>\n\n### telegramBot.setUserEmojiStatus(userId, [options]) ⇒ <code>Promise</code>\nChanges the emoji status for a given user that previously allowed the bot to manage their emoji status\nvia the Mini App method [requestEmojiStatusAccess](https://core.telegram.org/bots/webapps#initializing-mini-apps).\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setuseremojistatus  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getFile\"></a>\n\n### telegramBot.getFile(fileId, [options]) ⇒ <code>Promise</code>\nGet file.\nUse this method to get basic info about a file and prepare it for downloading.\n\nAttention: **link will be valid for 1 hour.**\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, a [File](https://core.telegram.org/bots/api#file) object is returned  \n**See**: https://core.telegram.org/bots/api#getfile  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| fileId | <code>String</code> | File identifier to get info about |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+banChatMember\"></a>\n\n### telegramBot.banChatMember(chatId, userId, [options]) ⇒ <code>Promise</code>\nUse this method to ban a user in a group, a supergroup or a channel.\nIn the case of supergroups and channels, the user will not be able to\nreturn to the chat on their own using invite links, etc., unless unbanned first..\n\nThe **bot must be an administrator in the group, supergroup or a channel** for this to work.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success.  \n**See**: https://core.telegram.org/bots/api#banchatmember  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+unbanChatMember\"></a>\n\n### telegramBot.unbanChatMember(chatId, userId, [options]) ⇒ <code>Promise</code>\nUse this method to unban a previously kicked user in a supergroup.\nThe user will not return to the group automatically, but will be\nable to join via link, etc.\n\nThe **bot must be an administrator** in the supergroup or channel for this to work.\n\n**By default**, this method guarantees that after the call the user is not a member of the chat, but will be able to join it.\nSo **if the user is a member of the chat they will also be removed from the chat**. If you don't want this, use the parameter *only_if_banned*\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#unbanchatmember  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+restrictChatMember\"></a>\n\n### telegramBot.restrictChatMember(chatId, userId, [options]) ⇒ <code>Promise</code>\nUse this method to restrict a user in a supergroup.\nThe bot **must be an administrator in the supergroup** for this to work\nand must have the appropriate admin rights. Pass True for all boolean parameters\nto lift restrictions from a user. Returns True on success.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#restrictchatmember  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+promoteChatMember\"></a>\n\n### telegramBot.promoteChatMember(chatId, userId, [options]) ⇒ <code>Promise</code>\nUse this method to promote or demote a user in a supergroup or a channel.\nThe bot **must be an administrator** in the chat for this to work\nand must have the appropriate admin rights. Pass False for all boolean parameters to demote a user.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success.  \n**See**: https://core.telegram.org/bots/api#promotechatmember  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| userId | <code>Number</code> |  |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setChatAdministratorCustomTitle\"></a>\n\n### telegramBot.setChatAdministratorCustomTitle(chatId, userId, customTitle, [options]) ⇒ <code>Promise</code>\nUse this method to set a custom title for an administrator in a supergroup promoted by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setchatadministratorcustomtitle  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| customTitle | <code>String</code> | New custom title for the administrator; 0-16 characters, emoji are not allowed |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setChatMemberTag\"></a>\n\n### telegramBot.setChatMemberTag(chatId, userId, [options]) ⇒ <code>Promise</code>\nUse this method to set a tag for a regular member in a group or a supergroup.\n\nThe bot must be an administrator in the chat for this to work and must have the can_manage_tags administrator right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setchatmembertag  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+banChatSenderChat\"></a>\n\n### telegramBot.banChatSenderChat(chatId, senderChatId, [options]) ⇒ <code>Promise</code>\nUse this method to ban a channel chat in a supergroup or a channel.\n\nUntil the chat is [unbanned](https://core.telegram.org/bots/api#unbanchatsenderchat), the owner of the banned chat won't be able to send messages on behalf of any of their channels.\nThe bot **must be an administrator in the supergroup or channel** for this to work and must have the appropriate administrator rights\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success.  \n**See**: https://core.telegram.org/bots/api#banchatsenderchat  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| senderChatId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+unbanChatSenderChat\"></a>\n\n### telegramBot.unbanChatSenderChat(chatId, senderChatId, [options]) ⇒ <code>Promise</code>\nUse this method to unban a previously banned channel chat in a supergroup or channel.\n\nThe bot **must be an administrator** for this to work and must have the appropriate administrator rights.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#unbanchatsenderchat  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| senderChatId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setChatPermissions\"></a>\n\n### telegramBot.setChatPermissions(chatId, chatPermissions, [options]) ⇒ <code>Promise</code>\nUse this method to set default chat permissions for all members.\n\nThe bot **must be an administrator in the group or a supergroup** for this to\nwork and **must have the `can_restrict_members` admin rights.**\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setchatpermissions  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| chatPermissions | <code>Array</code> | New default chat permissions |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+exportChatInviteLink\"></a>\n\n### telegramBot.exportChatInviteLink(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to generate a new primary invite link for a chat. **Any previously generated primary link is revoked**.\n\nThe bot **must be an administrator in the chat** for this to work and must have the appropriate administrator rights.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Exported invite link as String on success.  \n**See**: https://core.telegram.org/bots/api#exportchatinvitelink  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+createChatInviteLink\"></a>\n\n### telegramBot.createChatInviteLink(chatId, [options]) ⇒ <code>Object</code>\nUse this method to create an additional invite link for a chat.\n\nThe bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n\nThe link generated with this method can be revoked using the method [revokeChatInviteLink](https://core.telegram.org/bots/api#revokechatinvitelink)\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Object</code> - The new invite link as [ChatInviteLink](https://core.telegram.org/bots/api#chatinvitelink) object  \n**See**: https://core.telegram.org/bots/api#createchatinvitelink  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+editChatInviteLink\"></a>\n\n### telegramBot.editChatInviteLink(chatId, inviteLink, [options]) ⇒ <code>Promise</code>\nUse this method to edit a non-primary invite link created by the bot.\n\nThe bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - The edited invite link as a [ChatInviteLink](https://core.telegram.org/bots/api#chatinvitelink) object  \n**See**: https://core.telegram.org/bots/api#editchatinvitelink  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| inviteLink | <code>String</code> | Text with the invite link to edit |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+createChatSubscriptionInviteLink\"></a>\n\n### telegramBot.createChatSubscriptionInviteLink(chatId, subscriptionPeriod, subscriptionPrice, [options]) ⇒ <code>Promise</code>\nUse this method to create a subscription invite link for a channel chat.\n\nThe bot must have the can_invite_users administrator rights\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - The new invite link as a [ChatInviteLink](https://core.telegram.org/bots/api#chatinvitelink) object  \n**See**: https://core.telegram.org/bots/api#createchatsubscriptioninvitelink  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| subscriptionPeriod | <code>Number</code> | The number of seconds the subscription will be active for before the next payment. Currently, it must always be 2592000 (30 days) |\n| subscriptionPrice | <code>Number</code> | The amount of Telegram Stars a user must pay initially and after each subsequent subscription period to be a member of the chat (1-2500) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+editChatSubscriptionInviteLink\"></a>\n\n### telegramBot.editChatSubscriptionInviteLink(chatId, inviteLink, [options]) ⇒ <code>Promise</code>\nUse this method to edit a subscription invite link created by the bot.\n\nThe bot must have the can_invite_users administrator rights\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - The new invite link as a [ChatInviteLink](https://core.telegram.org/bots/api#chatinvitelink) object  \n**See**: https://core.telegram.org/bots/api#editchatsubscriptioninvitelink  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| inviteLink | <code>String</code> | The invite link to edit |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+revokeChatInviteLink\"></a>\n\n### telegramBot.revokeChatInviteLink(chatId, inviteLink, [options]) ⇒ <code>Promise</code>\nUse this method to revoke an invite link created by the bot.\nNote: If the primary link is revoked, a new link is automatically generated\n\nThe bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - The revoked invite link as [ChatInviteLink](https://core.telegram.org/bots/api#chatinvitelink) object  \n**See**: https://core.telegram.org/bots/api#revokechatinvitelink  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| inviteLink | <code>String</code> | The invite link to revoke |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+approveChatJoinRequest\"></a>\n\n### telegramBot.approveChatJoinRequest(chatId, userId, [options]) ⇒ <code>Promise</code>\nUse this method to approve a chat join request.\n\nThe bot **must be an administrator in the chat** for this to work and **must have the `can_invite_users` administrator right.**\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#approvechatjoinrequest  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+declineChatJoinRequest\"></a>\n\n### telegramBot.declineChatJoinRequest(chatId, userId, [options]) ⇒ <code>Promise</code>\nUse this method to decline a chat join request.\n\nThe bot **must be an administrator in the chat** for this to work and **must have the `can_invite_users` administrator right**.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#declinechatjoinrequest  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setChatPhoto\"></a>\n\n### telegramBot.setChatPhoto(chatId, photo, [options], [fileOptions]) ⇒ <code>Promise</code>\nUse this method to set a new profile photo for the chat. **Photos can't be changed for private chats**.\n\nThe bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setchatphoto  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| photo | <code>stream.Stream</code> \\| <code>Buffer</code> | A file path or a Stream. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+deleteChatPhoto\"></a>\n\n### telegramBot.deleteChatPhoto(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to delete a chat photo. **Photos can't be changed for private chats**.\n\nThe bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#deletechatphoto  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setChatTitle\"></a>\n\n### telegramBot.setChatTitle(chatId, title, [options]) ⇒ <code>Promise</code>\nUse this method to change the title of a chat. **Titles can't be changed for private chats**.\n\nThe bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setchattitle  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| title | <code>String</code> | New chat title, 1-255 characters |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setChatDescription\"></a>\n\n### telegramBot.setChatDescription(chatId, description, [options]) ⇒ <code>Promise</code>\nUse this method to change the description of a group, a supergroup or a channel.\n\nThe bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setchatdescription  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| description | <code>String</code> | New chat title, 0-255 characters |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+pinChatMessage\"></a>\n\n### telegramBot.pinChatMessage(chatId, messageId, [options]) ⇒ <code>Promise</code>\nUse this method to pin a message in a supergroup.\n\nIf the chat is not a private chat, the **bot must be an administrator in the chat** for this to work and must have the `can_pin_messages` administrator\nright in a supergroup or `can_edit_messages` administrator right in a channel.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#pinchatmessage  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| messageId | <code>Number</code> | Identifier of a message to pin |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+unpinChatMessage\"></a>\n\n### telegramBot.unpinChatMessage(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to remove a message from the list of pinned messages in a chat\n\nIf the chat is not a private chat, the **bot must be an administrator in the chat** for this to work and must have the `can_pin_messages` administrator\nright in a supergroup or `can_edit_messages` administrator right in a channel.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#unpinchatmessage  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+unpinAllChatMessages\"></a>\n\n### telegramBot.unpinAllChatMessages(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to clear the list of pinned messages in a chat.\n\nIf the chat is not a private chat, the **bot must be an administrator in the chat** for this to work and must have the `can_pin_messages` administrator\nright in a supergroup or `can_edit_messages` administrator right in a channel.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#unpinallchatmessages  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+leaveChat\"></a>\n\n### telegramBot.leaveChat(chatId, [options]) ⇒ <code>Promise</code>\nUse this method for your bot to leave a group, supergroup or channel\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#leavechat  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getChat\"></a>\n\n### telegramBot.getChat(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to get up to date information about the chat\n(current name of the user for one-on-one conversations, current\nusername of a user, group or channel, etc.).\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - [ChatFullInfo](https://core.telegram.org/bots/api#chatfullinfo) object on success  \n**See**: https://core.telegram.org/bots/api#getchat  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) or channel |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getChatAdministrators\"></a>\n\n### telegramBot.getChatAdministrators(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to get a list of administrators in a chat\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns an Array of [ChatMember](https://core.telegram.org/bots/api#chatmember) objects that contains information about all chat administrators except other bots.\nIf the chat is a group or a supergroup and no administrators were appointed, only the creator will be returned  \n**See**: https://core.telegram.org/bots/api#getchatadministrators  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getChatMemberCount\"></a>\n\n### telegramBot.getChatMemberCount(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to get the number of members in a chat.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Int on success  \n**See**: https://core.telegram.org/bots/api#getchatmembercount  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getChatMember\"></a>\n\n### telegramBot.getChatMember(chatId, userId, [options]) ⇒ <code>Promise</code>\nUse this method to get information about a member of a chat.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - [ChatMember](https://core.telegram.org/bots/api#chatmember) object on success  \n**See**: https://core.telegram.org/bots/api#getchatmember  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setChatStickerSet\"></a>\n\n### telegramBot.setChatStickerSet(chatId, stickerSetName, [options]) ⇒ <code>Promise</code>\nUse this method to set a new group sticker set for a supergroup.\n\nThe bot **must be an administrator in the chat** for this to work and must have the appropriate administrator rights.\n\n**Note:** Use the field `can_set_sticker_set` optionally returned in [getChat](https://core.telegram.org/bots/api#getchat) requests to check if the bot can use this method.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setchatstickerset  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| stickerSetName | <code>String</code> | Name of the sticker set to be set as the group sticker set |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+deleteChatStickerSet\"></a>\n\n### telegramBot.deleteChatStickerSet(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to delete a group sticker set from a supergroup.\n\nUse the field `can_set_sticker_set` optionally returned in [getChat](https://core.telegram.org/bots/api#getchat) requests to check if the bot can use this method.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#deletechatstickerset  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getForumTopicIconStickers\"></a>\n\n### telegramBot.getForumTopicIconStickers(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to get custom emoji stickers, which can be used as a forum topic icon by any user.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Array of [Sticker](https://core.telegram.org/bots/api#sticker) objects  \n**See**: https://core.telegram.org/bots/api#getforumtopiciconstickers  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+createForumTopic\"></a>\n\n### telegramBot.createForumTopic(chatId, name, [options])\nUse this method to create a topic in a forum supergroup chat.\nThe bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights.\n\nReturns information about the created topic as a [ForumTopic](https://core.telegram.org/bots/api#forumtopic) object.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**See**: https://core.telegram.org/bots/api#createforumtopic  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| name | <code>String</code> | Topic name, 1-128 characters |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+editForumTopic\"></a>\n\n### telegramBot.editForumTopic(chatId, messageThreadId, [options]) ⇒ <code>Promise</code>\nUse this method to edit name and icon of a topic in a forum supergroup chat.\nThe bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights, unless it is the creator of the topic.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#editforumtopic  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| messageThreadId | <code>Number</code> | Unique identifier for the target message thread of the forum topic |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+closeForumTopic\"></a>\n\n### telegramBot.closeForumTopic(chatId, messageThreadId, [options]) ⇒ <code>Promise</code>\nUse this method to close an open topic in a forum supergroup chat.\nThe bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#closeforumtopic  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| messageThreadId | <code>Number</code> | Unique identifier for the target message thread of the forum topic |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+reopenForumTopic\"></a>\n\n### telegramBot.reopenForumTopic(chatId, messageThreadId, [options]) ⇒ <code>Promise</code>\nUse this method to reopen a closed topic in a forum supergroup chat.\nThe bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#reopenforumtopic  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| messageThreadId | <code>Number</code> | Unique identifier for the target message thread of the forum topic |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+deleteForumTopic\"></a>\n\n### telegramBot.deleteForumTopic(chatId, messageThreadId, [options]) ⇒ <code>Promise</code>\nUse this method to delete a forum topic along with all its messages in a forum supergroup chat.\nThe bot must be an administrator in the chat for this to work and must have the can_delete_messages administrator rights.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#deleteforumtopic  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| messageThreadId | <code>Number</code> | Unique identifier for the target message thread of the forum topic |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+unpinAllForumTopicMessages\"></a>\n\n### telegramBot.unpinAllForumTopicMessages(chatId, messageThreadId, [options]) ⇒ <code>Promise</code>\nUse this method to clear the list of pinned messages in a forum topic.\nThe bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator right in the supergroup.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#unpinallforumtopicmessages  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| messageThreadId | <code>Number</code> | Unique identifier for the target message thread of the forum topic |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+editGeneralForumTopic\"></a>\n\n### telegramBot.editGeneralForumTopic(chatId, name, [options]) ⇒ <code>Promise</code>\nUse this method to edit the name of the 'General' topic in a forum supergroup chat.\nThe bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights.\nThe topic will be automatically unhidden if it was hidden.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#editgeneralforumtopic  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| name | <code>String</code> | New topic name, 1-128 characters |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+closeGeneralForumTopic\"></a>\n\n### telegramBot.closeGeneralForumTopic(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to close an open 'General' topic in a forum supergroup chat.\nThe bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights.\nThe topic will be automatically unhidden if it was hidden.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#closegeneralforumtopic  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+reopenGeneralForumTopic\"></a>\n\n### telegramBot.reopenGeneralForumTopic(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to reopen a closed 'General' topic in a forum supergroup chat.\nThe bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights.\nThe topic will be automatically unhidden if it was hidden.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#reopengeneralforumtopic  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+hideGeneralForumTopic\"></a>\n\n### telegramBot.hideGeneralForumTopic(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to hide the 'General' topic in a forum supergroup chat.\nThe bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights.\nThe topic will be automatically closed if it was open.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#hidegeneralforumtopic  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+unhideGeneralForumTopic\"></a>\n\n### telegramBot.unhideGeneralForumTopic(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to unhide the 'General' topic in a forum supergroup chat.\nThe bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#unhidegeneralforumtopic  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+unpinAllGeneralForumTopicMessages\"></a>\n\n### telegramBot.unpinAllGeneralForumTopicMessages(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to clear the list of pinned messages in a General forum topic.\nThe bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator right in the supergroup.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#unpinallgeneralforumtopicmessages  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername) |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+answerCallbackQuery\"></a>\n\n### telegramBot.answerCallbackQuery(callbackQueryId, [options]) ⇒ <code>Promise</code>\nUse this method to send answers to callback queries sent from\n[inline keyboards](https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating).\n\nThe answer will be displayed to the user as a notification at the top of the chat screen or as an alert.\n\nThis method has **older, compatible signatures ([1][answerCallbackQuery-v0.27.1])([2][answerCallbackQuery-v0.29.0])**\nthat are being deprecated.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#answercallbackquery  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| callbackQueryId | <code>String</code> | Unique identifier for the query to be answered |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+savePreparedInlineMessage\"></a>\n\n### telegramBot.savePreparedInlineMessage(userId, result, [options]) ⇒ <code>Promise</code>\nUse this method to stores a message that can be sent by a user of a Mini App.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns a [PreparedInlineMessage](https://core.telegram.org/bots/api#preparedinlinemessage) object.  \n**See**: https://core.telegram.org/bots/api#savepreparedinlinemessage  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| result | <code>InlineQueryResult</code> | object that represents one result of an inline query |\n| [options] | <code>Object</code> | Optional form data to include in the request |\n\n<a name=\"TelegramBot+getUserChatBoosts\"></a>\n\n### telegramBot.getUserChatBoosts(chatId, userId, [options]) ⇒ <code>Promise</code>\nUse this method to get the list of boosts added to a chat by a use.\nRequires administrator rights in the chat\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns a [UserChatBoosts](https://core.telegram.org/bots/api#userchatboosts) object  \n**See**: https://core.telegram.org/bots/api#getuserchatboosts  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the group/channel |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getBusinessConnection\"></a>\n\n### telegramBot.getBusinessConnection(businessConnectionId, [options]) ⇒ <code>Promise</code>\nUse this method to get information about the connection of the bot with a business account\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns [BusinessConnection](https://core.telegram.org/bots/api#businessconnection) object  \n**See**: https://core.telegram.org/bots/api#getbusinessconnection  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>Number</code> \\| <code>String</code> | Unique identifier for the group/channel |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setMyCommands\"></a>\n\n### telegramBot.setMyCommands(commands, [options]) ⇒ <code>Promise</code>\nUse this method to change the list of the bot's commands.\n\nSee https://core.telegram.org/bots#commands for more details about bot commands\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setmycommands  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| commands | <code>Array</code> | List of bot commands to be set as the list of the [bot's commands](https://core.telegram.org/bots/api#botcommand). At most 100 commands can be specified. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+deleteMyCommands\"></a>\n\n### telegramBot.deleteMyCommands([options]) ⇒ <code>Promise</code>\nUse this method to delete the list of the bot's commands for the given scope and user language.\n\n After deletion, [higher level commands](https://core.telegram.org/bots/api#determining-list-of-commands) will be shown to affected users.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#deletemycommands  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getMyCommands\"></a>\n\n### telegramBot.getMyCommands([options]) ⇒ <code>Promise</code>\nUse this method to get the current list of the bot's commands for the given scope and user language.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Array of [BotCommand](https://core.telegram.org/bots/api#botcommand) on success. If commands aren't set, an empty list is returned.  \n**See**: https://core.telegram.org/bots/api#getmycommands  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setMyName\"></a>\n\n### telegramBot.setMyName([options]) ⇒ <code>Promise</code>\nUse this method to change the bot's name.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setmyname  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getMyName\"></a>\n\n### telegramBot.getMyName([options]) ⇒ <code>Promise</code>\nUse this method to get the current bot name for the given user language.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - [BotName](https://core.telegram.org/bots/api#botname) on success  \n**See**: https://core.telegram.org/bots/api#getmyname  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setMyDescription\"></a>\n\n### telegramBot.setMyDescription([options]) ⇒ <code>Promise</code>\nUse this method to change the bot's description, which is shown in the chat with the bot if the chat is empty.\n\nReturns True on success.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setmydescription  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getMyDescription\"></a>\n\n### telegramBot.getMyDescription([options]) ⇒ <code>Promise</code>\nUse this method to get the current bot description for the given user language.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Returns [BotDescription](https://core.telegram.org/bots/api#botdescription) on success.  \n**See**: https://core.telegram.org/bots/api#getmydescription  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setMyShortDescription\"></a>\n\n### telegramBot.setMyShortDescription([options]) ⇒ <code>Promise</code>\nUse this method to change the bot's short description, which is shown on the bot's profile page\nand is sent together with the link when users share the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Returns True on success.  \n**See**: https://core.telegram.org/bots/api#setmyshortdescription  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getMyShortDescription\"></a>\n\n### telegramBot.getMyShortDescription([options]) ⇒ <code>Promise</code>\nUse this method to get the current bot short description for the given user language.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Returns [BotShortDescription](https://core.telegram.org/bots/api#botshortdescription) on success.  \n**See**: https://core.telegram.org/bots/api#getmyshortdescription  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setMyProfilePhoto\"></a>\n\n### telegramBot.setMyProfilePhoto(photo, [options]) ⇒ <code>Promise</code>\nChanges the profile photo of the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setmyprofilephoto  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| photo | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | New profile photo. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+removeMyProfilePhoto\"></a>\n\n### telegramBot.removeMyProfilePhoto([options]) ⇒ <code>Promise</code>\nRemoves the profile photo of the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#removemyprofilephoto  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setChatMenuButton\"></a>\n\n### telegramBot.setChatMenuButton([options]) ⇒ <code>Promise</code>\nUse this method to change the bot's menu button in a private chat, or the default menu button.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setchatmenubutton  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getChatMenuButton\"></a>\n\n### telegramBot.getChatMenuButton([options]) ⇒ <code>Promise</code>\nUse this method to get the current value of the bot's menu button in a private chat, or the default menu button.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - [MenuButton](https://core.telegram.org/bots/api#menubutton) on success  \n**See**: https://core.telegram.org/bots/api#getchatmenubutton  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setMyDefaultAdministratorRights\"></a>\n\n### telegramBot.setMyDefaultAdministratorRights([options]) ⇒ <code>Promise</code>\nUse this method to change the default administrator rights requested by the bot when it's added as an administrator to groups or channels.\n\nThese rights will be suggested to users, but they are are free to modify the list before adding the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#getchatmenubutton  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getMyDefaultAdministratorRights\"></a>\n\n### telegramBot.getMyDefaultAdministratorRights([options]) ⇒ <code>Promise</code>\nUse this method to get the current default administrator rights of the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - [ChatAdministratorRights](https://core.telegram.org/bots/api#chatadministratorrights) on success  \n**See**: https://core.telegram.org/bots/api#getmydefaultadministratorrights  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+editMessageText\"></a>\n\n### telegramBot.editMessageText(text, [options]) ⇒ <code>Promise</code>\nUse this method to edit text or [game](https://core.telegram.org/bots/api#games) messages sent by the bot or via the bot (for inline bots).\n\nNote: that **you must provide one of chat_id, message_id, or inline_message_id** in your request.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned  \n**See**: https://core.telegram.org/bots/api#editmessagetext  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| text | <code>String</code> | New text of the message |\n| [options] | <code>Object</code> | Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) |\n\n<a name=\"TelegramBot+editMessageCaption\"></a>\n\n### telegramBot.editMessageCaption(caption, [options]) ⇒ <code>Promise</code>\nUse this method to edit captions of messages sent by the bot or via the bot (for inline bots).\n\nNote: You **must provide one of chat_id, message_id, or inline_message_id** in your request.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned  \n**See**: https://core.telegram.org/bots/api#editmessagecaption  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| caption | <code>String</code> | New caption of the message |\n| [options] | <code>Object</code> | Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) |\n\n<a name=\"TelegramBot+editMessageMedia\"></a>\n\n### telegramBot.editMessageMedia(media, [options]) ⇒ <code>Promise</code>\nUse this method to edit animation, audio, document, photo, or video messages.\n\nIf a message is a part of a message album, then it can be edited only to a photo or a video.\n\nOtherwise, message type can be changed arbitrarily. When inline message is edited, new file can't be uploaded.\nUse previously uploaded file via its file_id or specify a URL.\n\nNote: You **must provide one of chat_id, message_id, or inline_message_id** in your request.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned  \n**See**: https://core.telegram.org/bots/api#editmessagemedia  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| media | <code>Object</code> | A JSON-serialized object for a new media content of the message |\n| [options] | <code>Object</code> | Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) |\n\n<a name=\"TelegramBot+editMessageChecklist\"></a>\n\n### telegramBot.editMessageChecklist(businessConnectionId, chatId, messageId, checklist, [options]) ⇒ <code>Promise</code>\nUse this method to edit a checklist on behalf of a business connection.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned.  \n**See**: https://core.telegram.org/bots/api#editmessagechecklist  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target business connection |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| messageId | <code>Number</code> | Unique identifier for the target message |\n| checklist | <code>Object</code> | A JSON-serialized object for the new checklist |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+editMessageReplyMarkup\"></a>\n\n### telegramBot.editMessageReplyMarkup(replyMarkup, [options]) ⇒ <code>Promise</code>\nUse this method to edit only the reply markup of messages sent by the bot or via the bot (for inline bots).\n\nNote: You **must provide one of chat_id, message_id, or inline_message_id** in your request.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned  \n**See**: https://core.telegram.org/bots/api#editmessagetext  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| replyMarkup | <code>Object</code> | A JSON-serialized object for an inline keyboard. |\n| [options] | <code>Object</code> | Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here) |\n\n<a name=\"TelegramBot+stopPoll\"></a>\n\n### telegramBot.stopPoll(chatId, pollId, [options]) ⇒ <code>Promise</code>\nUse this method to stop a poll which was sent by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the stopped [Poll](https://core.telegram.org/bots/api#poll) is returned  \n**See**: https://core.telegram.org/bots/api#stoppoll  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the group/channel |\n| pollId | <code>Number</code> | Identifier of the original message with the poll |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+approveSuggestedPost\"></a>\n\n### telegramBot.approveSuggestedPost(chatId, messageId, [options]) ⇒ <code>Promise</code>\nUse this method to approve a suggested post in a direct messages chat.\n\nThe bot must have the 'can_post_messages' administrator right in the corresponding channel chat.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - on success, returns True  \n**See**: https://core.telegram.org/bots/api#approvesuggestedpost  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the group/channel |\n| messageId | <code>Number</code> | Identifier of the original message with the suggested post |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+declineSuggestedPost\"></a>\n\n### telegramBot.declineSuggestedPost(chatId, messageId, [options]) ⇒ <code>Promise</code>\nUse this method to decline a suggested post in a direct messages chat.\n\nThe bot must have the 'can_manage_direct_messages' administrator right in the corresponding channel chat.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - on success, returns True  \n**See**: https://core.telegram.org/bots/api#declinesuggestedpost  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the group/channel |\n| messageId | <code>Number</code> | Identifier of the original message with the suggested post |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendSticker\"></a>\n\n### telegramBot.sendSticker(chatId, sticker, [options], [fileOptions]) ⇒ <code>Promise</code>\nUse this method to send static .WEBP, [animated](https://telegram.org/blog/animated-stickers) .TGS,\nor [video](https://telegram.org/blog/video-stickers-better-reactions) .WEBM stickers.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) is returned  \n**See**: https://core.telegram.org/bots/api#sendsticker  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| sticker | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | A file path, Stream or Buffer. Can also be a `file_id` previously uploaded. Stickers are WebP format files. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+getStickerSet\"></a>\n\n### telegramBot.getStickerSet(name, [options]) ⇒ <code>Promise</code>\nUse this method to get a sticker set.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, a [StickerSet](https://core.telegram.org/bots/api#stickerset) object is returned  \n**See**: https://core.telegram.org/bots/api#getstickerset  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| name | <code>String</code> | Name of the sticker set |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getCustomEmojiStickers\"></a>\n\n### telegramBot.getCustomEmojiStickers(custom_emoji_ids, [options]) ⇒ <code>Promise</code>\nUse this method to get information about custom emoji stickers by their identifiers.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - Array of [Sticker](https://core.telegram.org/bots/api#sticker) objects.  \n**See**: https://core.telegram.org/bots/api#getcustomemojistickers  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| custom_emoji_ids | <code>Array</code> | List of custom emoji identifiers. At most 200 custom emoji identifiers can be specified. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+uploadStickerFile\"></a>\n\n### telegramBot.uploadStickerFile(userId, sticker, stickerFormat, [options], [fileOptions]) ⇒ <code>Promise</code>\nUse this method to upload a file with a sticker for later use in *createNewStickerSet* and *addStickerToSet* methods (can be used multiple\ntimes).\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, a [File](https://core.telegram.org/bots/api#file) object is returned  \n**See**: https://core.telegram.org/bots/api#uploadstickerfile  \n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| userId | <code>Number</code> |  | User identifier of sticker file owner |\n| sticker | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> |  | A file path or a Stream with the sticker in .WEBP, .PNG, .TGS, or .WEBM format. Can also be a `file_id` previously uploaded. |\n| stickerFormat | <code>String</code> | <code>static</code> | Allow values:  `static`, `animated` or `video` |\n| [options] | <code>Object</code> |  | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> |  | Optional file related meta-data |\n\n<a name=\"TelegramBot+createNewStickerSet\"></a>\n\n### telegramBot.createNewStickerSet(userId, name, title, pngSticker, emojis, [options], [fileOptions]) ⇒ <code>Promise</code>\nUse this method to create new sticker set owned by a user.\n\nThe bot will be able to edit the created sticker set.\n\nYou must use exactly one of the fields *png_sticker*, *tgs_sticker*, or *webm_sticker*\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#createnewstickerset  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | User identifier of created sticker set owner |\n| name | <code>String</code> | Short name of sticker set, to be used in `t.me/addstickers/` URLs (e.g.,   *\"animals\"*). Can contain only english letters, digits and underscores.  Must begin with a letter, can't contain consecutive underscores and must end in `\"_by_<bot_username>\"`. `<bot_username>` is case insensitive. 1-64 characters. |\n| title | <code>String</code> | Sticker set title, 1-64 characters |\n| pngSticker | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | Png image with the sticker, must be up to 512 kilobytes in size,  dimensions must not exceed 512px, and either width or height must be exactly 512px. |\n| emojis | <code>String</code> | One or more emoji corresponding to the sticker |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+addStickerToSet\"></a>\n\n### telegramBot.addStickerToSet(userId, name, sticker, emojis, stickerType, [options], [fileOptions]) ⇒ <code>Promise</code>\nUse this method to add a new sticker to a set created by the bot.\n\nYou must use exactly one of the fields *png_sticker*, *tgs_sticker*, or *webm_sticker*\n\nAnimated stickers can be added to animated sticker sets and only to them\n\nNote:\n- Emoji sticker sets can have up to 200 sticker\n- Static or Animated sticker sets can have up to 120 stickers\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#addstickertoset  \n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| userId | <code>Number</code> |  | User identifier of sticker set owner |\n| name | <code>String</code> |  | Sticker set name |\n| sticker | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> |  | Png image with the sticker (must be up to 512 kilobytes in size, dimensions must not exceed 512px, and either width or height must be exactly 512px, [TGS animation](https://core.telegram.org/stickers#animated-sticker-requirements) with the sticker or [WEBM video](https://core.telegram.org/stickers#video-sticker-requirements) with the sticker. |\n| emojis | <code>String</code> |  | One or more emoji corresponding to the sticker |\n| stickerType | <code>String</code> | <code>png_sticker</code> | Allow values: `png_sticker`, `tgs_sticker`, or `webm_sticker`. |\n| [options] | <code>Object</code> |  | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> |  | Optional file related meta-data |\n\n<a name=\"TelegramBot+setStickerPositionInSet\"></a>\n\n### telegramBot.setStickerPositionInSet(sticker, position, [options]) ⇒ <code>Promise</code>\nUse this method to move a sticker in a set created by the bot to a specific position.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setstickerpositioninset  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| sticker | <code>String</code> | File identifier of the sticker |\n| position | <code>Number</code> | New sticker position in the set, zero-based |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+deleteStickerFromSet\"></a>\n\n### telegramBot.deleteStickerFromSet(sticker, [options]) ⇒ <code>Promise</code>\nUse this method to delete a sticker from a set created by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#deletestickerfromset  \n**Todo**\n\n- [ ] Add tests for this method!\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| sticker | <code>String</code> | File identifier of the sticker |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+replaceStickerInSet\"></a>\n\n### telegramBot.replaceStickerInSet(userId, name, sticker, [options]) ⇒ <code>Promise</code>\nUse this method to replace an existing sticker in a sticker set with a new one\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#replacestickerinset  \n**Todo**\n\n- [ ] Add tests for this method!\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | User identifier of the sticker set owner |\n| name | <code>String</code> | Sticker set name |\n| sticker | <code>String</code> | File identifier of the sticker |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setStickerEmojiList\"></a>\n\n### telegramBot.setStickerEmojiList(sticker, emojiList, [options]) ⇒ <code>Promise</code>\nUse this method to change the list of emoji assigned to a regular or custom emoji sticker.\n\nThe sticker must belong to a sticker set created by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setstickeremojilist  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| sticker | <code>String</code> | File identifier of the sticker |\n| emojiList | <code>Array</code> | A JSON-serialized list of 1-20 emoji associated with the sticker |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setStickerKeywords\"></a>\n\n### telegramBot.setStickerKeywords(sticker, [options]) ⇒ <code>Promise</code>\nUse this method to change the list of emoji assigned to a `regular` or `custom emoji` sticker.\n\nThe sticker must belong to a sticker set created by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setstickerkeywords  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| sticker | <code>String</code> | File identifier of the sticker |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setStickerMaskPosition\"></a>\n\n### telegramBot.setStickerMaskPosition(sticker, [options]) ⇒ <code>Promise</code>\nUse this method to change the [mask position](https://core.telegram.org/bots/api#maskposition) of a mask sticker.\n\nThe sticker must belong to a sticker set created by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setstickermaskposition  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| sticker | <code>String</code> | File identifier of the sticker |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setStickerSetTitle\"></a>\n\n### telegramBot.setStickerSetTitle(name, title, [options]) ⇒ <code>Promise</code>\nUse this method to set the title of a created sticker set.\n\nThe sticker must belong to a sticker set created by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setstickersettitle  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| name | <code>String</code> | Sticker set name |\n| title | <code>String</code> | Sticker set title, 1-64 characters |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setStickerSetThumbnail\"></a>\n\n### telegramBot.setStickerSetThumbnail(userId, name, thumbnail, [options], [fileOptions]) ⇒ <code>Promise</code>\nUse this method to add a thumb to a set created by the bot.\n\nAnimated thumbnails can be set for animated sticker sets only. Video thumbnails can be set only for video sticker sets only\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setstickersetthumbnail  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | User identifier of sticker set owner |\n| name | <code>String</code> | Sticker set name |\n| thumbnail | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | A .WEBP or .PNG image with the thumbnail, must be up to 128 kilobytes in size and have width and height exactly 100px, a TGS animation with the thumbnail up to 32 kilobytes in size or a WEBM video with the thumbnail up to 32 kilobytes in size. Pass a file_id as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one. Animated sticker set thumbnails can't be uploaded via HTTP URL. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n| [fileOptions] | <code>Object</code> | Optional file related meta-data |\n\n<a name=\"TelegramBot+setCustomEmojiStickerSetThumbnail\"></a>\n\n### telegramBot.setCustomEmojiStickerSetThumbnail(name, [options]) ⇒ <code>Promise</code>\nUse this method to set the thumbnail of a custom emoji sticker set.\n\nThe sticker must belong to a sticker set created by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#setcustomemojistickersetthumbnail  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| name | <code>String</code> | Sticker set name |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+deleteStickerSet\"></a>\n\n### telegramBot.deleteStickerSet(name, [options]) ⇒ <code>Promise</code>\nUse this method to delete a sticker set that was created by the bot.\n\nThe sticker must belong to a sticker set created by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#deletestickerset  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| name | <code>String</code> | Sticker set name |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+answerInlineQuery\"></a>\n\n### telegramBot.answerInlineQuery(inlineQueryId, results, [options]) ⇒ <code>Promise</code>\nSend answers to an inline query.\n\nNote: No more than 50 results per query are allowed.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, True is returned  \n**See**: https://core.telegram.org/bots/api#answerinlinequery  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| inlineQueryId | <code>String</code> | Unique identifier of the query |\n| results | <code>Array.&lt;InlineQueryResult&gt;</code> | An array of results for the inline query |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+answerWebAppQuery\"></a>\n\n### telegramBot.answerWebAppQuery(webAppQueryId, result, [options]) ⇒ <code>Promise</code>\nUse this method to set the result of an interaction with a [Web App](https://core.telegram.org/bots/webapps)\nand send a corresponding message on behalf of the user to the chat from which the query originated.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, a [SentWebAppMessage](https://core.telegram.org/bots/api#sentwebappmessage) object is returned  \n**See**: https://core.telegram.org/bots/api#answerwebappquery  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| webAppQueryId | <code>String</code> | Unique identifier for the query to be answered |\n| result | <code>InlineQueryResult</code> | object that represents one result of an inline query |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendInvoice\"></a>\n\n### telegramBot.sendInvoice(chatId, title, description, payload, providerToken, currency, prices, [options]) ⇒ <code>Promise</code>\nUse this method to send an invoice.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) is returned  \n**See**: https://core.telegram.org/bots/api#sendinvoice  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| title | <code>String</code> | Product name, 1-32 characters |\n| description | <code>String</code> | Product description, 1-255 characters |\n| payload | <code>String</code> | Bot defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes. |\n| providerToken | <code>String</code> | Payments provider token, obtained via `@BotFather` |\n| currency | <code>String</code> | Three-letter ISO 4217 currency code |\n| prices | <code>Array</code> | Breakdown of prices |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+createInvoiceLink\"></a>\n\n### telegramBot.createInvoiceLink(title, description, payload, providerToken, currency, prices, [options]) ⇒ <code>Promise</code>\nUse this method to create a link for an invoice.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - The created invoice link as String on success.  \n**See**: https://core.telegram.org/bots/api#createinvoicelink  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| title | <code>String</code> | Product name, 1-32 characters |\n| description | <code>String</code> | Product description, 1-255 characters |\n| payload | <code>String</code> | Bot defined invoice payload |\n| providerToken | <code>String</code> | Payment provider token |\n| currency | <code>String</code> | Three-letter ISO 4217 currency code |\n| prices | <code>Array</code> | Breakdown of prices |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+answerShippingQuery\"></a>\n\n### telegramBot.answerShippingQuery(shippingQueryId, ok, [options]) ⇒ <code>Promise</code>\nUse this method to reply to shipping queries.\n\nIf you sent an invoice requesting a shipping address and the parameter is_flexible was specified,\nthe Bot API will send an [Update](https://core.telegram.org/bots/api#update) with a shipping_query field to the bot\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, True is returned  \n**See**: https://core.telegram.org/bots/api#answershippingquery  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| shippingQueryId | <code>String</code> | Unique identifier for the query to be answered |\n| ok | <code>Boolean</code> | Specify if delivery of the product is possible |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+answerPreCheckoutQuery\"></a>\n\n### telegramBot.answerPreCheckoutQuery(preCheckoutQueryId, ok, [options]) ⇒ <code>Promise</code>\nUse this method to respond to such pre-checkout queries\n\nOnce the user has confirmed their payment and shipping details, the Bot API sends the final confirmation in the form of\nan [Update](https://core.telegram.org/bots/api#update) with the field *pre_checkout_query*.\n\n**Note:** The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, True is returned  \n**See**: https://core.telegram.org/bots/api#answerprecheckoutquery  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| preCheckoutQueryId | <code>String</code> | Unique identifier for the query to be answered |\n| ok | <code>Boolean</code> | Specify if every order details are ok |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getMyStarBalance\"></a>\n\n### telegramBot.getMyStarBalance([options]) ⇒ <code>Promise</code>\nUse this method to get the current Telegram Stars balance of the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns a [StarAmount](https://core.telegram.org/bots/api#staramount) object  \n**See**: https://core.telegram.org/bots/api#getmystarbalance  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getStarTransactions\"></a>\n\n### telegramBot.getStarTransactions([options]) ⇒ <code>Promise</code>\nUse this method for get the bot's Telegram Star transactions in chronological order\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns a [StarTransactions](https://core.telegram.org/bots/api#startransactions) object  \n**See**: https://core.telegram.org/bots/api#getstartransactions  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+refundStarPayment\"></a>\n\n### telegramBot.refundStarPayment(userId, telegramPaymentChargeId, [options]) ⇒ <code>Promise</code>\nUse this method for refund a successful payment in [Telegram Stars](https://t.me/BotNews/90)\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, True is returned  \n**See**: https://core.telegram.org/bots/api#refundstarpayment  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the user whose payment will be refunded |\n| telegramPaymentChargeId | <code>String</code> | Telegram payment identifier |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+editUserStarSubscription\"></a>\n\n### telegramBot.editUserStarSubscription(userId, telegramPaymentChargeId, isCanceled, [options]) ⇒ <code>Promise</code>\nAllows the bot to cancel or re-enable extension of a subscription paid in Telegram Stars.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, True is returned  \n**See**: https://core.telegram.org/bots/api#cancelrenewsubscription  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the user whose subscription will be canceled or re-enabled |\n| telegramPaymentChargeId | <code>String</code> | Telegram payment identifier for the subscription |\n| isCanceled | <code>Boolean</code> | True, if the subscription should be canceled, False, if it should be re-enabled |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+sendGame\"></a>\n\n### telegramBot.sendGame(chatId, gameShortName, [options]) ⇒ <code>Promise</code>\nUse this method to send a game.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, the sent [Message](https://core.telegram.org/bots/api#message) is returned  \n**See**: https://core.telegram.org/bots/api#sendgame  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) |\n| gameShortName | <code>String</code> | name of the game to be sent. Set up your games via `@BotFather`. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setGameScore\"></a>\n\n### telegramBot.setGameScore(userId, score, [options]) ⇒ <code>Promise</code>\nUse this method to set the score of the specified user in a game message.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, if the message is not an inline message, the [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned  \n**See**: https://core.telegram.org/bots/api#setgamescore  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| score | <code>Number</code> | New score value, must be non-negative |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getGameHighScores\"></a>\n\n### telegramBot.getGameHighScores(userId, [options]) ⇒ <code>Promise</code>\nUse this method to get data for high score tables.\n\nWill return the score of the specified user and several of their neighbors in a game.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns an Array of [GameHighScore](https://core.telegram.org/bots/api#gamehighscore) objects  \n**See**: https://core.telegram.org/bots/api#getgamehighscores  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+deleteMessage\"></a>\n\n### telegramBot.deleteMessage(chatId, messageId, [options]) ⇒ <code>Promise</code>\nUse this method to delete a message, including service messages, with the following limitations:\n- A message can only be deleted if it was sent less than 48 hours ago.\n- A dice message can only be deleted if it was sent more than 24 hours ago.\n- Bots can delete outgoing messages in groups and supergroups.\n- Bots can delete incoming messages in groups, supergroups and channels.\n- Bots granted `can_post_messages` permissions can delete outgoing messages in channels.\n- If the bot is an administrator of a group, it can delete any message there.\n- If the bot has `can_delete_messages` permission in a supergroup, it can delete any message there.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - True on success  \n**See**: https://core.telegram.org/bots/api#deletemessage  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format @channelusername) |\n| messageId | <code>Number</code> | Unique identifier of the target message |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+deleteMessages\"></a>\n\n### telegramBot.deleteMessages(chatId, messageIds, [options]) ⇒ <code>Promise.&lt;Boolean&gt;</code>\nUse this method to delete multiple messages simultaneously. If some of the specified messages can't be found, they are skipped.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise.&lt;Boolean&gt;</code> - True on success  \n**See**: https://core.telegram.org/bots/api#deletemessages  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format @channelusername) |\n| messageIds | <code>Array.&lt;(Number\\|String)&gt;</code> | Identifiers of 1-100 messages to delete. See deleteMessage for limitations on which messages can be deleted |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getAvailableGifts\"></a>\n\n### telegramBot.getAvailableGifts([options]) ⇒ <code>Promise</code>\nUse this method to returns the list of gifts that can be sent by the bot to users and channel chats.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns a [Gifts](https://core.telegram.org/bots/api#gifts) objects.  \n**See**: https://core.telegram.org/bots/api#getavailablegifts  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| [options] | <code>Object</code> | Additional Telegram query options. |\n\n<a name=\"TelegramBot+sendGift\"></a>\n\n### telegramBot.sendGift(giftId, [options]) ⇒ <code>Promise</code>\nUse this method to sends a gift to the given user or channel chat.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#getavailablegifts  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| giftId | <code>String</code> | Unique identifier of the gift |\n| [options] | <code>Object</code> | Additional Telegram query options. |\n\n<a name=\"TelegramBot+giftPremiumSubscription\"></a>\n\n### telegramBot.giftPremiumSubscription(userId, monthCount, starCount, [options]) ⇒ <code>Promise</code>\nUse this method to sends a gift to the given user or channel chat.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#getavailablegifts  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the target user who will receive a Telegram Premium subscription. |\n| monthCount | <code>Number</code> | Number of months the Telegram Premium subscription will be active for the user; must be one of 3, 6, or 12. |\n| starCount | <code>String</code> | Number of Telegram Stars to pay for the Telegram Premium subscription; must be 1000 for 3 months, 1500 for 6 months, and 2500 for 12 months. |\n| [options] | <code>Object</code> | Additional Telegram query options. |\n\n<a name=\"TelegramBot+verifyUser\"></a>\n\n### telegramBot.verifyUser(userId, [options]) ⇒ <code>Promise</code>\nThis method verifies a user [on behalf of the organization](https://telegram.org/verify#third-party-verification) which is represented by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#verifyuser  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the target user. |\n| [options] | <code>Object</code> | Additional Telegram query options. |\n\n<a name=\"TelegramBot+verifyChat\"></a>\n\n### telegramBot.verifyChat(chatId, [options]) ⇒ <code>Promise</code>\nThis method verifies a chat [on behalf of the organization](https://telegram.org/verify#third-party-verification) which is represented by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#verifychat  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> | Unique identifier of the target chat. |\n| [options] | <code>Object</code> | Additional Telegram query options. |\n\n<a name=\"TelegramBot+removeUserVerification\"></a>\n\n### telegramBot.removeUserVerification(userId, [options]) ⇒ <code>Promise</code>\nThis method removes verification from a user who is currently verified [on behalf of the organization](https://telegram.org/verify#third-party-verification) which is represented by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#removeuserverification  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the target user |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+removeChatVerification\"></a>\n\n### telegramBot.removeChatVerification(chatId, [options]) ⇒ <code>Promise</code>\nThis method removes verification from a chat who is currently verified [on behalf of the organization](https://telegram.org/verify#third-party-verification) which is represented by the bot.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#removechatverification  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> | Unique identifier of the target chat. |\n| [options] | <code>Object</code> | Additional Telegram query options. |\n\n<a name=\"TelegramBot+readBusinessMessage\"></a>\n\n### telegramBot.readBusinessMessage(businessConnectionId, chatId, messageId, [options]) ⇒ <code>Promise</code>\nThis method marks incoming message as read on behalf of a business account.\n\nRequires the **can_read_messages** business bot right\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#readbusinessmessage  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection on behalf of which to read the message. |\n| chatId | <code>Number</code> | Unique identifier of the chat in which the message was received. The chat must have been active in the last 24 hours. |\n| messageId | <code>Number</code> | Unique identifier of the message to mark as read. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+deleteBusinessMessages\"></a>\n\n### telegramBot.deleteBusinessMessages(businessConnectionId, messageIds, [options]) ⇒ <code>Promise</code>\nThis method delete messages on behalf of a business account.\n\nRequires the **can_delete_outgoing_messages** business bot right to delete messages sent by the bot itself, or the **can_delete_all_messages business** bot right to delete any message.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#deletebusinessmessages  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection on behalf of which to delete the message. |\n| messageIds | <code>Array.&lt;Number&gt;</code> | List of 1-100 identifiers of messages to delete. All messages **must be from the same chat**. |\n| [options] | <code>Object</code> | Additional Telegram query options. |\n\n<a name=\"TelegramBot+setBusinessAccountName\"></a>\n\n### telegramBot.setBusinessAccountName(businessConnectionId, firstName, [options]) ⇒ <code>Promise</code>\nThis method changes the first and last name of a managed business account.\n\nRequires the **can_change_name** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#setbusinessaccountname  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| firstName | <code>String</code> | The new value of the first name for the business account; 1-64 characters. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setBusinessAccountUsername\"></a>\n\n### telegramBot.setBusinessAccountUsername(businessConnectionId, [options]) ⇒ <code>Promise</code>\nThis method changes the username of a managed business account.\n\nRequires the **can_change_username** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#setbusinessaccountusername  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setBusinessAccountBio\"></a>\n\n### telegramBot.setBusinessAccountBio(businessConnectionId, [options]) ⇒ <code>Promise</code>\nThis method changes the bio of a managed business account.\n\nRequires the **can_change_bio** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#setbusinessaccountbio  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setBusinessAccountProfilePhoto\"></a>\n\n### telegramBot.setBusinessAccountProfilePhoto(businessConnectionId, photo, [options]) ⇒ <code>Promise</code>\nThis method changes the profile photo of a managed business account.\n\nRequires the **can_edit_profile_photo** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#setbusinessaccountprofilephoto  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| photo | <code>String</code> \\| <code>stream.Stream</code> \\| <code>Buffer</code> | New profile photo. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+removeBusinessAccountProfilePhoto\"></a>\n\n### telegramBot.removeBusinessAccountProfilePhoto(businessConnectionId, [options]) ⇒ <code>Promise</code>\nThis method removes the current profile photo of a managed business account.\n\nRequires the **can_edit_profile_photo** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#removebusinessaccountprofilephoto  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+setBusinessAccountGiftSettings\"></a>\n\n### telegramBot.setBusinessAccountGiftSettings(businessConnectionId, showGiftButton, acceptedGiftTypes, [options]) ⇒ <code>Promise</code>\nThis method changes the privacy settings pertaining to incoming gifts in a managed business account.\n\nRequires the **can_change_gift_settings** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns true.  \n**See**: https://core.telegram.org/bots/api#setbusinessaccountgiftsettings  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| showGiftButton | <code>Boolean</code> | Pass True, if a button for sending a gift to the user or by the business account must always be shown in the input field. |\n| acceptedGiftTypes | <code>Object</code> | Types of gifts accepted by the business account. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getBusinessAccountStarBalance\"></a>\n\n### telegramBot.getBusinessAccountStarBalance(businessConnectionId, [options]) ⇒ <code>Promise</code>\nThis method returns the amount of Telegram Stars owned by a managed business account.\n\nRequires the **can_view_gifts_and_stars** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns [StarAmount](https://core.telegram.org/bots/api#staramount).  \n**See**: https://core.telegram.org/bots/api#getbusinessaccountstarbalance  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+transferBusinessAccountStars\"></a>\n\n### telegramBot.transferBusinessAccountStars(businessConnectionId, starCount, [options]) ⇒ <code>Promise</code>\nThis method transfers Telegram Stars from the business account balance to the bot's balance.\n\nRequires the **can_transfer_stars** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns True.  \n**See**: https://core.telegram.org/bots/api#transferbusinessaccountstars  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| starCount | <code>Number</code> | Number of Telegram Stars to transfer; 1-10000. |\n| [options] | <code>Object</code> | Additional Telegram query options. |\n\n<a name=\"TelegramBot+getBusinessAccountGifts\"></a>\n\n### telegramBot.getBusinessAccountGifts(businessConnectionId, [options]) ⇒ <code>Promise</code>\nThis method returns the gifts received and owned by a managed business account.\n\nRequires the **can_view_gifts_and_stars** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns [OwnedGifts](https://core.telegram.org/bots/api#ownedgifts).  \n**See**: https://core.telegram.org/bots/api#getbusinessaccountgifts  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getUserGifts\"></a>\n\n### telegramBot.getUserGifts(userId, [options]) ⇒ <code>Promise</code>\nUse this method to get gifts owned by a regular user.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns an [OwnedGifts](https://core.telegram.org/bots/api#ownedgifts) object.  \n**See**: https://core.telegram.org/bots/api#getusergifts  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| userId | <code>Number</code> | Unique identifier of the target user. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+getChatGifts\"></a>\n\n### telegramBot.getChatGifts(chatId, [options]) ⇒ <code>Promise</code>\nUse this method to get gifts received by a channel chat or a business account managed by the bot.\n\nRequires the **can_view_gifts_and_stars** administrator right if the chat is a channel.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns an [OwnedGifts](https://core.telegram.org/bots/api#ownedgifts) object.  \n**See**: https://core.telegram.org/bots/api#getchatgifts  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| chatId | <code>Number</code> \\| <code>String</code> | Unique identifier for the target chat or username of the target channel (in the format `@channelusername`). |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+convertGiftToStars\"></a>\n\n### telegramBot.convertGiftToStars(businessConnectionId, ownedGiftId, [options]) ⇒ <code>Promise</code>\nThis method converts a given regular gift to Telegram Stars.\n\nRequires the **can_convert_gifts_to_stars** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns True.  \n**See**: https://core.telegram.org/bots/api#convertgifttostars  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| ownedGiftId | <code>String</code> | Unique identifier of the regular gift that should be converted to Telegram Stars. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+upgradeGift\"></a>\n\n### telegramBot.upgradeGift(businessConnectionId, ownedGiftId, [options]) ⇒ <code>Promise</code>\nThis method upgrades a given regular gift to a unique gift.\n\nRequires the **can_transfer_and_upgrade_gifts** business bot right.\nAdditionally requires the **can_transfer_stars** business bot right **if the upgrade is paid**.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns True.  \n**See**: https://core.telegram.org/bots/api#upgradegift  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| ownedGiftId | <code>String</code> | Unique identifier of the regular gift that should be upgraded to a unique one. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+transferGift\"></a>\n\n### telegramBot.transferGift(businessConnectionId, ownedGiftId, newOwnerChatId, [options]) ⇒ <code>Promise</code>\nThis method transfers an owned unique gift to another user.\n\nRequires the **can_transfer_and_upgrade_gifts** business bot right.\nAdditionally requires the **can_transfer_stars** business bot right **if the transfer is paid**.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns True.  \n**See**: https://core.telegram.org/bots/api#transfergift  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| ownedGiftId | <code>String</code> | Unique identifier of the regular gift that should be transferred. |\n| newOwnerChatId | <code>Number</code> | Unique identifier of the chat which will own the gift. The chat **must be active in the last 24 hours**. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+postStory\"></a>\n\n### telegramBot.postStory(businessConnectionId, content, activePeriod, [options]) ⇒ <code>Promise</code>\nThis method posts a story on behalf of a managed business account.\n\nRequires the **can_manage_stories** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns [Story](https://core.telegram.org/bots/api#story).  \n**See**: https://core.telegram.org/bots/api#poststory  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| content | <code>Array</code> | [InputStoryContent](https://core.telegram.org/bots/api#inputpaidmedia). The photo/video property can be String, Stream or Buffer. |\n| activePeriod | <code>Number</code> | Unique identifier of the chat which will own the gift. The chat **must be active in the last 24 hours**. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+repostStory\"></a>\n\n### telegramBot.repostStory(businessConnectionId, fromChatId, fromStoryId, activePeriod, [options]) ⇒ <code>Promise</code>\nThis method reposts a story on behalf of a managed business account.\n\nRequires the **can_manage_stories** business bot right for both the source and destination accounts.\nThe story must have been originally posted or reposted by the bot itself.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns a [Story](https://core.telegram.org/bots/api#story) object.  \n**See**: https://core.telegram.org/bots/api#repoststory  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection of the account that will repost the story. |\n| fromChatId | <code>Number</code> | Unique identifier of the chat that originally posted the story. |\n| fromStoryId | <code>Number</code> | Unique identifier of the story to repost. |\n| activePeriod | <code>Number</code> | The period after which the story is moved to archive, in seconds; must be one of 21600, 43200, 86400, or 172800. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+editStory\"></a>\n\n### telegramBot.editStory(businessConnectionId, storyId, content, [options]) ⇒ <code>Promise</code>\nThis method edits a story previously posted by the bot on behalf of a managed business account.\n\nRequires the **can_manage_stories** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns [Story](https://core.telegram.org/bots/api#story).  \n**See**: https://core.telegram.org/bots/api#editstory  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| storyId | <code>Number</code> | Unique identifier of the story to edit. |\n| content | <code>Array</code> | [InputStoryContent](https://core.telegram.org/bots/api#inputpaidmedia). The photo/video property can be String, Stream or Buffer. |\n| [options] | <code>Object</code> | Additional Telegram query options |\n\n<a name=\"TelegramBot+deleteStory\"></a>\n\n### telegramBot.deleteStory(businessConnectionId, storyId, [options]) ⇒ <code>Promise</code>\nThis method deletes a story previously posted by the bot on behalf of a managed business account.\n\nRequires the **can_manage_stories** business bot right.\n\n**Kind**: instance method of [<code>TelegramBot</code>](#TelegramBot)  \n**Returns**: <code>Promise</code> - On success, returns True.  \n**See**: https://core.telegram.org/bots/api#deletestory  \n\n| Param | Type | Description |\n| --- | --- | --- |\n| businessConnectionId | <code>String</code> | Unique identifier of the business connection. |\n| storyId | <code>Number</code> | Unique identifier of the story to delete. |\n| [options] | <code>Object</code> | Additional Telegram query options. |\n\n<a name=\"TelegramBot.errors\"></a>\n\n### TelegramBot.errors : <code>Object</code>\nThe different errors the library uses.\n\n**Kind**: static property of [<code>TelegramBot</code>](#TelegramBot)  \n<a name=\"TelegramBot.messageTypes\"></a>\n\n### TelegramBot.messageTypes : <code>Array.&lt;String&gt;</code>\nThe types of message updates the library handles.\n\n**Kind**: static property of [<code>TelegramBot</code>](#TelegramBot)  \n* * *\n\n\n[usage-sending-files-performance]:https://github.com/yagop/node-telegram-bot-api/tree/master/doc/usage.md#sending-files-performance\n[setWebHook-v0.25.0]:https://github.com/yagop/node-telegram-bot-api/tree/4e5a493cadfaad5589a8d79e55d9e0d103000ce4#telegrambotsetwebhookurl-cert\n[getUpdates-v0.25.0]:https://github.com/yagop/node-telegram-bot-api/tree/4e5a493cadfaad5589a8d79e55d9e0d103000ce4#TelegramBot+getUpdates\n[getUserProfilePhotos-v0.25.0]:https://github.com/yagop/node-telegram-bot-api/tree/4e5a493cadfaad5589a8d79e55d9e0d103000ce4#TelegramBot+getUserProfilePhotos\n[answerCallbackQuery-v0.27.1]:https://github.com/yagop/node-telegram-bot-api/blob/v0.27.1/doc/api.md#TelegramBot+answerCallbackQuery\n[answerCallbackQuery-v0.29.0]:https://github.com/yagop/node-telegram-bot-api/blob/v0.29.0/doc/api.md#TelegramBot+answerCallbackQuery\n"
  },
  {
    "path": "doc/experimental.md",
    "content": "# Experimental\n\nExperimental features are things we are trying out. We are **not** sure\nif they'll become stable and move into the `master` branch.\nTry them out and give feedback to support stabilizing them.\n\n* [Features](#features)\n* [API Reference][api-experimental]\n* [Installation](#installation)\n\n\n<a name=\"features\"></a>\n## features:\n\n* Support API method `deleteMessage`\n\nOpen issues tagged `experimental`: [link](https://github.com/yagop/node-telegram-bot-api/issues?q=is%3Apr+is%3Aopen+label%3Aexperimental)\n\n\n<a name=\"installation\"></a>\n## installation:\n\n```bash\n$ npm install yagop/node-telegram-bot-api#experimental\n```\n\n\n[api-experimental]:https://github.com/yagop/node-telegram-bot-api/tree/experimental/doc/api.md\n"
  },
  {
    "path": "doc/help.md",
    "content": "# Help Information\n\n* [Common Pitfalls](#pitfalls)\n* [FAQs](#faqs)\n\n<a name=\"pitfalls\"></a>\n## Common Pitfalls\n\n<a name=\"reply-to-message\"></a>\n### Failing to receive reply with `ReplyToMessage`\n\nThe user has to **manually reply** to your message, by tapping on the bot's message and select *Reply*.\n\nSources:\n\n* Issue [#113](https://github.com/yagop/node-telegram-bot-api/issues/113)\n\n<a name=\"faqs\"></a>\n## Frequently Asked Questions\n\n> Check out [all questions ever asked][questions] on our Github Issues.\n\n1. [How do I send GIFs?](#gifs)\n1. [Why and When do I need a certificate when using WebHooks?](#webhook-cert)\n1. [How do I know when a user leaves a chat?](#leave-chat)\n1. [What does this error mean?](#error-meanings)\n1. [How do I know the selected option in reply keyboard?](#reply-keyboard)\n1. [How do I send multiple message in correct sequence?](#ordered-sending)\n1. [How do I run my bot behind a proxy?](#proxy)\n1. [Can you add feature X to the library?](#new-feature)\n1. [Is this scalable?](#scalable)\n1. [How do I listen for messages in a chat group?](#messages-in-chat)\n1. [How do I know when a user blocks the bot?](#blocked-bot)\n\n<a name=\"gifs\"></a>\n### How do I send GIFs?\n\nYou might be trying to send your animated GIFs using *TelegramBot#sendPhoto()*.\nThe method mostly supports static images. As noted by the community,\nit seems you need to send them as documents, using *TelegramBot#sendDocument()*.\n\n```js\nbot.sendDocument(chatId, 'cat.gif');\n```\n\nSources:\n\n* Issue [#11](https://github.com/yagop/node-telegram-bot-api/issues/11)\n\n<a name=\"webhook-cert\"></a>\n### Why and When do I need a certificate when using WebHooks?\n\n*Not done. PRs welcome!*\n\nSources:\n\n* Issue [#63](https://github.com/yagop/node-telegram-bot-api/issues/63)\n* Issue [#125](https://github.com/yagop/node-telegram-bot-api/issues/125)\n\n<a name=\"leave-chat\"></a>\n### How do I know when a user leaves a chat?\n\n*Not done. PRs welcome!*\n\nSources:\n\n* Issue [#248](https://github.com/yagop/node-telegram-bot-api/issues/248)\n\n<a name=\"error-meanings\"></a>\n### What does this error mean?\n\n* [502 Bad Gateway](https://github.com/yagop/node-telegram-bot-api/issues/377)\n\n*Not complete. PRs welcome!*\n\nSources:\n\n* Issue [#73](https://github.com/yagop/node-telegram-bot-api/issues/73)\n* Issue [#99](https://github.com/yagop/node-telegram-bot-api/issues/99)\n* Issue [#101](https://github.com/yagop/node-telegram-bot-api/issues/101)\n* Issue [#107](https://github.com/yagop/node-telegram-bot-api/issues/107)\n* Issue [#156](https://github.com/yagop/node-telegram-bot-api/issues/156)\n* Issue [#170](https://github.com/yagop/node-telegram-bot-api/issues/170)\n* Issue [#244](https://github.com/yagop/node-telegram-bot-api/issues/244)\n\n<a name=\"reply-keyboard\"></a>\n### How do I know the selected option in reply keyboard?\n\n*Not done. PRs welcome!*\n\nSources:\n\n* Issue [#108](https://github.com/yagop/node-telegram-bot-api/issues/108)\n\n<a name=\"ordered-sending\"></a>\n### How do I send multiple message in correct sequence?\n\n*Not done. PRs welcome!*\n\nSources:\n\n* Issue [#240](https://github.com/yagop/node-telegram-bot-api/issues/240)\n\n<a name=\"proxy\"></a>\n### How do I run my bot behind a proxy?\n\n*Not done. PRs welcome!*\n\nSources:\n\n* Issue [#122](https://github.com/yagop/node-telegram-bot-api/issues/122)\n* Issue [#253](https://github.com/yagop/node-telegram-bot-api/issues/253)\n* Issue [#766](https://github.com/yagop/node-telegram-bot-api/issues/766)\n\n<a name=\"new-feature\"></a>\n### Can you add feature X to the library?\n\n*Not done. PRs welcome!*\n\nSources:\n\n* Issue [#238](https://github.com/yagop/node-telegram-bot-api/issues/238)\n\n<a name=\"scalable\"></a>\n### Is this scalable?\n\n*Not done. PRs welcome!*\n\nSources:\n\n* Issue [#219](https://github.com/yagop/node-telegram-bot-api/issues/219)\n\n<a name=\"messages-in-chat\"></a>\n### How do I listen for messages in a chat group?\n\n*Not done. PRs welcome!*\n\nSources:\n\n* Issue [#304](https://github.com/yagop/node-telegram-bot-api/issues/304)\n\n<a name=\"blocked-bot\"></a>\n### How do I know when a user blocks the bot?\n\n*Not done. PRs welcome!*\n\nSources:\n\n* Issue [#273](https://github.com/yagop/node-telegram-bot-api/issues/273)\n\n[questions]:https://github.com/yagop/node-telegram-bot-api/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Aquestion%20\n"
  },
  {
    "path": "doc/tutorials.md",
    "content": "# Tutorials\n\n* [node-telegram-bot-api-tutorial by @hosein2398](https://github.com/hosein2398/node-telegram-bot-api-tutorial)\n* [node-telegram-bot-api-persian-language by @saeedhei](https://github.com/saeedhei/node-telegram-bot-api-persian-language)\n* [Node.JS: Делаем своего Telegram бота [RUS]](https://archakov.im/post/telegram-bot-on-nodejs)\n* [YouTube: Пишем Telegram бота на NodeJS [RUS]](https://www.youtube.com/watch?v=RS1nmDMf69U&list=PL6AOr-PZtK-mM2QC1ixyfa5CtJZGK61aN)\n* [Node.jsでTelegramのチャットボットを作る - Qiita](https://qiita.com/neetshin/items/0e2f6fa3ade41adb77bc)\n* [Guía: Creación de bots de Telegram en Nodejs [ES]](https://tecnonucleous.com/creacion-de-bots-de-telegram-en-nodejs/)\n* [node-telegram-bot-api-tutorial:a telegram bot helper to send templates by sms](https://github.com/vito2005/chatManagerTelegramBot)\n* [Telegram bot using blockchain services](https://ilanolkies.com/post/Telegram-bot-using-blockchain-services)\n* [How to set webhooks using express local server and NGROK](https://github.com/leobloise/node-telegram-bot-api-wb-tutorial)\n> Send a PR with useful links **not** listed above\n"
  },
  {
    "path": "doc/usage.md",
    "content": "# Usage\n\n- [Usage](#usage)\n  - [Events](#events)\n  - [WebHooks](#webhooks)\n  - [Sending files](#sending-files)\n    - [File Options (metadata)](#file-options-metadata)\n    - [Performance Issue](#performance-issue)\n  - [Error handling](#error-handling)\n  - [Polling errors](#polling-errors)\n  - [WebHook errors](#webhook-errors)\n\n<a name=\"events\"></a>\n## Events\n\n*TelegramBot* is an [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)\nthat emits the following events:\n\n1. `message`: Received a new incoming [Message][message] of any kind\n   1. Depending on the properties of the [Message][message], one of these\n     events may **ALSO** be emitted: `text`, `audio`, `document`, `photo`,\n     `sticker`, `video`, `voice`, `contact`, `location`,\n     `new_chat_members`, `left_chat_member`, `new_chat_title`,\n     `new_chat_photo`, `delete_chat_photo`, `group_chat_created`,\n     `game`, `pinned_message`, `poll`, `dice`, `migrate_from_chat_id`, `migrate_to_chat_id`,\n     `channel_chat_created`, `supergroup_chat_created`,\n     `successful_payment`, `invoice`, `video_note`\n   1. **Arguments**: `message` ([Message][message]), `metadata` (`{ type?:string }`)\n   1. `new_chat_participant`, `left_chat_participant` are **deprecated**\n1. `callback_query`: Received a new incoming [Callback Query][callback-query]\n1. `inline_query`: Received a new incoming [Inline Query][inline-query]\n1. `chosen_inline_result`: Received result of an inline query i.e. [ChosenInlineResult][chosen-inline-result]\n1. `channel_post`: Received a new incoming channel post of any kind\n1. `edited_message`: Received a new version of a message that is known to the bot and was edited \\\n   Depending on the properties of the [Message][message], one of these events may **ALSO** be emitted:\n   1. `edited_message_text`\n   1. `edited_message_caption`\n1. `edited_channel_post`: Received a new version of a channel post that is known to the bot and was edited \\\n   Depending on the properties of the [Message][message], one of these events may **ALSO** be emitted:\n   1. `edited_channel_post_text`\n   1. `edited_channel_post_caption`\n1. `shipping_query`: Received a new incoming shipping query\n1. `pre_checkout_query`: Received a new  incoming pre-checkout query\n1. `poll`: Received a new  incoming poll\n2. `poll_answer`: A user has changed their answer in a non-anonymous poll (Only polls sent by the bot)\n3. `chat_member`: A chat member's status was updated in a chat\n4. `my_chat_member`: The bot's chat member status was updated in a chat\n5. `chat_join_request`: A request to join the chat has been sent (The bot must have the can_invite_users administrator right)\n5. `polling_error`: Error occurred during polling. See [polling errors](#polling-errors).\n6. `webhook_error`: Error occurred handling a webhook request. See [webhook errors](#webhook-errors).\n7. `error`: Unexpected error occurred, usually fatal!\n\n**Tip:** Its much better to listen a specific event rather than on\n`message` in order to stay safe from the content.\n\n**Tip:** Bot must be enabled on [inline mode][inline-mode] for receive some\nmessages.\n\n<a name=\"webhooks\"></a>\n## WebHooks\n\nTelegram only supports HTTPS connections to WebHooks.\nTherefore, in order to set a WebHook, you will need a SSL certificate.\nSince August 29, 2015 Telegram supports self-signed ones, thus, you can\ngenerate them:\n\n```bash\n# Our private cert will be key.pem, keep this file private\n$ openssl genrsa -out key.pem 2048\n\n# Our public certificate will be crt.pem\n$ openssl req -new -sha256 -key key.pem -out crt.pem\n```\n\nOnce they are generated, the `crt.pem` should be uploaded, when setting up\nyour webhook. For example,\n\n```js\nbot.setWebHook('public-url.com', {\n  certificate: 'path/to/crt.pem', // Path to your crt.pem\n});\n```\n\n**Note:** If you encounter an error, like\n`Error: error:0906D06C:PEM routines:PEM_read_bio:no start line`,\nyou may want to proceed to [this issue][issue-63] for more information.\n\n<a name=\"sending-files\"></a>\n## Sending files\n\nThe library makes it easy to get started sending files. *By default*, you\nmay provide a **file-path** and the library will handle reading it for you.\nFor example,\n\n```js\nbot.sendAudio(chatId, 'path/to/audio.mp3');\n```\n\nYou may also pass in a **Readable Stream** from which data will be piped.\nFor example,\n\n```js\nconst stream = fs.createReadStream('path/to/audio.mp3');\nbot.sendAudio(chatId, stream);\n```\n\nYou may also pass in a **Buffer** containing the contents of your file.\nFor example,\n\n```js\nconst buffer = fs.readFileSync('path/to/audio.mp3'); // sync! that's sad! :-( Just making a point!\nbot.sendAudio(chatId, buffer);\n```\n\nIf you already have a **File ID**, you earlier retrieved from Telegram,\nyou may pass it in, for example:\n\n```js\nconst fileId = getFileIdSomehow();\nbot.sendAudio(chatId, fileId);\n```\n\nSome API methods, such as *SendPhoto*, allow passing a **HTTP URL**, that\nthe Telegram servers will use to download the file. For example,\n\n```js\nconst url = 'https://telegram.org/img/t_logo.png';\nbot.sendPhoto(chatId, url);\n```\n\nIf you wish to explicitly specify the filename or\n[MIME type](http://en.wikipedia.org/wiki/Internet_media_type),\nyou may pass an additional argument as file options, like so:\n\n```js\nconst fileOptions = {\n  // Explicitly specify the file name.\n  filename: 'customfilename',\n  // Explicitly specify the MIME type.\n  contentType: 'audio/mpeg',\n};\nbot.sendAudio(chatId, data, {}, fileOptions);\n```\n\n**NOTE:** You **MUST** provide an empty object (`{}`) in place of\n*Additional Telegram query options*, if you have **no** query options\nto specify. For example,\n\n```js\n// WRONG!\n// 'fileOptions' will be taken as additional Telegram query options!!!\nbot.sendAudio(chatId, data, fileOptions);\n\n// RIGHT!\nbot.sendAudio(chatId, data, {}, fileOptions);\n```\n\n\n<a name=\"sending-files-options\"></a>\n### File Options (metadata)\n\nWhen sending files, the library automatically resolves\nthe `filename` and `contentType` properties.\n**For now, this has to be manually activated using environment\nvariable `NTBA_FIX_350`.**\n\nIn order of highest-to-lowest precedence in searching for\na value, when resolving the `filename`:\n\n*(`fileOptions` is the Object argument passed to the method.\nThe \"file\" argument passed to the method can be a `Stream`,\n`Buffer` or `filepath`.)*\n\n1. Is `fileOptions.filename` explictly defined?\n1. Does `Stream#path` exist?\n1. Is `filepath` provided?\n1. Default to `\"filename\"`\n\nAnd the `contentType`:\n\n1. Is `fileOptions.contentType` explictly-defined?\n1. Does `Stream#path` exist?\n1. Try detecting file-type from the `Buffer`\n1. Is `filepath` provided?\n1. Is `fileOptions.filename` explicitly defined?\n1. Default to `\"application/octet-stream\"`\n\n<a name=\"sending-files-performance\"></a>\n### Performance Issue\n\nTo support providing file-paths to methods that send files involves\nperforming a file operation, i.e. *fs.existsSync()*, that checks for\nthe existence of the file at the provided path. While the cost of\nthis operation *might* be negligible in most use cases, if you want\nto squeeze the best performance out of this library, you may wish to\ndisable this behavior.\n\nThis will mean that you will **NOT** be able to pass in file-paths.\nYou will have to use Streams or Buffers to provide the file contents.\n\nDisabling this behavior:\n\n```js\nconst bot = new TelegramBot(token, {\n  filepath: false,\n});\n```\n\n<a name=\"error-handling\"></a>\n## Error handling\n\nEvery `Error` object we pass back has the properties:\n\n* `code` (String):\n  * value is `EFATAL` if error was fatal e.g. network error\n  * value is `EPARSE` if response body could **not** be parsed\n  * value is `ETELEGRAM` if error was returned from Telegram servers\n* `response` ([http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)):\n  * available if `error.code` is **not** `EFATAL`\n* `response.body` (String|Object): Error response from Telegram\n  * type is `String` if `error.code` is `EPARSE`\n  * type is `Object` if `error.code` is `ETELEGRAM`\n\nFor example, sending message to a non-existent user:\n\n```js\nbot.sendMessage(nonExistentUserId, 'text').catch((error) => {\n  console.log(error.code);  // => 'ETELEGRAM'\n  console.log(error.response.body); // => { ok: false, error_code: 400, description: 'Bad Request: chat not found' }\n});\n```\n\n<a name=\"polling-errors\"></a>\n## Polling errors\n\nAn error may occur during polling. It is up to you to handle it\nas you see fit. You may decide to crash your bot after a maximum number\nof polling errors occurring. **It is all up to you.**\n\nBy default, the polling error is just logged to stderr, if you do\n**not** handle this event yourself.\n\nListen on the `'polling_error'` event. For example,\n\n```js\nbot.on('polling_error', (error) => {\n  console.log(error.code);  // => 'EFATAL'\n});\n```\n\n<a name=\"webhook-errors\"></a>\n## WebHook errors\n\nJust like with [polling errors](#polling-errors), you decide on how to\nhandle it. By default, the error is logged to stderr.\n\nListen on the `'webhook_error'` event. For example,\n\n```js\nbot.on('webhook_error', (error) => {\n  console.log(error.code);  // => 'EPARSE'\n});\n```\n\n[update]:https://core.telegram.org/bots/api#update\n[message]:https://core.telegram.org/bots/api#message\n[callback-query]:https://core.telegram.org/bots/api#callbackquery\n[inline-query]:https://core.telegram.org/bots/api#inlinequery\n[chosen-inline-result]:https://core.telegram.org/bots/api#choseninlineresult\n[inline-mode]:https://core.telegram.org/bots/api#inline-mode\n[issue-63]:https://github.com/yagop/node-telegram-bot-api/issues/63\n"
  },
  {
    "path": "examples/game/game.html",
    "content": "<!-- Game example taken from w3schools (https://www.w3schools.com/graphics/game_intro.asp) -->\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"/>\n    <style>\n    body {\n      font-family: 'Courier ';\n      text-align: center;\n    }\n    canvas {\n      border:1px solid #d3d3d3;\n      background-color: #f1f1f1;\n    }\n    </style>\n  </head>\n  <body onload=\"startGame()\">\n    <p><button onmousedown=\"accelerate(-0.2)\" onmouseup=\"accelerate(0.05)\">ACCELERATE</button></p>\n    <p>Use the ACCELERATE button to stay in the air</p>\n    <p>How long can you stay alive?</p>\n    <script>\nvar myGamePiece;\nvar myObstacles = [];\nvar myScore;\n\nfunction startGame() {\n    myGamePiece = new component(30, 30, \"red\", 10, 120);\n    myGamePiece.gravity = 0.05;\n    myScore = new component(\"30px\", \"Consolas\", \"black\", 280, 40, \"text\");\n    myGameArea.start();\n}\n\nvar myGameArea = {\n    canvas : document.createElement(\"canvas\"),\n    start : function() {\n        this.canvas.width = 480;\n        this.canvas.height = 270;\n        this.context = this.canvas.getContext(\"2d\");\n        document.body.insertBefore(this.canvas, document.body.childNodes[0]);\n        this.frameNo = 0;\n        this.interval = setInterval(updateGameArea, 20);\n        },\n    clear : function() {\n        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);\n    }\n}\n\nfunction component(width, height, color, x, y, type) {\n    this.type = type;\n    this.score = 0;\n    this.width = width;\n    this.height = height;\n    this.speedX = 0;\n    this.speedY = 0;\n    this.x = x;\n    this.y = y;\n    this.gravity = 0;\n    this.gravitySpeed = 0;\n    this.update = function() {\n        ctx = myGameArea.context;\n        if (this.type == \"text\") {\n            ctx.font = this.width + \" \" + this.height;\n            ctx.fillStyle = color;\n            ctx.fillText(this.text, this.x, this.y);\n        } else {\n            ctx.fillStyle = color;\n            ctx.fillRect(this.x, this.y, this.width, this.height);\n        }\n    }\n    this.newPos = function() {\n        this.gravitySpeed += this.gravity;\n        this.x += this.speedX;\n        this.y += this.speedY + this.gravitySpeed;\n        this.hitBottom();\n    }\n    this.hitBottom = function() {\n        var rockbottom = myGameArea.canvas.height - this.height;\n        if (this.y > rockbottom) {\n            this.y = rockbottom;\n            this.gravitySpeed = 0;\n        }\n    }\n    this.crashWith = function(otherobj) {\n        var myleft = this.x;\n        var myright = this.x + (this.width);\n        var mytop = this.y;\n        var mybottom = this.y + (this.height);\n        var otherleft = otherobj.x;\n        var otherright = otherobj.x + (otherobj.width);\n        var othertop = otherobj.y;\n        var otherbottom = otherobj.y + (otherobj.height);\n        var crash = true;\n        if ((mybottom < othertop) || (mytop > otherbottom) || (myright < otherleft) || (myleft > otherright)) {\n            crash = false;\n        }\n        return crash;\n    }\n}\n\nfunction updateGameArea() {\n    var x, height, gap, minHeight, maxHeight, minGap, maxGap;\n    for (i = 0; i < myObstacles.length; i += 1) {\n        if (myGamePiece.crashWith(myObstacles[i])) {\n            return;\n        }\n    }\n    myGameArea.clear();\n    myGameArea.frameNo += 1;\n    if (myGameArea.frameNo == 1 || everyinterval(150)) {\n        x = myGameArea.canvas.width;\n        minHeight = 20;\n        maxHeight = 200;\n        height = Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight);\n        minGap = 50;\n        maxGap = 200;\n        gap = Math.floor(Math.random()*(maxGap-minGap+1)+minGap);\n        myObstacles.push(new component(10, height, \"green\", x, 0));\n        myObstacles.push(new component(10, x - height - gap, \"green\", x, height + gap));\n    }\n    for (i = 0; i < myObstacles.length; i += 1) {\n        myObstacles[i].x += -1;\n        myObstacles[i].update();\n    }\n    myScore.text=\"SCORE: \" + myGameArea.frameNo;\n    myScore.update();\n    myGamePiece.newPos();\n    myGamePiece.update();\n}\n\nfunction everyinterval(n) {\n    if ((myGameArea.frameNo / n) % 1 == 0) {return true;}\n    return false;\n}\n\nfunction accelerate(n) {\n    myGamePiece.gravity = n;\n}\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/game/game.js",
    "content": "/**\n * This example demonstrates using HTML5 games with Telegram.\n */\n/* eslint-disable no-console */\n\nconst TOKEN = process.env.TELEGRAM_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN';\nconst gameName = process.env.TELEGRAM_GAMENAME || 'YOUR_TELEGRAM_GAMENAME';\n// Specify '0' to use ngrok i.e. localhost tunneling\nlet url = process.env.URL || 'https://<PUBLIC-URL>';\nconst port = process.env.PORT || 8080;\n\nconst TelegramBot = require('../..');\nconst express = require('express');\nconst path = require('path');\n\nconst bot = new TelegramBot(TOKEN, { polling: true });\nconst app = express();\n\n// Basic configurations\napp.set('view engine', 'ejs');\n\n// Tunnel to localhost.\n// This is just for demo purposes.\n// In your application, you will be using a static URL, probably that\n// you paid for. :)\nif (url === '0') {\n  const ngrok = require('ngrok');\n  ngrok.connect(port, function onConnect(error, u) {\n    if (error) throw error;\n    url = u;\n    console.log(`Game tunneled at ${url}`);\n  });\n}\n\n// Matches /start\nbot.onText(/\\/start/, function onPhotoText(msg) {\n  bot.sendGame(msg.chat.id, gameName);\n});\n\n// Handle callback queries\nbot.on('callback_query', function onCallbackQuery(callbackQuery) {\n  bot.answerCallbackQuery(callbackQuery.id, { url });\n});\n\n// Render the HTML game\napp.get('/', function requestListener(req, res) {\n  res.sendFile(path.join(__dirname, 'game.html'));\n});\n\n// Bind server to port\napp.listen(port, function listen() {\n  console.log(`Server is listening at http://localhost:${port}`);\n});\n"
  },
  {
    "path": "examples/polling.js",
    "content": "/**\n * This example demonstrates using polling.\n * It also demonstrates how you would process and send messages.\n */\n\n\nconst TOKEN = process.env.TELEGRAM_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN';\nconst TelegramBot = require('..');\nconst request = require('@cypress/request');\nconst options = {\n  polling: true\n};\nconst bot = new TelegramBot(TOKEN, options);\n\n\n// Matches /photo\nbot.onText(/\\/photo/, function onPhotoText(msg) {\n  // From file path\n  const photo = `${__dirname}/../test/data/photo.gif`;\n  bot.sendPhoto(msg.chat.id, photo, {\n    caption: \"I'm a bot!\"\n  });\n});\n\n\n// Matches /audio\nbot.onText(/\\/audio/, function onAudioText(msg) {\n  // From HTTP request\n  const url = 'https://upload.wikimedia.org/wikipedia/commons/c/c8/Example.ogg';\n  const audio = request(url);\n  bot.sendAudio(msg.chat.id, audio);\n});\n\n\n// Matches /love\nbot.onText(/\\/love/, function onLoveText(msg) {\n  const opts = {\n    reply_to_message_id: msg.message_id,\n    reply_markup: JSON.stringify({\n      keyboard: [\n        ['Yes, you are the bot of my life ❤'],\n        ['No, sorry there is another one...']\n      ]\n    })\n  };\n  bot.sendMessage(msg.chat.id, 'Do you love me?', opts);\n});\n\n\n// Matches /echo [whatever]\nbot.onText(/\\/echo (.+)/, function onEchoText(msg, match) {\n  const resp = match[1];\n  bot.sendMessage(msg.chat.id, resp);\n});\n\n\n// Matches /editable\nbot.onText(/\\/editable/, function onEditableText(msg) {\n  const opts = {\n    reply_markup: {\n      inline_keyboard: [\n        [\n          {\n            text: 'Edit Text',\n            // we shall check for this value when we listen\n            // for \"callback_query\"\n            callback_data: 'edit'\n          }\n        ]\n      ]\n    }\n  };\n  bot.sendMessage(msg.from.id, 'Original Text', opts);\n});\n\n\n// Handle callback queries\nbot.on('callback_query', function onCallbackQuery(callbackQuery) {\n  const action = callbackQuery.data;\n  const msg = callbackQuery.message;\n  const opts = {\n    chat_id: msg.chat.id,\n    message_id: msg.message_id,\n  };\n  let text;\n\n  if (action === 'edit') {\n    text = 'Edited Text';\n  }\n\n  bot.editMessageText(text, opts);\n});\n"
  },
  {
    "path": "examples/ssl/crt.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDmTCCAoGgAwIBAgIJAPz/mOxHHCRKMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV\nBAYTAlVTMQ0wCwYDVQQIDARVdGFoMQ4wDAYDVQQHDAVQcm92bzEjMCEGA1UECgwa\nQUNNRSBTaWduaW5nIEF1dGhvcml0eSBJbmMxEDAOBgNVBAMMB3lhZ28ubWUwHhcN\nMTUwNjI4MTk0MjAxWhcNMTgwNzA2MTk0MjAxWjBjMQswCQYDVQQGEwJVUzENMAsG\nA1UECAwEVXRhaDEOMAwGA1UEBwwFUHJvdm8xIzAhBgNVBAoMGkFDTUUgU2lnbmlu\nZyBBdXRob3JpdHkgSW5jMRAwDgYDVQQDDAd5YWdvLm1lMIIBIjANBgkqhkiG9w0B\nAQEFAAOCAQ8AMIIBCgKCAQEAw9YiYXN1s5KcoZy7UZyiXULpTrYPhlPhzlyJJdwg\ne61C/swbqtnh/+fPZp8g8a15ond9ShUvWLcxeoDBzxn0hJIEe+DlNNHUAdWoTWUx\nOP4hHDA6wCFepHWBlw10AoKAjoQA+nCX6NrdiFTpbodkEK0H4uOSCt37H616kdKU\nwRgXlca2Kw88UQ0qhKteb5hYD5tm4aCv6eRCqwYdYKUG+D1uJuJ+YZmaaIXp/5QZ\nq3a6mFsKLtUC33bhZZPr1qjh3zwF2JTZX1WFAxUHNxY5NVchUYDHjw0djXvw85il\niwWKFjFXfvk8WTfW3Ge3754BhYSt92Qj6BROD2AODhI8jwIDAQABo1AwTjAdBgNV\nHQ4EFgQUpgp5hovXcW+eIb3xRkF1KSJb/rwwHwYDVR0jBBgwFoAUpgp5hovXcW+e\nIb3xRkF1KSJb/rwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAjnKW\n+3lHe92Ut9XJdqGJsuRV5OUh8suOicz+AXtqUdoG9xbkv5N6Ynt+r06NjnYgTIzk\ni+9fXBZLrXH8qNT2PTzErs0LMXPWxWbiZwY9mI2z/xW/K6CFjb1h33hk+ypwTr1J\nQ1Eqy77FXKfQ2Y8kNLARSkvUEMm7UnVbUqRbA8AlWk9HZmoPHYfKPRGRVeIugH76\nb6Gm3ztmIgTZQ88+DxfedIjPib3LPsHIXrA2Qd8yrIaYDiE2HMMJ5q3SYdRY4yYB\n2a3P7jCPZfKVKpRE0J0yeNH+wQL0bzCMbl2wBUhivXD+sM00Xe3a22eAYbNgLdEg\n4Hvd/YIKm9yOjRolmw==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "examples/ssl/key.pem",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAw9YiYXN1s5KcoZy7UZyiXULpTrYPhlPhzlyJJdwge61C/swb\nqtnh/+fPZp8g8a15ond9ShUvWLcxeoDBzxn0hJIEe+DlNNHUAdWoTWUxOP4hHDA6\nwCFepHWBlw10AoKAjoQA+nCX6NrdiFTpbodkEK0H4uOSCt37H616kdKUwRgXlca2\nKw88UQ0qhKteb5hYD5tm4aCv6eRCqwYdYKUG+D1uJuJ+YZmaaIXp/5QZq3a6mFsK\nLtUC33bhZZPr1qjh3zwF2JTZX1WFAxUHNxY5NVchUYDHjw0djXvw85iliwWKFjFX\nfvk8WTfW3Ge3754BhYSt92Qj6BROD2AODhI8jwIDAQABAoIBAQCga6gMNh2DtSTT\nimUzrGCgjvA5RxAelFYTyl+agOCnDz4jJKXBZewoygZuZQoCj31lJgafCg2X2bER\nTan1caiIdGhx5b88bmoB+rh8ddlFe3857RQjUPKLO6qlRyLx719J3z5B6Lu3xpnU\nVOJHZWcF9gfQx2RZvI862svd6idqqFfKRVr7jxur1VuTQpk6g0xi6GnFk9s6sPw9\nChT6ykxzx+fQmYzeEW6SbWilOnm9BGuAEI2G7/mDQ6NFGFvFdPivI908vHPGbhFz\nIfdwt5F9NwQrSzYaDnYzCWrEmqSz9uRmX5DD9FwFokjN2d6o3V0/+1BrWLKDBDj+\njYcOV5IBAoGBAOFLTbfRLPP0z4vgTX8FeaZXreJQPblHmJQNwvJEYiiug4aDXCLv\nuBEVR+H1Y/Pm1U4s5LNESg2pOC0IZOElvAck+SY/K1KZFI9EzBLa0aybFOuLaHY1\nZ9cZfc1Cg3Vmpqnkyqahi+Tt1U/nayL3DFNcIwI30DweS+KLUmjIxxMBAoGBAN6H\nByD0+d3pfqkusTI3GT1NfWMBwS+usCayLP1gMpA+0tT+/lnYLLbmINaD6hoztWWD\nOUZ7PM3HkOXKly2bfKxlT8Bi3b0QpNyd54ybj4/60JLRAO5OU773an8MMsov+q1V\nxWYGVMnNihXFFVGaIK8dG/2mYomHjbzx3az/EZ+PAoGAJs3pnPeSXpKUDOudbXtr\n8JK5iHl5qCgEx7t3EHNm1Mr6LHkDraDMe2TG9MxnYuMnakehPJ9OgfvbiSYg+gad\n1D0yDLxkod1sBSE8ZSL7aldrywY//9xC/nGNkYUbT2VW33xgy0KX7d5pF1IsyeDz\nZohAH2mtnC07tNF6aEHsyAECgYAJ3EHcm/5WbvpF1OPVLcvYg46CzJka28rCbDLC\nJ3kWGzKMbaAnqwSQNjJOTxoYfyISlXX8QYm4NJefFxML2k/z86lNBRR+RDaJ8BVK\njboWzy5e0xQPezkKxTva1VeKzgV1mM9ebflj18++lzUSoJnCKLAM1UqYfYEyViVU\nfRjy0QKBgQCopUy7KDdKngBrSQwI9lMi1/bZJTXw1WktLZRma3uIw8uBKB2Fyf4/\n7xFo49Ha7l1W38PfkqOS+539V8cJSyyJKq+PgBQ8fuLCplCDeZCieSiYm+FkpIr0\n4V+hEMIkVuUBDwCbyMM5mUH+sBVtmzNYDRgYa5QN4FIBk8VcBgsIhw==\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "examples/webhook/express.js",
    "content": "/**\n * This example demonstrates setting up a webook, and receiving\n * updates in your express app\n */\n/* eslint-disable no-console */\n\nconst TOKEN = process.env.TELEGRAM_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN';\nconst url = 'https://<PUBLIC-URL>';\nconst port = process.env.PORT;\n\nconst TelegramBot = require('../..');\nconst express = require('express');\n\n// No need to pass any parameters as we will handle the updates with Express\nconst bot = new TelegramBot(TOKEN);\n\n// This informs the Telegram servers of the new webhook.\nbot.setWebHook(`${url}/bot${TOKEN}`);\n\nconst app = express();\n\n// parse the updates to JSON\napp.use(express.json());\n\n// We are receiving updates at the route below!\napp.post(`/bot${TOKEN}`, (req, res) => {\n  bot.processUpdate(req.body);\n  res.sendStatus(200);\n});\n\n// Start Express Server\napp.listen(port, () => {\n  console.log(`Express server is listening on ${port}`);\n});\n\n// Just to ping!\nbot.on('message', msg => {\n  bot.sendMessage(msg.chat.id, 'I am alive!');\n});\n"
  },
  {
    "path": "examples/webhook/heroku.js",
    "content": "/**\n * This example demonstrates setting up webhook\n * on the Heroku platform.\n */\n\n\nconst TOKEN = process.env.TELEGRAM_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN';\nconst TelegramBot = require('../..');\nconst options = {\n  webHook: {\n    // Port to which you should bind is assigned to $PORT variable\n    // See: https://devcenter.heroku.com/articles/dynos#local-environment-variables\n    port: process.env.PORT\n    // you do NOT need to set up certificates since Heroku provides\n    // the SSL certs already (https://<app-name>.herokuapp.com)\n    // Also no need to pass IP because on Heroku you need to bind to 0.0.0.0\n  }\n};\n// Heroku routes from port :443 to $PORT\n// Add URL of your app to env variable or enable Dyno Metadata\n// to get this automatically\n// See: https://devcenter.heroku.com/articles/dyno-metadata\nconst url = process.env.APP_URL || 'https://<app-name>.herokuapp.com:443';\nconst bot = new TelegramBot(TOKEN, options);\n\n\n// This informs the Telegram servers of the new webhook.\n// Note: we do not need to pass in the cert, as it already provided\nbot.setWebHook(`${url}/bot${TOKEN}`);\n\n\n// Just to ping!\nbot.on('message', function onMessage(msg) {\n  bot.sendMessage(msg.chat.id, 'I am alive on Heroku!');\n});\n"
  },
  {
    "path": "examples/webhook/https.js",
    "content": "/**\n * This example demonstrates setting up a webook, using a\n * self-signed certificate.\n */\n\n\nconst TOKEN = process.env.TELEGRAM_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN';\nconst TelegramBot = require('../..');\nconst options = {\n  webHook: {\n    port: 443,\n    key: `${__dirname}/../ssl/key.pem`, // Path to file with PEM private key\n    cert: `${__dirname}/../ssl/crt.pem` // Path to file with PEM certificate\n  }\n};\n// This URL must route to the port set above (i.e. 443)\nconst url = 'https://<PUBLIC-URL>';\nconst bot = new TelegramBot(TOKEN, options);\n\n\n// This informs the Telegram servers of the new webhook.\nbot.setWebHook(`${url}/bot${TOKEN}`, {\n  certificate: options.webHook.cert,\n});\n\n\n// Just to ping!\nbot.on('message', function onMessage(msg) {\n  bot.sendMessage(msg.chat.id, 'I am alive!');\n});\n"
  },
  {
    "path": "examples/webhook/now.js",
    "content": "/**\n * This example demonstrates setting up webhook on Zeit Now platform.\n * Attention: You have to use webhook with Zeit Now only, polling doesn't\n * work.\n */\n\n\nconst TOKEN = process.env.TELEGRAM_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN';\nconst TelegramBot = require('../..');\nconst options = {\n  webHook: {\n    // Just use 443 directly\n    port: 443\n  }\n};\n// You can use 'now alias <your deployment url> <custom url>' to assign fixed\n// domain.\n// See: https://zeit.co/blog/now-alias\n// Or just use NOW_URL to get deployment url from env.\nconst url = 'YOUR_DOMAIN_ALIAS' || process.env.NOW_URL;\nconst bot = new TelegramBot(TOKEN, options);\n\n\n// This informs the Telegram servers of the new webhook.\n// Note: we do not need to pass in the cert, as it already provided\nbot.setWebHook(`${url}/bot${TOKEN}`);\n\n\n// Just to ping!\nbot.on('message', function onMessage(msg) {\n  bot.sendMessage(msg.chat.id, 'I am alive on Zeit Now!');\n});\n"
  },
  {
    "path": "examples/webhook/openshift2.js",
    "content": "/**\n * This example demonstrates setting up webhook\n * on the OpenShift platform.\n *\n * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n * NOTE:\n *\n * Openshift 2 has been shut down.\n *\n * This example is kept here for historical/educational purposes.\n * No changes are expected to be made to the source code below.\n *\n * See https://github.com/yagop/node-telegram-bot-api/issues/426 for\n * more information.\n * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n */\n\n\nconst TOKEN = process.env.TELEGRAM_TOKEN || 'YOUR_TELEGRAM_BOT_TOKEN';\nconst TelegramBot = require('../..');\n// See https://developers.openshift.com/en/node-js-environment-variables.html\nconst options = {\n  webHook: {\n    port: process.env.OPENSHIFT_NODEJS_PORT,\n    host: process.env.OPENSHIFT_NODEJS_IP,\n    // you do NOT need to set up certificates since OpenShift provides\n    // the SSL certs already (https://<app-name>.rhcloud.com)\n  },\n};\n// OpenShift routes from port :443 to OPENSHIFT_NODEJS_PORT\nconst domain = process.env.OPENSHIFT_APP_DNS;\nconst url = `${domain}:443`;\nconst bot = new TelegramBot(TOKEN, options);\n\n\n// This informs the Telegram servers of the new webhook.\n// Note: we do not need to pass in the cert, as it already provided\nbot.setWebHook(`${url}/bot${TOKEN}`);\n\n\n// Just to ping!\nbot.on('message', function onMessage(msg) {\n  bot.sendMessage(msg.chat.id, 'I am alive on OpenShift!');\n});\n"
  },
  {
    "path": "index.js",
    "content": "/**\n * If running on Nodejs 5.x and below, we load the transpiled code.\n * Otherwise, we use the ES6 code.\n * We are deprecating support for Node.js v5.x and below.\n */\nconst majorVersion = parseInt(process.versions.node.split('.')[0], 10);\nif (majorVersion <= 5) {\n  const deprecate = require('./src/utils').deprecate;\n  deprecate('Node.js v5.x and below will no longer be supported in the future');\n  module.exports = require('./lib/telegram');\n} else {\n  module.exports = require('./src/telegram');\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"node-telegram-bot-api\",\n  \"version\": \"0.68.0\",\n  \"description\": \"Telegram Bot API\",\n  \"main\": \"./index.js\",\n  \"directories\": {\n    \"example\": \"examples\",\n    \"test\": \"test\"\n  },\n  \"keywords\": [\n    \"telegram\",\n    \"telegram bot\",\n    \"telegram bot api\",\n    \"bot\"\n  ],\n  \"scripts\": {\n    \"gen-doc\": \"echo 'WARNING: `npm run gen-doc` is deprecated. Use `npm run doc` instead.' && npm run doc\",\n    \"doc\": \"jsdoc2md --files src/telegram.js --template doc/api.hbs > doc/api.md\",\n    \"build\": \"babel -d ./lib src\",\n    \"prepublishOnly\": \"npm run build && npm run gen-doc\",\n    \"eslint\": \"eslint ./src ./test ./examples\",\n    \"mocha\": \"mocha\",\n    \"pretest\": \"npm run build\",\n    \"test\": \"npm run eslint && istanbul cover ./node_modules/mocha/bin/_mocha\"\n  },\n  \"author\": \"Yago Pérez <yagoperezs@gmail.com>\",\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=0.12\"\n  },\n  \"dependencies\": {\n    \"@cypress/request\": \"^3.0.8\",\n    \"@cypress/request-promise\": \"^5.0.0\",\n    \"array.prototype.findindex\": \"^2.0.2\",\n    \"bl\": \"^1.2.3\",\n    \"debug\": \"^3.2.7\",\n    \"eventemitter3\": \"^3.0.0\",\n    \"file-type\": \"^3.9.0\",\n    \"mime\": \"^1.6.0\",\n    \"pump\": \"^2.0.0\"\n  },\n  \"devDependencies\": {\n    \"babel-cli\": \"^6.26.0\",\n    \"babel-eslint\": \"^8.0.3\",\n    \"babel-plugin-transform-class-properties\": \"^6.24.1\",\n    \"babel-plugin-transform-es2015-destructuring\": \"^6.23.0\",\n    \"babel-plugin-transform-es2015-parameters\": \"^6.24.1\",\n    \"babel-plugin-transform-es2015-shorthand-properties\": \"^6.24.1\",\n    \"babel-plugin-transform-es2015-spread\": \"^6.22.0\",\n    \"babel-plugin-transform-object-rest-spread\": \"^6.26.0\",\n    \"babel-plugin-transform-strict-mode\": \"^6.24.1\",\n    \"babel-preset-es2015\": \"^6.24.1\",\n    \"babel-register\": \"^6.26.0\",\n    \"concat-stream\": \"^1.6.0\",\n    \"eslint\": \"^2.13.1\",\n    \"eslint-config-airbnb\": \"^6.2.0\",\n    \"eslint-plugin-mocha\": \"^4.11.0\",\n    \"is\": \"^3.2.1\",\n    \"is-ci\": \"^1.0.10\",\n    \"istanbul\": \"^1.1.0-alpha.1\",\n    \"jsdoc-to-markdown\": \"^9.1.3\",\n    \"mocha\": \"^3.5.3\",\n    \"mocha-lcov-reporter\": \"^1.3.0\",\n    \"node-static\": \"^0.7.10\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/yagop/node-telegram-bot-api.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/yagop/node-telegram-bot-api/issues\"\n  },\n  \"homepage\": \"https://github.com/yagop/node-telegram-bot-api\"\n}\n"
  },
  {
    "path": "src/errors.js",
    "content": "exports.BaseError = class BaseError extends Error {\n  /**\n   * @class BaseError\n   * @constructor\n   * @private\n   * @param  {String} code Error code\n   * @param  {String} message Error message\n   */\n  constructor(code, message) {\n    super(`${code}: ${message}`);\n    this.code = code;\n  }\n  toJSON() {\n    return {\n      code: this.code,\n      message: this.message,\n    };\n  }\n};\n\n\nexports.FatalError = class FatalError extends exports.BaseError {\n  /**\n   * Fatal Error. Error code is `\"EFATAL\"`.\n   * @class FatalError\n   * @constructor\n   * @param  {String|Error} data Error object or message\n   */\n  constructor(data) {\n    const error = (typeof data === 'string') ? null : data;\n    const message = error ? error.message : data;\n    super('EFATAL', message);\n    if (error) {\n      this.stack = error.stack;\n      this.cause = error;\n    }\n  }\n};\n\n\nexports.ParseError = class ParseError extends exports.BaseError {\n  /**\n   * Error during parsing. Error code is `\"EPARSE\"`.\n   * @class ParseError\n   * @constructor\n   * @param  {String} message Error message\n   * @param  {http.IncomingMessage} response Server response\n   */\n  constructor(message, response) {\n    super('EPARSE', message);\n    this.response = response;\n  }\n};\n\n\nexports.TelegramError = class TelegramError extends exports.BaseError {\n  /**\n   * Error returned from Telegram. Error code is `\"ETELEGRAM\"`.\n   * @class TelegramError\n   * @constructor\n   * @param  {String} message Error message\n   * @param  {http.IncomingMessage} response Server response\n   */\n  constructor(message, response) {\n    super('ETELEGRAM', message);\n    this.response = response;\n  }\n};\n"
  },
  {
    "path": "src/telegram.js",
    "content": "// shims\nrequire('array.prototype.findindex').shim(); // for Node.js v0.x\n\nconst errors = require('./errors');\nconst TelegramBotWebHook = require('./telegramWebHook');\nconst TelegramBotPolling = require('./telegramPolling');\nconst debug = require('debug')('node-telegram-bot-api');\nconst EventEmitter = require('eventemitter3');\nconst fileType = require('file-type');\nconst request = require('@cypress/request-promise');\nconst streamedRequest = require('@cypress/request');\nconst qs = require('querystring');\nconst stream = require('stream');\nconst mime = require('mime');\nconst path = require('path');\nconst URL = require('url');\nconst fs = require('fs');\nconst pump = require('pump');\nconst deprecate = require('./utils').deprecate;\n\nconst _messageTypes = [\n  'text',\n  'animation',\n  'audio',\n  'channel_chat_created',\n  'contact',\n  'delete_chat_photo',\n  'dice',\n  'document',\n  'game',\n  'group_chat_created',\n  'invoice',\n  'left_chat_member',\n  'location',\n  'migrate_from_chat_id',\n  'migrate_to_chat_id',\n  'new_chat_members',\n  'new_chat_photo',\n  'new_chat_title',\n  'passport_data',\n  'photo',\n  'pinned_message',\n  'poll',\n  'sticker',\n  'successful_payment',\n  'supergroup_chat_created',\n  'video',\n  'video_note',\n  'voice',\n  'video_chat_started',\n  'video_chat_ended',\n  'video_chat_participants_invited',\n  'video_chat_scheduled',\n  'message_auto_delete_timer_changed',\n  'chat_invite_link',\n  'chat_member_updated',\n  'web_app_data',\n  'message_reaction'\n];\n\nconst _deprecatedMessageTypes = [\n  'new_chat_participant', 'left_chat_participant'\n];\n\n/**\n * JSON-serialize data. If the provided data is already a String,\n * return it as is.\n * @private\n * @param {*} data\n * @return {String}\n */\nfunction stringify(data) {\n  if (typeof data === 'string') {\n    return data;\n  }\n  return JSON.stringify(data);\n}\n\n\nclass TelegramBot extends EventEmitter {\n  /**\n   * The different errors the library uses.\n   * @type {Object}\n   */\n  static get errors() {\n    return errors;\n  }\n\n  /**\n   * The types of message updates the library handles.\n   * @type {String[]}\n   */\n  static get messageTypes() {\n    return _messageTypes;\n  }\n\n  /**\n   * Add listener for the specified [event](https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#events).\n   * This is the usual `emitter.on()` method.\n   * @param {String} event\n   * @param {Function} listener\n   * @see {@link https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#events|Available events}\n   * @see https://nodejs.org/api/events.html#events_emitter_on_eventname_listener\n   */\n  on(event, listener) {\n    if (_deprecatedMessageTypes.indexOf(event) !== -1) {\n      const url = 'https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#events';\n      deprecate(`Events ${_deprecatedMessageTypes.join(',')} are deprecated. See the updated list of events: ${url}`);\n    }\n    super.on(event, listener);\n  }\n\n  /**\n   * Both request method to obtain messages are implemented. To use standard polling, set `polling: true`\n   * on `options`. Notice that [webHook](https://core.telegram.org/bots/api#setwebhook) will need a SSL certificate.\n   * Emits `message` when a message arrives.\n   *\n   * @class TelegramBot\n   * @constructor\n   * @param {String} token Bot Token\n   * @param {Object} [options]\n   * @param {Boolean|Object} [options.polling=false] Set true to enable polling or set options.\n   *  If a WebHook has been set, it will be deleted automatically.\n   * @param {String|Number} [options.polling.timeout=10] *Deprecated. Use `options.polling.params` instead*.\n   *  Timeout in seconds for long polling.\n   * @param {Boolean} [options.testEnvironment=false] Set true to  work with test enviroment.\n   * When working with the test environment, you may use HTTP links without TLS to test your Web App.\n   * @param {String|Number} [options.polling.interval=300] Interval between requests in miliseconds\n   * @param {Boolean} [options.polling.autoStart=true] Start polling immediately\n   * @param {Object} [options.polling.params] Parameters to be used in polling API requests.\n   *  See https://core.telegram.org/bots/api#getupdates for more information.\n   * @param {Number} [options.polling.params.timeout=10] Timeout in seconds for long polling.\n   * @param {Array<String>|String} [options.polling.params.allowed_updates] A JSON-serialized list of the update types you want your bot to receive.\n   *  For example, specify [\"message\", \"edited_channel_post\", \"callback_query\"] to only receive updates of these types.\n   * @param {Boolean|Object} [options.webHook=false] Set true to enable WebHook or set options\n   * @param {String} [options.webHook.host=\"0.0.0.0\"] Host to bind to\n   * @param {Number} [options.webHook.port=8443] Port to bind to\n   * @param {String} [options.webHook.key] Path to file with PEM private key for webHook server.\n   *  The file is read **synchronously**!\n   * @param {String} [options.webHook.cert] Path to file with PEM certificate (public) for webHook server.\n   *  The file is read **synchronously**!\n   * @param {String} [options.webHook.pfx] Path to file with PFX private key and certificate chain for webHook server.\n   *  The file is read **synchronously**!\n   * @param {Boolean} [options.webHook.autoOpen=true] Open webHook immediately\n   * @param {Object} [options.webHook.https] Options to be passed to `https.createServer()`.\n   *  Note that `options.webHook.key`, `options.webHook.cert` and `options.webHook.pfx`, if provided, will be\n   *  used to override `key`, `cert` and `pfx` in this object, respectively.\n   *  See https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener for more information.\n   * @param {String} [options.webHook.healthEndpoint=\"/healthz\"] An endpoint for health checks that always responds with 200 OK\n   * @param {Boolean} [options.onlyFirstMatch=false] Set to true to stop after first match. Otherwise, all regexps are executed\n   * @param {Object} [options.request] Options which will be added for all requests to telegram api.\n   *  See https://github.com/request/request#requestoptions-callback for more information.\n   * @param {String} [options.baseApiUrl=\"https://api.telegram.org\"] API Base URl; useful for proxying and testing\n   * @param {Boolean} [options.filepath=true] Allow passing file-paths as arguments when sending files,\n   *  such as photos using `TelegramBot#sendPhoto()`. See [usage information][usage-sending-files-performance]\n   *  for more information on this option and its consequences.\n   * @param {Boolean} [options.badRejection=false] Set to `true`\n   *  **if and only if** the Node.js version you're using terminates the\n   *  process on unhandled rejections. This option is only for\n   *  *forward-compatibility purposes*.\n   * @see https://core.telegram.org/bots/api\n   */\n  constructor(token, options = {}) {\n    super();\n    this.token = token;\n    this.options = options;\n    this.options.polling = (typeof options.polling === 'undefined') ? false : options.polling;\n    this.options.webHook = (typeof options.webHook === 'undefined') ? false : options.webHook;\n    this.options.baseApiUrl = options.baseApiUrl || 'https://api.telegram.org';\n    this.options.filepath = (typeof options.filepath === 'undefined') ? true : options.filepath;\n    this.options.badRejection = (typeof options.badRejection === 'undefined') ? false : options.badRejection;\n    this._textRegexpCallbacks = [];\n    this._replyListenerId = 0;\n    this._replyListeners = [];\n    this._polling = null;\n    this._webHook = null;\n\n    if (options.polling) {\n      const autoStart = options.polling.autoStart;\n      if (typeof autoStart === 'undefined' || autoStart === true) {\n        this.startPolling();\n      }\n    }\n\n    if (options.webHook) {\n      const autoOpen = options.webHook.autoOpen;\n      if (typeof autoOpen === 'undefined' || autoOpen === true) {\n        this.openWebHook();\n      }\n    }\n  }\n\n  /**\n   * Generates url with bot token and provided path/method you want to be got/executed by bot\n   * @param {String} path\n   * @return {String} url\n   * @private\n   * @see https://core.telegram.org/bots/api#making-requests\n   */\n  _buildURL(_path) {\n    return `${this.options.baseApiUrl}/bot${this.token}${this.options.testEnvironment ? '/test' : ''}/${_path}`;\n  }\n\n  /**\n   * Fix 'reply_markup' parameter by making it JSON-serialized, as\n   * required by the Telegram Bot API\n   * @param {Object} obj Object; either 'form' or 'qs'\n   * @private\n   * @see https://core.telegram.org/bots/api#sendmessage\n   */\n  _fixReplyMarkup(obj) {\n    const replyMarkup = obj.reply_markup;\n    if (replyMarkup && typeof replyMarkup !== 'string') {\n      obj.reply_markup = stringify(replyMarkup);\n    }\n  }\n\n  /**\n   * Fix 'entities' or 'caption_entities' or 'explanation_entities' parameter by making it JSON-serialized, as\n   * required by the Telegram Bot API\n   * @param {Object} obj Object;\n   * @private\n   * @see https://core.telegram.org/bots/api#sendmessage\n   * @see https://core.telegram.org/bots/api#copymessage\n   * @see https://core.telegram.org/bots/api#sendpoll\n   */\n  _fixEntitiesField(obj) {\n    const entities = obj.entities;\n    const captionEntities = obj.caption_entities;\n    const explanationEntities = obj.explanation_entities;\n    if (entities && typeof entities !== 'string') {\n      obj.entities = stringify(entities);\n    }\n\n    if (captionEntities && typeof captionEntities !== 'string') {\n      obj.caption_entities = stringify(captionEntities);\n    }\n\n    if (explanationEntities && typeof explanationEntities !== 'string') {\n      obj.explanation_entities = stringify(explanationEntities);\n    }\n  }\n\n  _fixAddFileThumbnail(options, opts) {\n    if (options.thumb) {\n      deprecate('The \"thumb\" parameter was renamed to \"thumbnail\" in Telegram Bot API v6.6. Please use the renamed parameter instead.');\n      options.thumbnail = options.thumb;\n    }\n    if (options.thumbnail) {\n      if (opts.formData === null) {\n        opts.formData = {};\n      }\n\n      const attachName = 'photo';\n      const [formData] = this._formatSendData(attachName, options.thumbnail.replace('attach://', ''));\n\n      if (formData) {\n        opts.formData[attachName] = formData[attachName];\n        opts.qs.thumbnail = `attach://${attachName}`;\n      }\n    }\n  }\n\n  _fixMessageIds(obj) {\n    const messageIds = obj.message_ids;\n    if (messageIds && typeof messageIds !== 'string') {\n      obj.message_ids = stringify(messageIds);\n    }\n  }\n\n  /**\n   * Fix 'reply_parameters' parameter by making it JSON-serialized, as\n   * required by the Telegram Bot API\n   * @param {Object} obj Object; either 'form' or 'qs'\n   * @private\n   * @see https://core.telegram.org/bots/api#sendmessage\n   */\n  _fixReplyParameters(obj) {\n    if (obj.hasOwnProperty('reply_parameters') && typeof obj.reply_parameters !== 'string') {\n      obj.reply_parameters = stringify(obj.reply_parameters);\n    }\n  }\n\n  /**\n   * Make request against the API\n   * @param {String} _path API endpoint\n   * @param {Object} [options]\n   * @private\n   * @return {Promise}\n   */\n  _request(_path, options = {}) {\n    if (!this.token) {\n      return Promise.reject(new errors.FatalError('Telegram Bot Token not provided!'));\n    }\n\n    if (this.options.request) {\n      Object.assign(options, this.options.request);\n    }\n\n    if (options.form) {\n      this._fixReplyMarkup(options.form);\n      this._fixEntitiesField(options.form);\n      this._fixReplyParameters(options.form);\n      this._fixMessageIds(options.form);\n    }\n    if (options.qs) {\n      this._fixReplyMarkup(options.qs);\n      this._fixReplyParameters(options.qs);\n    }\n\n    options.method = 'POST';\n    options.url = this._buildURL(_path);\n    options.simple = false;\n    options.resolveWithFullResponse = true;\n    options.forever = true;\n    debug('HTTP request: %j', options);\n    return request(options)\n      .then(resp => {\n        let data;\n        try {\n          data = resp.body = JSON.parse(resp.body);\n        } catch (err) {\n          throw new errors.ParseError(`Error parsing response: ${resp.body}`, resp);\n        }\n\n        if (data.ok) {\n          return data.result;\n        }\n\n        throw new errors.TelegramError(`${data.error_code} ${data.description}`, resp);\n      }).catch(error => {\n        // TODO: why can't we do `error instanceof errors.BaseError`?\n        if (error.response) throw error;\n        throw new errors.FatalError(error);\n      });\n  }\n\n  /**\n   * Format data to be uploaded; handles file paths, streams and buffers\n   * @param {String} type\n   * @param {String|stream.Stream|Buffer} data\n   * @param {Object} fileOptions File options\n   * @param {String} [fileOptions.filename] File name\n   * @param {String} [fileOptions.contentType] Content type (i.e. MIME)\n   * @return {Array} formatted\n   * @return {Object} formatted[0] formData\n   * @return {String} formatted[1] fileId\n   * @throws Error if Buffer file type is not supported.\n   * @see https://npmjs.com/package/file-type\n   * @private\n   */\n  _formatSendData(type, data, fileOptions = {}) {\n    const deprecationMessage =\n      'See https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files' +\n      ' for more information on how sending files has been improved and' +\n      ' on how to disable this deprecation message altogether.';\n    let filedata = data;\n    let filename = fileOptions.filename;\n    let contentType = fileOptions.contentType;\n\n    if (data instanceof stream.Stream) {\n      if (!filename && data.path) {\n        // Will be 'null' if could not be parsed.\n        // For example, 'data.path' === '/?id=123' from 'request(\"https://example.com/?id=123\")'\n        const url = URL.parse(path.basename(data.path.toString()));\n        if (url.pathname) {\n          filename = qs.unescape(url.pathname);\n        }\n      }\n    } else if (Buffer.isBuffer(data)) {\n      if (!filename && !process.env.NTBA_FIX_350) {\n        deprecate(`Buffers will have their filenames default to \"filename\" instead of \"data\". ${deprecationMessage}`);\n        filename = 'data';\n      }\n      if (!contentType) {\n        const filetype = fileType(data);\n        if (filetype) {\n          contentType = filetype.mime;\n          const ext = filetype.ext;\n          if (ext && !process.env.NTBA_FIX_350) {\n            filename = `${filename}.${ext}`;\n          }\n        } else if (!process.env.NTBA_FIX_350) {\n          deprecate(`An error will no longer be thrown if file-type of buffer could not be detected. ${deprecationMessage}`);\n          throw new errors.FatalError('Unsupported Buffer file-type');\n        }\n      }\n    } else if (data) {\n      if (this.options.filepath && fs.existsSync(data)) {\n        filedata = fs.createReadStream(data);\n        if (!filename) {\n          filename = path.basename(data);\n        }\n      } else {\n        return [null, data];\n      }\n    } else {\n      return [null, data];\n    }\n\n    filename = filename || 'filename';\n    contentType = contentType || mime.lookup(filename);\n    if (process.env.NTBA_FIX_350) {\n      contentType = contentType || 'application/octet-stream';\n    } else {\n      deprecate(`In the future, content-type of files you send will default to \"application/octet-stream\". ${deprecationMessage}`);\n    }\n\n    // TODO: Add missing file extension.\n\n    return [{\n      [type]: {\n        value: filedata,\n        options: {\n          filename,\n          contentType,\n        },\n      },\n    }, null];\n  }\n\n\n  /**\n   * Format multiple files to be uploaded; handles file paths, streams, and buffers\n   * @param {String} type\n   * @param {Array} files Array of file data objects\n   * @param {Object} fileOptions File options\n   * @param {String} [fileOptions.filename] File name\n   * @param {String} [fileOptions.contentType] Content type (i.e. MIME)\n   * @return {Object} formatted\n   * @return {Object} formatted.formData Form data object with all files\n   * @return {Array} formatted.fileIds Array of fileIds for non-file data\n   * @throws Error if Buffer file type is not supported.\n   * @see https://npmjs.com/package/file-type\n   * @private\n   */\n  _formatSendMultipleData(type, files, fileOptions = {}) {\n    const formData = {};\n    const fileIds = {};\n\n    files.forEach((file, index) => {\n      let filedata = file.media || file.data || file[type];\n      let filename = file.filename || fileOptions.filename;\n      let contentType = file.contentType || fileOptions.contentType;\n\n      if (filedata instanceof stream.Stream) {\n        if (!filename && filedata.path) {\n          const url = URL.parse(path.basename(filedata.path.toString()), true);\n          if (url.pathname) {\n            filename = qs.unescape(url.pathname);\n          }\n        }\n      } else if (Buffer.isBuffer(filedata)) {\n        filename = `filename_${index}`;\n\n        if (!contentType) {\n          const filetype = fileType(filedata);\n\n          if (filetype) {\n            contentType = filetype.mime;\n            const ext = filetype.ext;\n\n            if (ext) {\n              filename = `${filename}.${ext}`;\n            }\n          } else {\n            throw new errors.FatalError('Unsupported Buffer file-type');\n          }\n        }\n      } else if (fs.existsSync(filedata)) {\n        filedata = fs.createReadStream(filedata);\n\n        if (!filename) {\n          filename = path.basename(filedata.path);\n        }\n      } else {\n        fileIds[index] = filedata;\n        return;\n      }\n\n      filename = filename || `filename_${index}`;\n      contentType = contentType || 'application/octet-stream';\n\n      formData[`${type}_${index}`] = {\n        value: filedata,\n        options: {\n          filename,\n          contentType,\n        },\n      };\n    });\n\n    return { formData, fileIds };\n  }\n  /**\n   * Start polling.\n   * Rejects returned promise if a WebHook is being used by this instance.\n   * @param {Object} [options]\n   * @param {Boolean} [options.restart=true] Consecutive calls to this method causes polling to be restarted\n   * @return {Promise}\n   */\n  startPolling(options = {}) {\n    if (this.hasOpenWebHook()) {\n      return Promise.reject(new errors.FatalError('Polling and WebHook are mutually exclusive'));\n    }\n    options.restart = typeof options.restart === 'undefined' ? true : options.restart;\n    if (!this._polling) {\n      this._polling = new TelegramBotPolling(this);\n    }\n    return this._polling.start(options);\n  }\n\n  /**\n   * Alias of `TelegramBot#startPolling()`. This is **deprecated**.\n   * @param {Object} [options]\n   * @return {Promise}\n   * @deprecated\n   */\n  initPolling() {\n    deprecate('TelegramBot#initPolling() is deprecated. Use TelegramBot#startPolling() instead.');\n    return this.startPolling();\n  }\n\n  /**\n   * Stops polling after the last polling request resolves.\n   * Multiple invocations do nothing if polling is already stopped.\n   * Returning the promise of the last polling request is **deprecated**.\n   * @param {Object} [options] Options\n   * @param {Boolean} [options.cancel] Cancel current request\n   * @param {String} [options.reason] Reason for stopping polling\n   * @return {Promise}\n   */\n  stopPolling(options) {\n    if (!this._polling) {\n      return Promise.resolve();\n    }\n    return this._polling.stop(options);\n  }\n\n  /**\n   * Get link for file.\n   * Use this method to get link for file for subsequent use.\n   * Attention: link will be valid for 1 hour.\n   *\n   * This method is a sugar extension of the (getFile)[#getfilefileid] method,\n   * which returns just path to file on remote server (you will have to manually build full uri after that).\n   *\n   * @param {String} fileId  File identifier to get info about\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} Promise which will have  *fileURI* in resolve callback\n   * @see https://core.telegram.org/bots/api#getfile\n   */\n  getFileLink(fileId, form = {}) {\n    return this.getFile(fileId, form)\n      .then(resp => `${this.options.baseApiUrl}/file/bot${this.token}/${resp.file_path}`);\n  }\n\n  /**\n   * Return a readable stream for file.\n   *\n   * `fileStream.path` is the specified file ID i.e. `fileId`.\n   * `fileStream` emits event `info` passing a single argument i.e.\n   * `info` with the interface `{ uri }` where `uri` is the URI of the\n   * file on Telegram servers.\n   *\n   * This method is a sugar extension of the [getFileLink](#TelegramBot+getFileLink) method,\n   * which returns the full URI to the file on remote server.\n   *\n   * @param {String} fileId File identifier to get info about\n   * @param {Object} [options] Additional Telegram query options\n   * @return {stream.Readable} fileStream\n   */\n  getFileStream(fileId, form = {}) {\n    const fileStream = new stream.PassThrough();\n    fileStream.path = fileId;\n    this.getFileLink(fileId, form)\n      .then((fileURI) => {\n        fileStream.emit('info', {\n          uri: fileURI,\n        });\n        pump(streamedRequest(Object.assign({ uri: fileURI }, this.options.request)), fileStream);\n      })\n      .catch((error) => {\n        fileStream.emit('error', error);\n      });\n    return fileStream;\n  }\n\n  /**\n   * Downloads file in the specified folder.\n   *\n   * This method is a sugar extension of the [getFileStream](#TelegramBot+getFileStream) method,\n   * which returns a readable file stream.\n   *\n   * @param {String} fileId  File identifier to get info about\n   * @param {String} downloadDir Absolute path to the folder in which file will be saved\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} Promise, which will have *filePath* of downloaded file in resolve callback\n   */\n  downloadFile(fileId, downloadDir, form = {}) {\n    let resolve;\n    let reject;\n    const promise = new Promise((a, b) => {\n      resolve = a;\n      reject = b;\n    });\n    const fileStream = this.getFileStream(fileId, form);\n    fileStream.on('info', (info) => {\n      const fileName = info.uri.slice(info.uri.lastIndexOf('/') + 1);\n      // TODO: Ensure fileName doesn't contains slashes\n      const filePath = path.join(downloadDir, fileName);\n      pump(fileStream, fs.createWriteStream(filePath), (error) => {\n        if (error) { return reject(error); }\n        return resolve(filePath);\n      });\n    });\n    fileStream.on('error', (err) => {\n      reject(err);\n    });\n    return promise;\n  }\n\n  /**\n   * Register a RegExp to test against an incomming text message.\n   * @param {RegExp}   regexpRexecuted with `exec`.\n   * @param {Function} callback     Callback will be called with 2 parameters,\n   * the `msg` and the result of executing `regexp.exec` on message text.\n   */\n  onText(regexp, callback) {\n    this._textRegexpCallbacks.push({ regexp, callback });\n  }\n\n  /**\n   * Remove a listener registered with `onText()`.\n   * @param {RegExp} regexp RegExp used previously in `onText()`\n   * @return {Object} deletedListener The removed reply listener if\n   *   found. This object has `regexp` and `callback`\n   *   properties. If not found, returns `null`.\n   */\n  removeTextListener(regexp) {\n    const index = this._textRegexpCallbacks.findIndex((textListener) => {\n      return String(textListener.regexp) === String(regexp);\n    });\n    if (index === -1) {\n      return null;\n    }\n    return this._textRegexpCallbacks.splice(index, 1)[0];\n  }\n\n  /**\n   * Remove all listeners registered with `onText()`.\n   */\n  clearTextListeners() {\n    this._textRegexpCallbacks = [];\n  }\n\n  /**\n   * Register a reply to wait for a message response.\n   *\n   * @param {Number|String} chatId The chat id where the message cames from.\n   * @param {Number|String} messageId The message id to be replied.\n   * @param {Function} callback Callback will be called with the reply\n   *  message.\n   * @return {Number} id The ID of the inserted reply listener.\n   */\n  onReplyToMessage(chatId, messageId, callback) {\n    const id = ++this._replyListenerId;\n    this._replyListeners.push({\n      id,\n      chatId,\n      messageId,\n      callback\n    });\n    return id;\n  }\n\n  /**\n   * Removes a reply that has been prev. registered for a message response.\n   * @param {Number} replyListenerId The ID of the reply listener.\n   * @return {Object} deletedListener The removed reply listener if\n   *   found. This object has `id`, `chatId`, `messageId` and `callback`\n   *   properties. If not found, returns `null`.\n   */\n  removeReplyListener(replyListenerId) {\n    const index = this._replyListeners.findIndex((replyListener) => {\n      return replyListener.id === replyListenerId;\n    });\n    if (index === -1) {\n      return null;\n    }\n    return this._replyListeners.splice(index, 1)[0];\n  }\n\n  /**\n   * Removes all replies that have been prev. registered for a message response.\n   *\n   * @return {Array} deletedListeners An array of removed listeners.\n   */\n  clearReplyListeners() {\n    this._replyListeners = [];\n  }\n\n  /**\n   * Return true if polling. Otherwise, false.\n   *\n   * @return {Boolean}\n   */\n  isPolling() {\n    return this._polling ? this._polling.isPolling() : false;\n  }\n\n  /**\n   * Open webhook.\n   * Multiple invocations do nothing if webhook is already open.\n   * Rejects returned promise if Polling is being used by this instance.\n   *\n   * @return {Promise}\n   */\n  openWebHook() {\n    if (this.isPolling()) {\n      return Promise.reject(new errors.FatalError('WebHook and Polling are mutually exclusive'));\n    }\n    if (!this._webHook) {\n      this._webHook = new TelegramBotWebHook(this);\n    }\n    return this._webHook.open();\n  }\n\n  /**\n   * Close webhook after closing all current connections.\n   * Multiple invocations do nothing if webhook is already closed.\n   *\n   * @return {Promise} Promise\n   */\n  closeWebHook() {\n    if (!this._webHook) {\n      return Promise.resolve();\n    }\n    return this._webHook.close();\n  }\n\n  /**\n   * Return true if using webhook and it is open i.e. accepts connections.\n   * Otherwise, false.\n   *\n   * @return {Boolean}\n   */\n  hasOpenWebHook() {\n    return this._webHook ? this._webHook.isOpen() : false;\n  }\n\n\n  /**\n   * Process an update; emitting the proper events and executing regexp\n   * callbacks. This method is useful should you be using a different\n   * way to fetch updates, other than those provided by TelegramBot.\n   *\n   * @param {Object} update\n   * @see https://core.telegram.org/bots/api#update\n   */\n  processUpdate(update) {\n    debug('Process Update %j', update);\n    const message = update.message;\n    const editedMessage = update.edited_message;\n    const channelPost = update.channel_post;\n    const editedChannelPost = update.edited_channel_post;\n    const businessConnection = update.business_connection;\n    const businessMessage = update.business_message;\n    const editedBusinessMessage = update.edited_business_message;\n    const deletedBusinessMessage = update.deleted_business_messages;\n    const messageReaction = update.message_reaction;\n    const messageReactionCount = update.message_reaction_count;\n    const inlineQuery = update.inline_query;\n    const chosenInlineResult = update.chosen_inline_result;\n    const callbackQuery = update.callback_query;\n    const shippingQuery = update.shipping_query;\n    const preCheckoutQuery = update.pre_checkout_query;\n    const purchasedPaidMedia = update.purchased_paid_media;\n    const poll = update.poll;\n    const pollAnswer = update.poll_answer;\n    const myChatMember = update.my_chat_member;\n    const chatMember = update.chat_member;\n    const chatJoinRequest = update.chat_join_request;\n    const chatBoost = update.chat_boost;\n    const removedChatBoost = update.removed_chat_boost;\n\n\n    if (message) {\n      debug('Process Update message %j', message);\n      const metadata = {};\n      metadata.type = TelegramBot.messageTypes.find((messageType) => {\n        return message[messageType];\n      });\n      this.emit('message', message, metadata);\n      if (metadata.type) {\n        debug('Emitting %s: %j', metadata.type, message);\n        this.emit(metadata.type, message, metadata);\n      }\n      if (message.text) {\n        debug('Text message');\n        this._textRegexpCallbacks.some(reg => {\n          debug('Matching %s with %s', message.text, reg.regexp);\n\n          if (!(reg.regexp instanceof RegExp)) {\n            reg.regexp = new RegExp(reg.regexp);\n          }\n\n          const result = reg.regexp.exec(message.text);\n          if (!result) {\n            return false;\n          }\n          // reset index so we start at the beginning of the regex each time\n          reg.regexp.lastIndex = 0;\n          debug('Matches %s', reg.regexp);\n          reg.callback(message, result);\n          // returning truthy value exits .some\n          return this.options.onlyFirstMatch;\n        });\n      }\n      if (message.reply_to_message) {\n        // Only callbacks waiting for this message\n        this._replyListeners.forEach(reply => {\n          // Message from the same chat\n          if (reply.chatId === message.chat.id) {\n            // Responding to that message\n            if (reply.messageId === message.reply_to_message.message_id) {\n              // Resolve the promise\n              reply.callback(message);\n            }\n          }\n        });\n      }\n    } else if (editedMessage) {\n      debug('Process Update edited_message %j', editedMessage);\n      this.emit('edited_message', editedMessage);\n      if (editedMessage.text) {\n        this.emit('edited_message_text', editedMessage);\n      }\n      if (editedMessage.caption) {\n        this.emit('edited_message_caption', editedMessage);\n      }\n    } else if (channelPost) {\n      debug('Process Update channel_post %j', channelPost);\n      this.emit('channel_post', channelPost);\n    } else if (editedChannelPost) {\n      debug('Process Update edited_channel_post %j', editedChannelPost);\n      this.emit('edited_channel_post', editedChannelPost);\n      if (editedChannelPost.text) {\n        this.emit('edited_channel_post_text', editedChannelPost);\n      }\n      if (editedChannelPost.caption) {\n        this.emit('edited_channel_post_caption', editedChannelPost);\n      }\n    } else if (businessConnection) {\n      debug('Process Update business_connection %j', businessConnection);\n      this.emit('business_connection', businessConnection);\n    } else if (businessMessage) {\n      debug('Process Update business_message %j', businessMessage);\n      this.emit('business_message', businessMessage);\n    } else if (editedBusinessMessage) {\n      debug('Process Update edited_business_message %j', editedBusinessMessage);\n      this.emit('edited_business_message', editedBusinessMessage);\n    } else if (deletedBusinessMessage) {\n      debug('Process Update deleted_business_messages %j', deletedBusinessMessage);\n      this.emit('deleted_business_messages', deletedBusinessMessage);\n    } else if (messageReaction) {\n      debug('Process Update message_reaction %j', messageReaction);\n      this.emit('message_reaction', messageReaction);\n    } else if (messageReactionCount) {\n      debug('Process Update message_reaction_count %j', messageReactionCount);\n      this.emit('message_reaction_count', messageReactionCount);\n    } else if (inlineQuery) {\n      debug('Process Update inline_query %j', inlineQuery);\n      this.emit('inline_query', inlineQuery);\n    } else if (chosenInlineResult) {\n      debug('Process Update chosen_inline_result %j', chosenInlineResult);\n      this.emit('chosen_inline_result', chosenInlineResult);\n    } else if (callbackQuery) {\n      debug('Process Update callback_query %j', callbackQuery);\n      this.emit('callback_query', callbackQuery);\n    } else if (shippingQuery) {\n      debug('Process Update shipping_query %j', shippingQuery);\n      this.emit('shipping_query', shippingQuery);\n    } else if (preCheckoutQuery) {\n      debug('Process Update pre_checkout_query %j', preCheckoutQuery);\n      this.emit('pre_checkout_query', preCheckoutQuery);\n    } else if (purchasedPaidMedia) {\n      debug('Process Update purchased_paid_media %j', purchasedPaidMedia);\n      this.emit('purchased_paid_media', purchasedPaidMedia);\n    } else if (poll) {\n      debug('Process Update poll %j', poll);\n      this.emit('poll', poll);\n    } else if (pollAnswer) {\n      debug('Process Update poll_answer %j', pollAnswer);\n      this.emit('poll_answer', pollAnswer);\n    } else if (chatMember) {\n      debug('Process Update chat_member %j', chatMember);\n      this.emit('chat_member', chatMember);\n    } else if (myChatMember) {\n      debug('Process Update my_chat_member %j', myChatMember);\n      this.emit('my_chat_member', myChatMember);\n    } else if (chatJoinRequest) {\n      debug('Process Update my_chat_member %j', chatJoinRequest);\n      this.emit('chat_join_request', chatJoinRequest);\n    } else if (chatBoost) {\n      debug('Process Update chat_boost %j', chatBoost);\n      this.emit('chat_boost', chatBoost);\n    } else if (removedChatBoost) {\n      debug('Process Update removed_chat_boost %j', removedChatBoost);\n      this.emit('removed_chat_boost', removedChatBoost);\n    }\n  }\n\n  /** Start Telegram Bot API methods */\n\n  /**\n  * Use this method to receive incoming updates using long polling.\n  * This method has an [older, compatible signature][getUpdates-v0.25.0]\n  * that is being deprecated.\n  *\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise}\n  * @see https://core.telegram.org/bots/api#getupdates\n  */\n  getUpdates(form = {}) {\n    /* The older method signature was getUpdates(timeout, limit, offset).\n     * We need to ensure backwards-compatibility while maintaining\n     * consistency of the method signatures throughout the library */\n    if (typeof form !== 'object') {\n      /* eslint-disable no-param-reassign, prefer-rest-params */\n      deprecate('The method signature getUpdates(timeout, limit, offset) has been deprecated since v0.25.0');\n      form = {\n        timeout: arguments[0],\n        limit: arguments[1],\n        offset: arguments[2],\n      };\n      /* eslint-enable no-param-reassign, prefer-rest-params */\n    }\n\n    // If allowed_updates is present and is an array, stringify it.\n    // If it's already a string (e.g., user did JSON.stringify), leave as is.\n    if (form.allowed_updates) {\n      form.allowed_updates = stringify(form.allowed_updates);\n    }\n\n    return this._request('getUpdates', { form });\n  }\n\n  /**\n   * Specify an url to receive incoming updates via an outgoing webHook.\n   * This method has an [older, compatible signature][setWebHook-v0.25.0]\n   * that is being deprecated.\n   *\n   * @param {String} url URL where Telegram will make HTTP Post. Leave empty to\n   * delete webHook.\n   * @param {Object} [options] Additional Telegram query options\n   * @param {String|stream.Stream} [options.certificate] PEM certificate key (public).\n   * @param {String} [options.secret_token] Optional secret token to be sent in a header `X-Telegram-Bot-Api-Secret-Token` in every webhook request.\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise}\n   * @see https://core.telegram.org/bots/api#setwebhook\n   * @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n   */\n  setWebHook(url, options = {}, fileOptions = {}) {\n    /* The older method signature was setWebHook(url, cert).\n     * We need to ensure backwards-compatibility while maintaining\n     * consistency of the method signatures throughout the library */\n    let cert;\n    // Note: 'options' could be an object, if a stream was provided (in place of 'cert')\n    if (typeof options !== 'object' || options instanceof stream.Stream) {\n      deprecate('The method signature setWebHook(url, cert) has been deprecated since v0.25.0');\n      cert = options;\n      options = {}; // eslint-disable-line no-param-reassign\n    } else {\n      cert = options.certificate;\n    }\n\n    const opts = {\n      qs: options,\n    };\n    opts.qs.url = url;\n\n    if (cert) {\n      try {\n        const sendData = this._formatSendData('certificate', cert, fileOptions);\n        opts.formData = sendData[0];\n        opts.qs.certificate = sendData[1];\n      } catch (ex) {\n        return Promise.reject(ex);\n      }\n    }\n\n    return this._request('setWebHook', opts);\n  }\n\n  /**\n   * Use this method to remove webhook integration if you decide to\n   * switch back to getUpdates. Returns True on success.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise}\n   * @see https://core.telegram.org/bots/api#deletewebhook\n   */\n  deleteWebHook(form = {}) {\n    return this._request('deleteWebhook', { form });\n  }\n\n  /**\n   * Use this method to get current webhook status.\n   * On success, returns a [WebhookInfo](https://core.telegram.org/bots/api#webhookinfo) object.\n   * If the bot is using getUpdates, will return an object with the\n   * url field empty.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise}\n   * @see https://core.telegram.org/bots/api#getwebhookinfo\n   */\n  getWebHookInfo(form = {}) {\n    return this._request('getWebhookInfo', { form });\n  }\n\n  /**\n   * A simple method for testing your bot's authentication token. Requires no parameters.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} basic information about the bot in form of a [User](https://core.telegram.org/bots/api#user) object.\n   * @see https://core.telegram.org/bots/api#getme\n   */\n  getMe(form = {}) {\n    return this._request('getMe', { form });\n  }\n\n  /**\n   * This method log out your bot from the cloud Bot API server before launching the bot locally.\n   * You must log out the bot before running it locally, otherwise there is no guarantee that the bot will receive updates.\n   * After a successful call, you will not be able to log in again using the same token for 10 minutes.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise}  True on success\n   * @see https://core.telegram.org/bots/api#logout\n   */\n  logOut(form = {}) {\n    return this._request('logOut', { form });\n  }\n\n  /**\n   * This method close the bot instance before moving it from one local server to another.\n   * This method will return error 429 in the first 10 minutes after the bot is launched.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise}  True on success\n   * @see https://core.telegram.org/bots/api#close\n   */\n  close(form = {}) {\n    return this._request('close', { form });\n  }\n\n  /**\n   * Send text message.\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String} text Text of the message to be sent\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @see https://core.telegram.org/bots/api#sendmessage\n   */\n  sendMessage(chatId, text, form = {}) {\n    form.chat_id = chatId;\n    form.text = text;\n    return this._request('sendMessage', { form });\n  }\n\n  /**\n   * Forward messages of any kind.\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * or username of the target channel (in the format `@channelusername`)\n   * @param {Number|String} fromChatId Unique identifier for the chat where the\n   * original message was sent (or channel username in the format `@channelusername`)\n   * @param {Number|String} messageId  Unique message identifier in the chat specified in fromChatId\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise}\n   * @see https://core.telegram.org/bots/api#forwardmessage\n   */\n  forwardMessage(chatId, fromChatId, messageId, form = {}) {\n    form.chat_id = chatId;\n    form.from_chat_id = fromChatId;\n    form.message_id = messageId;\n    return this._request('forwardMessage', { form });\n  }\n\n  /**\n   * Use this method to forward multiple messages of any kind.\n   * If some of the specified messages can't be found or forwarded, they are skipped.\n   *\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * or username of the target channel (in the format `@channelusername`)\n   * @param {Number|String} fromChatId Unique identifier for the chat where the\n   * original message was sent (or channel username in the format `@channelusername`)\n   * @param {Array<Number|String>} messageIds Identifiers of 1-100 messages in the chat from_chat_id to forward.\n   * The identifiers must be specified in a strictly increasing order.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} An array of MessageId of the sent messages on success\n   * @see https://core.telegram.org/bots/api#forwardmessages\n   */\n  forwardMessages(chatId, fromChatId, messageIds, form = {}) {\n    form.chat_id = chatId;\n    form.from_chat_id = fromChatId;\n    form.message_ids = messageIds;\n    return this._request('forwardMessages', { form });\n  }\n\n  /**\n   * Copy messages of any kind. **Service messages and invoice messages can't be copied.**\n   * The method is analogous to the method forwardMessages, but the copied message doesn't\n   * have a link to the original message.\n   * Returns the MessageId of the sent message on success.\n   * @param {Number|String} chatId     Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Number|String} fromChatId Unique identifier for the chat where the\n   * original message was sent\n   * @param {Number|String} messageId  Unique message identifier\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} The [MessageId](https://core.telegram.org/bots/api#messageid) of the sent message on success\n   * @see https://core.telegram.org/bots/api#copymessage\n   */\n  copyMessage(chatId, fromChatId, messageId, form = {}) {\n    form.chat_id = chatId;\n    form.from_chat_id = fromChatId;\n    form.message_id = messageId;\n    return this._request('copyMessage', { form });\n  }\n\n  /**\n   * Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped.\n   * Service messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied.\n   * Returns the MessageId of the sent message on success.\n   * @param {Number|String} chatId Unique identifier for the target chat\n   * @param {Number|String} fromChatId Unique identifier for the chat where the\n   * original message was sent\n   * @param {Array} messageIds  Identifiers of 1-100 messages in the chat from_chat_id to copy.\n   * The identifiers must be specified in a strictly increasing order.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} An array of MessageId of the sent messages\n   * @see https://core.telegram.org/bots/api#copymessages\n   */\n  copyMessages(chatId, fromChatId, messageIds, form = {}) {\n    form.chat_id = chatId;\n    form.from_chat_id = fromChatId;\n    form.message_ids = stringify(messageIds);\n    return this._request('copyMessages', { form });\n  }\n\n  /**\n   * Send photo\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String|stream.Stream|Buffer} photo A file path or a Stream. Can\n   * also be a `file_id` previously uploaded\n   * @param {Object} [options] Additional Telegram query options\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @see https://core.telegram.org/bots/api#sendphoto\n   * @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n   */\n  sendPhoto(chatId, photo, options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options,\n    };\n    opts.qs.chat_id = chatId;\n    try {\n      const sendData = this._formatSendData('photo', photo, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.photo = sendData[1];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('sendPhoto', opts);\n  }\n\n  /**\n  * Send audio\n  *\n  * **Your audio must be in the .MP3 or .M4A format.**\n  *\n  * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n  * @param {String|stream.Stream|Buffer} audio A file path, Stream or Buffer.\n  * Can also be a `file_id` previously uploaded.\n  * @param {Object} [options] Additional Telegram query options\n  * @param {Object} [fileOptions] Optional file related meta-data\n  * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n  * @see https://core.telegram.org/bots/api#sendaudio\n  * @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n  */\n  sendAudio(chatId, audio, options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options\n    };\n\n    opts.qs.chat_id = chatId;\n\n    try {\n      const sendData = this._formatSendData('audio', audio, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.audio = sendData[1];\n      this._fixAddFileThumbnail(options, opts);\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n\n    return this._request('sendAudio', opts);\n  }\n\n  /**\n  * Send Document\n  * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n  * @param {String|stream.Stream|Buffer} doc A file path, Stream or Buffer.\n  * Can also be a `file_id` previously uploaded.\n  * @param {Object} [options] Additional Telegram query options\n  * @param {Object} [fileOptions] Optional file related meta-data\n  * @return {Promise}  On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n  * @see https://core.telegram.org/bots/api#sendDocument\n  * @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n  */\n  sendDocument(chatId, doc, options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options\n    };\n    opts.qs.chat_id = chatId;\n    try {\n      const sendData = this._formatSendData('document', doc, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.document = sendData[1];\n      this._fixAddFileThumbnail(options, opts);\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n\n    return this._request('sendDocument', opts);\n  }\n\n  /**\n   * Use this method to send video files, **Telegram clients support mp4 videos** (other formats may be sent as Document).\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String|stream.Stream|Buffer} video A file path or Stream.\n   * Can also be a `file_id` previously uploaded.\n   * @param {Object} [options] Additional Telegram query options\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @see https://core.telegram.org/bots/api#sendvideo\n   * @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n   */\n  sendVideo(chatId, video, options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options\n    };\n    opts.qs.chat_id = chatId;\n    try {\n      const sendData = this._formatSendData('video', video, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.video = sendData[1];\n      this._fixAddFileThumbnail(options, opts);\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('sendVideo', opts);\n  }\n\n  /**\n   * Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound).\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String|stream.Stream|Buffer} animation A file path, Stream or Buffer.\n   * Can also be a `file_id` previously uploaded.\n   * @param {Object} [options] Additional Telegram query options\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @see https://core.telegram.org/bots/api#sendanimation\n   * @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n   */\n  sendAnimation(chatId, animation, options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options\n    };\n    opts.qs.chat_id = chatId;\n    try {\n      const sendData = this._formatSendData('animation', animation, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.animation = sendData[1];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('sendAnimation', opts);\n  }\n\n  /**\n   * Send voice\n   *\n   * **Your audio must be in an .OGG file encoded with OPUS**, or in .MP3 format, or in .M4A format (other formats may be sent as Audio or Document)\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String|stream.Stream|Buffer} voice A file path, Stream or Buffer.\n   * Can also be a `file_id` previously uploaded.\n   * @param {Object} [options] Additional Telegram query options\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @see https://core.telegram.org/bots/api#sendvoice\n   * @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n   */\n  sendVoice(chatId, voice, options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options\n    };\n    opts.qs.chat_id = chatId;\n    try {\n      const sendData = this._formatSendData('voice', voice, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.voice = sendData[1];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('sendVoice', opts);\n  }\n\n  /**\n   * Use this method to send video messages\n   * Telegram clients support **rounded square MPEG4 videos** of up to 1 minute long.\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String|stream.Stream|Buffer} videoNote A file path or Stream.\n   * Can also be a `file_id` previously uploaded.\n   * @param {Object} [options] Additional Telegram query options\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @info The length parameter is actually optional. However, the API (at time of writing) requires you to always provide it until it is fixed.\n   * @see https://core.telegram.org/bots/api#sendvideonote\n   * @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n  */\n  sendVideoNote(chatId, videoNote, options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options\n    };\n    opts.qs.chat_id = chatId;\n    try {\n      const sendData = this._formatSendData('video_note', videoNote, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.video_note = sendData[1];\n      this._fixAddFileThumbnail(options, opts);\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('sendVideoNote', opts);\n  }\n\n  /**\n   * Use this method to send paid media.\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Number} starCount The number of Telegram Stars that must be paid to buy access to the media; 1-10000\n   * @param {Array} media Array of [InputPaidMedia](https://core.telegram.org/bots/api#inputpaidmedia). The media property can bea String, Stream or Buffer.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @see https://core.telegram.org/bots/api#sendpaidmedia\n  */\n  sendPaidMedia(chatId, starCount, media, options = {}) {\n    const opts = {\n      qs: options\n    };\n\n    opts.qs.chat_id = chatId;\n    opts.qs.star_count = starCount;\n\n    try {\n      const inputPaidMedia = [];\n      opts.formData = {};\n\n      const { formData, fileIds } = this._formatSendMultipleData('media', media);\n\n      opts.formData = formData;\n\n      inputPaidMedia.push(...media.map((item, index) => {\n        if (fileIds[index]) {\n          item.media = fileIds[index];\n        } else {\n          item.media = `attach://media_${index}`;\n        }\n        return item;\n      }));\n\n      opts.qs.media = stringify(inputPaidMedia);\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n\n    return this._request('sendPaidMedia', opts);\n  }\n\n  /**\n   * Use this method to send a group of photos or videos as an album.\n   *\n   * **Documents and audio files can be only grouped in an album with messages of the same type**\n   *\n   * If you wish to [specify file options](https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files),\n   * add a `fileOptions` property to the target input in `media`.\n   *\n   * @param {String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Array} media A JSON-serialized array describing photos and videos to be sent, must include 2–10 items\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, an array of the sent [Messages](https://core.telegram.org/bots/api#message)\n   * is returned.\n   * @see https://core.telegram.org/bots/api#sendmediagroup\n   * @see https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files\n   */\n  sendMediaGroup(chatId, media, options = {}) {\n    const opts = {\n      qs: options,\n    };\n    opts.qs.chat_id = chatId;\n\n    opts.formData = {};\n    const inputMedia = [];\n    let index = 0;\n    for (const input of media) {\n      const payload = Object.assign({}, input);\n      delete payload.media;\n      delete payload.fileOptions;\n      try {\n        const attachName = String(index);\n        const [formData, fileId] = this._formatSendData(attachName, input.media, input.fileOptions);\n        if (formData) {\n          opts.formData[attachName] = formData[attachName];\n          payload.media = `attach://${attachName}`;\n        } else {\n          payload.media = fileId;\n        }\n      } catch (ex) {\n        return Promise.reject(ex);\n      }\n      inputMedia.push(payload);\n      index++;\n    }\n    opts.qs.media = stringify(inputMedia);\n\n    return this._request('sendMediaGroup', opts);\n  }\n\n\n  /**\n   * Send location.\n   * Use this method to send point on the map.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Float} latitude Latitude of location\n   * @param {Float} longitude Longitude of location\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @see https://core.telegram.org/bots/api#sendlocation\n   */\n  sendLocation(chatId, latitude, longitude, form = {}) {\n    form.chat_id = chatId;\n    form.latitude = latitude;\n    form.longitude = longitude;\n    return this._request('sendLocation', { form });\n  }\n\n  /**\n   * Use this method to edit live location messages sent by\n   * the bot or via the bot (for inline bots).\n   *\n   *  A location **can be edited until its live_period expires or editing is explicitly disabled by a call to [stopMessageLiveLocation](https://core.telegram.org/bots/api#stopmessagelivelocation)**\n   *\n   * Note that you must provide one of chat_id, message_id, or\n   * inline_message_id in your request.\n   *\n   * @param {Float} latitude Latitude of location\n   * @param {Float} longitude Longitude of location\n   * @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)\n   * @return {Promise} On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned.\n   * @see https://core.telegram.org/bots/api#editmessagelivelocation\n   */\n  editMessageLiveLocation(latitude, longitude, form = {}) {\n    form.latitude = latitude;\n    form.longitude = longitude;\n    return this._request('editMessageLiveLocation', { form });\n  }\n\n  /**\n   * Use this method to stop updating a live location message sent by\n   * the bot or via the bot (for inline bots) before live_period expires.\n   *\n   * Note that you must provide one of chat_id, message_id, or\n   * inline_message_id in your request.\n   *\n   * @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)\n   * @return {Promise} On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned.\n   * @see https://core.telegram.org/bots/api#stopmessagelivelocation\n   */\n  stopMessageLiveLocation(form = {}) {\n    return this._request('stopMessageLiveLocation', { form });\n  }\n\n  /**\n   * Send venue.\n   * Use this method to send information about a venue.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Float} latitude Latitude of location\n   * @param {Float} longitude Longitude of location\n   * @param {String} title Name of the venue\n   * @param {String} address Address of the venue\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned.\n   * @see https://core.telegram.org/bots/api#sendvenue\n   */\n  sendVenue(chatId, latitude, longitude, title, address, form = {}) {\n    form.chat_id = chatId;\n    form.latitude = latitude;\n    form.longitude = longitude;\n    form.title = title;\n    form.address = address;\n    return this._request('sendVenue', { form });\n  }\n\n  /**\n   * Send contact.\n   * Use this method to send phone contacts.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String} phoneNumber Contact's phone number\n   * @param {String} firstName Contact's first name\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @see https://core.telegram.org/bots/api#sendcontact\n   */\n  sendContact(chatId, phoneNumber, firstName, form = {}) {\n    form.chat_id = chatId;\n    form.phone_number = phoneNumber;\n    form.first_name = firstName;\n    return this._request('sendContact', { form });\n  }\n\n  /**\n   * Send poll.\n   * Use this method to send a native poll.\n   *\n   * @param {Number|String} chatId  Unique identifier for the group/channel\n   * @param {String} question Poll question, 1-300 characters\n   * @param {Array} pollOptions Poll options, between 2-10 options (only 1-100 characters each)\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @see https://core.telegram.org/bots/api#sendpoll\n   */\n  sendPoll(chatId, question, pollOptions, form = {}) {\n    form.chat_id = chatId;\n    form.question = question;\n    form.options = stringify(pollOptions);\n    return this._request('sendPoll', { form });\n  }\n\n  /**\n   * Send sendChecklist.\n   * Use this method to send a checklist on behalf of a connected business account.\n   *\n   * @param {Number|String} businessConnectionId  Unique identifier for the business connection\n   * @param {Number|String} chatId  Unique identifier for the group/channel\n   * @param {Object} checklist A JSON-serialized object for the checklist to send\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @see https://core.telegram.org/bots/api#sendchecklist\n   */\n  sendChecklist(businessConnectionId, chatId, checklist, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.chat_id = chatId;\n    form.checklist = stringify(checklist);\n    return this._request('sendChecklist', { form });\n  }\n\n  /**\n   * Send Dice\n   * Use this method to send an animated emoji that will display a random value.\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise}  On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned\n   * @see https://core.telegram.org/bots/api#senddice\n   */\n  sendDice(chatId, options = {}) {\n    const opts = {\n      qs: options,\n    };\n    opts.qs.chat_id = chatId;\n    try {\n      const sendData = this._formatSendData('dice');\n      opts.formData = sendData[0];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('sendDice', opts);\n  }\n\n  /**\n   * Send Message Draft\n   * Use this method to stream a partial message to a user while the message is being generated; supported only for bots with forum topic mode enabled. Returns True on success.\n   * @param {Number|String} chatId  Unique identifier for the target private chat\n   * @param {Number} draftId  Unique identifier of the message draft; must be non-zero. Changes of drafts with the same identifier are animated\n   * @param {String} text  Text of the message to be sent, 1-4096 characters after entities parsing\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise}  On success, return true\n   * @see https://core.telegram.org/bots/api#sendmessagedraft\n   */\n  sendMessageDraft(chatId, draftId, text, form = {}) {\n    form.chat_id = chatId;\n    form.draft_id = draftId;\n    form.text = text;\n    return this._request('sendMessageDraft', { form });\n  }\n\n  /**\n   * Send chat action.\n   *\n   * Use this method when you need to tell the user that something is happening on the bot's side.\n   * **The status is set for 5 seconds or less** (when a message arrives from your bot, Telegram clients clear its typing status).\n   *\n   *  Action `typing` for [text messages](https://core.telegram.org/bots/api#sendmessage),\n   * `upload_photo` for [photos](https://core.telegram.org/bots/api#sendphoto), `record_video` or `upload_video` for [videos](https://core.telegram.org/bots/api#sendvideo),\n   * `record_voice` or `upload_voice` for [voice notes](https://core.telegram.org/bots/api#sendvoice), `upload_document` for [general files](https://core.telegram.org/bots/api#senddocument),\n   * `choose_sticker` for [stickers](https://core.telegram.org/bots/api#sendsticker), `find_location` for [location data](https://core.telegram.org/bots/api#sendlocation),\n   * `record_video_note` or `upload_video_note` for [video notes](https://core.telegram.org/bots/api#sendvideonote).\n   *\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String} action Type of action to broadcast.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#sendchataction\n   */\n  sendChatAction(chatId, action, form = {}) {\n    form.chat_id = chatId;\n    form.action = action;\n    return this._request('sendChatAction', { form });\n  }\n\n  /**\n   * Use this method to change the chosen reactions on a message.\n   * - Service messages can't be reacted to.\n   * - Automatically forwarded messages from a channel to its discussion group have the same available reactions as messages in the channel.\n   * - In albums, bots must react to the first message.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format @channelusername)\n   * @param {Number} messageId  Unique identifier of the target message\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise<Boolean>} True on success\n   * @see https://core.telegram.org/bots/api#setmessagereaction\n   */\n  setMessageReaction(chatId, messageId, form = {}) {\n    form.chat_id = chatId;\n    form.message_id = messageId;\n    if (form.reaction) {\n      form.reaction = stringify(form.reaction);\n    }\n    return this._request('setMessageReaction', { form });\n  }\n\n  /**\n   * Use this method to get a list of profile pictures for a user.\n   * Returns a [UserProfilePhotos](https://core.telegram.org/bots/api#userprofilephotos) object.\n   *\n   * @param {Number} userId  Unique identifier of the target user\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise}  Returns a [UserProfilePhotos](https://core.telegram.org/bots/api#userprofilephotos) object\n   * @see https://core.telegram.org/bots/api#getuserprofilephotos\n   */\n  getUserProfilePhotos(userId, form = {}) {\n    form.user_id = userId;\n    return this._request('getUserProfilePhotos', { form });\n  }\n\n  /**\n   * Use this method to get a list of profile audios for a user.\n   * Returns a [UserProfileAudios](https://core.telegram.org/bots/api#userprofileaudios) object.\n   *\n   * @param {Number} userId  Unique identifier of the target user\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise}  Returns a [UserProfileAudios](https://core.telegram.org/bots/api#userprofileaudios) object\n   * @see https://core.telegram.org/bots/api#getuserprofileaudios\n   */\n  getUserProfileAudios(userId, form = {}) {\n    form.user_id = userId;\n    return this._request('getUserProfileAudios', { form });\n  }\n\n\n  /**\n   * Changes the emoji status for a given user that previously allowed the bot to manage their emoji status\n   * via the Mini App method [requestEmojiStatusAccess](https://core.telegram.org/bots/webapps#initializing-mini-apps).\n   *\n   * @param {Number} userId Unique identifier of the target user\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setuseremojistatus\n  */\n  setUserEmojiStatus(userId, form = {}) {\n    form.user_id = userId;\n    return this._request('setUserEmojiStatus', { form });\n  }\n\n  /**\n   * Get file.\n   * Use this method to get basic info about a file and prepare it for downloading.\n   *\n   * Attention: **link will be valid for 1 hour.**\n   *\n   * @param {String} fileId  File identifier to get info about\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, a [File](https://core.telegram.org/bots/api#file) object is returned\n   * @see https://core.telegram.org/bots/api#getfile\n   */\n  getFile(fileId, form = {}) {\n    form.file_id = fileId;\n    return this._request('getFile', { form });\n  }\n\n  /**\n    * Use this method to ban a user in a group, a supergroup or a channel.\n    * In the case of supergroups and channels, the user will not be able to\n    * return to the chat on their own using invite links, etc., unless unbanned first..\n    *\n    * The **bot must be an administrator in the group, supergroup or a channel** for this to work.\n    *\n    *\n    * @param {Number|String} chatId   Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n    * @param {Number} userId  Unique identifier of the target user\n    * @param {Object} [options] Additional Telegram query options\n    * @return {Promise} True on success.\n    * @see https://core.telegram.org/bots/api#banchatmember\n    */\n  banChatMember(chatId, userId, form = {}) {\n    form.chat_id = chatId;\n    form.user_id = userId;\n    return this._request('banChatMember', { form });\n  }\n\n  /**\n  * Use this method to unban a previously kicked user in a supergroup.\n  * The user will not return to the group automatically, but will be\n  * able to join via link, etc.\n  *\n  * The **bot must be an administrator** in the supergroup or channel for this to work.\n  *\n  * **By default**, this method guarantees that after the call the user is not a member of the chat, but will be able to join it.\n  * So **if the user is a member of the chat they will also be removed from the chat**. If you don't want this, use the parameter *only_if_banned*\n  *\n  * @param {Number|String} chatId   Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n  * @param {Number} userId  Unique identifier of the target user\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise} True on success\n  * @see https://core.telegram.org/bots/api#unbanchatmember\n  */\n  unbanChatMember(chatId, userId, form = {}) {\n    form.chat_id = chatId;\n    form.user_id = userId;\n    return this._request('unbanChatMember', { form });\n  }\n\n  /**\n  * Use this method to restrict a user in a supergroup.\n  * The bot **must be an administrator in the supergroup** for this to work\n  * and must have the appropriate admin rights. Pass True for all boolean parameters\n  * to lift restrictions from a user. Returns True on success.\n  *\n  * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n  * @param {Number} userId Unique identifier of the target user\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise} True on success\n  * @see https://core.telegram.org/bots/api#restrictchatmember\n  */\n  restrictChatMember(chatId, userId, form = {}) {\n    form.chat_id = chatId;\n    form.user_id = userId;\n    return this._request('restrictChatMember', { form });\n  }\n\n  /**\n   * Use this method to promote or demote a user in a supergroup or a channel.\n   * The bot **must be an administrator** in the chat for this to work\n   * and must have the appropriate admin rights. Pass False for all boolean parameters to demote a user.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Number} userId\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success.\n   * @see https://core.telegram.org/bots/api#promotechatmember\n   */\n  promoteChatMember(chatId, userId, form = {}) {\n    form.chat_id = chatId;\n    form.user_id = userId;\n    return this._request('promoteChatMember', { form });\n  }\n\n  /**\n   * Use this method to set a custom title for an administrator in a supergroup promoted by the bot.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Number} userId Unique identifier of the target user\n   * @param {String} customTitle New custom title for the administrator; 0-16 characters, emoji are not allowed\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setchatadministratorcustomtitle\n   */\n  setChatAdministratorCustomTitle(chatId, userId, customTitle, form = {}) {\n    form.chat_id = chatId;\n    form.user_id = userId;\n    form.custom_title = customTitle;\n    return this._request('setChatAdministratorCustomTitle', { form });\n  }\n\n  /**\n   * Use this method to set a tag for a regular member in a group or a supergroup.\n   *\n   * The bot must be an administrator in the chat for this to work and must have the can_manage_tags administrator right.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Number} userId Unique identifier of the target user\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setchatmembertag\n   */\n  setChatMemberTag(chatId, userId, form = {}) {\n    form.chat_id = chatId;\n    form.user_id = userId;\n    return this._request('setChatMemberTag', { form });\n  }\n\n  /**\n   * Use this method to ban a channel chat in a supergroup or a channel.\n   *\n   * Until the chat is [unbanned](https://core.telegram.org/bots/api#unbanchatsenderchat), the owner of the banned chat won't be able to send messages on behalf of any of their channels.\n   * The bot **must be an administrator in the supergroup or channel** for this to work and must have the appropriate administrator rights\n   *\n   * @param {Number|String} chatId   Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Number} senderChatId  Unique identifier of the target user\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success.\n   * @see https://core.telegram.org/bots/api#banchatsenderchat\n   */\n  banChatSenderChat(chatId, senderChatId, form = {}) {\n    form.chat_id = chatId;\n    form.sender_chat_id = senderChatId;\n    return this._request('banChatSenderChat', { form });\n  }\n\n  /**\n  * Use this method to unban a previously banned channel chat in a supergroup or channel.\n  *\n  * The bot **must be an administrator** for this to work and must have the appropriate administrator rights.\n  *\n  * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n  * @param {Number} senderChatId Unique identifier of the target user\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise} True on success\n  * @see https://core.telegram.org/bots/api#unbanchatsenderchat\n  */\n  unbanChatSenderChat(chatId, senderChatId, form = {}) {\n    form.chat_id = chatId;\n    form.sender_chat_id = senderChatId;\n    return this._request('unbanChatSenderChat', { form });\n  }\n\n  /**\n   * Use this method to set default chat permissions for all members.\n   *\n   * The bot **must be an administrator in the group or a supergroup** for this to\n   * work and **must have the `can_restrict_members` admin rights.**\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Array} chatPermissions New default chat permissions\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setchatpermissions\n   */\n  setChatPermissions(chatId, chatPermissions, form = {}) {\n    form.chat_id = chatId;\n    form.permissions = stringify(chatPermissions);\n    return this._request('setChatPermissions', { form });\n  }\n\n  /**\n   * Use this method to generate a new primary invite link for a chat. **Any previously generated primary link is revoked**.\n   *\n   * The bot **must be an administrator in the chat** for this to work and must have the appropriate administrator rights.\n   *\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} Exported invite link as String on success.\n   * @see https://core.telegram.org/bots/api#exportchatinvitelink\n   */\n  exportChatInviteLink(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('exportChatInviteLink', { form });\n  }\n\n  /**\n   * Use this method to create an additional invite link for a chat.\n   *\n   * The bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n   *\n   * The link generated with this method can be revoked using the method [revokeChatInviteLink](https://core.telegram.org/bots/api#revokechatinvitelink)\n   *\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Object} The new invite link as [ChatInviteLink](https://core.telegram.org/bots/api#chatinvitelink) object\n   * @see https://core.telegram.org/bots/api#createchatinvitelink\n   */\n  createChatInviteLink(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('createChatInviteLink', { form });\n  }\n\n  /**\n   * Use this method to edit a non-primary invite link created by the bot.\n   *\n   * The bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n   *\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String} inviteLink Text with the invite link to edit\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} The edited invite link as a [ChatInviteLink](https://core.telegram.org/bots/api#chatinvitelink) object\n   * @see https://core.telegram.org/bots/api#editchatinvitelink\n   */\n  editChatInviteLink(chatId, inviteLink, form = {}) {\n    form.chat_id = chatId;\n    form.invite_link = inviteLink;\n    return this._request('editChatInviteLink', { form });\n  }\n\n  /**\n   * Use this method to create a subscription invite link for a channel chat.\n   *\n   * The bot must have the can_invite_users administrator rights\n   *\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Number} subscriptionPeriod The number of seconds the subscription will be active for before the next payment. Currently, it must always be 2592000 (30 days)\n   * @param {Number} subscriptionPrice The amount of Telegram Stars a user must pay initially and after each subsequent subscription period to be a member of the chat (1-2500)\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} The new invite link as a [ChatInviteLink](https://core.telegram.org/bots/api#chatinvitelink) object\n   * @see https://core.telegram.org/bots/api#createchatsubscriptioninvitelink\n   */\n  createChatSubscriptionInviteLink(chatId, subscriptionPeriod, subscriptionPrice, form = {}) {\n    form.chat_id = chatId;\n    form.subscription_period = subscriptionPeriod;\n    form.subscription_price = subscriptionPrice;\n    return this._request('createChatSubscriptionInviteLink', { form });\n  }\n\n  /**\n   * Use this method to edit a subscription invite link created by the bot.\n   *\n   * The bot must have the can_invite_users administrator rights\n   *\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String} inviteLink The invite link to edit\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} The new invite link as a [ChatInviteLink](https://core.telegram.org/bots/api#chatinvitelink) object\n   * @see https://core.telegram.org/bots/api#editchatsubscriptioninvitelink\n   */\n  editChatSubscriptionInviteLink(chatId, inviteLink, form = {}) {\n    form.chat_id = chatId;\n    form.invite_link = inviteLink;\n    return this._request('editChatSubscriptionInviteLink', { form });\n  }\n\n  /**\n   * Use this method to revoke an invite link created by the bot.\n   * Note: If the primary link is revoked, a new link is automatically generated\n   *\n   * The bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n   *\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String} inviteLink The invite link to revoke\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} The revoked invite link as [ChatInviteLink](https://core.telegram.org/bots/api#chatinvitelink) object\n   * @see https://core.telegram.org/bots/api#revokechatinvitelink\n   */\n  revokeChatInviteLink(chatId, inviteLink, form = {}) {\n    form.chat_id = chatId;\n    form.invite_link = inviteLink;\n    return this._request('revokeChatInviteLink', { form });\n  }\n\n  /**\n   * Use this method to approve a chat join request.\n   *\n   * The bot **must be an administrator in the chat** for this to work and **must have the `can_invite_users` administrator right.**\n   *\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Number} userId  Unique identifier of the target user\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#approvechatjoinrequest\n   */\n  approveChatJoinRequest(chatId, userId, form = {}) {\n    form.chat_id = chatId;\n    form.user_id = userId;\n    return this._request('approveChatJoinRequest', { form });\n  }\n\n  /**\n   * Use this method to decline a chat join request.\n   *\n   * The bot **must be an administrator in the chat** for this to work and **must have the `can_invite_users` administrator right**.\n   *\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Number} userId  Unique identifier of the target user\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#declinechatjoinrequest\n   */\n  declineChatJoinRequest(chatId, userId, form = {}) {\n    form.chat_id = chatId;\n    form.user_id = userId;\n    return this._request('declineChatJoinRequest', { form });\n  }\n\n  /**\n   * Use this method to set a new profile photo for the chat. **Photos can't be changed for private chats**.\n   *\n   * The bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {stream.Stream|Buffer} photo A file path or a Stream.\n   * @param {Object} [options] Additional Telegram query options\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setchatphoto\n   */\n  setChatPhoto(chatId, photo, options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options,\n    };\n    opts.qs.chat_id = chatId;\n    try {\n      const sendData = this._formatSendData('photo', photo, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.photo = sendData[1];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('setChatPhoto', opts);\n  }\n\n  /**\n  * Use this method to delete a chat photo. **Photos can't be changed for private chats**.\n  *\n  * The bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n  *\n  * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise} True on success\n  * @see https://core.telegram.org/bots/api#deletechatphoto\n  */\n  deleteChatPhoto(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('deleteChatPhoto', { form });\n  }\n\n  /**\n   * Use this method to change the title of a chat. **Titles can't be changed for private chats**.\n   *\n   * The bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String} title New chat title, 1-255 characters\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setchattitle\n   */\n  setChatTitle(chatId, title, form = {}) {\n    form.chat_id = chatId;\n    form.title = title;\n    return this._request('setChatTitle', { form });\n  }\n\n  /**\n   * Use this method to change the description of a group, a supergroup or a channel.\n   *\n   * The bot **must be an administrator in the chat** for this to work and must have the appropriate admin rights.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String} description New chat title, 0-255 characters\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setchatdescription\n   */\n  setChatDescription(chatId, description, form = {}) {\n    form.chat_id = chatId;\n    form.description = description;\n    return this._request('setChatDescription', { form });\n  }\n\n  /**\n   * Use this method to pin a message in a supergroup.\n   *\n   * If the chat is not a private chat, the **bot must be an administrator in the chat** for this to work and must have the `can_pin_messages` administrator\n   * right in a supergroup or `can_edit_messages` administrator right in a channel.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Number} messageId Identifier of a message to pin\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#pinchatmessage\n   */\n  pinChatMessage(chatId, messageId, form = {}) {\n    form.chat_id = chatId;\n    form.message_id = messageId;\n    return this._request('pinChatMessage', { form });\n  }\n\n  /**\n   * Use this method to remove a message from the list of pinned messages in a chat\n   *\n   * If the chat is not a private chat, the **bot must be an administrator in the chat** for this to work and must have the `can_pin_messages` administrator\n   * right in a supergroup or `can_edit_messages` administrator right in a channel.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#unpinchatmessage\n   */\n  unpinChatMessage(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('unpinChatMessage', { form });\n  }\n\n  /**\n  * Use this method to clear the list of pinned messages in a chat.\n  *\n  * If the chat is not a private chat, the **bot must be an administrator in the chat** for this to work and must have the `can_pin_messages` administrator\n  * right in a supergroup or `can_edit_messages` administrator right in a channel.\n  *\n  * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise} True on success\n  * @see https://core.telegram.org/bots/api#unpinallchatmessages\n  */\n  unpinAllChatMessages(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('unpinAllChatMessages', { form });\n  }\n\n  /**\n   * Use this method for your bot to leave a group, supergroup or channel\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#leavechat\n   */\n  leaveChat(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('leaveChat', { form });\n  }\n\n  /**\n   * Use this method to get up to date information about the chat\n   * (current name of the user for one-on-one conversations, current\n   * username of a user, group or channel, etc.).\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`) or channel\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} [ChatFullInfo](https://core.telegram.org/bots/api#chatfullinfo) object on success\n   * @see https://core.telegram.org/bots/api#getchat\n   */\n  getChat(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('getChat', { form });\n  }\n\n  /**\n   * Use this method to get a list of administrators in a chat\n   *\n   * @param {Number|String} chatId  Unique identifier for the target group or username of the target supergroup\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns an Array of [ChatMember](https://core.telegram.org/bots/api#chatmember) objects that contains information about all chat administrators except other bots.\n   * If the chat is a group or a supergroup and no administrators were appointed, only the creator will be returned\n   * @see https://core.telegram.org/bots/api#getchatadministrators\n   */\n  getChatAdministrators(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('getChatAdministrators', { form });\n  }\n\n  /**\n  * Use this method to get the number of members in a chat.\n  *\n  * @param {Number|String} chatId  Unique identifier for the target group or username of the target supergroup\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise} Int on success\n  * @see https://core.telegram.org/bots/api#getchatmembercount\n  */\n  getChatMemberCount(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('getChatMemberCount', { form });\n  }\n\n  /**\n   * Use this method to get information about a member of a chat.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target group or username of the target supergroup\n   * @param {Number} userId  Unique identifier of the target user\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} [ChatMember](https://core.telegram.org/bots/api#chatmember) object on success\n   * @see https://core.telegram.org/bots/api#getchatmember\n   */\n  getChatMember(chatId, userId, form = {}) {\n    form.chat_id = chatId;\n    form.user_id = userId;\n    return this._request('getChatMember', { form });\n  }\n\n  /**\n   * Use this method to set a new group sticker set for a supergroup.\n   *\n   * The bot **must be an administrator in the chat** for this to work and must have the appropriate administrator rights.\n   *\n   * **Note:** Use the field `can_set_sticker_set` optionally returned in [getChat](https://core.telegram.org/bots/api#getchat) requests to check if the bot can use this method.\n   *\n   * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n   * @param {String} stickerSetName Name of the sticker set to be set as the group sticker set\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setchatstickerset\n   */\n  setChatStickerSet(chatId, stickerSetName, form = {}) {\n    form.chat_id = chatId;\n    form.sticker_set_name = stickerSetName;\n    return this._request('setChatStickerSet', { form });\n  }\n\n\n  /**\n   * Use this method to delete a group sticker set from a supergroup.\n   *\n   * Use the field `can_set_sticker_set` optionally returned in [getChat](https://core.telegram.org/bots/api#getchat) requests to check if the bot can use this method.\n   *\n   * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#deletechatstickerset\n   */\n  deleteChatStickerSet(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('deleteChatStickerSet', { form });\n  }\n\n  /**\n   * Use this method to get custom emoji stickers, which can be used as a forum topic icon by any user.\n   *\n   * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} Array of [Sticker](https://core.telegram.org/bots/api#sticker) objects\n   * @see https://core.telegram.org/bots/api#getforumtopiciconstickers\n   */\n  getForumTopicIconStickers(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('getForumTopicIconStickers', { form });\n  }\n\n  /**\n   * Use this method to create a topic in a forum supergroup chat.\n   * The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights.\n   *\n   * Returns information about the created topic as a [ForumTopic](https://core.telegram.org/bots/api#forumtopic) object.\n   *\n   * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n   * @param {String} name Topic name, 1-128 characters\n   * @param {Object} [options] Additional Telegram query options\n   * @see https://core.telegram.org/bots/api#createforumtopic\n   */\n  createForumTopic(chatId, name, form = {}) {\n    form.chat_id = chatId;\n    form.name = name;\n    return this._request('createForumTopic', { form });\n  }\n\n  /**\n   * Use this method to edit name and icon of a topic in a forum supergroup chat.\n   * The bot must be an administrator in the chat for this to work and must have can_manage_topics administrator rights, unless it is the creator of the topic.\n   *\n   * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n   * @param {Number} messageThreadId Unique identifier for the target message thread of the forum topic\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#editforumtopic\n   */\n  editForumTopic(chatId, messageThreadId, form = {}) {\n    form.chat_id = chatId;\n    form.message_thread_id = messageThreadId;\n    return this._request('editForumTopic', { form });\n  }\n\n  /**\n   * Use this method to close an open topic in a forum supergroup chat.\n   * The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic.\n   *\n   * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n   * @param {Number} messageThreadId Unique identifier for the target message thread of the forum topic\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#closeforumtopic\n   */\n  closeForumTopic(chatId, messageThreadId, form = {}) {\n    form.chat_id = chatId;\n    form.message_thread_id = messageThreadId;\n    return this._request('closeForumTopic', { form });\n  }\n\n  /**\n   * Use this method to reopen a closed topic in a forum supergroup chat.\n   * The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless it is the creator of the topic.\n   *\n   * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n   * @param {Number} messageThreadId Unique identifier for the target message thread of the forum topic\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#reopenforumtopic\n   */\n  reopenForumTopic(chatId, messageThreadId, form = {}) {\n    form.chat_id = chatId;\n    form.message_thread_id = messageThreadId;\n    return this._request('reopenForumTopic', { form });\n  }\n\n  /**\n   * Use this method to delete a forum topic along with all its messages in a forum supergroup chat.\n   * The bot must be an administrator in the chat for this to work and must have the can_delete_messages administrator rights.\n   *\n   * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n   * @param {Number} messageThreadId Unique identifier for the target message thread of the forum topic\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#deleteforumtopic\n   */\n  deleteForumTopic(chatId, messageThreadId, form = {}) {\n    form.chat_id = chatId;\n    form.message_thread_id = messageThreadId;\n    return this._request('deleteForumTopic', { form });\n  }\n\n  /**\n   * Use this method to clear the list of pinned messages in a forum topic.\n   * The bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator right in the supergroup.\n   *\n   * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n   * @param {Number} messageThreadId Unique identifier for the target message thread of the forum topic\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#unpinallforumtopicmessages\n   */\n  unpinAllForumTopicMessages(chatId, messageThreadId, form = {}) {\n    form.chat_id = chatId;\n    form.message_thread_id = messageThreadId;\n    return this._request('unpinAllForumTopicMessages', { form });\n  }\n\n  /**\n  * Use this method to edit the name of the 'General' topic in a forum supergroup chat.\n  * The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights.\n  * The topic will be automatically unhidden if it was hidden.\n  *\n  * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n  * @param {String} name New topic name, 1-128 characters\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise} True on success\n  * @see https://core.telegram.org/bots/api#editgeneralforumtopic\n  */\n  editGeneralForumTopic(chatId, name, form = {}) {\n    form.chat_id = chatId;\n    form.name = name;\n    return this._request('editGeneralForumTopic', { form });\n  }\n\n  /**\n  * Use this method to close an open 'General' topic in a forum supergroup chat.\n  * The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights.\n  * The topic will be automatically unhidden if it was hidden.\n  *\n  * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise} True on success\n  * @see https://core.telegram.org/bots/api#closegeneralforumtopic\n  */\n  closeGeneralForumTopic(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('closeGeneralForumTopic', { form });\n  }\n\n  /**\n  * Use this method to reopen a closed 'General' topic in a forum supergroup chat.\n  * The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights.\n  * The topic will be automatically unhidden if it was hidden.\n  *\n  * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise} True on success\n  * @see https://core.telegram.org/bots/api#reopengeneralforumtopic\n  */\n  reopenGeneralForumTopic(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('reopenGeneralForumTopic', { form });\n  }\n\n  /**\n  * Use this method to hide the 'General' topic in a forum supergroup chat.\n  * The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights.\n  * The topic will be automatically closed if it was open.\n  *\n  * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise} True on success\n  * @see https://core.telegram.org/bots/api#hidegeneralforumtopic\n  */\n  hideGeneralForumTopic(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('hideGeneralForumTopic', { form });\n  }\n\n  /**\n   * Use this method to unhide the 'General' topic in a forum supergroup chat.\n   * The bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator rights\n   *\n   * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#unhidegeneralforumtopic\n   */\n  unhideGeneralForumTopic(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('unhideGeneralForumTopic', { form });\n  }\n\n  /**\n   * Use this method to clear the list of pinned messages in a General forum topic.\n   * The bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator right in the supergroup.\n   *\n   * @param {Number|String} chatId Unique identifier for the target group or username of the target supergroup (in the format @supergroupusername)\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#unpinallgeneralforumtopicmessages\n   */\n  unpinAllGeneralForumTopicMessages(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('unpinAllGeneralForumTopicMessages', { form });\n  }\n\n  /**\n   * Use this method to send answers to callback queries sent from\n   * [inline keyboards](https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating).\n   *\n   * The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.\n   *\n   * This method has **older, compatible signatures ([1][answerCallbackQuery-v0.27.1])([2][answerCallbackQuery-v0.29.0])**\n   * that are being deprecated.\n   *\n   * @param {String} callbackQueryId Unique identifier for the query to be answered\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#answercallbackquery\n   */\n  answerCallbackQuery(callbackQueryId, form = {}) {\n    /* The older method signature (in/before v0.27.1) was answerCallbackQuery(callbackQueryId, text, showAlert).\n     * We need to ensure backwards-compatibility while maintaining\n     * consistency of the method signatures throughout the library */\n    if (typeof form !== 'object') {\n      /* eslint-disable no-param-reassign, prefer-rest-params */\n      deprecate('The method signature answerCallbackQuery(callbackQueryId, text, showAlert) has been deprecated since v0.27.1');\n      form = {\n        callback_query_id: arguments[0],\n        text: arguments[1],\n        show_alert: arguments[2],\n      };\n      /* eslint-enable no-param-reassign, prefer-rest-params */\n    }\n    /* The older method signature (in/before v0.29.0) was answerCallbackQuery([options]).\n     * We need to ensure backwards-compatibility while maintaining\n     * consistency of the method signatures throughout the library. */\n    if (typeof callbackQueryId === 'object') {\n      /* eslint-disable no-param-reassign, prefer-rest-params */\n      deprecate('The method signature answerCallbackQuery([options]) has been deprecated since v0.29.0');\n      form = callbackQueryId;\n      /* eslint-enable no-param-reassign, prefer-rest-params */\n    } else {\n      form.callback_query_id = callbackQueryId;\n    }\n    return this._request('answerCallbackQuery', { form });\n  }\n\n  /**\n   * Use this method to stores a message that can be sent by a user of a Mini App.\n   *\n   * @param {Number} userId Unique identifier of the target user\n   * @param {InlineQueryResult} result object that represents one result of an inline query\n   * @param {Object} [options] Optional form data to include in the request\n   * @return {Promise} On success, returns a [PreparedInlineMessage](https://core.telegram.org/bots/api#preparedinlinemessage) object.\n   * @see https://core.telegram.org/bots/api#savepreparedinlinemessage\n   */\n  savePreparedInlineMessage(userId, result, form = {}) {\n    form.user_id = userId;\n    form.result = stringify(result);\n    return this._request('savePreparedInlineMessage', { form });\n  }\n\n  /**\n   * Use this method to get the list of boosts added to a chat by a use.\n   * Requires administrator rights in the chat\n   *\n   * @param {Number|String} chatId  Unique identifier for the group/channel\n   * @param {Number} userId Unique identifier of the target user\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns a [UserChatBoosts](https://core.telegram.org/bots/api#userchatboosts) object\n   * @see https://core.telegram.org/bots/api#getuserchatboosts\n   */\n  getUserChatBoosts(chatId, userId, form = {}) {\n    form.chat_id = chatId;\n    form.user_id = userId;\n    return this._request('getUserChatBoosts', { form });\n  }\n\n  /**\n   * Use this method to get information about the connection of the bot with a business account\n   *\n   * @param {Number|String} businessConnectionId  Unique identifier for the group/channel\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns [BusinessConnection](https://core.telegram.org/bots/api#businessconnection) object\n   * @see https://core.telegram.org/bots/api#getbusinessconnection\n   */\n  getBusinessConnection(businessConnectionId, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    return this._request('getBusinessConnection', { form });\n  }\n\n  /**\n   * Use this method to change the list of the bot's commands.\n   *\n   * See https://core.telegram.org/bots#commands for more details about bot commands\n   *\n   * @param {Array} commands  List of bot commands to be set as the list of the [bot's commands](https://core.telegram.org/bots/api#botcommand). At most 100 commands can be specified.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setmycommands\n   */\n  setMyCommands(commands, form = {}) {\n    form.commands = stringify(commands);\n\n    if (form.scope) {\n      form.scope = stringify(form.scope);\n    }\n\n    return this._request('setMyCommands', { form });\n  }\n\n  /**\n   * Use this method to delete the list of the bot's commands for the given scope and user language.\n   *\n   *  After deletion, [higher level commands](https://core.telegram.org/bots/api#determining-list-of-commands) will be shown to affected users.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#deletemycommands\n   */\n  deleteMyCommands(form = {}) {\n    if (form.scope) {\n      form.scope = stringify(form.scope);\n    }\n    return this._request('deleteMyCommands', { form });\n  }\n\n\n  /**\n   * Use this method to get the current list of the bot's commands for the given scope and user language.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} Array of [BotCommand](https://core.telegram.org/bots/api#botcommand) on success. If commands aren't set, an empty list is returned.\n   * @see https://core.telegram.org/bots/api#getmycommands\n   */\n  getMyCommands(form = {}) {\n    if (form.scope) {\n      form.scope = stringify(form.scope);\n    }\n    return this._request('getMyCommands', { form });\n  }\n\n  /**\n   * Use this method to change the bot's name.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setmyname\n   */\n  setMyName(form = {}) {\n    return this._request('setMyName', { form });\n  }\n\n  /**\n   * Use this method to get the current bot name for the given user language.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} [BotName](https://core.telegram.org/bots/api#botname) on success\n   * @see https://core.telegram.org/bots/api#getmyname\n   */\n  getMyName(form = {}) {\n    return this._request('getMyName', { form });\n  }\n\n  /**\n   * Use this method to change the bot's description, which is shown in the chat with the bot if the chat is empty.\n   *\n   * Returns True on success.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setmydescription\n   */\n  setMyDescription(form = {}) {\n    return this._request('setMyDescription', { form });\n  }\n\n  /**\n   * Use this method to get the current bot description for the given user language.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} Returns [BotDescription](https://core.telegram.org/bots/api#botdescription) on success.\n   * @see https://core.telegram.org/bots/api#getmydescription\n   */\n  getMyDescription(form = {}) {\n    return this._request('getMyDescription', { form });\n  }\n\n  /**\n   * Use this method to change the bot's short description, which is shown on the bot's profile page\n   * and is sent together with the link when users share the bot.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} Returns True on success.\n   * @see https://core.telegram.org/bots/api#setmyshortdescription\n   */\n  setMyShortDescription(form = {}) {\n    return this._request('setMyShortDescription', { form });\n  }\n\n  /**\n   * Use this method to get the current bot short description for the given user language.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} Returns [BotShortDescription](https://core.telegram.org/bots/api#botshortdescription) on success.\n   * @see https://core.telegram.org/bots/api#getmyshortdescription\n   */\n  getMyShortDescription(form = {}) {\n    return this._request('getMyShortDescription', { form });\n  }\n\n  /**\n   * Changes the profile photo of the bot.\n   *\n   * @param {String|stream.Stream|Buffer} photo New profile photo.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setmyprofilephoto\n   */\n  setMyProfilePhoto(photo, options = {}) {\n    const opts = {\n      qs: options,\n    };\n\n    try {\n      const sendData = this._formatSendData('photo', photo);\n      opts.formData = sendData[0];\n      opts.qs.photo = sendData[1];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n\n    return this._request('setMyProfilePhoto', opts);\n  }\n\n  /**\n   * Removes the profile photo of the bot.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#removemyprofilephoto\n   */\n  removeMyProfilePhoto(form = {}) {\n    return this._request('removeMyProfilePhoto', { form });\n  }\n\n  /**\n   * Use this method to change the bot's menu button in a private chat, or the default menu button.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setchatmenubutton\n   */\n  setChatMenuButton(form = {}) {\n    return this._request('setChatMenuButton', { form });\n  }\n\n  /**\n   * Use this method to get the current value of the bot's menu button in a private chat, or the default menu button.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} [MenuButton](https://core.telegram.org/bots/api#menubutton) on success\n   * @see https://core.telegram.org/bots/api#getchatmenubutton\n   */\n  getChatMenuButton(form = {}) {\n    return this._request('getChatMenuButton', { form });\n  }\n\n  /**\n   * Use this method to change the default administrator rights requested by the bot when it's added as an administrator to groups or channels.\n   *\n   * These rights will be suggested to users, but they are are free to modify the list before adding the bot.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#getchatmenubutton\n   */\n  setMyDefaultAdministratorRights(form = {}) {\n    return this._request('setMyDefaultAdministratorRights', { form });\n  }\n\n  /**\n   * Use this method to get the current default administrator rights of the bot.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} [ChatAdministratorRights](https://core.telegram.org/bots/api#chatadministratorrights) on success\n   * @see https://core.telegram.org/bots/api#getmydefaultadministratorrights\n   */\n  getMyDefaultAdministratorRights(form = {}) {\n    return this._request('getMyDefaultAdministratorRights', { form });\n  }\n\n  /**\n   * Use this method to edit text or [game](https://core.telegram.org/bots/api#games) messages sent by the bot or via the bot (for inline bots).\n   *\n   * Note: that **you must provide one of chat_id, message_id, or inline_message_id** in your request.\n   *\n   * @param {String} text  New text of the message\n   * @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)\n   * @return {Promise} On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned\n   * @see https://core.telegram.org/bots/api#editmessagetext\n   */\n  editMessageText(text, form = {}) {\n    form.text = text;\n    return this._request('editMessageText', { form });\n  }\n\n  /**\n   * Use this method to edit captions of messages sent by the bot or via the bot (for inline bots).\n   *\n   * Note: You **must provide one of chat_id, message_id, or inline_message_id** in your request.\n   *\n   * @param {String} caption  New caption of the message\n   * @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)\n   * @return {Promise} On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned\n   * @see https://core.telegram.org/bots/api#editmessagecaption\n   */\n  editMessageCaption(caption, form = {}) {\n    form.caption = caption;\n    return this._request('editMessageCaption', { form });\n  }\n\n  /**\n   * Use this method to edit animation, audio, document, photo, or video messages.\n   *\n   * If a message is a part of a message album, then it can be edited only to a photo or a video.\n   *\n   * Otherwise, message type can be changed arbitrarily. When inline message is edited, new file can't be uploaded.\n   * Use previously uploaded file via its file_id or specify a URL.\n   *\n   * Note: You **must provide one of chat_id, message_id, or inline_message_id** in your request.\n   *\n   * @param {Object} media  A JSON-serialized object for a new media content of the message\n   * @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)\n   * @return {Promise} On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned\n   * @see https://core.telegram.org/bots/api#editmessagemedia\n   */\n  editMessageMedia(media, form = {}) {\n    const regexAttach = /attach:\\/\\/.+/;\n\n    if (typeof media.media === 'string' && regexAttach.test(media.media)) {\n      const opts = {\n        qs: form,\n      };\n\n      opts.formData = {};\n\n      const payload = Object.assign({}, media);\n      delete payload.media;\n\n      try {\n        const attachName = String(0);\n        const [formData] = this._formatSendData(\n          attachName,\n          media.media.replace('attach://', ''),\n          media.fileOptions\n        );\n\n        if (formData) {\n          opts.formData[attachName] = formData[attachName];\n          payload.media = `attach://${attachName}`;\n        } else {\n          throw new errors.FatalError(`Failed to process the replacement action for your ${media.type}`);\n        }\n      } catch (ex) {\n        return Promise.reject(ex);\n      }\n\n      opts.qs.media = stringify(payload);\n\n      return this._request('editMessageMedia', opts);\n    }\n\n    form.media = stringify(media);\n\n    return this._request('editMessageMedia', { form });\n  }\n\n  /**\n   * Use this method to edit a checklist on behalf of a business connection.\n   * @param {Number|String} businessConnectionId  Unique identifier for the target business connection\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {Number} messageId  Unique identifier for the target message\n   * @param {Object} checklist  A JSON-serialized object for the new checklist\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) object is returned.\n   * @see https://core.telegram.org/bots/api#editmessagechecklist\n   */\n  editMessageChecklist(businessConnectionId, chatId, messageId, checklist, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.chat_id = chatId;\n    form.message_id = messageId;\n    form.checklist = stringify(checklist);\n    return this._request('editMessageChecklist', { form });\n  }\n\n  /**\n   * Use this method to edit only the reply markup of messages sent by the bot or via the bot (for inline bots).\n   *\n   * Note: You **must provide one of chat_id, message_id, or inline_message_id** in your request.\n   *\n   * @param {Object} replyMarkup  A JSON-serialized object for an inline keyboard.\n   * @param {Object} [options] Additional Telegram query options (provide either one of chat_id, message_id, or inline_message_id here)\n   * @return {Promise} On success, if the edited message is not an inline message, the edited [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned\n   * @see https://core.telegram.org/bots/api#editmessagetext\n   */\n  editMessageReplyMarkup(replyMarkup, form = {}) {\n    form.reply_markup = replyMarkup;\n    return this._request('editMessageReplyMarkup', { form });\n  }\n\n  /**\n   * Use this method to stop a poll which was sent by the bot.\n   *\n   * @param {Number|String} chatId  Unique identifier for the group/channel\n   * @param {Number} pollId Identifier of the original message with the poll\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, the stopped [Poll](https://core.telegram.org/bots/api#poll) is returned\n   * @see https://core.telegram.org/bots/api#stoppoll\n   */\n  stopPoll(chatId, pollId, form = {}) {\n    form.chat_id = chatId;\n    form.message_id = pollId;\n    return this._request('stopPoll', { form });\n  }\n\n  /**\n   * Use this method to approve a suggested post in a direct messages chat.\n   *\n   * The bot must have the 'can_post_messages' administrator right in the corresponding channel chat. \n   *\n   * @param {Number|String} chatId  Unique identifier for the group/channel\n   * @param {Number} messageId Identifier of the original message with the suggested post\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} on success, returns True\n   * @see https://core.telegram.org/bots/api#approvesuggestedpost\n   */\n  approveSuggestedPost(chatId, messageId, form = {}) {\n    form.chat_id = chatId;\n    form.message_id = messageId;\n    return this._request('approveSuggestedPost', { form });\n  }\n\n  /**\n   * Use this method to decline a suggested post in a direct messages chat.\n   *\n   * The bot must have the 'can_manage_direct_messages' administrator right in the corresponding channel chat.\n   *\n   * @param {Number|String} chatId  Unique identifier for the group/channel\n   * @param {Number} messageId Identifier of the original message with the suggested post\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} on success, returns True\n   * @see https://core.telegram.org/bots/api#declinesuggestedpost\n   */\n  declineSuggestedPost(chatId, messageId, form = {}) {\n    form.chat_id = chatId;\n    form.message_id = messageId;\n    return this._request('declineSuggestedPost', { form });\n  }\n\n  /**\n   * Use this method to send static .WEBP, [animated](https://telegram.org/blog/animated-stickers) .TGS,\n   * or [video](https://telegram.org/blog/video-stickers-better-reactions) .WEBM stickers.\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String|stream.Stream|Buffer} sticker A file path, Stream or Buffer.\n   * Can also be a `file_id` previously uploaded. Stickers are WebP format files.\n   * @param {Object} [options] Additional Telegram query options\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) is returned\n   * @see https://core.telegram.org/bots/api#sendsticker\n   */\n  sendSticker(chatId, sticker, options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options\n    };\n    opts.qs.chat_id = chatId;\n    try {\n      const sendData = this._formatSendData('sticker', sticker, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.sticker = sendData[1];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('sendSticker', opts);\n  }\n\n  /**\n   * Use this method to get a sticker set.\n   *\n   * @param {String} name Name of the sticker set\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, a [StickerSet](https://core.telegram.org/bots/api#stickerset) object is returned\n   * @see https://core.telegram.org/bots/api#getstickerset\n   */\n  getStickerSet(name, form = {}) {\n    form.name = name;\n    return this._request('getStickerSet', { form });\n  }\n\n  /**\n   * Use this method to get information about custom emoji stickers by their identifiers.\n   *\n   * @param {Array} custom_emoji_ids List of custom emoji identifiers. At most 200 custom emoji identifiers can be specified.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} Array of [Sticker](https://core.telegram.org/bots/api#sticker) objects.\n   * @see https://core.telegram.org/bots/api#getcustomemojistickers\n   */\n  getCustomEmojiStickers(customEmojiIds, form = {}) {\n    form.custom_emoji_ids = stringify(customEmojiIds);\n    return this._request('getCustomEmojiStickers', { form });\n  }\n\n  /**\n   * Use this method to upload a file with a sticker for later use in *createNewStickerSet* and *addStickerToSet* methods (can be used multiple\n   * times).\n   *\n   * @param {Number} userId User identifier of sticker file owner\n   * @param {String|stream.Stream|Buffer} sticker A file path or a Stream with the sticker in .WEBP, .PNG, .TGS, or .WEBM format. Can also be a `file_id` previously uploaded.\n   * @param {String} stickerFormat Allow values:  `static`, `animated` or `video`\n   * @param {Object} [options] Additional Telegram query options\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise} On success, a [File](https://core.telegram.org/bots/api#file) object is returned\n   * @see https://core.telegram.org/bots/api#uploadstickerfile\n   */\n  uploadStickerFile(userId, sticker, stickerFormat = 'static', options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options,\n    };\n    opts.qs.user_id = userId;\n    opts.qs.sticker_format = stickerFormat;\n\n    try {\n      const sendData = this._formatSendData('sticker', sticker, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.sticker = sendData[1];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('uploadStickerFile', opts);\n  }\n\n  /**\n   * Use this method to create new sticker set owned by a user.\n   *\n   * The bot will be able to edit the created sticker set.\n   *\n   * You must use exactly one of the fields *png_sticker*, *tgs_sticker*, or *webm_sticker*\n   *\n   * @param {Number} userId User identifier of created sticker set owner\n   * @param {String} name Short name of sticker set, to be used in `t.me/addstickers/` URLs (e.g.,   *\"animals\"*). Can contain only english letters, digits and underscores.\n   *  Must begin with a letter, can't contain consecutive underscores and must end in `\"_by_<bot_username>\"`. `<bot_username>` is case insensitive. 1-64 characters.\n   * @param {String} title Sticker set title, 1-64 characters\n   * @param {String|stream.Stream|Buffer} pngSticker Png image with the sticker, must be up to 512 kilobytes in size,\n   *  dimensions must not exceed 512px, and either width or height must be exactly 512px.\n   * @param {String} emojis One or more emoji corresponding to the sticker\n   * @param {Object} [options] Additional Telegram query options\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise}  True on success\n   * @see https://core.telegram.org/bots/api#createnewstickerset\n   */\n  createNewStickerSet(userId, name, title, pngSticker, emojis, options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options,\n    };\n    opts.qs.user_id = userId;\n    opts.qs.name = name;\n    opts.qs.title = title;\n    opts.qs.emojis = emojis;\n    opts.qs.mask_position = stringify(options.mask_position);\n    try {\n      const sendData = this._formatSendData('png_sticker', pngSticker, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.png_sticker = sendData[1];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('createNewStickerSet', opts);\n  }\n\n  /**\n   * Use this method to add a new sticker to a set created by the bot.\n   *\n   * You must use exactly one of the fields *png_sticker*, *tgs_sticker*, or *webm_sticker*\n   *\n   * Animated stickers can be added to animated sticker sets and only to them\n   *\n   * Note:\n   * - Emoji sticker sets can have up to 200 sticker\n   * - Static or Animated sticker sets can have up to 120 stickers\n   *\n   * @param {Number} userId User identifier of sticker set owner\n   * @param {String} name Sticker set name\n   * @param {String|stream.Stream|Buffer} sticker Png image with the sticker (must be up to 512 kilobytes in size,\n   * dimensions must not exceed 512px, and either width or height must be exactly 512px, [TGS animation](https://core.telegram.org/stickers#animated-sticker-requirements)\n   * with the sticker or [WEBM video](https://core.telegram.org/stickers#video-sticker-requirements) with the sticker.\n   * @param {String} emojis One or more emoji corresponding to the sticker\n   * @param {String} stickerType Allow values: `png_sticker`, `tgs_sticker`, or `webm_sticker`.\n   * @param {Object} [options] Additional Telegram query options\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise}  True on success\n   * @see https://core.telegram.org/bots/api#addstickertoset\n   */\n  addStickerToSet(userId, name, sticker, emojis, stickerType = 'png_sticker', options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options,\n    };\n    opts.qs.user_id = userId;\n    opts.qs.name = name;\n    opts.qs.emojis = emojis;\n    opts.qs.mask_position = stringify(options.mask_position);\n\n    if (typeof stickerType !== 'string' || ['png_sticker', 'tgs_sticker', 'webm_sticker'].indexOf(stickerType) === -1) {\n      return Promise.reject(new Error('stickerType must be a string and the allow types is: png_sticker, tgs_sticker, webm_sticker'));\n    }\n\n    try {\n      const sendData = this._formatSendData(stickerType, sticker, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs[stickerType] = sendData[1];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('addStickerToSet', opts);\n  }\n\n  /**\n   * Use this method to move a sticker in a set created by the bot to a specific position.\n   *\n   * @param {String} sticker File identifier of the sticker\n   * @param {Number} position New sticker position in the set, zero-based\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setstickerpositioninset\n   */\n  setStickerPositionInSet(sticker, position, form = {}) {\n    form.sticker = sticker;\n    form.position = position;\n    return this._request('setStickerPositionInSet', { form });\n  }\n\n  /**\n   * Use this method to delete a sticker from a set created by the bot.\n   *\n   * @param {String} sticker File identifier of the sticker\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#deletestickerfromset\n   * @todo Add tests for this method!\n   */\n  deleteStickerFromSet(sticker, form = {}) {\n    form.sticker = sticker;\n    return this._request('deleteStickerFromSet', { form });\n  }\n\n  /**\n   * Use this method to replace an existing sticker in a sticker set with a new one\n   *\n   * @param {Number} userId User identifier of the sticker set owner\n   * @param {String} name Sticker set name\n   * @param {String} sticker File identifier of the sticker\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#replacestickerinset\n   * @todo Add tests for this method!\n   */\n  replaceStickerInSet(userId, name, oldSticker, form = {}) {\n    form.user_id = userId;\n    form.name = name;\n    form.old_sticker = oldSticker;\n    return this._request('replaceStickerInSet', { form });\n  }\n\n\n  /**\n   * Use this method to change the list of emoji assigned to a regular or custom emoji sticker.\n   *\n   * The sticker must belong to a sticker set created by the bot.\n   *\n   * @param {String} sticker File identifier of the sticker\n   * @param { Array } emojiList A JSON-serialized list of 1-20 emoji associated with the sticker\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setstickeremojilist\n   */\n  setStickerEmojiList(sticker, emojiList, form = {}) {\n    form.sticker = sticker;\n    form.emoji_list = stringify(emojiList);\n    return this._request('setStickerEmojiList', { form });\n  }\n\n  /**\n   * Use this method to change the list of emoji assigned to a `regular` or `custom emoji` sticker.\n   *\n   * The sticker must belong to a sticker set created by the bot.\n   *\n   * @param {String} sticker File identifier of the sticker\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setstickerkeywords\n   */\n  setStickerKeywords(sticker, form = {}) {\n    form.sticker = sticker;\n    if (form.keywords) {\n      form.keywords = stringify(form.keywords);\n    }\n    return this._request('setStickerKeywords', { form });\n  }\n\n  /**\n   * Use this method to change the [mask position](https://core.telegram.org/bots/api#maskposition) of a mask sticker.\n   *\n   * The sticker must belong to a sticker set created by the bot.\n   *\n   * @param {String} sticker File identifier of the sticker\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setstickermaskposition\n   */\n  setStickerMaskPosition(sticker, form = {}) {\n    form.sticker = sticker;\n    if (form.mask_position) {\n      form.mask_position = stringify(form.mask_position);\n    }\n    return this._request('setStickerMaskPosition', { form });\n  }\n\n  /**\n   * Use this method to set the title of a created sticker set.\n   *\n   * The sticker must belong to a sticker set created by the bot.\n   *\n   * @param {String} name Sticker set name\n   * @param {String} title Sticker set title, 1-64 characters\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setstickersettitle\n   */\n  setStickerSetTitle(name, title, form = {}) {\n    form.name = name;\n    form.title = title;\n    return this._request('setStickerSetTitle', { form });\n  }\n\n  /**\n   * Use this method to add a thumb to a set created by the bot.\n   *\n   * Animated thumbnails can be set for animated sticker sets only. Video thumbnails can be set only for video sticker sets only\n   *\n   * @param {Number} userId User identifier of sticker set owner\n   * @param {String} name Sticker set name\n   * @param {String|stream.Stream|Buffer} thumbnail A .WEBP or .PNG image with the thumbnail,\n   * must be up to 128 kilobytes in size and have width and height exactly 100px,\n   * a TGS animation with the thumbnail up to 32 kilobytes in size or a WEBM video with the thumbnail up to 32 kilobytes in size.\n   *\n   * Pass a file_id as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram\n   * to get a file from the Internet, or upload a new one. Animated sticker set thumbnails can't be uploaded via HTTP URL.\n   * @param {Object} [options] Additional Telegram query options\n   * @param {Object} [fileOptions] Optional file related meta-data\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setstickersetthumbnail\n   */\n  setStickerSetThumbnail(userId, name, thumbnail, options = {}, fileOptions = {}) {\n    const opts = {\n      qs: options,\n    };\n    opts.qs.user_id = userId;\n    opts.qs.name = name;\n    opts.qs.mask_position = stringify(options.mask_position);\n    try {\n      const sendData = this._formatSendData('thumbnail', thumbnail, fileOptions);\n      opts.formData = sendData[0];\n      opts.qs.thumbnail = sendData[1];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n    return this._request('setStickerSetThumbnail', opts);\n  }\n\n\n  /**\n   * Use this method to set the thumbnail of a custom emoji sticker set.\n   *\n   * The sticker must belong to a sticker set created by the bot.\n   *\n   * @param {String} name Sticker set name\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#setcustomemojistickersetthumbnail\n   */\n  setCustomEmojiStickerSetThumbnail(name, form = {}) {\n    form.name = name;\n    return this._request('setCustomEmojiStickerSetThumbnail', { form });\n  }\n\n  /**\n   * Use this method to delete a sticker set that was created by the bot.\n   *\n   * The sticker must belong to a sticker set created by the bot.\n   *\n   * @param {String} name Sticker set name\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} True on success\n   * @see https://core.telegram.org/bots/api#deletestickerset\n   */\n  deleteStickerSet(name, form = {}) {\n    form.name = name;\n    return this._request('deleteStickerSet', { form });\n  }\n\n  /**\n   * Send answers to an inline query.\n   *\n   * Note: No more than 50 results per query are allowed.\n   *\n   * @param {String} inlineQueryId Unique identifier of the query\n   * @param {InlineQueryResult[]} results An array of results for the inline query\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, True is returned\n   * @see https://core.telegram.org/bots/api#answerinlinequery\n   */\n  answerInlineQuery(inlineQueryId, results, form = {}) {\n    form.inline_query_id = inlineQueryId;\n    form.results = stringify(results);\n    return this._request('answerInlineQuery', { form });\n  }\n\n  /**\n   * Use this method to set the result of an interaction with a [Web App](https://core.telegram.org/bots/webapps)\n   * and send a corresponding message on behalf of the user to the chat from which the query originated.\n   *\n   * @param {String} webAppQueryId Unique identifier for the query to be answered\n   * @param {InlineQueryResult} result object that represents one result of an inline query\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, a [SentWebAppMessage](https://core.telegram.org/bots/api#sentwebappmessage) object is returned\n   * @see https://core.telegram.org/bots/api#answerwebappquery\n   */\n  answerWebAppQuery(webAppQueryId, result, form = {}) {\n    form.web_app_query_id = webAppQueryId;\n    form.result = stringify(result);\n    return this._request('answerWebAppQuery', { form });\n  }\n\n  /**\n   * Use this method to send an invoice.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String} title Product name, 1-32 characters\n   * @param {String} description Product description, 1-255 characters\n   * @param {String} payload Bot defined invoice payload, 1-128 bytes. This will not be displayed to the user, use for your internal processes.\n   * @param {String} providerToken Payments provider token, obtained via `@BotFather`\n   * @param {String} currency Three-letter ISO 4217 currency code\n   * @param {Array} prices Breakdown of prices\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) is returned\n   * @see https://core.telegram.org/bots/api#sendinvoice\n   */\n  sendInvoice(chatId, title, description, payload, providerToken, currency, prices, form = {}) {\n    form.chat_id = chatId;\n    form.title = title;\n    form.description = description;\n    form.payload = payload;\n    form.provider_token = providerToken;\n    form.currency = currency;\n    form.prices = stringify(prices);\n    form.provider_data = stringify(form.provider_data);\n    if (form.suggested_tip_amounts) {\n      form.suggested_tip_amounts = stringify(form.suggested_tip_amounts);\n    }\n    return this._request('sendInvoice', { form });\n  }\n\n  /**\n  * Use this method to create a link for an invoice.\n  *\n  * @param {String} title Product name, 1-32 characters\n  * @param {String} description Product description, 1-255 characters\n  * @param {String} payload Bot defined invoice payload\n  * @param {String} providerToken Payment provider token\n  * @param {String} currency Three-letter ISO 4217 currency code\n  * @param {Array} prices Breakdown of prices\n  * @param {Object} [options] Additional Telegram query options\n  * @returns {Promise} The created invoice link as String on success.\n  * @see https://core.telegram.org/bots/api#createinvoicelink\n  */\n  createInvoiceLink(title, description, payload, providerToken, currency, prices, form = {}) {\n    form.title = title;\n    form.description = description;\n    form.payload = payload;\n    form.provider_token = providerToken;\n    form.currency = currency;\n    form.prices = stringify(prices);\n    return this._request('createInvoiceLink', { form });\n  }\n\n  /**\n  * Use this method to reply to shipping queries.\n  *\n  * If you sent an invoice requesting a shipping address and the parameter is_flexible was specified,\n  * the Bot API will send an [Update](https://core.telegram.org/bots/api#update) with a shipping_query field to the bot\n  *\n  * @param {String} shippingQueryId  Unique identifier for the query to be answered\n  * @param {Boolean} ok Specify if delivery of the product is possible\n  * @param {Object} [options] Additional Telegram query options\n  * @return {Promise} On success, True is returned\n  * @see https://core.telegram.org/bots/api#answershippingquery\n  */\n  answerShippingQuery(shippingQueryId, ok, form = {}) {\n    form.shipping_query_id = shippingQueryId;\n    form.ok = ok;\n    form.shipping_options = stringify(form.shipping_options);\n    return this._request('answerShippingQuery', { form });\n  }\n\n  /**\n   * Use this method to respond to such pre-checkout queries\n   *\n   * Once the user has confirmed their payment and shipping details, the Bot API sends the final confirmation in the form of\n   * an [Update](https://core.telegram.org/bots/api#update) with the field *pre_checkout_query*.\n   *\n   * **Note:** The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.\n   *\n   * @param {String} preCheckoutQueryId  Unique identifier for the query to be answered\n   * @param {Boolean} ok Specify if every order details are ok\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, True is returned\n   * @see https://core.telegram.org/bots/api#answerprecheckoutquery\n   */\n  answerPreCheckoutQuery(preCheckoutQueryId, ok, form = {}) {\n    form.pre_checkout_query_id = preCheckoutQueryId;\n    form.ok = ok;\n    return this._request('answerPreCheckoutQuery', { form });\n  }\n\n  /**\n   * Use this method to get the current Telegram Stars balance of the bot.\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns a [StarAmount](https://core.telegram.org/bots/api#staramount) object\n   * @see https://core.telegram.org/bots/api#getmystarbalance\n   */\n  getMyStarBalance(form = {}) {\n    return this._request('getMyStarBalance', { form });\n  }\n\n  /**\n   * Use this method for get the bot's Telegram Star transactions in chronological order\n   *\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns a [StarTransactions](https://core.telegram.org/bots/api#startransactions) object\n   * @see https://core.telegram.org/bots/api#getstartransactions\n   */\n  getStarTransactions(form = {}) {\n    return this._request('getStarTransactions', { form });\n  }\n\n  /**\n   * Use this method for refund a successful payment in [Telegram Stars](https://t.me/BotNews/90)\n   *\n   * @param {Number} userId  Unique identifier of the user whose payment will be refunded\n   * @param {String} telegramPaymentChargeId Telegram payment identifier\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, True is returned\n   * @see https://core.telegram.org/bots/api#refundstarpayment\n   */\n  refundStarPayment(userId, telegramPaymentChargeId, form = {}) {\n    form.user_id = userId;\n    form.telegram_payment_charge_id = telegramPaymentChargeId;\n    return this._request('refundStarPayment', { form });\n  }\n\n  /**\n   * Allows the bot to cancel or re-enable extension of a subscription paid in Telegram Stars.\n   *\n   * @param {Number} userId Unique identifier of the user whose subscription will be canceled or re-enabled\n   * @param {String} telegramPaymentChargeId Telegram payment identifier for the subscription\n   * @param {Boolean} isCanceled True, if the subscription should be canceled, False, if it should be re-enabled\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, True is returned\n   * @see https://core.telegram.org/bots/api#cancelrenewsubscription\n   */\n  editUserStarSubscription(userId, telegramPaymentChargeId, isCanceled, form = {}) {\n    form.user_id = userId;\n    form.telegram_payment_charge_id = telegramPaymentChargeId;\n    form.is_canceled = isCanceled;\n    return this._request('editUserStarSubscription', { form });\n  }\n\n  /**\n   * Use this method to send a game.\n   *\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`)\n   * @param {String} gameShortName name of the game to be sent. Set up your games via `@BotFather`.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, the sent [Message](https://core.telegram.org/bots/api#message) is returned\n   * @see https://core.telegram.org/bots/api#sendgame\n   */\n  sendGame(chatId, gameShortName, form = {}) {\n    form.chat_id = chatId;\n    form.game_short_name = gameShortName;\n    return this._request('sendGame', { form });\n  }\n\n  /**\n   * Use this method to set the score of the specified user in a game message.\n   *\n   * @param {Number} userId  Unique identifier of the target user\n   * @param {Number} score New score value, must be non-negative\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, if the message is not an inline message, the [Message](https://core.telegram.org/bots/api#message) is returned, otherwise True is returned\n   * @see https://core.telegram.org/bots/api#setgamescore\n   */\n  setGameScore(userId, score, form = {}) {\n    form.user_id = userId;\n    form.score = score;\n    return this._request('setGameScore', { form });\n  }\n\n  /**\n   * Use this method to get data for high score tables.\n   *\n   * Will return the score of the specified user and several of their neighbors in a game.\n   *\n   * @param {Number} userId  Unique identifier of the target user\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns an Array of [GameHighScore](https://core.telegram.org/bots/api#gamehighscore) objects\n   * @see https://core.telegram.org/bots/api#getgamehighscores\n   */\n  getGameHighScores(userId, form = {}) {\n    form.user_id = userId;\n    return this._request('getGameHighScores', { form });\n  }\n\n\n  /**\n * Use this method to delete a message, including service messages, with the following limitations:\n * - A message can only be deleted if it was sent less than 48 hours ago.\n * - A dice message can only be deleted if it was sent more than 24 hours ago.\n * - Bots can delete outgoing messages in groups and supergroups.\n * - Bots can delete incoming messages in groups, supergroups and channels.\n * - Bots granted `can_post_messages` permissions can delete outgoing messages in channels.\n * - If the bot is an administrator of a group, it can delete any message there.\n * - If the bot has `can_delete_messages` permission in a supergroup, it can delete any message there.\n *\n * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format @channelusername)\n * @param {Number} messageId  Unique identifier of the target message\n * @param {Object} [options] Additional Telegram query options\n * @return {Promise} True on success\n * @see https://core.telegram.org/bots/api#deletemessage\n */\n  deleteMessage(chatId, messageId, form = {}) {\n    form.chat_id = chatId;\n    form.message_id = messageId;\n    return this._request('deleteMessage', { form });\n  }\n\n  /**\n   * Use this method to delete multiple messages simultaneously. If some of the specified messages can't be found, they are skipped.\n   *\n   * @param {Number|String} chatId  Unique identifier for the target chat or username of the target channel (in the format @channelusername)\n   * @param {Array<Number|String>} messageIds  Identifiers of 1-100 messages to delete. See deleteMessage for limitations on which messages can be deleted\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise<Boolean>} True on success\n   * @see https://core.telegram.org/bots/api#deletemessages\n   */\n  deleteMessages(chatId, messageIds, form = {}) {\n    form.chat_id = chatId;\n    form.message_ids = stringify(messageIds);\n    return this._request('deleteMessages', { form });\n  }\n\n  /**\n   * Use this method to returns the list of gifts that can be sent by the bot to users and channel chats.\n   *\n   * @param {Object} [options] Additional Telegram query options.\n   * @return {Promise} On success, returns a [Gifts](https://core.telegram.org/bots/api#gifts) objects.\n   * @see https://core.telegram.org/bots/api#getavailablegifts\n   */\n  getAvailableGifts(form = {}) {\n    return this._request('getAvailableGifts', { form });\n  }\n\n  /**\n   * Use this method to sends a gift to the given user or channel chat.\n   *\n   * @param {String} giftId Unique identifier of the gift\n   * @param {Object} [options] Additional Telegram query options.\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#getavailablegifts\n   */\n  sendGift(giftId, form = {}) {\n    form.gift_id = giftId;\n    return this._request('sendGift', { form });\n  }\n\n  /**\n   * Use this method to sends a gift to the given user or channel chat.\n   *\n   * @param {Number} userId Unique identifier of the target user who will receive a Telegram Premium subscription.\n   * @param {Number} monthCount Number of months the Telegram Premium subscription will be active for the user; must be one of 3, 6, or 12.\n   * @param {String} starCount Number of Telegram Stars to pay for the Telegram Premium subscription; must be 1000 for 3 months, 1500 for 6 months, and 2500 for 12 months.\n   * @param {Object} [options] Additional Telegram query options.\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#getavailablegifts\n   */\n  giftPremiumSubscription(userId, monthCount, starCount, form = {}) {\n    form.user_id = userId;\n    form.month_count = monthCount;\n    form.star_count = starCount;\n    return this._request('giftPremiumSubscription', { form });\n  }\n\n  /**\n   * This method verifies a user [on behalf of the organization](https://telegram.org/verify#third-party-verification) which is represented by the bot.\n   *\n   * @param {Number} userId Unique identifier of the target user.\n   * @param {Object} [options] Additional Telegram query options.\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#verifyuser\n   */\n  verifyUser(userId, form = {}) {\n    form.user_id = userId;\n    return this._request('verifyUser', { form });\n  }\n\n  /**\n   * This method verifies a chat [on behalf of the organization](https://telegram.org/verify#third-party-verification) which is represented by the bot.\n   *\n   * @param {Number} chatId Unique identifier of the target chat.\n   * @return {Promise} On success, returns true.\n   * @param {Object} [options] Additional Telegram query options.\n   * @see https://core.telegram.org/bots/api#verifychat\n   */\n  verifyChat(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('verifyChat', { form });\n  }\n\n  /**\n   * This method removes verification from a user who is currently verified [on behalf of the organization](https://telegram.org/verify#third-party-verification) which is represented by the bot.\n   *\n   * @param {Number} userId Unique identifier of the target user\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#removeuserverification\n   */\n  removeUserVerification(userId, form = {}) {\n    form.user_id = userId;\n    return this._request('removeUserVerification', { form });\n  }\n\n  /**\n   * This method removes verification from a chat who is currently verified [on behalf of the organization](https://telegram.org/verify#third-party-verification) which is represented by the bot.\n   *\n   * @param {Number} chatId Unique identifier of the target chat.\n   * @param {Object} [options] Additional Telegram query options.\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#removechatverification\n   */\n  removeChatVerification(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('removeChatVerification', { form });\n  }\n\n  /**\n   * This method marks incoming message as read on behalf of a business account.\n   *\n   * Requires the **can_read_messages** business bot right\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection on behalf of which to read the message.\n   * @param {Number} chatId Unique identifier of the chat in which the message was received. The chat must have been active in the last 24 hours.\n   * @param {Number} messageId Unique identifier of the message to mark as read.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#readbusinessmessage\n   */\n  readBusinessMessage(businessConnectionId, chatId, messageId, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.chat_id = chatId;\n    form.message_id = messageId;\n    return this._request('readBusinessMessage', { form });\n  }\n\n  /**\n   * This method delete messages on behalf of a business account.\n   *\n   * Requires the **can_delete_outgoing_messages** business bot right to delete messages sent by the bot itself, or the **can_delete_all_messages business** bot right to delete any message.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection on behalf of which to delete the message.\n   * @param {Number[]} messageIds List of 1-100 identifiers of messages to delete. All messages **must be from the same chat**.\n   * @param {Object} [options] Additional Telegram query options.\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#deletebusinessmessages\n   */\n  deleteBusinessMessages(businessConnectionId, messageIds, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.message_ids = stringify(messageIds);\n    return this._request('deleteBusinessMessages', { form });\n  }\n\n  /**\n   * This method changes the first and last name of a managed business account.\n   *\n   * Requires the **can_change_name** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {String} firstName The new value of the first name for the business account; 1-64 characters.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#setbusinessaccountname\n   */\n  setBusinessAccountName(businessConnectionId, firstName, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.first_name = firstName;\n    return this._request('setBusinessAccountName', { form });\n  }\n\n  /**\n   * This method changes the username of a managed business account.\n   *\n   * Requires the **can_change_username** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#setbusinessaccountusername\n   */\n  setBusinessAccountUsername(businessConnectionId, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    return this._request('setBusinessAccountUsername', { form });\n  }\n\n  /**\n   * This method changes the bio of a managed business account.\n   *\n   * Requires the **can_change_bio** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#setbusinessaccountbio\n   */\n  setBusinessAccountBio(businessConnectionId, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    return this._request('setBusinessAccountBio', { form });\n  }\n\n  /**\n   * This method changes the profile photo of a managed business account.\n   *\n   * Requires the **can_edit_profile_photo** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {String|stream.Stream|Buffer} photo New profile photo.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#setbusinessaccountprofilephoto\n   */\n  setBusinessAccountProfilePhoto(businessConnectionId, photo, options = {}) {\n    const opts = {\n      qs: options,\n    };\n\n    opts.qs.business_connection_id = businessConnectionId;\n\n    try {\n      const sendData = this._formatSendData('photo', photo);\n      opts.formData = sendData[0];\n      opts.qs.photo = sendData[1];\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n\n    return this._request('setBusinessAccountProfilePhoto', opts);\n  }\n\n  /**\n   * This method removes the current profile photo of a managed business account.\n   *\n   * Requires the **can_edit_profile_photo** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#removebusinessaccountprofilephoto\n   */\n  removeBusinessAccountProfilePhoto(businessConnectionId, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    return this._request('removeBusinessAccountProfilePhoto', { form });\n  }\n\n  /**\n   * This method changes the privacy settings pertaining to incoming gifts in a managed business account.\n   *\n   * Requires the **can_change_gift_settings** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {Boolean} showGiftButton Pass True, if a button for sending a gift to the user or by the business account must always be shown in the input field.\n   * @param {Object} acceptedGiftTypes Types of gifts accepted by the business account.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns true.\n   * @see https://core.telegram.org/bots/api#setbusinessaccountgiftsettings\n   */\n  setBusinessAccountGiftSettings(businessConnectionId, showGiftButton, acceptedGiftTypes, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.show_gift_button = showGiftButton;\n    form.accepted_gift_types = acceptedGiftTypes;\n    return this._request('setBusinessAccountGiftSettings', { form });\n  }\n\n  /**\n   * This method returns the amount of Telegram Stars owned by a managed business account.\n   *\n   * Requires the **can_view_gifts_and_stars** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns [StarAmount](https://core.telegram.org/bots/api#staramount).\n   * @see https://core.telegram.org/bots/api#getbusinessaccountstarbalance\n   */\n  getBusinessAccountStarBalance(businessConnectionId, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    return this._request('getBusinessAccountStarBalance', { form });\n  }\n\n  /**\n   * This method transfers Telegram Stars from the business account balance to the bot's balance.\n   *\n   * Requires the **can_transfer_stars** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {Number} starCount Number of Telegram Stars to transfer; 1-10000.\n   * @param {Object} [options] Additional Telegram query options.\n   * @return {Promise} On success, returns True.\n   * @see https://core.telegram.org/bots/api#transferbusinessaccountstars\n   */\n  transferBusinessAccountStars(businessConnectionId, startCount, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.star_count = startCount;\n    return this._request('transferBusinessAccountStars', { form });\n  }\n\n  /**\n   * This method returns the gifts received and owned by a managed business account.\n   *\n   * Requires the **can_view_gifts_and_stars** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns [OwnedGifts](https://core.telegram.org/bots/api#ownedgifts).\n   * @see https://core.telegram.org/bots/api#getbusinessaccountgifts\n   */\n  getBusinessAccountGifts(businessConnectionId, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    return this._request('getBusinessAccountGifts', { form });\n  }\n\n  /**\n   * Use this method to get gifts owned by a regular user.\n   *\n   * @param {Number} userId Unique identifier of the target user.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns an [OwnedGifts](https://core.telegram.org/bots/api#ownedgifts) object.\n   * @see https://core.telegram.org/bots/api#getusergifts\n   */\n  getUserGifts(userId, form = {}) {\n    form.user_id = userId;\n    return this._request('getUserGifts', { form });\n  }\n\n  /**\n   * Use this method to get gifts received by a channel chat or a business account managed by the bot.\n   *\n   * Requires the **can_view_gifts_and_stars** administrator right if the chat is a channel.\n   *\n   * @param {Number|String} chatId Unique identifier for the target chat or username of the target channel (in the format `@channelusername`).\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns an [OwnedGifts](https://core.telegram.org/bots/api#ownedgifts) object.\n   * @see https://core.telegram.org/bots/api#getchatgifts\n   */\n  getChatGifts(chatId, form = {}) {\n    form.chat_id = chatId;\n    return this._request('getChatGifts', { form });\n  }\n\n  /**\n   * This method converts a given regular gift to Telegram Stars.\n   *\n   * Requires the **can_convert_gifts_to_stars** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {String} ownedGiftId Unique identifier of the regular gift that should be converted to Telegram Stars.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns True.\n   * @see https://core.telegram.org/bots/api#convertgifttostars\n   */\n  convertGiftToStars(businessConnectionId, ownedGiftId, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.owned_gift_id = ownedGiftId;\n    return this._request('convertGiftToStars', { form });\n  }\n\n  /**\n   * This method upgrades a given regular gift to a unique gift.\n   *\n   * Requires the **can_transfer_and_upgrade_gifts** business bot right.\n   * Additionally requires the **can_transfer_stars** business bot right **if the upgrade is paid**.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {String} ownedGiftId Unique identifier of the regular gift that should be upgraded to a unique one.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns True.\n   * @see https://core.telegram.org/bots/api#upgradegift\n   */\n  upgradeGift(businessConnectionId, ownedGiftId, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.owned_gift_id = ownedGiftId;\n    return this._request('upgradeGift', { form });\n  }\n\n  /**\n   * This method transfers an owned unique gift to another user.\n   *\n   * Requires the **can_transfer_and_upgrade_gifts** business bot right.\n   * Additionally requires the **can_transfer_stars** business bot right **if the transfer is paid**.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {String} ownedGiftId Unique identifier of the regular gift that should be transferred.\n   * @param {Number} newOwnerChatId Unique identifier of the chat which will own the gift. The chat **must be active in the last 24 hours**.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns True.\n   * @see https://core.telegram.org/bots/api#transfergift\n   */\n  transferGift(businessConnectionId, ownedGiftId, newOwnerChatId, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.owned_gift_id = ownedGiftId;\n    form.new_owner_chat_id = newOwnerChatId;\n    return this._request('transferGift', { form });\n  }\n\n  /**\n   * This method posts a story on behalf of a managed business account.\n   *\n   * Requires the **can_manage_stories** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {Array} content [InputStoryContent](https://core.telegram.org/bots/api#inputpaidmedia). The photo/video property can be String, Stream or Buffer.\n   * @param {Number} activePeriod Unique identifier of the chat which will own the gift. The chat **must be active in the last 24 hours**.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns [Story](https://core.telegram.org/bots/api#story).\n   * @see https://core.telegram.org/bots/api#poststory\n   */\n  postStory(businessConnectionId, content, activePeriod, options = {}) {\n    const opts = {\n      qs: options,\n    };\n\n    opts.qs.business_connection_id = businessConnectionId;\n    opts.qs.active_period = activePeriod;\n\n    try {\n      const inputHistoryContent = content;\n      opts.formData = {};\n\n      if (!content.type) {\n        return Promise.reject(new Error('content.type is required'));\n      }\n\n      const { formData, fileIds } = this._formatSendMultipleData(content.type, [content]);\n\n      opts.formData = formData;\n\n      if (fileIds[0]) {\n        inputHistoryContent[content.type] = fileIds[0];\n      } else {\n        inputHistoryContent[content.type] = `attach://${content.type}_0`;\n      }\n\n      opts.qs.content = stringify(inputHistoryContent);\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n\n    return this._request('postStory', opts);\n  }\n\n  /**\n   * This method reposts a story on behalf of a managed business account.\n   *\n   * Requires the **can_manage_stories** business bot right for both the source and destination accounts.\n   * The story must have been originally posted or reposted by the bot itself.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection of the account that will repost the story.\n   * @param {Number} fromChatId Unique identifier of the chat that originally posted the story.\n   * @param {Number} fromStoryId Unique identifier of the story to repost.\n   * @param {Number} activePeriod The period after which the story is moved to archive, in seconds; must be one of 21600, 43200, 86400, or 172800.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns a [Story](https://core.telegram.org/bots/api#story) object.\n   * @see https://core.telegram.org/bots/api#repoststory\n   */\n  repostStory(businessConnectionId, fromChatId, fromStoryId, activePeriod, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.from_chat_id = fromChatId;\n    form.from_story_id = fromStoryId;\n    form.active_period = activePeriod;\n    return this._request('repostStory', { form });\n  }\n\n  /**\n   * This method edits a story previously posted by the bot on behalf of a managed business account.\n   *\n   * Requires the **can_manage_stories** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {Number} storyId Unique identifier of the story to edit.\n   * @param {Array} content [InputStoryContent](https://core.telegram.org/bots/api#inputpaidmedia). The photo/video property can be String, Stream or Buffer.\n   * @param {Object} [options] Additional Telegram query options\n   * @return {Promise} On success, returns [Story](https://core.telegram.org/bots/api#story).\n   * @see https://core.telegram.org/bots/api#editstory\n   */\n  editStory(businessConnectionId, storyId, content, options = {}) {\n    const opts = {\n      qs: options,\n    };\n\n    opts.qs.business_connection_id = businessConnectionId;\n    opts.qs.story_id = storyId;\n\n    try {\n      const inputHistoryContent = content;\n      opts.formData = {};\n\n      if (!content.type) {\n        return Promise.reject(new Error('content.type is required'));\n      }\n\n      const { formData, fileIds } = this._formatSendMultipleData(content.type, [content]);\n\n      opts.formData = formData;\n\n      if (fileIds[0]) {\n        inputHistoryContent[content.type] = fileIds[0];\n      } else {\n        inputHistoryContent[content.type] = `attach://${content.type}_0`;\n      }\n\n      opts.qs.content = stringify(inputHistoryContent);\n    } catch (ex) {\n      return Promise.reject(ex);\n    }\n\n    return this._request('editStory', opts);\n  }\n\n\n  /**\n   * This method deletes a story previously posted by the bot on behalf of a managed business account.\n   *\n   * Requires the **can_manage_stories** business bot right.\n   *\n   * @param {String} businessConnectionId Unique identifier of the business connection.\n   * @param {Number} storyId Unique identifier of the story to delete.\n   * @param {Object} [options] Additional Telegram query options.\n   * @return {Promise} On success, returns True.\n   * @see https://core.telegram.org/bots/api#deletestory\n   */\n  deleteStory(businessConnectionId, storyId, form = {}) {\n    form.business_connection_id = businessConnectionId;\n    form.story_id = storyId;\n    return this._request('deleteStory', { form });\n  }\n\n}\n\nmodule.exports = TelegramBot;\n"
  },
  {
    "path": "src/telegramPolling.js",
    "content": "const errors = require('./errors');\nconst debug = require('debug')('node-telegram-bot-api');\nconst deprecate = require('./utils').deprecate;\nconst ANOTHER_WEB_HOOK_USED = 409;\n\n\nclass TelegramBotPolling {\n  /**\n   * Handles polling against the Telegram servers.\n   * @param  {TelegramBot} bot\n   * @see https://core.telegram.org/bots/api#getting-updates\n   */\n  constructor(bot) {\n    this.bot = bot;\n    this.options = (typeof bot.options.polling === 'boolean') ? {} : bot.options.polling;\n    this.options.interval = (typeof this.options.interval === 'number') ? this.options.interval : 300;\n    this.options.params = (typeof this.options.params === 'object') ? this.options.params : {};\n    this.options.params.offset = (typeof this.options.params.offset === 'number') ? this.options.params.offset : 0;\n    this.options.params.timeout = (typeof this.options.params.timeout === 'number') ? this.options.params.timeout : 10;\n    if (typeof this.options.timeout === 'number') {\n      deprecate('`options.polling.timeout` is deprecated. Use `options.polling.params` instead.');\n      this.options.params.timeout = this.options.timeout;\n    }\n    this._lastUpdate = 0;\n    this._lastRequest = null;\n    this._abort = false;\n    this._pollingTimeout = null;\n  }\n\n  /**\n   * Start polling\n   * @param  {Object} [options]\n   * @param  {Object} [options.restart]\n   * @return {Promise}\n   */\n  start(options = {}) {\n    if (this._lastRequest) {\n      if (!options.restart) {\n        return Promise.resolve();\n      }\n      return this.stop({\n        cancel: true,\n        reason: 'Polling restart',\n      }).then(() => {\n        return this._polling();\n      });\n    }\n    return this._polling();\n  }\n\n  /**\n   * Stop polling\n   * @param  {Object} [options] Options\n   * @param  {Boolean} [options.cancel] Cancel current request\n   * @param  {String} [options.reason] Reason for stopping polling\n   * @return {Promise}\n   */\n  stop(options = {}) {\n    if (!this._lastRequest) {\n      return Promise.resolve();\n    }\n    const lastRequest = this._lastRequest;\n    this._lastRequest = null;\n    clearTimeout(this._pollingTimeout);\n    if (options.cancel) {\n      const reason = options.reason || 'Polling stop';\n      lastRequest.cancel(reason);\n      return Promise.resolve();\n    }\n    this._abort = true;\n    return lastRequest.finally(() => {\n      this._abort = false;\n    });\n  }\n\n  /**\n   * Return `true` if is polling. Otherwise, `false`.\n   */\n  isPolling() {\n    return !!this._lastRequest;\n  }\n\n  /**\n   * Handle error thrown during polling.\n   * @private\n   * @param  {Error} error\n   */\n  _error(error) {\n    if (!this.bot.listeners('polling_error').length) {\n      return console.error(`${new Date().toISOString()} error: [polling_error] %j`, error); // eslint-disable-line no-console\n    }\n    return this.bot.emit('polling_error', error);\n  }\n\n  /**\n   * Invokes polling (with recursion!)\n   * @return {Promise} promise of the current request\n   * @private\n   */\n  _polling() {\n    this._lastRequest = this\n      ._getUpdates()\n      .then(updates => {\n        this._lastUpdate = Date.now();\n        debug('polling data %j', updates);\n        updates.forEach(update => {\n          this.options.params.offset = update.update_id + 1;\n          debug('updated offset: %s', this.options.params.offset);\n          try {\n            this.bot.processUpdate(update);\n          } catch (err) {\n            err._processing = true;\n            throw err;\n          }\n        });\n        return null;\n      })\n      .catch(err => {\n        debug('polling error: %s', err.message);\n        if (!err._processing) {\n          return this._error(err);\n        }\n        delete err._processing;\n        /*\n         * An error occured while processing the items,\n         * i.e. in `this.bot.processUpdate()` above.\n         * We need to mark the already-processed items\n         * to avoid fetching them again once the application\n         * is restarted, or moves to next polling interval\n         * (in cases where unhandled rejections do not terminate\n         * the process).\n         * See https://github.com/yagop/node-telegram-bot-api/issues/36#issuecomment-268532067\n         */\n        if (!this.bot.options.badRejection) {\n          return this._error(err);\n        }\n        const opts = {\n          offset: this.options.params.offset,\n          limit: 1,\n          timeout: 0,\n        };\n        return this.bot.getUpdates(opts).then(() => {\n          return this._error(err);\n        }).catch(requestErr => {\n          /*\n           * We have been unable to handle this error.\n           * We have to log this to stderr to ensure devops\n           * understands that they may receive already-processed items\n           * on app restart.\n           * We simply can not rescue this situation, emit \"error\"\n           * event, with the hope that the application exits.\n           */\n          /* eslint-disable no-console */\n          const bugUrl = 'https://github.com/yagop/node-telegram-bot-api/issues/36#issuecomment-268532067';\n          const ts = new Date().toISOString();\n          console.error(`${ts} error: Internal handling of The Offset Infinite Loop failed`);\n          console.error(`${ts} error: Due to error '${requestErr}'`);\n          console.error(`${ts} error: You may receive already-processed updates on app restart`);\n          console.error(`${ts} error: Please see ${bugUrl} for more information`);\n          /* eslint-enable no-console */\n          return this.bot.emit('error', new errors.FatalError(err));\n        });\n      })\n      .finally(() => {\n        if (this._abort) {\n          debug('Polling is aborted!');\n        } else {\n          debug('setTimeout for %s miliseconds', this.options.interval);\n          this._pollingTimeout = setTimeout(() => this._polling(), this.options.interval);\n        }\n      });\n    return this._lastRequest;\n  }\n\n  /**\n   * Unset current webhook. Used when we detect that a webhook has been set\n   * and we are trying to poll. Polling and WebHook are mutually exclusive.\n   * @see https://core.telegram.org/bots/api#getting-updates\n   * @private\n   */\n  _unsetWebHook() {\n    debug('unsetting webhook');\n    return this.bot._request('setWebHook');\n  }\n\n  /**\n   * Retrieve updates\n   */\n  _getUpdates() {\n    debug('polling with options: %j', this.options.params);\n    return this.bot.getUpdates(this.options.params)\n      .catch(err => {\n        if (err.response && err.response.statusCode === ANOTHER_WEB_HOOK_USED) {\n          return this._unsetWebHook().then(() => {\n            return this.bot.getUpdates(this.options.params);\n          });\n        }\n        throw err;\n      });\n  }\n}\n\nmodule.exports = TelegramBotPolling;\n"
  },
  {
    "path": "src/telegramWebHook.js",
    "content": "const errors = require('./errors');\nconst debug = require('debug')('node-telegram-bot-api');\nconst https = require('https');\nconst http = require('http');\nconst fs = require('fs');\nconst bl = require('bl');\n\nclass TelegramBotWebHook {\n  /**\n   * Sets up a webhook to receive updates\n   * @param  {TelegramBot} bot\n   * @see https://core.telegram.org/bots/api#getting-updates\n   */\n  constructor(bot) {\n    this.bot = bot;\n    this.options = (typeof bot.options.webHook === 'boolean') ? {} : bot.options.webHook;\n    this.options.host = this.options.host || '0.0.0.0';\n    this.options.port = this.options.port || 8443;\n    this.options.https = this.options.https || {};\n    this.options.healthEndpoint = this.options.healthEndpoint || '/healthz';\n    this._healthRegex = new RegExp(this.options.healthEndpoint);\n    this._webServer = null;\n    this._open = false;\n    this._requestListener = this._requestListener.bind(this);\n    this._parseBody = this._parseBody.bind(this);\n\n    if (this.options.key && this.options.cert) {\n      debug('HTTPS WebHook enabled (by key/cert)');\n      this.options.https.key = fs.readFileSync(this.options.key);\n      this.options.https.cert = fs.readFileSync(this.options.cert);\n      this._webServer = https.createServer(this.options.https, this._requestListener);\n    } else if (this.options.pfx) {\n      debug('HTTPS WebHook enabled (by pfx)');\n      this.options.https.pfx = fs.readFileSync(this.options.pfx);\n      this._webServer = https.createServer(this.options.https, this._requestListener);\n    } else if (Object.keys(this.options.https).length) {\n      debug('HTTPS WebHook enabled by (https)');\n      this._webServer = https.createServer(this.options.https, this._requestListener);\n    } else {\n      debug('HTTP WebHook enabled');\n      this._webServer = http.createServer(this._requestListener);\n    }\n  }\n\n  /**\n   * Open WebHook by listening on the port\n   * @return {Promise}\n   */\n  open() {\n    if (this.isOpen()) {\n      return Promise.resolve();\n    }\n    return new Promise((resolve, reject) => {\n      this._webServer.listen(this.options.port, this.options.host, () => {\n        debug('WebHook listening on port %s', this.options.port);\n        this._open = true;\n        return resolve();\n      });\n\n      this._webServer.once('error', (err) => {\n        reject(err);\n      });\n    });\n  }\n\n  /**\n   * Close the webHook\n   * @return {Promise}\n   */\n  close() {\n    if (!this.isOpen()) {\n      return Promise.resolve();\n    }\n    return new Promise((resolve, reject) => {\n      this._webServer.close(error => {\n        if (error) return reject(error);\n        this._open = false;\n        return resolve();\n      });\n    });\n  }\n\n  /**\n   * Return `true` if server is listening. Otherwise, `false`.\n   */\n  isOpen() {\n    // NOTE: Since `http.Server.listening` was added in v5.7.0\n    // and we still need to support Node v4,\n    // we are going to fallback to 'this._open'.\n    // The following LOC would suffice for newer versions of Node.js\n    // return this._webServer.listening;\n    return this._open;\n  }\n\n  /**\n   * Handle error thrown during processing of webhook request.\n   * @private\n   * @param  {Error} error\n   */\n  _error(error) {\n    if (!this.bot.listeners('webhook_error').length) {\n      return console.error(`${new Date().toISOString()} error: [webhook_error] %j`, error); // eslint-disable-line no-console\n    }\n    return this.bot.emit('webhook_error', error);\n  }\n\n  /**\n   * Handle request body by passing it to 'callback'\n   * @private\n   */\n  _parseBody(error, body) {\n    if (error) {\n      return this._error(new errors.FatalError(error));\n    }\n\n    let data;\n    try {\n      data = JSON.parse(body.toString());\n    } catch (parseError) {\n      return this._error(new errors.ParseError(parseError.message));\n    }\n\n    return this.bot.processUpdate(data);\n  }\n\n  /**\n   * Listener for 'request' event on server\n   * @private\n   * @see https://nodejs.org/docs/latest/api/http.html#http_http_createserver_requestlistener\n   * @see https://nodejs.org/docs/latest/api/https.html#https_https_createserver_options_requestlistener\n   */\n  _requestListener(req, res) {\n    debug('WebHook request URL: %s', req.url);\n    debug('WebHook request headers: %j', req.headers);\n\n    if (req.url.indexOf(this.bot.token) !== -1) {\n      if (req.method !== 'POST') {\n        debug('WebHook request isn\\'t a POST');\n        res.statusCode = 418; // I'm a teabot!\n        res.end();\n      } else {\n        req\n          .pipe(bl(this._parseBody))\n          .on('finish', () => res.end('OK'));\n      }\n    } else if (this._healthRegex.test(req.url)) {\n      debug('WebHook health check passed');\n      res.statusCode = 200;\n      res.end('OK');\n    } else {\n      debug('WebHook request unauthorized');\n      res.statusCode = 401;\n      res.end();\n    }\n  }\n}\n\nmodule.exports = TelegramBotWebHook;\n"
  },
  {
    "path": "src/utils.js",
    "content": "const util = require('util');\n// Native deprecation warning\nexports.deprecate = (msg) => util.deprecate(() => { }, msg, 'node-telegram-bot-api')();\n"
  },
  {
    "path": "test/README.md",
    "content": "Running the tests:\n\n```bash\n# Token to be used\nexport TEST_TELEGRAM_TOKEN=<YOUR_BOT_TOKEN>\n\n# User Id which you want to send the messages.\nexport TEST_USER_ID=<USER_ID>\n\n# Group Id which to use in some of the tests, e.g. for TelegramBot#getChat()\nexport TEST_GROUP_ID=<GROUP_ID>\n\n# Game short name to use in some tests, e.g. TelegramBot#sendGame()\n# Defaults to \"medusalab_test\".\nexport TEST_GAME_SHORT_NAME=<GAME_SHORT_NAME>\n\n# Sticker set name to use in some tests, e.g. TelegramBot#getStickerSet()\n# Defaults to \"pusheen\".\nexport TEST_STICKER_SET_NAME=<STICKER_SET_NAME>\n\n# Payment provider token to be used\nexport TEST_PROVIDER_TOKEN=<YOUR_PROVIDER_TOKEN>\n\n# Run ALL tests\nnpm run test\n\n# Run individual tests\nnpm run eslint              # static-analysis\nnpm run mocha               # mocha tests\n```\nNote: The bot must be an administrator in the chat for this to work and must have the appropriate admin rights."
  },
  {
    "path": "test/mocha.opts",
    "content": "--reporter spec\n--require  babel-register\n--timeout  30000\n"
  },
  {
    "path": "test/telegram.js",
    "content": "const TelegramBot = require('..');\nconst request = require('@cypress/request-promise');\nconst assert = require('assert');\nconst fs = require('fs');\nconst os = require('os');\nconst path = require('path');\nconst stream = require('stream');\nconst is = require('is');\nconst utils = require('./utils');\nconst isCI = require('is-ci');\nconst concat = require('concat-stream');\n\n// Allows self-signed certificates to be used in our tests\nprocess.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';\n\nconst TOKEN = process.env.TEST_TELEGRAM_TOKEN;\nif (!TOKEN) {\n  throw new Error('Bot token not provided');\n}\n\nconst PROVIDER_TOKEN = process.env.TEST_PROVIDER_TOKEN;\nif (!PROVIDER_TOKEN && !isCI) { // If is not running in Travis / Appveyor\n  throw new Error('Provider token not supplied');\n}\n\n// Telegram service if not User Id\nconst USERID = process.env.TEST_USER_ID || 777000;\nconst GROUPID = process.env.TEST_GROUP_ID || -1001075450562;\nconst GAME_SHORT_NAME = process.env.TEST_GAME_SHORT_NAME || 'medusalab_test';\nconst STICKER_SET_NAME = process.env.TEST_STICKER_SET_NAME || 'pusheen';\nconst CURRENT_TIMESTAMP = Date.now();\nconst timeout = 60 * 1000;\nlet portindex = 8091;\nconst staticPort = portindex++;\nconst pollingPort = portindex++;\nconst webHookPort = portindex++;\nconst pollingPort2 = portindex++;\nconst webHookPort2 = portindex++;\nconst badTgServerPort = portindex++;\nconst staticUrl = `http://127.0.0.1:${staticPort}`;\nconst key = `${__dirname}/../examples/ssl/key.pem`;\nconst cert = `${__dirname}/../examples/ssl/crt.pem`;\nconst ip = '216.58.210.174'; // Google IP ¯\\_(ツ)_/¯\nconst lat = 47.5351072;\nconst long = -52.7508537;\nconst FILE_PATH = `${__dirname}/data/photo.png`;\nlet FILE_ID;\nlet GAME_CHAT_ID;\nlet GAME_MSG_ID;\nlet BOT_USERNAME;\nlet CHAT_INFO;\nlet STICKER_FILE_ID_FROM_SET;\nlet STICKERS_FROM_BOT_SET;\n\nbefore(function beforeAll() {\n  utils.startStaticServer(staticPort);\n  return utils.startMockServer(pollingPort)\n    .then(() => {\n      return utils.startMockServer(pollingPort2);\n    }).then(() => {\n      return utils.startMockServer(badTgServerPort, { bad: true });\n    });\n});\n\n\ndescribe('module.exports', function moduleExportsSuite() {\n  const nodeVersion = parseInt(process.versions.node.split('.')[0], 10);\n  it('is loaded from src/ on Node.js v6+ and above', function test() {\n    if (nodeVersion <= 5) this.skip(); // skip on Node.js v5 and below\n    assert.strictEqual(TelegramBot, require('../src/telegram'));\n  });\n  it('is loaded from lib/ on Node.js v5 and below', function test() {\n    if (nodeVersion > 5) this.skip(); // skip on newer versions\n    assert.strictEqual(TelegramBot, require('../lib/telegram'));\n  });\n});\n\n\ndescribe('TelegramBot', function telegramSuite() {\n  let bot;\n  let testbot;\n  let botPolling;\n  let botWebHook;\n\n  before(function beforeAll() {\n    this.timeout(timeout);\n    bot = new TelegramBot(TOKEN);\n    testbot = new TelegramBot(TOKEN, {\n      baseApiUrl: `http://127.0.0.1:${pollingPort}`,\n      polling: {\n        autoStart: false,\n      },\n      webHook: {\n        autoOpen: false,\n        port: webHookPort,\n      },\n    });\n    botPolling = new TelegramBot(TOKEN, {\n      baseApiUrl: `http://127.0.0.1:${pollingPort2}`,\n      polling: true,\n    });\n    botWebHook = new TelegramBot(TOKEN, {\n      webHook: {\n        port: webHookPort2,\n      },\n    });\n\n    utils.handleRatelimit(bot, 'sendPhoto', this);\n    utils.handleRatelimit(bot, 'sendMessage', this);\n    utils.handleRatelimit(bot, 'sendGame', this);\n    utils.handleRatelimit(bot, 'getMe', this);\n    utils.handleRatelimit(bot, 'getChat', this);\n\n    return bot.sendPhoto(USERID, FILE_PATH).then(resp => {\n      FILE_ID = resp.photo[0].file_id;\n      return bot.sendMessage(USERID, 'chat');\n    }).then(resp => {\n      GAME_CHAT_ID = resp.chat.id;\n      return bot.sendGame(USERID, GAME_SHORT_NAME);\n    }).then(resp => {\n      GAME_MSG_ID = resp.message_id;\n    }).then(() => {\n      return bot.getMe().then(resp => {\n        BOT_USERNAME = resp.username;\n      });\n    }).then(() =>\n      bot.getChat(GROUPID).then(resp => {\n        CHAT_INFO = resp;\n      }));\n  });\n\n  it('automatically starts polling', function test() {\n    assert.strictEqual(botPolling.isPolling(), true);\n    return utils.isPollingMockServer(pollingPort2);\n  });\n\n  it('automatically opens webhook', function test() {\n    assert.strictEqual(botWebHook.hasOpenWebHook(), true);\n    return utils.hasOpenWebHook(webHookPort2);\n  });\n\n  it('does not automatically poll if \"autoStart\" is false', function test() {\n    assert.strictEqual(testbot.isPolling(), false);\n    return utils.isPollingMockServer(pollingPort, true);\n  });\n\n  it('does not automatically open webhook if \"autoOpen\" is false', function test() {\n    assert.strictEqual(testbot.hasOpenWebHook(), false);\n    return utils.hasOpenWebHook(webHookPort, true);\n  });\n\n  it('correctly deletes the webhook if polling', function test() {\n    const myBot = new TelegramBot(TOKEN, {\n      polling: { autoStart: false, params: { timeout: 0 } },\n    });\n    utils.handleRatelimit(myBot, 'setWebHook', this);\n    myBot.on('polling_error', (error) => {\n      assert.ifError(error);\n    });\n    return myBot.setWebHook(ip, {}).then(() => {\n      return myBot.startPolling();\n    }).then(() => {\n      return myBot.stopPolling();\n    });\n  });\n\n  describe('Events', function eventsSuite() {\n    it('(polling) emits \"message\" on receiving message', function test(done) {\n      botPolling.once('message', () => {\n        return done();\n      });\n    });\n    it('(polling) emits \"polling_error\" if error occurs during polling', function test(done) {\n      const myBot = new TelegramBot(12345, { polling: true });\n      myBot.once('polling_error', (error) => {\n        assert.ok(error);\n        assert.strictEqual(error.code, 'ETELEGRAM');\n        return myBot.stopPolling().then(() => { done(); }).catch(done);\n      });\n    });\n    it('(webhook) emits \"message\" on receiving message', function test(done) {\n      botWebHook.once('message', () => {\n        return done();\n      });\n      utils.sendWebHookMessage(webHookPort2, TOKEN);\n    });\n    it('(webhook) emits \"webhook_error\" if could not parse webhook request body', function test(done) {\n      botWebHook.once('webhook_error', (error) => {\n        assert.ok(error);\n        assert.strictEqual(error.code, 'EPARSE');\n        return done();\n      });\n      utils.sendWebHookMessage(webHookPort2, TOKEN, { update: 'unparseable!', json: false });\n    });\n  });\n\n  describe('WebHook', function webHookSuite() {\n    it('returns 200 OK for health endpoint', function test(done) {\n      utils.sendWebHookRequest(webHookPort2, '/healthz').then(resp => {\n        assert.strictEqual(resp, 'OK');\n        return done();\n      });\n    });\n    it('returns 401 error if token is wrong', function test(done) {\n      utils.sendWebHookMessage(webHookPort2, 'wrong-token').catch(resp => {\n        assert.strictEqual(resp.statusCode, 401);\n        return done();\n      });\n    });\n    it('only accepts POST method', function test() {\n      const methods = ['GET', 'PUT', 'DELETE', 'OPTIONS'];\n      return Promise.all(methods, (method) => {\n        return utils.sendWebHookMessage(webHookPort2, TOKEN, {\n          method,\n        }).then(() => {\n          throw new Error(`expected error with webhook ${method} request`);\n        }).catch(resp => {\n          if (!resp.statusCode) throw resp;\n          if (resp.statusCode !== 418) throw new Error(`unexpected error: ${resp.body}`);\n        });\n      }); // Promise.each\n    });\n  });\n\n  describe('WebHook HTTPS', function webHookHTTPSSuite() {\n    const port = portindex++;\n    let httpsbot;\n    afterEach(function afterEach() {\n      return httpsbot.closeWebHook();\n    });\n    it('is enabled, through options.key and options.cert', function test() {\n      httpsbot = new TelegramBot(TOKEN, { webHook: { port, key, cert } });\n      return utils.sendWebHookMessage(port, TOKEN, { https: true });\n    });\n    it('is enabled, through options.pfx');\n    it('is enabled, through options.https', function test() {\n      httpsbot = new TelegramBot(TOKEN, {\n        webHook: {\n          port,\n          https: {\n            key: fs.readFileSync(key),\n            cert: fs.readFileSync(cert),\n          },\n        },\n      });\n      return utils.sendWebHookMessage(port, TOKEN, { https: true });\n    });\n  });\n\n  describe('errors', function errorsSuite() {\n    const botParse = new TelegramBot('useless-token', {\n      baseApiUrl: `http://localhost:${badTgServerPort}`,\n    });\n    it('FatalError is thrown if token is missing', function test() {\n      const myBot = new TelegramBot(null);\n      return myBot.sendMessage(USERID, 'text').catch(error => {\n        // FIX: assert.ok(error instanceof TelegramBot.errors.FatalError);\n        assert.strictEqual(error.code, 'EFATAL');\n        assert.ok(error.message.indexOf('not provided') > -1);\n      });\n    });\n    it('FatalError is thrown if file-type of Buffer could not be determined', function test() {\n      let buffer;\n      try {\n        buffer = Buffer.from('12345');\n      } catch (ex) {\n        buffer = new Buffer('12345');\n      }\n      return bot.sendPhoto(USERID, buffer).catch(error => {\n        // FIX: assert.ok(error instanceof TelegramBot.errors.FatalError);\n        assert.strictEqual(error.code, 'EFATAL');\n        assert.ok(error.message.indexOf('Unsupported') > -1);\n      });\n    });\n    it('FatalError is thrown on network error', function test() {\n      const myBot = new TelegramBot('useless-token', {\n        baseApiUrl: 'http://localhost:23', // are we sure this port is not bound to?\n      });\n      return myBot.getMe().catch(error => {\n        // FIX: assert.ok(error instanceof TelegramBot.errors.FatalError);\n        assert.strictEqual(error.code, 'EFATAL');\n      });\n    });\n    it('ParseError is thrown if response body could not be parsed', function test() {\n      botParse.sendMessage(USERID, 'text').catch(error => {\n        // FIX: assert.ok(error instanceof TelegramBot.errors.ParseError);\n        assert.strictEqual(error.code, 'EPARSE');\n        assert.ok(typeof error.response === 'object');\n        assert.ok(typeof error.response.body === 'string');\n      });\n    });\n    it('TelegramError is thrown if error is from Telegram', function test() {\n      return bot.sendMessage('404', 'text').catch(error => {\n        // FIX: assert.ok(error instanceof TelegramBot.errors.TelegramError);\n        assert.strictEqual(error.code, 'ETELEGRAM');\n        assert.ok(typeof error.response === 'object');\n        assert.ok(typeof error.response.body === 'object');\n      });\n    });\n  });\n\n  describe('#startPolling', function initPollingSuite() {\n    it('initiates polling', function test() {\n      return testbot.startPolling().then(() => {\n        return utils.isPollingMockServer(pollingPort);\n      });\n    });\n    it('returns error if using webhook', function test() {\n      return botWebHook.startPolling().catch((err) => {\n        // TODO: check for error in a better way\n        // FIX: assert.ok(err instanceof TelegramBot.errors.FatalError);\n        assert.strictEqual(err.code, 'EFATAL');\n        assert.ok(err.message.indexOf('mutually exclusive') !== -1);\n      });\n    });\n  });\n\n  describe('#isPolling', function isPollingSuite() {\n    it('returns true if bot is polling', function test() {\n      assert.strictEqual(testbot.isPolling(), true);\n      return utils.isPollingMockServer(pollingPort);\n    });\n    it('returns false if bot is not polling', function test() {\n      return testbot.stopPolling().then(() => {\n        assert.strictEqual(testbot.isPolling(), false);\n        utils.clearPollingCheck(pollingPort);\n        return utils.isPollingMockServer(pollingPort, true);\n      });\n    });\n    after(function after() {\n      return testbot.initPolling();\n    });\n  });\n\n  describe('#stopPolling', function stopPollingSuite() {\n    it('stops polling by bot', function test() {\n      return testbot.stopPolling().then(() => {\n        utils.clearPollingCheck(pollingPort);\n        return utils.isPollingMockServer(pollingPort, true);\n      });\n    });\n  });\n\n  describe('#openWebHook', function openWebHookSuite() {\n    it('opens webhook', function test() {\n      return testbot.openWebHook().then(() => {\n        return utils.hasOpenWebHook(webHookPort);\n      });\n    });\n    it('returns error if using polling', function test() {\n      return botPolling.openWebHook().catch((err) => {\n        // TODO: check for error in a better way\n        // FIX: assert.ok(err instanceof TelegramBot.errors.FatalError);\n        assert.strictEqual(err.code, 'EFATAL');\n        assert.ok(err.message.indexOf('mutually exclusive') !== -1);\n      });\n    });\n  });\n\n  describe('#hasOpenWebHook', function hasOpenWebHookSuite() {\n    it('returns true if webhook is opened', function test() {\n      assert.strictEqual(testbot.hasOpenWebHook(), true);\n      return utils.hasOpenWebHook(webHookPort);\n    });\n    it('returns false if webhook is closed', function test() {\n      testbot.closeWebHook().then(() => {\n        assert.strictEqual(testbot.hasOpenWebHook(), false);\n        return utils.hasOpenWebHook(webHookPort, true);\n      });\n    });\n    after(function after() {\n      return testbot.openWebHook();\n    });\n  });\n\n  describe('#closeWebHook', function closeWebHookSuite() {\n    it('closes webhook', function test() {\n      testbot.closeWebHook().then(() => {\n        return utils.hasOpenWebHook(webHookPort, true);\n      });\n    });\n  });\n\n\n  describe('#setWebHook', function setWebHookSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setWebHook', this);\n    });\n    it('should set a webHook', function test() {\n      return bot\n        .setWebHook(ip, {})\n        .then(resp => {\n          assert.strictEqual(resp, true);\n        });\n    });\n    it('should set a webHook with certificate', function test() {\n      return bot\n        .setWebHook(ip, { certificate: cert })\n        .then(resp => {\n          assert.strictEqual(resp, true);\n        });\n    });\n    it('(v0.25.0 and lower) should set a webHook with certificate', function test() {\n      return bot\n        .setWebHook(ip, cert)\n        .then(resp => {\n          assert.strictEqual(resp, true);\n        });\n    });\n    it('should delete the webHook', function test() {\n      return bot\n        .setWebHook('', {})\n        .then(resp => {\n          assert.strictEqual(resp, true);\n        });\n    });\n  });\n\n  describe('#getWebHookInfo', function getWebHookInfoSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'getWebHookInfo', this);\n    });\n    it('should return WebhookInfo', function test() {\n      return bot.getWebHookInfo().then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.boolean(resp.has_custom_certificate));\n        assert.ok(is.number(resp.pending_update_count));\n      });\n    });\n  });\n\n  describe('#deleteWebHook', function deleteWebHookSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'deleteWebHook', this);\n    });\n    it('should delete webhook', function test() {\n      return bot.deleteWebHook().then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#getUpdates', function getUpdatesSuite() {\n    const opts = {\n      timeout: 0,\n      limit: 10,\n    };\n    before(function before() {\n      utils.handleRatelimit(bot, 'setWebHook', this);\n      utils.handleRatelimit(bot, 'getUpdates', this);\n      return bot.deleteWebHook();\n    });\n    it('should return an Array', function test() {\n      return bot.getUpdates(opts).then(resp => {\n        assert.strictEqual(Array.isArray(resp), true);\n      });\n    });\n    it('(v0.25.0 and lower) should return an Array', function test() {\n      return bot.getUpdates(opts.timeout, opts.limit).then(resp => {\n        assert.strictEqual(Array.isArray(resp), true);\n      });\n    });\n  });\n\n  describe('#getMe', function getMeSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'getMe', this);\n    });\n    it('should return an User object', function test() {\n      return bot.getMe().then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.number(resp.id));\n        assert.ok(is.string(resp.first_name));\n      });\n    });\n  });\n\n  describe('#getFileLink', function getFileLinkSuite() {\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'getFileLink', this);\n    });\n    it('should get a file link', function test() {\n      return bot.getFileLink(FILE_ID)\n        .then(fileURI => {\n          assert.ok(is.string(fileURI));\n          assert.ok(utils.isTelegramFileURI(fileURI));\n        });\n    });\n  });\n\n  describe('#getFileStream', function getFileStreamSuite() {\n    this.timeout(timeout);\n    before(function before() {\n      // utils.handleRatelimit(bot, 'getFileStream', this);\n    });\n    it('should get a file stream', function test(done) {\n      const fileStream = bot.getFileStream(FILE_ID);\n      assert.ok(fileStream instanceof stream.Readable);\n      assert.strictEqual(fileStream.path, FILE_ID);\n      fileStream.on('info', (info) => {\n        assert.ok(info);\n        assert.ok(utils.isTelegramFileURI(info.uri), `${info.uri} is not a file URI`);\n        fileStream.pipe(concat(function readFile(buffer) {\n          buffer.equals(fs.readFileSync(FILE_PATH)); // sync :(\n          return done();\n        }));\n      });\n    });\n  });\n\n  describe('#downloadFile', function downloadFileSuite() {\n    const downloadPath = os.tmpdir();\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'downloadFile', this);\n    });\n    it('should download a file', function test() {\n      return bot.downloadFile(FILE_ID, downloadPath)\n        .then(filePath => {\n          assert.ok(is.string(filePath));\n          assert.strictEqual(path.dirname(filePath), downloadPath);\n          assert.ok(fs.existsSync(filePath));\n          fs.unlinkSync(filePath); // Delete file after test\n        });\n    });\n  });\n\n  describe('#onText', function onTextSuite() {\n    it('should call `onText` callback on match', function test(done) {\n      const regexp = /\\/onText (.+)/;\n      botWebHook.onText(regexp, (msg, match) => {\n        assert.strictEqual(match[1], 'ECHO ALOHA');\n        assert.ok(botWebHook.removeTextListener(regexp));\n        return done();\n      });\n      utils.sendWebHookMessage(webHookPort2, TOKEN, {\n        message: { text: '/onText ECHO ALOHA' },\n      });\n    });\n    it('should reset the global regex state with each message', function test(done) {\n      const regexp = /\\/onText (.+)/g;\n      botWebHook.onText(regexp, () => {\n        assert.strictEqual(regexp.lastIndex, 0);\n        assert.ok(botWebHook.removeTextListener(regexp));\n        return done();\n      });\n      utils.sendWebHookMessage(webHookPort2, TOKEN, {\n        message: { text: '/onText ECHO ALOHA' },\n      });\n    });\n  });\n\n  describe('#removeTextListener', function removeTextListenerSuite() {\n    const regexp = /\\/onText/;\n    const regexp2 = /\\/onText/;\n    const callback = function noop() { };\n    after(function after() {\n      bot.removeTextListener(regexp);\n      bot.removeTextListener(regexp2);\n    });\n    it('removes the right text-listener', function test() {\n      bot.onText(regexp, callback);\n      bot.onText(regexp2, callback);\n      const textListener = bot.removeTextListener(regexp);\n      assert.strictEqual(regexp, textListener.regexp);\n    });\n    it('returns `null` if missing', function test() {\n      assert.strictEqual(null, bot.removeTextListener(/404/));\n    });\n  });\n\n  describe.skip('#onReplyToMessage', function onReplyToMessageSuite() { });\n\n  describe('#removeReplyListener', function removeReplyListenerSuite() {\n    const chatId = -1234;\n    const messageId = 1;\n    const callback = function noop() { };\n    it('returns the right reply-listener', function test() {\n      const id = bot.onReplyToMessage(chatId, messageId, callback);\n      const replyListener = bot.removeReplyListener(id);\n      assert.strictEqual(id, replyListener.id);\n      assert.strictEqual(chatId, replyListener.chatId);\n      assert.strictEqual(messageId, replyListener.messageId);\n      assert.strictEqual(callback, replyListener.callback);\n    });\n    it('returns `null` if missing', function test() {\n      // NOTE: '0' is never a valid reply listener ID :)\n      assert.strictEqual(null, bot.removeReplyListener(0));\n    });\n  });\n\n  /** Telegram Bot API Methods */\n\n  describe.skip('#logOut', function logOutSuite() { });\n\n  describe.skip('#close', function closeSuite() { });\n\n  describe('#sendMessage', function sendMessageSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendMessage', this);\n    });\n    it('should send a message', function test() {\n      return bot.sendMessage(USERID, 'test').then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.number(resp.message_id));\n      });\n    });\n  });\n\n  describe('#forwardMessage', function forwardMessageSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendMessage', this);\n      utils.handleRatelimit(bot, 'forwardMessage', this);\n    });\n    it('should forward a message', function test() {\n      return bot.sendMessage(USERID, 'test').then(resp => {\n        const messageId = resp.message_id;\n        return bot.forwardMessage(USERID, USERID, messageId)\n          .then(forwarded => {\n            assert.ok(is.object(forwarded));\n            assert.ok(is.number(forwarded.message_id));\n          });\n      });\n    });\n  });\n\n  describe('#forwardMessages', function forwardMessagesSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendMessage', this);\n      utils.handleRatelimit(bot, 'forwardMessages', this);\n    });\n    it('should forward multiple messages', function test() {\n      return Promise.all([\n        bot.sendMessage(USERID, 'test 1'),\n        bot.sendMessage(USERID, 'test 2'),\n      ]).then(responses => {\n        const messageIds = [\n          responses[0].message_id,\n          responses[1].message_id,\n        ].sort();\n        return bot.forwardMessages(GROUPID, USERID, messageIds).then(forwarded => {\n          assert.ok(is.array(forwarded));\n          assert.ok(forwarded.length === 2);\n        });\n      });\n    });\n  });\n\n  describe('#copyMessage', function copyMessageSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendMessage', this);\n      utils.handleRatelimit(bot, 'copyMessage', this);\n    });\n    it('should send copy of a message', function test() {\n      return bot.sendMessage(USERID, 'test').then(resp => {\n        const messageId = resp.message_id;\n        return bot.copyMessage(USERID, USERID, messageId)\n          .then(copy => {\n            assert.ok(is.object(copy));\n            assert.ok(is.number(copy.message_id));\n          });\n      });\n    });\n  });\n\n  describe('#sendPhoto', function sendPhotoSuite() {\n    let photoId;\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendPhoto', this);\n    });\n    it('should send a photo from file', function test() {\n      const photo = `${__dirname}/data/photo.png`;\n      return bot.sendPhoto(USERID, photo).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.array(resp.photo));\n        photoId = resp.photo[0].file_id;\n      });\n    });\n    it('should send a photo from id', function test() {\n      // Send the same photo as before\n      const photo = photoId;\n      return bot.sendPhoto(USERID, photo).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.array(resp.photo));\n      });\n    });\n    it('should send a photo from fs.readStream', function test() {\n      const photo = fs.createReadStream(`${__dirname}/data/photo.png`);\n      return bot.sendPhoto(USERID, photo).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.array(resp.photo));\n      });\n    });\n    it('should send a photo from request Stream', function test() {\n      const photo = request(`${staticUrl}/photo.png`);\n      return bot.sendPhoto(USERID, photo).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.array(resp.photo));\n      });\n    });\n    it('should send a photo from a Buffer', function test() {\n      const photo = fs.readFileSync(`${__dirname}/data/photo.png`);\n      return bot.sendPhoto(USERID, photo).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.array(resp.photo));\n      });\n    });\n  });\n\n  describe('#sendAudio', function sendAudioSuite() {\n    let audioId;\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendAudio', this);\n    });\n    it('should send an MP3 audio', function test() {\n      const audio = `${__dirname}/data/audio.mp3`;\n      return bot.sendAudio(USERID, audio).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.audio));\n        audioId = resp.audio.file_id;\n      });\n    });\n    it('should send an audio from id', function test() {\n      // Send the same audio as before\n      const audio = audioId;\n      return bot.sendAudio(USERID, audio).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.audio));\n      });\n    });\n    it('should send an audio from fs.readStream', function test() {\n      const audio = fs.createReadStream(`${__dirname}/data/audio.mp3`);\n      return bot.sendAudio(USERID, audio).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.audio));\n      });\n    });\n    it('should send an audio from request Stream', function test() {\n      const audio = request(`${staticUrl}/audio.mp3`);\n      return bot.sendAudio(USERID, audio).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.audio));\n      });\n    });\n    it('should send an audio from a Buffer', function test() {\n      const audio = fs.readFileSync(`${__dirname}/data/audio.mp3`);\n      return bot.sendAudio(USERID, audio).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.audio));\n      });\n    });\n    it('should send an audio file with thumbnail', function test() {\n      const audio = `${__dirname}/data/audio.mp3`;\n      const thumbImg = `attach://${__dirname}/data/sticker_thumb.png`;\n\n      return bot.sendAudio(USERID, audio, { thumbnail: thumbImg }).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.audio));\n        assert.ok(is.object(resp.audio.thumbnail));\n      });\n    });\n  });\n\n  describe('#sendDocument', function sendDocumentSuite() {\n    let documentId;\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendDocument', this);\n    });\n    it('should send a document from file', function test() {\n      const document = `${__dirname}/data/photo.gif`;\n      return bot.sendDocument(USERID, document).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.document));\n        documentId = resp.document.file_id;\n      });\n    });\n    it('should send a document from id', function test() {\n      // Send the same document as before\n      const document = documentId;\n      return bot.sendDocument(USERID, document).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.document));\n      });\n    });\n    it('should send a document from fs.readStream', function test() {\n      const document = fs.createReadStream(`${__dirname}/data/photo.gif`);\n      return bot.sendDocument(USERID, document).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.document));\n      });\n    });\n    it('should send a document from request Stream', function test() {\n      const document = request(`${staticUrl}/photo.gif`);\n      return bot.sendDocument(USERID, document).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.document));\n      });\n    });\n    it('should send a document from a Buffer', function test() {\n      const document = fs.readFileSync(`${__dirname}/data/photo.gif`);\n      return bot.sendDocument(USERID, document).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.document));\n      });\n    });\n  });\n\n  describe('#sendVideo', function sendVideoSuite() {\n    let videoId;\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendVideo', this);\n    });\n    it('should send a video from file', function test() {\n      const video = `${__dirname}/data/video.mp4`;\n      return bot.sendVideo(USERID, video).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.video));\n        videoId = resp.video.file_id;\n      });\n    });\n    it('should send a video from id', function test() {\n      // Send the same video as before\n      return bot.sendVideo(USERID, videoId).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.video));\n      });\n    });\n    it('should send a video from fs.readStream', function test() {\n      const video = fs.createReadStream(`${__dirname}/data/video.mp4`);\n      return bot.sendVideo(USERID, video).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.video));\n      });\n    });\n    it('should send a video from request Stream', function test() {\n      const video = request(`${staticUrl}/video.mp4`);\n      return bot.sendVideo(USERID, video).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.video));\n      });\n    });\n    it('should send a video from a Buffer', function test() {\n      const video = fs.readFileSync(`${__dirname}/data/video.mp4`);\n      return bot.sendVideo(USERID, video).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.video));\n      });\n    });\n  });\n\n  describe('#sendAnimation', function sendAnimationSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendAnimation', this);\n    });\n    it('should send a gif as an animation', function test() {\n      return bot.sendAnimation(USERID, `${__dirname}/data/photo.gif`).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.document));\n      });\n    });\n  });\n\n  describe('#sendVoice', function sendVoiceSuite() {\n    let voiceId;\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendVoice', this);\n    });\n    it('should send a voice from file', function test() {\n      const voice = `${__dirname}/data/voice.ogg`;\n      return bot.sendVoice(USERID, voice).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.voice));\n        voiceId = resp.voice.file_id;\n      });\n    });\n    it('should send a voice from id', function test() {\n      // Send the same voice as before\n      return bot.sendVoice(USERID, voiceId).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.voice));\n      });\n    });\n    it('should send a voice from fs.readStream', function test() {\n      const voice = fs.createReadStream(`${__dirname}/data/voice.ogg`);\n      return bot.sendVoice(USERID, voice).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.voice));\n      });\n    });\n    it('should send a voice from request Stream', function test() {\n      const voice = request(`${staticUrl}/voice.ogg`);\n      return bot.sendVoice(USERID, voice).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.voice));\n      });\n    });\n    it('should send a voice from a Buffer', function test() {\n      const voice = fs.readFileSync(`${__dirname}/data/voice.ogg`);\n      return bot.sendVoice(USERID, voice).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.voice));\n      });\n    });\n  });\n\n\n  describe('#sendVideoNote', function sendVideoNoteSuite() {\n    let videoNoteId;\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendVideoNote', this);\n    });\n    it('should send a video from file', function test() {\n      const video = `${__dirname}/data/video.mp4`;\n      return bot.sendVideoNote(USERID, video, { length: 5 }).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.video));\n        videoNoteId = resp.video.file_id;\n      });\n    });\n    it('should send a video from id', function test() {\n      // Send the same videonote as before\n      assert.ok(videoNoteId);\n      return bot.sendVideoNote(USERID, videoNoteId, { length: 5 }).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.video));\n      });\n    });\n    it('should send a video from fs.readStream', function test() {\n      const video = fs.createReadStream(`${__dirname}/data/video.mp4`);\n      return bot.sendVideoNote(USERID, video, { length: 5 }).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.video));\n      });\n    });\n    it('should send a video from a Buffer', function test() {\n      const video = fs.readFileSync(`${__dirname}/data/video.mp4`);\n      return bot.sendVideoNote(USERID, video, { length: 5 }).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.video));\n      });\n    });\n  });\n\n  describe('#sendMediaGroup', function sendMediaGroupSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendMediaGroup', this);\n    });\n    it('should send group of photos/videos as album', function test() {\n      return bot.sendMediaGroup(USERID, [\n        {\n          type: 'photo',\n          media: `${__dirname}/data/photo.png`,\n        },\n        {\n          type: 'video',\n          media: `${__dirname}/data/video.mp4`,\n        },\n        {\n          type: 'photo',\n          media: FILE_ID,\n        },\n      ], {\n        disable_notification: true,\n      }).then(resp => {\n        assert.ok(is.array(resp));\n        assert.strictEqual(resp.length, 3);\n      });\n    });\n  });\n\n  describe('#sendLocation', function sendLocationSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendLocation', this);\n    });\n    it('should send a location', function test() {\n      return bot.sendLocation(USERID, lat, long).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.location));\n        assert.ok(is.number(resp.location.latitude));\n        assert.ok(is.number(resp.location.longitude));\n      });\n    });\n  });\n\n  describe('#editMessageLiveLocation', function editMessageLiveLocationSuite() {\n    let message;\n    before(function before() {\n      utils.handleRatelimit(bot, 'editMessageLiveLocation', this);\n      const opts = { live_period: 86400 };\n      return bot.sendLocation(USERID, lat, long, opts).then(resp => { message = resp; });\n    });\n    it('edits live location', function test() {\n      const opts = { chat_id: USERID, message_id: message.message_id };\n      return bot.editMessageLiveLocation(lat + 1, long + 1, opts).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.location));\n        assert.ok(is.number(resp.location.latitude));\n        assert.ok(is.number(resp.location.longitude));\n      });\n    });\n  });\n\n  describe.skip('#stopMessageLiveLocation', function editMessageLiveLocationSuite() {\n    let message;\n    before(function before() {\n      utils.handleRatelimit(bot, 'stopMessageLiveLocation', this);\n      return bot.sendLocation(USERID, lat, long, { live_period: 86400 })\n        .then((resp) => {\n          message = resp;\n        });\n    });\n    it('stops location updates', function test() {\n      const opts = { chat_id: USERID, message_id: message.message_id };\n      return bot.stopMessageLiveLocation(opts).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.location));\n        assert.ok(is.number(resp.location.latitude));\n        assert.ok(is.number(resp.location.longitude));\n      });\n    });\n  });\n\n\n  describe('#sendVenue', function sendVenueSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendVenue', this);\n    });\n    it('should send a venue', function test() {\n      const title = 'The Village Shopping Centre';\n      const address = '430 Topsail Rd,St. John\\'s, NL A1E 4N1, Canada';\n      return bot.sendVenue(USERID, lat, long, title, address).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.venue));\n        assert.ok(is.object(resp.venue.location));\n        assert.ok(is.number(resp.venue.location.latitude));\n        assert.ok(is.number(resp.venue.location.longitude));\n        assert.ok(is.string(resp.venue.title));\n        assert.ok(is.string(resp.venue.address));\n      });\n    });\n  });\n\n\n  // NOTE: We are skipping TelegramBot#sendContact() as the\n  // corresponding rate-limits enforced by the Telegram servers\n  // are too strict! During our initial tests, we were required\n  // to retry after ~72000 secs (1200 mins / 20 hrs).\n  // We surely can NOT wait for that much time during testing\n  // (or in most practical cases for that matter!)\n  describe.skip('#sendContact', function sendContactSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendContact', this);\n    });\n    it('should send a contact', function test() {\n      const phoneNumber = '+1(000)000-000';\n      const firstName = 'John Doe';\n      return bot.sendContact(USERID, phoneNumber, firstName).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.contact));\n        assert.ok(is.string(resp.contact.phone_number));\n        assert.ok(is.string(resp.contact.first_name));\n      });\n    });\n  });\n\n  describe('#sendPoll', function sendPollSuite() {\n    it('should send a Poll', function test() {\n      const question = '¿Are you okey?';\n      const answers = ['Yes', 'No'];\n      const opts = { is_anonymous: true };\n      return bot.sendPoll(GROUPID, question, answers, opts).then(resp => {\n        assert.ok(is.object(resp));\n      });\n    });\n    it('should send a Quiz', function test() {\n      const question = '¿Are you okey?';\n      const answers = ['Yes', 'No'];\n      const opts = {\n        is_anonymous: true,\n        type: 'quiz',\n        correct_option_id: 0\n      };\n      return bot.sendPoll(GROUPID, question, answers, opts).then(resp => {\n        assert.ok(is.object(resp));\n      });\n    });\n  });\n\n  describe('#sendDice', function sendDiceSuite() {\n    it('should send a Dice', function test() {\n      return bot.sendDice(GROUPID).then(resp => {\n        assert.ok(is.object(resp));\n      });\n    });\n    it('should send a Dart', function test() {\n      const opts = { emoji: '🎯' };\n      return bot.sendDice(GROUPID, opts).then(resp => {\n        assert.ok(is.object(resp));\n      });\n    });\n  });\n\n  describe('#sendMessageDraft', function sendMessageDraftSuite() {\n    it('should send a Draft', function test() {\n      const draftId = Date.now();\n      const text = 'test content';\n      return bot.sendMessageDraft(GROUPID, draftId, text).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#sendChatAction', function sendChatActionSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendChatAction', this);\n    });\n    it('should send a chat action', function test() {\n      const action = 'typing';\n      return bot.sendChatAction(USERID, action).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#getUserProfilePhotos', function getUserProfilePhotosSuite() {\n    const opts = {\n      offset: 0,\n      limit: 1,\n    };\n    before(function before() {\n      utils.handleRatelimit(bot, 'getUserProfilePhotos', this);\n    });\n    it('should get user profile photos', function test() {\n      return bot.getUserProfilePhotos(USERID, opts).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.number(resp.total_count));\n        assert.ok(is.array(resp.photos));\n      });\n    });\n  });\n\n  describe.skip('#getUserProfileAudios', function getUserProfileAudiosSuite() { });\n\n  describe('#getFile', function getFileSuite() {\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'getFile', this);\n    });\n    it('should get a file', function test() {\n      return bot.getFile(FILE_ID)\n        .then(resp => {\n          assert.ok(is.object(resp));\n          assert.ok(is.string(resp.file_path));\n        });\n    });\n  });\n\n  describe.skip('#banChatMember', function banChatMemberSuite() { });\n\n  describe.skip('#unbanChatMember', function unbanChatMemberSuite() { });\n\n  describe.skip('#restrictChatMember', function restrictChatMemberSuite() { });\n\n  describe.skip('#promoteChatMember', function promoteChatMemberSuite() { });\n\n  describe.skip('#setChatAdministratorCustomTitle', function setChatAdministratorCustomTitleSuite() {\n    it('should set chat permissions', function test() {\n      return bot.setChatAdministratorCustomTitle(GROUPID, USERID, 'Custom Name').then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#setChatMemberTag', function setChatMemberTagSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setChatMemberTag', this);\n    });\n\n    it('should set tag for a chat member', function test() {\n      return bot.setChatMemberTag(GROUPID, USERID, { tag: 'nodebot' }).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe.skip('#unpinAllGeneralForumTopicMessages', function unpinAllGeneralForumTopicMessagesSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'unpinAllGeneralForumTopicMessages', this);\n    });\n\n    it('should unpin all general forum topic messages', function test() {\n      return bot.unpinAllGeneralForumTopicMessages(GROUPID).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe.skip('#banChatSenderChat', function banChatSenderChatSuite() { });\n\n  describe.skip('#unbanChatSenderChat', function banChatSenderChatSuite() { });\n\n  describe('#setChatPermissions ', function setChatPermissionsSuite() {\n    it('should set chat permissions', function test() {\n      const ChatPermissions = {\n        can_send_messages: true,\n        can_send_media_messages: true,\n        can_send_polls: false,\n        can_send_other_messages: false,\n        can_add_web_page_previews: true,\n        can_change_info: false,\n        can_invite_users: false,\n        can_pin_messages: true\n      };\n      return bot.setChatPermissions(GROUPID, ChatPermissions).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#exportChatInviteLink', function exportChatInviteLinkSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'exportChatInviteLink', this);\n    });\n    it('should export the group invite link', function test() {\n      return bot.exportChatInviteLink(GROUPID).then(resp => {\n        assert(resp.match(/^https:\\/\\/t\\.me\\/.+$/i), 'is a telegram invite link');\n      });\n    });\n  });\n\n  describe('#createChatInviteLink', function createChatInviteLinkSuite() {\n    let inviteLink;\n    before(function before() {\n      utils.handleRatelimit(bot, 'createChatInviteLink', this);\n      utils.handleRatelimit(bot, 'editChatInviteLink', this);\n      utils.handleRatelimit(bot, 'revokeChatInviteLink', this);\n    });\n    it('should create a chat invite link', function test() {\n      return bot.createChatInviteLink(GROUPID).then(resp => {\n        assert(resp.invite_link.match(/^https:\\/\\/t\\.me\\/.+$/i), 'is a telegram invite link');\n        inviteLink = resp.invite_link;\n      });\n    });\n\n    it('should edit chat invite link', function test() {\n      return bot.editChatInviteLink(GROUPID, inviteLink, { member_limit: 3 }).then(resp => {\n        assert.strictEqual(resp.member_limit, 3);\n      });\n    });\n\n    it('should revoke chat invite link', function test() {\n      return bot.revokeChatInviteLink(GROUPID, inviteLink).then(resp => {\n        assert.strictEqual(resp.is_revoked, true);\n      });\n    });\n  });\n\n  describe.skip('#approveChatJoinRequest', function approveChatJoinRequestSuite() { });\n\n  describe.skip('#declineChatJoinRequest', function declineChatJoinRequestSuite() { });\n\n  describe('#setChatPhoto', function setChatPhotoSuite() {\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'setChatPhoto', this);\n    });\n    it('should set a chat photo from file', function test() {\n      const photo = `${__dirname}/data/chat_photo.png`;\n      return bot.setChatPhoto(GROUPID, photo).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n    it('should set a chat photo from fs.readStream', function test() {\n      const photo = fs.createReadStream(`${__dirname}/data/chat_photo.png`);\n      return bot.setChatPhoto(GROUPID, photo).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n    it('should set a chat photo from request Stream', function test() {\n      const photo = request(`${staticUrl}/chat_photo.png`);\n      return bot.setChatPhoto(GROUPID, photo).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n    it('should set a chat photo from a Buffer', function test() {\n      const photo = fs.readFileSync(`${__dirname}/data/chat_photo.png`);\n      return bot.setChatPhoto(GROUPID, photo).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#deleteChatPhoto', function deleteChatPhotoSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'deleteChatPhoto', this);\n    });\n    it('should delete the chat photo', function test() {\n      return bot.deleteChatPhoto(GROUPID).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#setChatTitle', function setChatTitleSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setChatTitle', this);\n    });\n    it('should set the chat title', function test() {\n      const random = Math.floor(Math.random() * 1000);\n      return bot.setChatTitle(GROUPID, `ntba test group (random: ${random})`).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#setChatDescription', function setChatDescriptionSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setChatDescription', this);\n    });\n    it('should set the chat description', function test() {\n      const random = Math.floor(Math.random() * 1000);\n      const description = `node-telegram-bot-api test group (random: ${random})`;\n      return bot.setChatDescription(GROUPID, description).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#pinChatMessage', function pinChatMessageSuite() {\n    let messageId;\n    before(function before() {\n      utils.handleRatelimit(bot, 'pinChatMessage', this);\n      return bot.sendMessage(GROUPID, 'To be pinned').then(resp => {\n        messageId = resp.message_id;\n      });\n    });\n    it('should pin chat message', function test() {\n      return bot.pinChatMessage(GROUPID, messageId).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#unpinChatMessage', function unpinChatMessageSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'unpinChatMessage', this);\n    });\n    it('should unpin chat message', function test() {\n      return bot.unpinChatMessage(GROUPID).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#unpinAllChatMessages', function unpinAllChatMessagesSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'unpinAllChatMessages', this);\n    });\n    it('should unpin all chats messages', function test() {\n      return bot.unpinAllChatMessages(GROUPID).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe.skip('#leaveChat', function leaveChatSuite() { });\n\n  describe('#getChat', function getChatSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'getChat', this);\n    });\n    it('should return a Chat object', function test() {\n      return bot.getChat(USERID).then(resp => {\n        assert.ok(is.object(resp));\n      });\n    });\n  });\n\n  describe('#getChatAdministrators', function getChatAdministratorsSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'getChatAdministrators', this);\n    });\n    it('should return an Array', function test() {\n      return bot.getChatAdministrators(GROUPID).then(resp => {\n        assert.ok(Array.isArray(resp));\n      });\n    });\n  });\n\n  describe('#getChatMemberCount', function getChatMemberCountSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'getChatMemberCount', this);\n    });\n    it('should return an Integer', function test() {\n      return bot.getChatMemberCount(GROUPID).then(resp => {\n        assert.ok(Number.isInteger(resp));\n      });\n    });\n  });\n\n  describe('#getChatMember', function getChatMemberSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'getChatMember', this);\n    });\n    it('should return a ChatMember', function test() {\n      return bot.getChatMember(GROUPID, USERID).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.user));\n        assert.ok(is.string(resp.status));\n      });\n    });\n  });\n\n  describe('#setChatStickerSet', function setChatStickerSetSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setChatStickerSet', this);\n      // Check if the chat can set sticker sets\n      if (!CHAT_INFO.can_set_sticker_set) {\n        this.skip();\n      }\n    });\n    it('should return a Boolean', function test() {\n      return bot.setChatStickerSet(GROUPID, STICKER_SET_NAME).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#deleteChatStickerSet', function deleteChatStickerSetSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'deleteChatStickerSet', this);\n      // Check if the chat can delete sticker sets\n      if (!CHAT_INFO.can_set_sticker_set) {\n        this.skip();\n      }\n    });\n    it('should return a Boolean', function test() {\n      return bot.deleteChatStickerSet(GROUPID).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe.skip('#answerCallbackQuery', function answerCallbackQuerySuite() { });\n\n  describe('#setMyCommands', function setMyCommandsSuite() {\n    it('should set bot commands', function test() {\n      const opts = [\n        { command: 'eat', description: 'Command for eat' },\n        { command: 'run', description: 'Command for run' }\n      ];\n      return bot.setMyCommands(opts).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#deleteMyCommands', function deleteMyCommandsSuite() {\n    it('should delete bot commands', function test() {\n      return bot.deleteMyCommands().then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#setMyDescription', function getMyCommandsSuite() {\n    it('should set bot description for users with a specific lang code', function test() {\n      return bot.setMyDescription({ description: 'Bot description' }).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n    it('should set bot description for Spanish users', function test() {\n      return bot.setMyDescription({ description: 'Spanish bot description', language_code: 'es' }).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#setMyName', function setMyNameSuite() {\n    it('should set bot name for Spanish users', function test() {\n      return bot.setMyName({ name: 'Spanish Bot', language_code: 'es' }).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#getMyName', function setMyNameSuite() {\n    it('should get bot name for Spanish users', function test() {\n      return bot.getMyName({ language_code: 'es' }).then(resp => {\n        assert.ok(is.equal(resp.name, 'Spanish Bot'));\n      });\n    });\n  });\n\n  describe('#getMyDescription', function getMyDescriptionSuite() {\n    it('should get bot description for a user without lang code', function test() {\n      return bot.getMyDescription().then(resp => {\n        assert.ok(is.equal(resp.description, 'Bot description'));\n      });\n    });\n    it('should get bot description for Spanish users', function test() {\n      return bot.getMyDescription({ language_code: 'es' }).then(resp => {\n        assert.ok(is.equal(resp.description, 'Spanish bot description'));\n      });\n    });\n  });\n\n  describe('#setMyShortDescription', function setMyShortDescriptionSuite() {\n    it('should set sort bot description for a user without lang code', function test() {\n      return bot.setMyShortDescription({ short_description: 'Bot sort description' }).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n    it('should set sort description for Spanish users', function test() {\n      return bot.setMyShortDescription({ short_description: 'Spanish bot sort description', language_code: 'es' }).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#getMyShortDescription', function getMyShortDescriptionSuite() {\n    it('should get bot sort description for a user without lang code', function test() {\n      return bot.getMyShortDescription().then(resp => {\n        assert.ok(is.equal(resp.short_description, 'Bot sort description'));\n      });\n    });\n    it('should get bot sort description for Spanish users', function test() {\n      return bot.getMyShortDescription({ language_code: 'es' }).then(resp => {\n        assert.ok(is.equal(resp.short_description, 'Spanish bot sort description'));\n      });\n    });\n  });\n\n  describe('#setMyProfilePhoto', function setMyProfilePhotoSuite() {\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'setMyProfilePhoto', this);\n    });\n\n    it('should set bot profile photo from file', function test() {\n      const photo = `${__dirname}/data/chat_photo.png`;\n      return bot.setMyProfilePhoto(photo).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#removeMyProfilePhoto', function removeMyProfilePhotoSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'removeMyProfilePhoto', this);\n    });\n\n    it('should remove bot profile photo', function test() {\n      return bot.removeMyProfilePhoto().then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#getMyCommands', function getMyCommandsSuite() {\n    it('should get bot commands', function test() {\n      return bot.getMyCommands().then(resp => {\n        assert.ok(is.array(resp));\n      });\n    });\n  });\n\n  describe('#setChatMenuButton', function setChatMenuButtonSuite() {\n    it('should set chat menu button', function test() {\n      return bot.setChatMenuButton({\n        chat_id: USERID,\n        menu_button: JSON.stringify({ type: 'web_app', text: 'Hello', web_app: { url: 'https://webappcontent.telegram.org/cafe' } }),\n      })\n        .then(resp => {\n          assert.ok(is.boolean(resp));\n        });\n    });\n  });\n\n  describe('#getChatMenuButton', function getChatMenuButtonSuite() {\n    it('should get chat menu button', function test() {\n      return bot.getChatMenuButton({ chat_id: USERID }).then(resp => {\n        assert.ok(is.equal(resp, {\n          type: 'web_app',\n          text: 'Hello',\n          web_app: { url: 'https://webappcontent.telegram.org/cafe' }\n        }));\n      });\n    });\n  });\n\n  describe('#setMyDefaultAdministratorRights', function setMyDefaultAdministratorRightsSuite() {\n    it('should set default administrator rights', function test() {\n      return bot.setMyDefaultAdministratorRights({\n        rights: JSON.stringify({\n          can_manage_chat: true,\n          can_change_info: true,\n          can_delete_messages: false,\n          can_invite_users: true,\n          can_restrict_members: false,\n          can_pin_messages: true,\n          can_promote_members: false,\n          can_manage_video_chats: false,\n          is_anonymous: false\n        }),\n        for_channels: false\n      }).then(resp => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#getMyDefaultAdministratorRights', function getMyDefaultAdministratorRightsSuite() {\n    it('should get my default administrator rights', function test() {\n      return bot.getMyDefaultAdministratorRights({\n        for_channels: false\n      }).then(resp => {\n        assert.ok(is.equal(resp, {\n          can_manage_chat: true,\n          can_change_info: true,\n          can_delete_messages: false,\n          can_invite_users: true,\n          can_restrict_members: false,\n          can_pin_messages: true,\n          can_manage_topics: false,\n          can_promote_members: false,\n          can_manage_video_chats: false,\n          can_post_stories: false,\n          can_edit_stories: false,\n          can_delete_stories: false,\n          is_anonymous: false\n        }));\n      });\n    });\n  });\n\n  describe('#editMessageText', function editMessageTextSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendMessage', this);\n      utils.handleRatelimit(bot, 'editMessageText', this);\n    });\n    it('should edit a message sent by the bot', function test() {\n      return bot.sendMessage(USERID, 'test').then(resp => {\n        assert.strictEqual(resp.text, 'test');\n        const opts = {\n          chat_id: USERID,\n          message_id: resp.message_id\n        };\n        return bot.editMessageText('edit test', opts).then(msg => {\n          assert.strictEqual(msg.text, 'edit test');\n        });\n      });\n    });\n  });\n\n  describe('#editMessageCaption', function editMessageCaptionSuite() {\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendPhoto', this);\n      utils.handleRatelimit(bot, 'editMessageCaption', this);\n    });\n    it('should edit a caption sent by the bot', function test() {\n      const photo = `${__dirname}/data/photo.png`;\n      const options = { caption: 'test caption' };\n      return bot.sendPhoto(USERID, photo, options).then(resp => {\n        assert.strictEqual(resp.caption, 'test caption');\n        const opts = {\n          chat_id: USERID,\n          message_id: resp.message_id\n        };\n        return bot.editMessageCaption('new test caption', opts).then(msg => {\n          assert.strictEqual(msg.caption, 'new test caption');\n        });\n      });\n    });\n  });\n\n  describe('#editMessageMedia', function editMessageMediaSuite() {\n    let photoId;\n    let messageID;\n    before(function before() {\n      utils.handleRatelimit(bot, 'editMessageMedia', this);\n      const photo = `${__dirname}/data/photo.png`;\n      return bot.sendPhoto(USERID, photo).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.array(resp.photo));\n        photoId = resp.photo[0].file_id;\n        messageID = resp.message_id;\n      });\n    });\n    it('should edit a media message', function nextTest() {\n      return bot.editMessageMedia({ type: 'photo', media: photoId, caption: 'edited' }, { chat_id: USERID, message_id: messageID }).then(editedResp => {\n        assert.ok(is.object(editedResp));\n        assert.ok(is.string(editedResp.caption));\n      });\n    });\n  });\n\n\n  describe('#editMessageReplyMarkup', function editMessageReplyMarkupSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendMessage', this);\n      utils.handleRatelimit(bot, 'editMessageReplyMarkup', this);\n    });\n    it('should edit previously-set reply markup', function test() {\n      return bot.sendMessage(USERID, 'test').then(resp => {\n        const replyMarkup = JSON.stringify({\n          inline_keyboard: [[{\n            text: 'Test button',\n            callback_data: 'test'\n          }]]\n        });\n        const opts = {\n          chat_id: USERID,\n          message_id: resp.message_id\n        };\n        return bot.editMessageReplyMarkup(replyMarkup, opts).then(msg => {\n          // Keyboard markup is not returned, do a simple object check\n          assert.ok(is.object(msg));\n        });\n      });\n    });\n  });\n\n  describe('#stopPoll', function stopPollSuite() {\n    let msg;\n    before(function before() {\n      utils.handleRatelimit(bot, 'stopPoll', this);\n      return bot.sendPoll(GROUPID, '¿Poll for stop before?', ['Yes', 'No']).then(resp => {\n        msg = resp;\n      });\n    });\n    it('should stop a Poll', function test() {\n      return bot.stopPoll(GROUPID, msg.message_id).then(resp => {\n        assert.ok(is.boolean(resp.is_closed) && resp.is_closed === true);\n      });\n    }\n    );\n  });\n\n  describe.skip('#approveSuggestedPost', function approveSuggestedPostSuite() { });\n\n  describe.skip('#declineSuggestedPost', function declineSuggestedPostSuite() { });\n\n  describe('#deleteMessage', function deleteMessageSuite() {\n    let messageId;\n    before(function before() {\n      utils.handleRatelimit(bot, 'deleteMessage', this);\n      return bot.sendMessage(USERID, 'To be deleted').then(resp => {\n        messageId = resp.message_id;\n      });\n    });\n    it('should delete message', function test() {\n      return bot.deleteMessage(USERID, messageId).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#sendSticker', function sendStickerSuite() {\n    let stickerId;\n    this.timeout(timeout);\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendSticker', this);\n    });\n    it('should send a sticker from file', function test() {\n      const sticker = `${__dirname}/data/sticker.webp`;\n      return bot.sendSticker(USERID, sticker).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.sticker));\n        stickerId = resp.sticker.file_id;\n      });\n    });\n    it('should send a sticker from id', function test() {\n      // Send the same photo as before\n      return bot.sendSticker(USERID, stickerId).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.sticker));\n      });\n    });\n    it('should send a sticker from fs.readStream', function test() {\n      const sticker = fs.createReadStream(`${__dirname}/data/sticker.webp`);\n      return bot.sendSticker(USERID, sticker).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.sticker));\n      });\n    });\n    it('should send a sticker from request Stream', function test() {\n      const sticker = request(`${staticUrl}/sticker.webp`);\n      return bot.sendSticker(USERID, sticker).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.sticker));\n      });\n    });\n    it('should send a sticker from a Buffer', function test() {\n      const sticker = fs.readFileSync(`${__dirname}/data/sticker.webp`);\n      return bot.sendSticker(USERID, sticker).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.sticker));\n      });\n    });\n  });\n\n  describe('#uploadStickerFile', function sendPhotoSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'uploadStickerFile', this);\n    });\n    it('should upload a sticker from file', function test() {\n      const sticker = `${__dirname}/data/sticker.png`;\n\n      bot.uploadStickerFile(USERID, sticker).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.string(resp.file_id));\n      });\n    });\n    // Other tests (eg. Buffer, URL) are skipped, because they rely on the same features as sendPhoto.\n  });\n\n  describe('#createNewStickerSet', function createNewStickerSetSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'createNewStickerSet', this);\n    });\n\n    it('should create a new sticker set', function test(done) {\n      const sticker = `${__dirname}/data/sticker.png`;\n      const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;\n\n      bot.createNewStickerSet(USERID, stickerPackName, 'Sticker Pack Title', sticker, '😍').then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n      setTimeout(() => done(), 2000);\n    });\n  });\n\n  describe('#getStickerSet', function getStickerSetSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'getStickerSet', this);\n    });\n    it('should get the sticker set given the name of the set', function test() {\n      return bot.getStickerSet(STICKER_SET_NAME).then(resp => {\n        assert.ok(is.object(resp));\n        assert.strictEqual(resp.name.toLowerCase(), STICKER_SET_NAME);\n        assert.ok(is.string(resp.title));\n        assert.ok(is.string(resp.sticker_type));\n        assert.ok(is.array(resp.stickers));\n      });\n    });\n    // This test depends on the previous test createNewStickerSet\n    it('should get the recent sticker set created given the name of the set', function test() {\n      const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;\n      return bot.getStickerSet(stickerPackName).then(resp => {\n        STICKER_FILE_ID_FROM_SET = resp.stickers[0].file_id;\n        assert.ok(is.object(resp));\n        assert.strictEqual(resp.name.toLowerCase(), stickerPackName.toLowerCase());\n        assert.ok(is.string(resp.title));\n        assert.ok(is.string(resp.sticker_type));\n        assert.ok(is.array(resp.stickers));\n      });\n    });\n  });\n\n  describe('#getCustomEmojiStickers', function getCustomEmojiStickersSuite() {\n    const CHERRY_EMOJI_STICKERS_ID = ['5380109565226391871', '5431711346724968789'];\n    const STICKER_EMOJI_SET_NAME = 'CherryEmoji';\n\n    it('should get the custom emoji stickers', function test() {\n      return bot.getCustomEmojiStickers([CHERRY_EMOJI_STICKERS_ID[0]]).then(resp => {\n        assert.ok(is.array(resp));\n        assert.ok(is.object(resp[0]));\n        assert.ok(is.string(resp[0].set_name) && resp[0].set_name === STICKER_EMOJI_SET_NAME);\n        assert.ok(resp[0].custom_emoji_id === CHERRY_EMOJI_STICKERS_ID[0]);\n      });\n    });\n    it('should get 2 custom emoji stickers', function test() {\n      return bot.getCustomEmojiStickers(CHERRY_EMOJI_STICKERS_ID).then(resp => {\n        assert.ok(is.array(resp) && resp.length === 2);\n        assert.ok(is.object(resp[1]));\n        assert.ok(is.string(resp[1].set_name) && resp[1].set_name === STICKER_EMOJI_SET_NAME);\n        assert.ok(resp[1].custom_emoji_id === CHERRY_EMOJI_STICKERS_ID[1]);\n      });\n    });\n  });\n\n\n  describe('#addStickerToSet', function addStickerToSetSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'addStickerToSet', this);\n    });\n\n    it('should add a sticker to a set', function test() {\n      const sticker = `${__dirname}/data/sticker.png`;\n      const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;\n\n      bot.addStickerToSet(USERID, stickerPackName, sticker, '😊😍🤔', 'png_sticker').then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n    it('should add a sticker to a set using the file Id', function test(done) {\n      const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;\n\n      bot.addStickerToSet(USERID, stickerPackName, STICKER_FILE_ID_FROM_SET, '😊🤔', 'png_sticker').then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n      setTimeout(() => done(), 2000);\n    });\n  });\n\n  describe('#setStickerPositionInSet', function setStickerPositionInSet() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setStickerPositionInSet', this);\n    });\n    it('should set the position of a sticker in a set', function test() {\n      bot.setStickerPositionInSet(STICKER_FILE_ID_FROM_SET, 0).then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#deleteStickerFromSet', function deleteStickerFromSetSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'deleteStickerFromSet', this);\n    });\n    it('should delete a sticker from a set', function test() {\n      bot.deleteStickerFromSet(STICKER_FILE_ID_FROM_SET).then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#setStickerEmojiList', function setStickerEmojiListSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setStickerEmojiList', this);\n    });\n\n    it('should get the list for the given sticker of the bot sticker pack', function test(done) {\n      const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;\n\n      bot.getStickerSet(stickerPackName).then(resp => {\n        STICKERS_FROM_BOT_SET = resp.stickers;\n        assert.ok(is.array(STICKERS_FROM_BOT_SET));\n      });\n\n      setTimeout(() => done(), 2000);\n    });\n\n    it('should set a emoji list for the given sticker', function test() {\n      assert.ok(is.equal(STICKERS_FROM_BOT_SET[0].type, 'regular'));\n\n      bot.setStickerEmojiList(STICKERS_FROM_BOT_SET[0].file_id, ['🥳', '😀', '😇']).then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#setStickerKeywords', function setStickerKeywordsSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setStickerKeywords', this);\n    });\n    it('should set a keywords list for the given sticker', function test() {\n      assert.ok(is.equal(STICKERS_FROM_BOT_SET[0].type, 'regular'));\n      bot.setStickerKeywords(STICKERS_FROM_BOT_SET[0].file_id, { keywords: ['house', 'cat'] }).then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe.skip('#setStickerMaskPosition', function setStickerKeywordsSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setStickerMaskPosition', this);\n    });\n    it('should delete a sticker from a set', function test() {\n      bot.setStickerMaskPosition(STICKER_FILE_ID_FROM_SET, { point: 'eyes', scale: 2, x_shift: 1, y_shift: 1 }).then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#setStickerSetTitle', function setStickerSetTitleSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setStickerSetTitle', this);\n    });\n    it('should set a new sticker set title', function test() {\n      const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;\n\n      bot.setStickerSetTitle(stickerPackName, 'New title').then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#setStickerSetThumbnail', function setStickerSetThumbnailSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setStickerSetThumbnail', this);\n    });\n\n    it('should set a sticker set thumbnail', function test() {\n      const stickerThumb = `${__dirname}/data/sticker_thumb.png`;\n      const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;\n\n      bot.setStickerSetThumbnail(USERID, stickerPackName, stickerThumb).then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe.skip('#setCustomEmojiStickerSetThumbnail', function setCustomEmojiStickerSetThumbnailSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setCustomEmojiStickerSetThumbnail', this);\n    });\n\n    it('should set a custom emoji sticjer set as thumbnail', function test() {\n      const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;\n\n      bot.setCustomEmojiStickerSetThumbnail(stickerPackName, { custom_emoji_id: null }).then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe.skip('#deleteStickerSet', function deleteStickerSetSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'deleteStickerSet', this);\n    });\n\n    it('should delete sticker set', function test() {\n      const stickerPackName = `s${CURRENT_TIMESTAMP}_by_${BOT_USERNAME}`;\n\n      bot.deleteStickerSet(stickerPackName).then((resp) => {\n        assert.ok(is.boolean(resp));\n      });\n    });\n  });\n\n  describe.skip('#answerInlineQuery', function answerInlineQuerySuite() { });\n\n  describe.skip('#answerWebAppQuery', function answerCallbackQuerySuite() { });\n\n  describe('#sendInvoice', function sendInvoiceSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendInvoice', this);\n    });\n    it('should send an invoice', function test() {\n      if (isCI) {\n        this.skip(); // Skip test for now\n      }\n      const title = 'Demo product';\n      const description = 'our test product';\n      const payload = 'sku-p001';\n      const providerToken = PROVIDER_TOKEN;\n      const currency = 'USD';\n      const prices = [{ label: 'product', amount: 11000 }, { label: 'tax', amount: 11000 }];\n      return bot.sendInvoice(USERID, title, description, payload, providerToken, currency, prices).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.invoice));\n        assert.ok(is.number(resp.invoice.total_amount));\n      });\n    });\n  });\n\n  describe('#createInvoiceLink', function createInvoiceLinkSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'createInvoiceLink', this);\n    });\n    it('should create an invoice link', function test() {\n      if (isCI) {\n        this.skip(); // Skip test for now\n      }\n      const title = 'Invoice link product';\n      const description = 'Our test invoice link product';\n      const payload = 'sku-p002';\n      const providerToken = PROVIDER_TOKEN;\n      const currency = 'EUR';\n      const prices = [{ label: 'NTBA API', amount: 12000 }, { label: 'tax', amount: 10000 }];\n      return bot.createInvoiceLink(title, description, payload, providerToken, currency, prices).then(resp => {\n        assert.ok(is.string(resp));\n      });\n    });\n  });\n\n  describe.skip('#answerShippingQuery', function answerShippingQuerySuite() { });\n\n\n  describe.skip('#answerPreCheckoutQuery', function answerPreCheckoutQuerySuite() { });\n\n  describe('#sendGame', function sendGameSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'sendGame', this);\n    });\n    it('should send a Game', function test() {\n      return bot.sendGame(USERID, GAME_SHORT_NAME).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.object(resp.game));\n      });\n    });\n  });\n\n  describe('#setGameScore', function setGameScoreSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'setGameScore', this);\n    });\n    it('should set GameScore', function test() {\n      const score = Math.floor(Math.random() * 1000);\n      const opts = {\n        chat_id: GAME_CHAT_ID,\n        message_id: GAME_MSG_ID,\n        force: true\n      };\n      return bot.setGameScore(USERID, score, opts).then(resp => {\n        assert.ok(is.object(resp) || is.boolean(resp));\n      });\n    });\n  });\n\n  describe('#getGameHighScores', function getGameHighScoresSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'getGameHighScores', this);\n    });\n    it('should get GameHighScores', function test() {\n      const opts = {\n        chat_id: GAME_CHAT_ID,\n        message_id: GAME_MSG_ID,\n      };\n      return bot.getGameHighScores(USERID, opts).then(resp => {\n        assert.ok(is.array(resp));\n      });\n    });\n  });\n\n  describe('#setMessageReaction', function setMessageReactionSuite() {\n    let messageId;\n    const Reactions = [{ type: 'emoji', emoji: '👍' }];\n    before(function before() {\n      utils.handleRatelimit(bot, 'setMessageReaction', this);\n      return bot.sendMessage(USERID, 'To be reacted').then(resp => {\n        messageId = resp.message_id;\n      });\n    });\n    it('should add reactions to message', function test() {\n      return bot.setMessageReaction(USERID, messageId, { reaction: Reactions, is_big: true }).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#deleteMessages', function setMessageReactionSuite() {\n    let messageId;\n    before(function before() {\n      utils.handleRatelimit(bot, 'deleteMessages', this);\n      return bot.sendMessage(USERID, 'To be deleted').then(resp => {\n        messageId = resp.message_id;\n      });\n    });\n    it('should delete message from array', function test() {\n      return bot.deleteMessages(USERID, [messageId]).then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe('#copyMessages', function setMessageReactionSuite() {\n    let messageId;\n    before(function before() {\n      utils.handleRatelimit(bot, 'copyMessages', this);\n      return bot.sendMessage(GROUPID, 'To be copyed').then(resp => {\n        messageId = resp.message_id;\n      });\n    });\n    it('should copy messages from array', function test() {\n      return bot.copyMessages(USERID, GROUPID, [messageId]).then(resp => {\n        assert.ok(is.array(resp));\n        assert.ok(resp && resp.length === 1);\n      });\n    });\n  });\n\n  describe('#getUserGifts', function getUserGiftsSuite() {\n    before(function before() {\n      utils.handleRatelimit(bot, 'getUserGifts', this);\n    });\n    it('should return an OwnedGifts object', function test() {\n      return bot.getUserGifts(USERID).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.array(resp.gifts));\n        assert.ok(is.number(resp.total_count));\n      });\n    });\n    it('should support pagination options', function test() {\n      return bot.getUserGifts(USERID, { limit: 10, offset: '' }).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.array(resp.gifts));\n      });\n    });\n  });\n\n  describe.skip('#getChatGifts', function getChatGiftsSuite() {\n    // Requires can_view_gifts_and_stars administrator right for channels\n    it('should return an OwnedGifts object for a channel', function test() {\n      return bot.getChatGifts(GROUPID).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.array(resp.gifts));\n        assert.ok(is.number(resp.total_count));\n      });\n    });\n  });\n\n  describe.skip('#sendMessageDraft', function sendMessageDraftSuite() {\n    // Requires special bot permissions; available to all bots since Bot API 9.5\n    it('should send a message draft', function test() {\n      return bot.sendMessageDraft(USERID, 1, 'Draft text...').then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n    it('should update an existing draft with the same draft_id', function test() {\n      return bot.sendMessageDraft(USERID, 1, 'Updated draft text.').then(resp => {\n        assert.strictEqual(resp, true);\n      });\n    });\n  });\n\n  describe.skip('#repostStory', function repostStorySuite() {\n    // Requires two managed business accounts and a story posted by the bot\n    it('should repost a story to another business account', function test() {\n      const businessConnectionId = process.env.TEST_BUSINESS_CONNECTION_ID;\n      const fromChatId = process.env.TEST_STORY_CHAT_ID;\n      const fromStoryId = parseInt(process.env.TEST_STORY_ID, 10);\n      const activePeriod = 86400;\n      return bot.repostStory(businessConnectionId, fromChatId, fromStoryId, activePeriod).then(resp => {\n        assert.ok(is.object(resp));\n        assert.ok(is.number(resp.id));\n      });\n    });\n  });\n}); // End Telegram\n"
  },
  {
    "path": "test/test.format-send-data.js",
    "content": "const assert = require('assert');\nconst fs = require('fs');\nconst path = require('path');\nconst TelegramBot = require('..');\n\nconst paths = {\n  audio: path.join(__dirname, 'data/audio.mp3'),\n};\n\n\ndescribe('#_formatSendData', function sendfileSuite() {\n  const bot = new TelegramBot('token');\n  const type = 'file';\n\n  before(function beforeSuite() {\n    process.env.NTBA_FIX_350 = 1;\n  });\n  after(function afterSuite() {\n    delete process.env.NTBA_FIX_350;\n  });\n\n  describe('using fileOptions', function sendfileOptionsSuite() {\n    const stream = fs.createReadStream(paths.audio);\n    const nonPathStream = fs.createReadStream(paths.audio);\n    const buffer = fs.readFileSync(paths.audio);\n    const nonDetectableBuffer = fs.readFileSync(__filename);\n    const filepath = paths.audio;\n    const files = [stream, nonPathStream, buffer, nonDetectableBuffer, filepath];\n\n    delete nonPathStream.path;\n\n    describe('filename', function filenameSuite() {\n      it('(1) fileOptions.filename', function test() {\n        const filename = 'custom-filename';\n        files.forEach((file) => {\n          const [{ [type]: data }] = bot._formatSendData(type, file, { filename });\n          assert.equal(data.options.filename, filename);\n        });\n      });\n\n      it('(2) Stream#path', function test() {\n        if (!stream.path) {\n          this.skip('Stream#path unsupported');\n          return;\n        }\n        const [{ [type]: data }] = bot._formatSendData(type, stream);\n        assert.equal(data.options.filename, path.basename(paths.audio));\n      });\n\n      it('(3) filepath', function test() {\n        const [{ [type]: data }] = bot._formatSendData(type, filepath);\n        assert.equal(data.options.filename, path.basename(paths.audio));\n      });\n\n      it('(4) final default', function test() {\n        [nonPathStream, buffer, nonDetectableBuffer].forEach((file) => {\n          const [{ [type]: data }] = bot._formatSendData(type, file);\n          assert.equal(data.options.filename, 'filename');\n        });\n      });\n    });\n\n    describe('contentType', function contentTypeSuite() {\n      it('(1) fileOpts.contentType', function test() {\n        const contentType = 'application/custom-type';\n        files.forEach((file) => {\n          const [{ [type]: data }] = bot._formatSendData(type, file, { contentType });\n          assert.equal(data.options.contentType, contentType);\n        });\n      });\n\n      it('(2) Stream#path', function test() {\n        if (!stream.path) {\n          this.skip('Stream#path unsupported');\n          return;\n        }\n        const [{ [type]: data }] = bot._formatSendData(type, stream);\n        assert.equal(data.options.contentType, 'audio/mpeg');\n      });\n\n      it('(3) Buffer file-type', function test() {\n        const [{ [type]: data }] = bot._formatSendData(type, buffer);\n        assert.equal(data.options.contentType, 'audio/mpeg');\n      });\n\n      it('(4) filepath', function test() {\n        const [{ [type]: data }] = bot._formatSendData(type, filepath);\n        assert.equal(data.options.contentType, 'audio/mpeg');\n      });\n\n      it('(5) fileOptions.filename', function test() {\n        [nonPathStream, nonDetectableBuffer].forEach((file) => {\n          const [{ [type]: data }] = bot._formatSendData(type, file, {\n            filename: 'image.gif',\n          });\n          assert.equal(data.options.contentType, 'image/gif');\n        });\n      });\n\n      it('(6) Final default', function test() {\n        [nonPathStream, nonDetectableBuffer].forEach((file) => {\n          const [{ [type]: data }] = bot._formatSendData(type, file);\n          assert.equal(data.options.contentType, 'application/octet-stream');\n        });\n      });\n    });\n  });\n\n  it('should handle buffer path from fs.readStream', function test() {\n    let file;\n    try {\n      file = fs.createReadStream(Buffer.from(paths.audio));\n    } catch (ex) {\n      // Older Node.js versions do not support passing a Buffer\n      // representation of the path to fs.createReadStream()\n      if (ex instanceof TypeError) {\n        Promise.resolve();\n        return;\n      }\n    }\n    const [{ [type]: data }] = bot._formatSendData('file', file);\n    assert.equal(data.options.filename, path.basename(paths.audio));\n  });\n\n  it('should not accept file-paths if disallowed with constructor option', function test() {\n    const tgbot = new TelegramBot('token', { filepath: false });\n    const [formData, fileId] = tgbot._formatSendData('file', paths.audio);\n    assert.ok(fileId);\n    assert.ok(!formData);\n  });\n\n  it('should allow stream.path that can not be parsed', function test() {\n    const stream = fs.createReadStream(paths.audio);\n    stream.path = '/?id=123'; // for example, 'http://example.com/?id=666'\n    assert.doesNotThrow(function assertDoesNotThrow() {\n      bot._formatSendData('file', stream);\n    });\n  });\n});\n"
  },
  {
    "path": "test/utils.js",
    "content": "/* eslint-disable no-use-before-define */\nexports = module.exports = {\n  /**\n   * Clear polling check, so that 'isPollingMockServer()' returns false\n   * if the bot stopped polling the mock server.\n   * @param  {Number} port\n   */\n  clearPollingCheck,\n  /**\n   * Redefine a bot method to allow us to ignore 429 (rate-limit) errors\n   * @param  {TelegramBot} bot\n   * @param  {String} methodName\n   * @param  {Suite} suite From mocha\n   * @return {TelegramBot}\n   */\n  handleRatelimit,\n  /**\n   * Return true if a webhook has been opened at the specified port.\n   * Otherwise throw an error.\n   * @param  {Number} port\n   * @param  {Boolean} [reverse] Throw error when it should have returned true (and vice versa)\n   * @return {Promise}\n   */\n  hasOpenWebHook,\n  /**\n   * Return true if the mock server is being polled by a bot.\n   * Otherwise throw an error.\n   * @param  {Number} port\n   * @param  {Boolean} [reverse] Throw error when it should have returned true (and vice versa)\n   * @return {Promise}\n   */\n  isPollingMockServer,\n  /**\n   * Return true if the string is a URI to a file\n   * on Telegram servers.\n   * @param  {String} uri\n   * @return {Boolean}\n   */\n  isTelegramFileURI,\n  /**\n   * Send a message to the webhook at the specified port and path.\n   * @param  {Number} port\n   * @param  {String} path\n   * @param  {Object} [options]\n   * @param  {String} [options.method=POST] Method to use\n   * @param  {Object} [options.update] Update object to send.\n   * @param  {Object} [options.message] Message to send. Default to a generic text message\n   * @param  {Boolean} [options.https=false] Use https\n   * @return {Promise}\n   */\n  sendWebHookRequest,\n  /**\n   * Send a message to the webhook at the specified port.\n   * @param  {Number} port\n   * @param  {String} token\n   * @param  {Object} [options]\n   * @param  {String} [options.method=POST] Method to use\n   * @param  {Object} [options.update] Update object to send.\n   * @param  {Object} [options.message] Message to send. Default to a generic text message\n   * @param  {Boolean} [options.https=false] Use https\n   * @return {Promise}\n   */\n  sendWebHookMessage,\n  /**\n   * Start a mock server at the specified port.\n   * @param  {Number} port\n   * @param  {Object} [options]\n   * @param  {Boolean} [options.bad=false] Bad Mock Server; responding with\n   *  unparseable messages\n   * @return {Promise}\n   */\n  startMockServer,\n  /**\n   * Start the static server, serving files in './data'\n   * @param  {Number} port\n   */\n  startStaticServer,\n};\n/* eslint-enable no-use-before-define */\n\n\nconst assert = require('assert');\nconst http = require('http');\nconst request = require('@cypress/request-promise');\nconst statics = require('node-static');\n\nconst servers = {};\n\n\nfunction startMockServer(port, options = {}) {\n  assert.ok(port);\n  const server = http.Server((req, res) => {\n    servers[port].polling = true;\n    if (options.bad) {\n      return res.end('can not be parsed with JSON.parse()');\n    }\n    return res.end(JSON.stringify({\n      ok: true,\n      result: [{\n        update_id: 0,\n        message: { text: 'test' },\n      }],\n    }));\n  });\n  return new Promise((resolve, reject) => {\n    servers[port] = { server, polling: false };\n    server.on('error', reject).listen(port, resolve);\n  });\n}\n\n\nfunction startStaticServer(port) {\n  const fileServer = new statics.Server(`${__dirname}/data`);\n  http.Server((req, res) => {\n    req.addListener('end', () => {\n      fileServer.serve(req, res);\n    }).resume();\n  }).listen(port);\n}\n\n\nfunction isPollingMockServer(port, reverse) {\n  assert.ok(port);\n  return new Promise((resolve, reject) => {\n    // process.nextTick() does not wait until a poll request\n    // is complete!\n    setTimeout(() => {\n      let polling = servers[port] && servers[port].polling;\n      if (reverse) polling = !polling;\n      if (polling) return resolve(true);\n      return reject(new Error('polling-check failed'));\n    }, 1000);\n  });\n}\n\n\nfunction clearPollingCheck(port) {\n  assert.ok(port);\n  if (servers[port]) servers[port].polling = false;\n}\n\n\nfunction hasOpenWebHook(port, reverse) {\n  assert.ok(port);\n  const error = new Error('open-webhook-check failed');\n  let connected = false;\n  return request.get(`http://127.0.0.1:${port}`)\n    .then(() => {\n      connected = true;\n    }).catch(e => {\n      if (e.statusCode < 500) connected = true;\n    }).finally(() => {\n      if (reverse) {\n        if (connected) throw error;\n        return;\n      }\n      if (!connected) throw error;\n    });\n}\n\n\nfunction sendWebHookRequest(port, path, options = {}) {\n  assert.ok(port);\n  assert.ok(path);\n  const protocol = options.https ? 'https' : 'http';\n  const url = `${protocol}://127.0.0.1:${port}${path}`;\n  return request({\n    url,\n    method: options.method || 'POST',\n    body: options.update || {\n      update_id: 1,\n      message: options.message || { text: 'test' }\n    },\n    json: (typeof options.json === 'undefined') ? true : options.json,\n  });\n}\n\n\nfunction sendWebHookMessage(port, token, options = {}) {\n  assert.ok(port);\n  assert.ok(token);\n  const path = `/bot${token}`;\n  return sendWebHookRequest(port, path, options);\n}\n\n\nfunction handleRatelimit(bot, methodName, suite) {\n  const backupMethodName = `__${methodName}`;\n  if (!bot[backupMethodName]) bot[backupMethodName] = bot[methodName];\n\n  const maxRetries = 3;\n  const addSecs = 5;\n  const method = bot[backupMethodName];\n  assert.equal(typeof method, 'function');\n\n  bot[methodName] = (...args) => {\n    let retry = 0;\n    function exec() {\n      return method.call(bot, ...args)\n        .catch(error => {\n          if (!error.response || error.response.statusCode !== 429) {\n            throw error;\n          }\n          retry++;\n          if (retry > maxRetries) {\n            throw error;\n          }\n          if (typeof error.response.body === 'string') {\n            error.response.body = JSON.parse(error.response.body);\n          }\n          const retrySecs = error.response.body.parameters.retry_after;\n          const timeout = (1000 * retrySecs) + (1000 * addSecs);\n          console.error('tests: Handling rate-limit error. Retrying after %d secs', timeout / 1000); // eslint-disable-line no-console\n          suite.timeout(timeout * 2);\n          return new Promise(function timeoutPromise(resolve, reject) {\n            setTimeout(function execTimeout() {\n              return exec().then(resolve).catch(reject);\n            }, timeout);\n          });\n        });\n    }\n    return exec();\n  };\n  return bot;\n}\n\n\nfunction isTelegramFileURI(uri) {\n  return /https?:\\/\\/.*\\/file\\/bot.*\\/.*/.test(uri);\n}\n"
  }
]