From 538f1e3972af63cdcc0232016c71250e7c72cc52 Mon Sep 17 00:00:00 2001 From: Dan <14043624+delivrance@users.noreply.github.com> Date: Sat, 22 Aug 2020 08:05:05 +0200 Subject: [PATCH] Deep rewrite: preparing for v1.0 - Pyrogram core is now fully asynchronous - Ditched Python 3.5, welcome 3.6 as minimum version. - Moved all types to pyrogram.types - Turned the Filters class into a module (filters) - Moved all filters to pyrogram.filters - Moved all handlers to pyrogram.handlers - Moved all emoji to pyrogram.emoji - Renamed pyrogram.api to pyrogram.raw - Clock is now synced with server's time - Telegram schema updated to Layer 117 - Greatly improved the TL compiler (proper type-constructor hierarchy) - Added "do not edit" warning in generated files - Crypto parts are executed in a thread pool to avoid blocking the event loop - idle() is now a separate function (it doesn't deal with Client instances) - Async storage, async filters and async progress callback (optional, can be sync too) - Added getpass back, for hidden password inputs --- .gitignore | 7 +- MANIFEST.in | 6 +- README.md | 38 +- compiler/api/compiler.py | 689 +- compiler/api/source/main_api.tl | 21 +- compiler/api/template/combinator.txt | 35 + compiler/api/template/mtproto.txt | 30 - compiler/api/template/pyrogram.txt | 12 - compiler/api/template/type.txt | 17 + compiler/docs/compiler.py | 33 +- compiler/docs/template/bound-methods.rst | 2 +- compiler/docs/template/methods.rst | 17 +- compiler/docs/template/types.rst | 2 +- compiler/error/source/400_BAD_REQUEST.tsv | 2 +- docs/Makefile | 7 +- docs/requirements.txt | 3 +- docs/scripts/sitemap.py | 16 +- docs/source/api/decorators.rst | 1 + docs/source/api/errors.rst | 78 - docs/source/api/errors/bad-request.rst | 7 + docs/source/api/errors/flood.rst | 7 + docs/source/api/errors/forbidden.rst | 7 + docs/source/api/errors/index.rst | 37 + .../api/errors/internal-server-error.rst | 7 + docs/source/api/errors/not-acceptable.rst | 7 + docs/source/api/errors/see-other.rst | 7 + docs/source/api/errors/unauthorized.rst | 7 + docs/source/api/filters.rst | 5 +- docs/source/api/handlers.rst | 6 +- docs/source/faq.rst | 1 + docs/source/glossary.rst | 1 + docs/source/index.rst | 182 +- docs/source/intro/install.rst | 44 +- docs/source/intro/quickstart.rst | 4 +- docs/source/intro/setup.rst | 1 + docs/source/powered-by.rst | 1 + docs/source/start/auth.rst | 3 +- docs/source/start/errors.rst | 24 +- docs/source/start/examples/bot_keyboards.rst | 61 + .../start/examples/callback_queries.rst | 19 + docs/source/start/examples/echobot.rst | 21 + .../start/examples/get_chat_members.rst | 15 + docs/source/start/examples/get_dialogs.rst | 14 + docs/source/start/examples/get_history.rst | 15 + docs/source/start/examples/hello_world.rst | 21 + docs/source/start/examples/index.rst | 46 + docs/source/start/examples/inline_queries.rst | 61 + docs/source/start/examples/raw_updates.rst | 18 + .../source/start/examples/use_inline_bots.rst | 18 + docs/source/start/examples/welcomebot.rst | 33 + docs/source/start/invoking.rst | 97 +- docs/source/start/updates.rst | 122 +- docs/source/topics/advanced-usage.rst | 17 +- docs/source/topics/bots-interaction.rst | 1 + docs/source/topics/config-file.rst | 1 + docs/source/topics/create-filters.rst | 34 +- docs/source/topics/debugging.rst | 1 + docs/source/topics/more-on-updates.rst | 43 +- docs/source/topics/mtproto-vs-botapi.rst | 1 + docs/source/topics/proxy.rst | 1 + docs/source/topics/scheduling.rst | 4 +- docs/source/topics/serializing.rst | 1 + docs/source/topics/session-settings.rst | 1 + docs/source/topics/smart-plugins.rst | 18 +- docs/source/topics/storage-engines.rst | 1 + docs/source/topics/test-servers.rst | 1 + docs/source/topics/text-formatting.rst | 1 + docs/source/topics/use-filters.rst | 34 +- examples/LICENSE | 121 - examples/README.md | 23 - examples/bot_keyboards.py | 57 - examples/callback_queries.py | 16 - examples/echobot.py | 17 - examples/get_chat_members.py | 10 - examples/get_dialogs.py | 9 - examples/get_history.py | 10 - examples/hello_world.py | 16 - examples/inline_queries.py | 54 - examples/raw_updates.py | 13 - examples/use_inline_bots.py | 13 - examples/welcomebot.py | 29 - pyrogram/__init__.py | 21 +- pyrogram/client.py | 1069 +++ pyrogram/client/__init__.py | 25 - pyrogram/client/client.py | 2151 ----- pyrogram/client/ext/__init__.py | 24 - pyrogram/client/ext/emoji.py | 7850 ----------------- pyrogram/client/ext/file_data.py | 41 - pyrogram/client/ext/link.py | 52 - pyrogram/client/filters/__init__.py | 19 - pyrogram/client/filters/filter.py | 84 - pyrogram/client/filters/filters.py | 404 - pyrogram/client/methods/password/utils.py | 104 - .../types/inline_mode/inline_query_result.py | 71 - pyrogram/connection/transport/tcp/tcp.py | 2 +- .../transport/tcp/tcp_abridged_o.py | 12 +- .../transport/tcp/tcp_intermediate_o.py | 10 +- pyrogram/crypto/__init__.py | 6 - pyrogram/crypto/aes.py | 146 +- pyrogram/crypto/mtproto.py | 69 +- pyrogram/crypto/prime.py | 99 +- pyrogram/crypto/rsa.py | 362 +- pyrogram/{client/ext => }/dispatcher.py | 77 +- pyrogram/emoji.py | 3521 ++++++++ pyrogram/errors/rpc_error.py | 17 +- pyrogram/filters.py | 877 ++ pyrogram/{client => }/handlers/__init__.py | 7 +- .../handlers/callback_query_handler.py | 8 +- .../handlers/chosen_inline_result_handler.py | 8 +- .../handlers/deleted_messages_handler.py | 19 +- .../handlers/disconnect_handler.py | 6 +- pyrogram/{client => }/handlers/handler.py | 28 +- .../handlers/inline_query_handler.py | 8 +- .../{client => }/handlers/message_handler.py | 8 +- .../{client => }/handlers/poll_handler.py | 8 +- .../handlers/raw_update_handler.py | 12 +- .../handlers/user_status_handler.py | 8 +- pyrogram/{client => }/methods/__init__.py | 8 +- pyrogram/methods/advanced/__init__.py | 29 + pyrogram/methods/advanced/resolve_peer.py | 123 + pyrogram/methods/advanced/save_file.py | 222 + pyrogram/methods/advanced/send.py | 73 + pyrogram/methods/auth/__init__.py | 53 + .../methods/auth/accept_terms_of_service.py | 41 + pyrogram/methods/auth/check_password.py | 55 + pyrogram/methods/auth/connect.py | 50 + pyrogram/methods/auth/disconnect.py | 38 + pyrogram/methods/auth/get_password_hint.py | 34 + pyrogram/methods/auth/initialize.py | 49 + pyrogram/methods/auth/log_out.py | 47 + pyrogram/methods/auth/recover_password.py | 52 + pyrogram/methods/auth/resend_code.py | 58 + pyrogram/methods/auth/send_code.py | 74 + .../auth/send_recovery_code.py} | 28 +- pyrogram/methods/auth/sign_in.py | 78 + pyrogram/methods/auth/sign_in_bot.py | 74 + pyrogram/methods/auth/sign_up.py | 71 + pyrogram/methods/auth/terminate.py | 53 + .../{client => }/methods/bots/__init__.py | 0 .../methods/bots/answer_callback_query.py | 8 +- .../methods/bots/answer_inline_query.py | 22 +- .../methods/bots/get_game_high_scores.py | 16 +- .../methods/bots/get_inline_bot_results.py | 14 +- .../methods/bots/request_callback_answer.py | 8 +- .../{client => }/methods/bots/send_game.py | 34 +- .../methods/bots/send_inline_bot_result.py | 12 +- .../methods/bots/set_game_score.py | 21 +- .../{client => }/methods/chats/__init__.py | 0 .../methods/chats/add_chat_members.py | 12 +- .../methods/chats/archive_chats.py | 10 +- .../methods/chats/create_channel.py | 16 +- .../methods/chats/create_group.py | 16 +- .../methods/chats/create_supergroup.py | 16 +- .../methods/chats/delete_channel.py | 8 +- .../methods/chats/delete_chat_photo.py | 20 +- .../methods/chats/delete_supergroup.py | 8 +- .../methods/chats/delete_user_history.py | 18 +- .../methods/chats/export_chat_invite_link.py | 17 +- .../{client => }/methods/chats/get_chat.py | 35 +- .../methods/chats/get_chat_member.py | 29 +- .../methods/chats/get_chat_members.py | 42 +- .../methods/chats/get_chat_members_count.py | 16 +- .../{client => }/methods/chats/get_dialogs.py | 33 +- .../methods/chats/get_dialogs_count.py | 14 +- .../methods/chats/get_nearby_chats.py | 21 +- .../methods/chats/iter_chat_members.py | 27 +- .../methods/chats/iter_dialogs.py | 27 +- .../{client => }/methods/chats/join_chat.py | 24 +- .../methods/chats/kick_chat_member.py | 26 +- .../{client => }/methods/chats/leave_chat.py | 18 +- .../methods/chats/pin_chat_message.py | 8 +- .../methods/chats/promote_chat_member.py | 10 +- .../methods/chats/restrict_chat_member.py | 22 +- .../methods/chats/set_administrator_title.py | 16 +- .../methods/chats/set_chat_description.py | 12 +- .../methods/chats/set_chat_permissions.py | 22 +- .../methods/chats/set_chat_photo.py | 35 +- .../methods/chats/set_chat_title.py | 16 +- .../methods/chats/set_slow_mode.py | 8 +- .../methods/chats/unarchive_chats.py | 10 +- .../methods/chats/unban_chat_member.py | 10 +- .../methods/chats/unpin_chat_message.py | 8 +- .../methods/chats/update_chat_username.py | 14 +- .../{client => }/methods/contacts/__init__.py | 0 .../methods/contacts/add_contacts.py | 14 +- .../methods/contacts/delete_contacts.py | 10 +- .../methods/contacts/get_contacts.py | 17 +- .../methods/contacts/get_contacts_count.py | 8 +- .../methods/decorators/__init__.py | 2 +- .../methods/decorators/on_callback_query.py | 12 +- .../decorators/on_chosen_inline_result.py | 13 +- .../methods/decorators/on_deleted_messages.py | 12 +- .../methods/decorators/on_disconnect.py | 9 +- .../methods/decorators/on_inline_query.py | 13 +- .../methods/decorators/on_message.py | 13 +- .../methods/decorators/on_poll.py | 13 +- .../methods/decorators/on_raw_update.py | 11 +- .../methods/decorators/on_user_status.py | 13 +- .../{client => }/methods/messages/__init__.py | 0 .../methods/messages/delete_messages.py | 18 +- .../methods/messages/download_media.py | 58 +- .../methods/messages/edit_inline_caption.py | 10 +- .../methods/messages/edit_inline_media.py | 44 +- .../messages/edit_inline_reply_markup.py | 15 +- .../methods/messages/edit_inline_text.py | 15 +- .../methods/messages/edit_message_caption.py | 14 +- .../methods/messages/edit_message_media.py | 110 +- .../messages/edit_message_reply_markup.py | 22 +- .../methods/messages/edit_message_text.py | 22 +- .../methods/messages/forward_messages.py | 29 +- .../methods/messages/get_history.py | 19 +- .../methods/messages/get_history_count.py | 10 +- .../methods/messages/get_messages.py | 28 +- .../methods/messages/iter_history.py | 19 +- .../methods/messages/read_history.py | 12 +- .../methods/messages/retract_vote.py | 16 +- .../methods/messages/search_global.py | 24 +- .../methods/messages/search_messages.py | 59 +- .../methods/messages/send_animation.py | 64 +- .../methods/messages/send_audio.py | 59 +- .../methods/messages/send_cached_media.py | 33 +- .../methods/messages/send_chat_action.py | 34 +- .../methods/messages/send_contact.py | 34 +- .../methods/messages/send_dice.py | 34 +- .../methods/messages/send_document.py | 56 +- .../methods/messages/send_location.py | 36 +- .../methods/messages/send_media_group.py | 67 +- .../methods/messages/send_message.py | 42 +- .../methods/messages/send_photo.py | 45 +- .../methods/messages/send_poll.py | 38 +- .../methods/messages/send_sticker.py | 52 +- .../methods/messages/send_venue.py | 36 +- .../methods/messages/send_video.py | 57 +- .../methods/messages/send_video_note.py | 50 +- .../methods/messages/send_voice.py | 51 +- .../methods/messages/stop_poll.py | 24 +- .../methods/messages/vote_poll.py | 16 +- .../{client => }/methods/password/__init__.py | 0 .../methods/password/change_cloud_password.py | 18 +- .../methods/password/enable_cloud_password.py | 18 +- .../methods/password/remove_cloud_password.py | 18 +- .../{client => }/methods/users/__init__.py | 0 .../{client => }/methods/users/block_user.py | 8 +- .../methods/users/delete_profile_photos.py | 12 +- .../methods/users/get_common_chats.py | 18 +- pyrogram/{client => }/methods/users/get_me.py | 18 +- .../methods/users/get_profile_photos.py | 26 +- .../methods/users/get_profile_photos_count.py | 16 +- .../{client => }/methods/users/get_users.py | 22 +- .../methods/users/iter_profile_photos.py | 23 +- .../methods/users/set_profile_photo.py | 8 +- .../methods/users/unblock_user.py | 8 +- .../methods/users/update_profile.py | 8 +- .../methods/users/update_username.py | 10 +- pyrogram/methods/utilities/__init__.py | 39 + pyrogram/methods/utilities/add_handler.py | 63 + .../utilities/export_session_string.py | 44 + pyrogram/methods/utilities/idle.py | 78 + pyrogram/methods/utilities/remove_handler.py | 59 + pyrogram/methods/utilities/restart.py | 70 + pyrogram/methods/utilities/run.py | 57 + pyrogram/methods/utilities/start.py | 69 + pyrogram/methods/utilities/stop.py | 65 + .../methods/utilities/stop_transmission.py | 47 + pyrogram/{client/ext => }/mime.types | 0 pyrogram/{client => }/parser/__init__.py | 0 pyrogram/{client => }/parser/html.py | 54 +- pyrogram/{client => }/parser/markdown.py | 8 +- pyrogram/{client => }/parser/parser.py | 4 +- pyrogram/{client => }/parser/utils.py | 0 pyrogram/{api => raw}/__init__.py | 1 + pyrogram/{api => raw}/core/__init__.py | 7 +- pyrogram/{api => raw}/core/future_salt.py | 13 +- pyrogram/{api => raw}/core/future_salts.py | 19 +- pyrogram/{api => raw}/core/gzip_packed.py | 16 +- pyrogram/{api => raw}/core/list.py | 12 +- pyrogram/{api => raw}/core/message.py | 17 +- pyrogram/{api => raw}/core/msg_container.py | 15 +- .../{api => raw}/core/primitives/__init__.py | 2 - pyrogram/{api => raw}/core/primitives/bool.py | 19 +- .../{api => raw}/core/primitives/bytes.py | 21 +- .../{api => raw}/core/primitives/double.py | 11 +- pyrogram/{api => raw}/core/primitives/int.py | 9 +- .../{api => raw}/core/primitives/string.py | 11 +- .../{api => raw}/core/primitives/vector.py | 27 +- pyrogram/{api => raw}/core/tl_object.py | 37 +- .../ext/base_client.py => scaffold.py} | 103 +- pyrogram/session/auth.py | 60 +- pyrogram/session/internals/msg_factory.py | 12 +- pyrogram/session/internals/msg_id.py | 20 +- pyrogram/session/session.py | 261 +- pyrogram/{client => }/storage/__init__.py | 0 pyrogram/{client => }/storage/file_storage.py | 8 +- .../{client => }/storage/memory_storage.py | 18 +- pyrogram/{client => }/storage/schema.sql | 9 +- .../{client => }/storage/sqlite_storage.py | 54 +- pyrogram/{client => }/storage/storage.py | 40 +- pyrogram/sync.py | 80 + pyrogram/{client/ext => }/syncer.py | 15 +- pyrogram/{client => }/types/__init__.py | 2 +- .../types/authorization/__init__.py | 2 +- .../types/authorization/sent_code.py | 26 +- .../types/authorization/terms_of_service.py | 14 +- .../types/bots_and_keyboards/__init__.py | 0 .../types/bots_and_keyboards/callback_game.py | 0 .../bots_and_keyboards/callback_query.py | 76 +- .../types/bots_and_keyboards/force_reply.py | 4 +- .../bots_and_keyboards/game_high_score.py | 21 +- .../inline_keyboard_button.py | 30 +- .../inline_keyboard_markup.py | 18 +- .../bots_and_keyboards/keyboard_button.py | 16 +- .../reply_keyboard_markup.py | 18 +- .../reply_keyboard_remove.py | 5 +- .../types/inline_mode/__init__.py | 2 +- .../types/inline_mode/chosen_inline_result.py | 42 +- .../types/inline_mode/inline_query.py | 28 +- .../types/inline_mode/inline_query_result.py | 70 + .../inline_query_result_animation.py | 23 +- .../inline_query_result_article.py | 18 +- .../inline_mode/inline_query_result_photo.py | 23 +- .../types/input_media/__init__.py | 0 .../types/input_media/input_media.py | 10 +- .../input_media/input_media_animation.py | 2 +- .../types/input_media/input_media_audio.py | 6 +- .../types/input_media/input_media_document.py | 2 +- .../types/input_media/input_media_photo.py | 4 +- .../types/input_media/input_media_video.py | 4 +- .../types/input_media/input_phone_contact.py | 5 +- .../types/input_message_content/__init__.py | 0 .../input_message_content.py | 8 +- .../input_text_message_content.py | 6 +- pyrogram/{client => }/types/list.py | 4 +- .../types/messages_and_media/__init__.py | 2 +- .../types/messages_and_media/animation.py | 18 +- .../types/messages_and_media/audio.py | 18 +- .../types/messages_and_media/contact.py | 7 +- .../types/messages_and_media/dice.py | 6 +- .../types/messages_and_media/document.py | 16 +- .../types/messages_and_media/game.py | 27 +- .../types/messages_and_media/location.py | 8 +- .../types/messages_and_media/message.py | 618 +- .../messages_and_media/message_entity.py | 45 +- .../types/messages_and_media/photo.py | 20 +- .../types/messages_and_media/poll.py | 22 +- .../types/messages_and_media/poll_option.py | 2 +- .../types/messages_and_media/sticker.py | 29 +- .../messages_and_media/stripped_thumbnail.py | 6 +- .../types/messages_and_media/thumbnail.py | 18 +- .../types/messages_and_media/venue.py | 14 +- .../types/messages_and_media/video.py | 18 +- .../types/messages_and_media/video_note.py | 20 +- .../types/messages_and_media/voice.py | 8 +- .../types/messages_and_media/webpage.py | 55 +- pyrogram/{client => }/types/object.py | 35 +- pyrogram/{client => }/types/update.py | 11 +- .../types/user_and_chats/__init__.py | 0 .../{client => }/types/user_and_chats/chat.py | 148 +- .../types/user_and_chats/chat_member.py | 42 +- .../types/user_and_chats/chat_permissions.py | 6 +- .../types/user_and_chats/chat_photo.py | 18 +- .../types/user_and_chats/chat_preview.py | 21 +- .../types/user_and_chats/dialog.py | 21 +- .../types/user_and_chats/restriction.py | 4 +- .../{client => }/types/user_and_chats/user.py | 82 +- pyrogram/{client/ext => }/utils.py | 164 +- requirements.txt | 3 +- setup.py | 12 +- 367 files changed, 12085 insertions(+), 15090 deletions(-) create mode 100644 compiler/api/template/combinator.txt delete mode 100644 compiler/api/template/mtproto.txt delete mode 100644 compiler/api/template/pyrogram.txt create mode 100644 compiler/api/template/type.txt delete mode 100644 docs/source/api/errors.rst create mode 100644 docs/source/api/errors/bad-request.rst create mode 100644 docs/source/api/errors/flood.rst create mode 100644 docs/source/api/errors/forbidden.rst create mode 100644 docs/source/api/errors/index.rst create mode 100644 docs/source/api/errors/internal-server-error.rst create mode 100644 docs/source/api/errors/not-acceptable.rst create mode 100644 docs/source/api/errors/see-other.rst create mode 100644 docs/source/api/errors/unauthorized.rst create mode 100644 docs/source/start/examples/bot_keyboards.rst create mode 100644 docs/source/start/examples/callback_queries.rst create mode 100644 docs/source/start/examples/echobot.rst create mode 100644 docs/source/start/examples/get_chat_members.rst create mode 100644 docs/source/start/examples/get_dialogs.rst create mode 100644 docs/source/start/examples/get_history.rst create mode 100644 docs/source/start/examples/hello_world.rst create mode 100644 docs/source/start/examples/index.rst create mode 100644 docs/source/start/examples/inline_queries.rst create mode 100644 docs/source/start/examples/raw_updates.rst create mode 100644 docs/source/start/examples/use_inline_bots.rst create mode 100644 docs/source/start/examples/welcomebot.rst delete mode 100644 examples/LICENSE delete mode 100644 examples/README.md delete mode 100644 examples/bot_keyboards.py delete mode 100644 examples/callback_queries.py delete mode 100644 examples/echobot.py delete mode 100644 examples/get_chat_members.py delete mode 100644 examples/get_dialogs.py delete mode 100644 examples/get_history.py delete mode 100644 examples/hello_world.py delete mode 100644 examples/inline_queries.py delete mode 100644 examples/raw_updates.py delete mode 100644 examples/use_inline_bots.py delete mode 100644 examples/welcomebot.py create mode 100644 pyrogram/client.py delete mode 100644 pyrogram/client/__init__.py delete mode 100644 pyrogram/client/client.py delete mode 100644 pyrogram/client/ext/__init__.py delete mode 100644 pyrogram/client/ext/emoji.py delete mode 100644 pyrogram/client/ext/file_data.py delete mode 100644 pyrogram/client/ext/link.py delete mode 100644 pyrogram/client/filters/__init__.py delete mode 100644 pyrogram/client/filters/filter.py delete mode 100644 pyrogram/client/filters/filters.py delete mode 100644 pyrogram/client/methods/password/utils.py delete mode 100644 pyrogram/client/types/inline_mode/inline_query_result.py rename pyrogram/{client/ext => }/dispatcher.py (72%) create mode 100644 pyrogram/emoji.py create mode 100644 pyrogram/filters.py rename pyrogram/{client => }/handlers/__init__.py (85%) rename pyrogram/{client => }/handlers/callback_query_handler.py (88%) rename pyrogram/{client => }/handlers/chosen_inline_result_handler.py (87%) rename pyrogram/{client => }/handlers/deleted_messages_handler.py (77%) rename pyrogram/{client => }/handlers/disconnect_handler.py (91%) rename pyrogram/{client => }/handlers/handler.py (59%) rename pyrogram/{client => }/handlers/inline_query_handler.py (88%) rename pyrogram/{client => }/handlers/message_handler.py (90%) rename pyrogram/{client => }/handlers/poll_handler.py (89%) rename pyrogram/{client => }/handlers/raw_update_handler.py (88%) rename pyrogram/{client => }/handlers/user_status_handler.py (89%) rename pyrogram/{client => }/methods/__init__.py (88%) create mode 100644 pyrogram/methods/advanced/__init__.py create mode 100644 pyrogram/methods/advanced/resolve_peer.py create mode 100644 pyrogram/methods/advanced/save_file.py create mode 100644 pyrogram/methods/advanced/send.py create mode 100644 pyrogram/methods/auth/__init__.py create mode 100644 pyrogram/methods/auth/accept_terms_of_service.py create mode 100644 pyrogram/methods/auth/check_password.py create mode 100644 pyrogram/methods/auth/connect.py create mode 100644 pyrogram/methods/auth/disconnect.py create mode 100644 pyrogram/methods/auth/get_password_hint.py create mode 100644 pyrogram/methods/auth/initialize.py create mode 100644 pyrogram/methods/auth/log_out.py create mode 100644 pyrogram/methods/auth/recover_password.py create mode 100644 pyrogram/methods/auth/resend_code.py create mode 100644 pyrogram/methods/auth/send_code.py rename pyrogram/{crypto/kdf.py => methods/auth/send_recovery_code.py} (58%) create mode 100644 pyrogram/methods/auth/sign_in.py create mode 100644 pyrogram/methods/auth/sign_in_bot.py create mode 100644 pyrogram/methods/auth/sign_up.py create mode 100644 pyrogram/methods/auth/terminate.py rename pyrogram/{client => }/methods/bots/__init__.py (100%) rename pyrogram/{client => }/methods/bots/answer_callback_query.py (94%) rename pyrogram/{client => }/methods/bots/answer_inline_query.py (88%) rename pyrogram/{client => }/methods/bots/get_game_high_scores.py (85%) rename pyrogram/{client => }/methods/bots/get_inline_bot_results.py (88%) rename pyrogram/{client => }/methods/bots/request_callback_answer.py (93%) rename pyrogram/{client => }/methods/bots/send_game.py (77%) rename pyrogram/{client => }/methods/bots/send_inline_bot_result.py (87%) rename pyrogram/{client => }/methods/bots/set_game_score.py (85%) rename pyrogram/{client => }/methods/chats/__init__.py (100%) rename pyrogram/{client => }/methods/chats/add_chat_members.py (92%) rename pyrogram/{client => }/methods/chats/archive_chats.py (91%) rename pyrogram/{client => }/methods/chats/create_channel.py (81%) rename pyrogram/{client => }/methods/chats/create_group.py (85%) rename pyrogram/{client => }/methods/chats/create_supergroup.py (82%) rename pyrogram/{client => }/methods/chats/delete_channel.py (90%) rename pyrogram/{client => }/methods/chats/delete_chat_photo.py (77%) rename pyrogram/{client => }/methods/chats/delete_supergroup.py (90%) rename pyrogram/{client => }/methods/chats/delete_user_history.py (82%) rename pyrogram/{client => }/methods/chats/export_chat_invite_link.py (80%) rename pyrogram/{client => }/methods/chats/get_chat.py (67%) rename pyrogram/{client => }/methods/chats/get_chat_member.py (77%) rename pyrogram/{client => }/methods/chats/get_chat_members.py (79%) rename pyrogram/{client => }/methods/chats/get_chat_members_count.py (82%) rename pyrogram/{client => }/methods/chats/get_dialogs.py (75%) rename pyrogram/{client => }/methods/chats/get_dialogs_count.py (81%) rename pyrogram/{client => }/methods/chats/get_nearby_chats.py (77%) rename pyrogram/{client => }/methods/chats/iter_chat_members.py (85%) rename pyrogram/{client => }/methods/chats/iter_dialogs.py (79%) rename pyrogram/{client => }/methods/chats/join_chat.py (75%) rename pyrogram/{client => }/methods/chats/kick_chat_member.py (83%) rename pyrogram/{client => }/methods/chats/leave_chat.py (83%) rename pyrogram/{client => }/methods/chats/pin_chat_message.py (93%) rename pyrogram/{client => }/methods/chats/promote_chat_member.py (95%) rename pyrogram/{client => }/methods/chats/restrict_chat_member.py (88%) rename pyrogram/{client => }/methods/chats/set_administrator_title.py (90%) rename pyrogram/{client => }/methods/chats/set_chat_description.py (85%) rename pyrogram/{client => }/methods/chats/set_chat_permissions.py (85%) rename pyrogram/{client => }/methods/chats/set_chat_photo.py (74%) rename pyrogram/{client => }/methods/chats/set_chat_title.py (84%) rename pyrogram/{client => }/methods/chats/set_slow_mode.py (92%) rename pyrogram/{client => }/methods/chats/unarchive_chats.py (91%) rename pyrogram/{client => }/methods/chats/unban_chat_member.py (90%) rename pyrogram/{client => }/methods/chats/unpin_chat_message.py (91%) rename pyrogram/{client => }/methods/chats/update_chat_username.py (84%) rename pyrogram/{client => }/methods/contacts/__init__.py (100%) rename pyrogram/{client => }/methods/contacts/add_contacts.py (84%) rename pyrogram/{client => }/methods/contacts/delete_contacts.py (88%) rename pyrogram/{client => }/methods/contacts/get_contacts.py (72%) rename pyrogram/{client => }/methods/contacts/get_contacts_count.py (86%) rename pyrogram/{client => }/methods/decorators/__init__.py (100%) rename pyrogram/{client => }/methods/decorators/on_callback_query.py (84%) rename pyrogram/{client => }/methods/decorators/on_chosen_inline_result.py (82%) rename pyrogram/{client => }/methods/decorators/on_deleted_messages.py (83%) rename pyrogram/{client => }/methods/decorators/on_disconnect.py (84%) rename pyrogram/{client => }/methods/decorators/on_inline_query.py (83%) rename pyrogram/{client => }/methods/decorators/on_message.py (83%) rename pyrogram/{client => }/methods/decorators/on_poll.py (84%) rename pyrogram/{client => }/methods/decorators/on_raw_update.py (83%) rename pyrogram/{client => }/methods/decorators/on_user_status.py (83%) rename pyrogram/{client => }/methods/messages/__init__.py (100%) rename pyrogram/{client => }/methods/messages/delete_messages.py (86%) rename pyrogram/{client => }/methods/messages/download_media.py (84%) rename pyrogram/{client => }/methods/messages/edit_inline_caption.py (89%) rename pyrogram/{client => }/methods/messages/edit_inline_media.py (76%) rename pyrogram/{client => }/methods/messages/edit_inline_reply_markup.py (83%) rename pyrogram/{client => }/methods/messages/edit_inline_text.py (88%) rename pyrogram/{client => }/methods/messages/edit_message_caption.py (87%) rename pyrogram/{client => }/methods/messages/edit_message_media.py (74%) rename pyrogram/{client => }/methods/messages/edit_message_reply_markup.py (79%) rename pyrogram/{client => }/methods/messages/edit_message_text.py (84%) rename pyrogram/{client => }/methods/messages/forward_messages.py (83%) rename pyrogram/{client => }/methods/messages/get_history.py (90%) rename pyrogram/{client => }/methods/messages/get_history_count.py (90%) rename pyrogram/{client => }/methods/messages/get_messages.py (81%) rename pyrogram/{client => }/methods/messages/iter_history.py (88%) rename pyrogram/{client => }/methods/messages/read_history.py (89%) rename pyrogram/{client => }/methods/messages/retract_vote.py (83%) rename pyrogram/{client => }/methods/messages/search_global.py (83%) rename pyrogram/{client => }/methods/messages/search_messages.py (80%) rename pyrogram/{client => }/methods/messages/send_animation.py (82%) rename pyrogram/{client => }/methods/messages/send_audio.py (82%) rename pyrogram/{client => }/methods/messages/send_cached_media.py (80%) rename pyrogram/{client => }/methods/messages/send_chat_action.py (78%) rename pyrogram/{client => }/methods/messages/send_contact.py (77%) rename pyrogram/{client => }/methods/messages/send_dice.py (76%) rename pyrogram/{client => }/methods/messages/send_document.py (81%) rename pyrogram/{client => }/methods/messages/send_location.py (74%) rename pyrogram/{client => }/methods/messages/send_media_group.py (74%) rename pyrogram/{client => }/methods/messages/send_message.py (82%) rename pyrogram/{client => }/methods/messages/send_photo.py (83%) rename pyrogram/{client => }/methods/messages/send_poll.py (79%) rename pyrogram/{client => }/methods/messages/send_sticker.py (79%) rename pyrogram/{client => }/methods/messages/send_venue.py (79%) rename pyrogram/{client => }/methods/messages/send_video.py (82%) rename pyrogram/{client => }/methods/messages/send_video_note.py (83%) rename pyrogram/{client => }/methods/messages/send_voice.py (82%) rename pyrogram/{client => }/methods/messages/stop_poll.py (79%) rename pyrogram/{client => }/methods/messages/vote_poll.py (86%) rename pyrogram/{client => }/methods/password/__init__.py (100%) rename pyrogram/{client => }/methods/password/change_cloud_password.py (80%) rename pyrogram/{client => }/methods/password/enable_cloud_password.py (83%) rename pyrogram/{client => }/methods/password/remove_cloud_password.py (77%) rename pyrogram/{client => }/methods/users/__init__.py (100%) rename pyrogram/{client => }/methods/users/block_user.py (92%) rename pyrogram/{client => }/methods/users/delete_profile_photos.py (86%) rename pyrogram/{client => }/methods/users/get_common_chats.py (78%) rename pyrogram/{client => }/methods/users/get_me.py (74%) rename pyrogram/{client => }/methods/users/get_profile_photos.py (81%) rename pyrogram/{client => }/methods/users/get_profile_photos_count.py (83%) rename pyrogram/{client => }/methods/users/get_users.py (77%) rename pyrogram/{client => }/methods/users/iter_profile_photos.py (80%) rename pyrogram/{client => }/methods/users/set_profile_photo.py (94%) rename pyrogram/{client => }/methods/users/unblock_user.py (91%) rename pyrogram/{client => }/methods/users/update_profile.py (93%) rename pyrogram/{client => }/methods/users/update_username.py (88%) create mode 100644 pyrogram/methods/utilities/__init__.py create mode 100644 pyrogram/methods/utilities/add_handler.py create mode 100644 pyrogram/methods/utilities/export_session_string.py create mode 100644 pyrogram/methods/utilities/idle.py create mode 100644 pyrogram/methods/utilities/remove_handler.py create mode 100644 pyrogram/methods/utilities/restart.py create mode 100644 pyrogram/methods/utilities/run.py create mode 100644 pyrogram/methods/utilities/start.py create mode 100644 pyrogram/methods/utilities/stop.py create mode 100644 pyrogram/methods/utilities/stop_transmission.py rename pyrogram/{client/ext => }/mime.types (100%) rename pyrogram/{client => }/parser/__init__.py (100%) rename pyrogram/{client => }/parser/html.py (74%) rename pyrogram/{client => }/parser/markdown.py (95%) rename pyrogram/{client => }/parser/parser.py (93%) rename pyrogram/{client => }/parser/utils.py (100%) rename pyrogram/{api => raw}/__init__.py (95%) rename pyrogram/{api => raw}/core/__init__.py (80%) rename pyrogram/{api => raw}/core/future_salt.py (83%) rename pyrogram/{api => raw}/core/future_salts.py (73%) rename pyrogram/{api => raw}/core/gzip_packed.py (82%) rename pyrogram/{api => raw}/core/list.py (81%) rename pyrogram/{api => raw}/core/message.py (81%) rename pyrogram/{api => raw}/core/msg_container.py (79%) rename pyrogram/{api => raw}/core/primitives/__init__.py (89%) rename pyrogram/{api => raw}/core/primitives/bool.py (73%) rename pyrogram/{api => raw}/core/primitives/bytes.py (74%) rename pyrogram/{api => raw}/core/primitives/double.py (78%) rename pyrogram/{api => raw}/core/primitives/int.py (79%) rename pyrogram/{api => raw}/core/primitives/string.py (76%) rename pyrogram/{api => raw}/core/primitives/vector.py (73%) rename pyrogram/{api => raw}/core/tl_object.py (71%) rename pyrogram/{client/ext/base_client.py => scaffold.py} (65%) rename pyrogram/{client => }/storage/__init__.py (100%) rename pyrogram/{client => }/storage/file_storage.py (93%) rename pyrogram/{client => }/storage/memory_storage.py (81%) rename pyrogram/{client => }/storage/schema.sql (95%) rename pyrogram/{client => }/storage/sqlite_storage.py (76%) rename pyrogram/{client => }/storage/storage.py (65%) create mode 100644 pyrogram/sync.py rename pyrogram/{client/ext => }/syncer.py (87%) rename pyrogram/{client => }/types/__init__.py (100%) rename pyrogram/{client => }/types/authorization/__init__.py (100%) rename pyrogram/{client => }/types/authorization/sent_code.py (74%) rename pyrogram/{client => }/types/authorization/terms_of_service.py (77%) rename pyrogram/{client => }/types/bots_and_keyboards/__init__.py (100%) rename pyrogram/{client => }/types/bots_and_keyboards/callback_game.py (100%) rename pyrogram/{client => }/types/bots_and_keyboards/callback_query.py (79%) rename pyrogram/{client => }/types/bots_and_keyboards/force_reply.py (95%) rename pyrogram/{client => }/types/bots_and_keyboards/game_high_score.py (75%) rename pyrogram/{client => }/types/bots_and_keyboards/inline_keyboard_button.py (85%) rename pyrogram/{client => }/types/bots_and_keyboards/inline_keyboard_markup.py (79%) rename pyrogram/{client => }/types/bots_and_keyboards/keyboard_button.py (82%) rename pyrogram/{client => }/types/bots_and_keyboards/reply_keyboard_markup.py (88%) rename pyrogram/{client => }/types/bots_and_keyboards/reply_keyboard_remove.py (96%) rename pyrogram/{client => }/types/inline_mode/__init__.py (100%) rename pyrogram/{client => }/types/inline_mode/chosen_inline_result.py (67%) rename pyrogram/{client => }/types/inline_mode/inline_query.py (89%) create mode 100644 pyrogram/types/inline_mode/inline_query_result.py rename pyrogram/{client => }/types/inline_mode/inline_query_result_animation.py (87%) rename pyrogram/{client => }/types/inline_mode/inline_query_result_article.py (83%) rename pyrogram/{client => }/types/inline_mode/inline_query_result_photo.py (86%) rename pyrogram/{client => }/types/input_media/__init__.py (100%) rename pyrogram/{client => }/types/input_media/input_media.py (83%) rename pyrogram/{client => }/types/input_media/input_media_animation.py (98%) rename pyrogram/{client => }/types/input_media/input_media_audio.py (94%) rename pyrogram/{client => }/types/input_media/input_media_document.py (98%) rename pyrogram/{client => }/types/input_media/input_media_photo.py (94%) rename pyrogram/{client => }/types/input_media/input_media_video.py (96%) rename pyrogram/{client => }/types/input_media/input_phone_contact.py (93%) rename pyrogram/{client => }/types/input_message_content/__init__.py (100%) rename pyrogram/{client => }/types/input_message_content/input_message_content.py (83%) rename pyrogram/{client => }/types/input_message_content/input_text_message_content.py (95%) rename pyrogram/{client => }/types/list.py (88%) rename pyrogram/{client => }/types/messages_and_media/__init__.py (100%) rename pyrogram/{client => }/types/messages_and_media/animation.py (88%) rename pyrogram/{client => }/types/messages_and_media/audio.py (88%) rename pyrogram/{client => }/types/messages_and_media/contact.py (92%) rename pyrogram/{client => }/types/messages_and_media/dice.py (88%) rename pyrogram/{client => }/types/messages_and_media/document.py (86%) rename pyrogram/{client => }/types/messages_and_media/game.py (79%) rename pyrogram/{client => }/types/messages_and_media/location.py (88%) rename pyrogram/{client => }/types/messages_and_media/message.py (83%) rename pyrogram/{client => }/types/messages_and_media/message_entity.py (68%) rename pyrogram/{client => }/types/messages_and_media/photo.py (82%) rename pyrogram/{client => }/types/messages_and_media/poll.py (88%) rename pyrogram/{client => }/types/messages_and_media/poll_option.py (96%) rename pyrogram/{client => }/types/messages_and_media/sticker.py (84%) rename pyrogram/{client => }/types/messages_and_media/stripped_thumbnail.py (88%) rename pyrogram/{client => }/types/messages_and_media/thumbnail.py (86%) rename pyrogram/{client => }/types/messages_and_media/venue.py (86%) rename pyrogram/{client => }/types/messages_and_media/video.py (89%) rename pyrogram/{client => }/types/messages_and_media/video_note.py (84%) rename pyrogram/{client => }/types/messages_and_media/voice.py (91%) rename pyrogram/{client => }/types/messages_and_media/webpage.py (73%) rename pyrogram/{client => }/types/object.py (77%) rename pyrogram/{client => }/types/update.py (83%) rename pyrogram/{client => }/types/user_and_chats/__init__.py (100%) rename pyrogram/{client => }/types/user_and_chats/chat.py (81%) rename pyrogram/{client => }/types/user_and_chats/chat_member.py (89%) rename pyrogram/{client => }/types/user_and_chats/chat_permissions.py (96%) rename pyrogram/{client => }/types/user_and_chats/chat_photo.py (86%) rename pyrogram/{client => }/types/user_and_chats/chat_preview.py (79%) rename pyrogram/{client => }/types/user_and_chats/dialog.py (83%) rename pyrogram/{client => }/types/user_and_chats/restriction.py (93%) rename pyrogram/{client => }/types/user_and_chats/user.py (79%) rename pyrogram/{client/ext => }/utils.py (58%) diff --git a/.gitignore b/.gitignore index eb4fcccc..357f483f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,9 +6,10 @@ unknown_errors.txt # Pyrogram generated code pyrogram/errors/exceptions/ -pyrogram/api/functions/ -pyrogram/api/types/ -pyrogram/api/all.py +pyrogram/raw/functions/ +pyrogram/raw/types/ +pyrogram/raw/base/ +pyrogram/raw/all.py # PyCharm stuff .idea/ diff --git a/MANIFEST.in b/MANIFEST.in index 9f4d328c..67900cba 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -5,6 +5,6 @@ recursive-include pyrogram mime.types schema.sql ## Exclude prune pyrogram/errors/exceptions -prune pyrogram/api/functions -prune pyrogram/api/types -exclude pyrogram/api/all.py \ No newline at end of file +prune pyrogram/raw/functions +prune pyrogram/raw/types +exclude pyrogram/raw/all.py \ No newline at end of file diff --git a/README.md b/README.md index d9fa613e..61ece568 100644 --- a/README.md +++ b/README.md @@ -21,25 +21,22 @@ ## Pyrogram ``` python -from pyrogram import Client, Filters +from pyrogram import Client, filters app = Client("my_account") -@app.on_message(Filters.private) -def hello(client, message): - message.reply_text("Hello {}".format(message.from_user.first_name)) +@app.on_message(filters.private) +async def hello(client, message): + await message.reply_text(f"Hello {message.from_user.mention}") app.run() ``` -**Pyrogram** is an elegant, easy-to-use [Telegram](https://telegram.org/) client library and framework written from the -ground up in Python and C. It enables you to easily create custom apps for both user and bot identities (bot API alternative) via the [MTProto API](https://core.telegram.org/api#telegram-api). - -> [Pyrogram in fully-asynchronous mode is also available »](https://github.com/pyrogram/pyrogram/issues/181) -> -> [Working PoC of Telegram voice calls using Pyrogram »](https://github.com/bakatrouble/pytgvoip) +**Pyrogram** is a modern, elegant and easy-to-use [Telegram](https://telegram.org/) framework written from the ground up +in Python and C. It enables you to easily create custom apps for both user and bot identities (bot API alternative) via +the [MTProto API](https://core.telegram.org/api#telegram-api). ### Features @@ -47,8 +44,9 @@ ground up in Python and C. It enables you to easily create custom apps for both - **Elegant**: Low-level details are abstracted and re-presented in a much nicer and easier way. - **Fast**: Crypto parts are boosted up by [TgCrypto](https://github.com/pyrogram/tgcrypto), a high-performance library written in pure C. -- **Documented**: Pyrogram API methods, types and public interfaces are well documented. -- **Type-hinted**: Exposed Pyrogram types and method parameters are all type-hinted. +- **Asynchronous**: Allows both synchronous and asynchronous usages to fit all usage needs. +- **Documented**: API methods, types and public interfaces are all [well documented](https://docs.pyrogram.org). +- **Type-hinted**: Types and methods are all type-hinted, enabling excellent editor support. - **Updated**, to make use of the latest Telegram API version and features. - **Bot API-like**: Similar to the Bot API in its simplicity, but much more powerful and detailed. - **Pluggable**: The Smart Plugin system allows to write components with minimal boilerplate code. @@ -56,7 +54,7 @@ ground up in Python and C. It enables you to easily create custom apps for both ### Requirements -- Python 3.5.3 or higher. +- Python 3.6 or higher. - A [Telegram API key](https://docs.pyrogram.org/intro/setup#api-keys). ### Installing @@ -67,17 +65,9 @@ pip3 install pyrogram ### Resources -- The Docs contain lots of resources to help you getting started with Pyrogram: https://docs.pyrogram.org. -- Reading [Examples in this repository](https://github.com/pyrogram/pyrogram/tree/master/examples) is also a good way - for learning how Pyrogram works. -- Seeking extra help? Don't be shy, come join and ask our [Community](https://t.me/PyrogramChat)! -- For other requests you can send an [Email](mailto:dan@pyrogram.org) or a [Message](https://t.me/haskell). - -### Contributing - -Pyrogram is brand new, and **you are welcome to try it and help make it even better** by either submitting pull -requests or reporting issues/bugs as well as suggesting best practices, ideas, enhancements on both code -and documentation. Any help is appreciated! +- The docs contain lots of resources to help you get started with Pyrogram: https://docs.pyrogram.org. +- Seeking extra help? Come join and ask our community: https://t.me/pyrogram. +- For other kind of inquiries, you can send a [message](https://t.me/haskell) or an [e-mail](mailto:dan@pyrogram.org). ### Copyright & License diff --git a/compiler/api/compiler.py b/compiler/api/compiler.py index 3b0876f9..e956085f 100644 --- a/compiler/api/compiler.py +++ b/compiler/api/compiler.py @@ -19,142 +19,110 @@ import os import re import shutil +from functools import partial +from pathlib import Path +from typing import NamedTuple, List, Tuple -HOME = "compiler/api" -DESTINATION = "pyrogram/api" +# from autoflake import fix_code +# from black import format_str, FileMode + +HOME_PATH = Path("compiler/api") +DESTINATION_PATH = Path("pyrogram/raw") NOTICE_PATH = "NOTICE" + SECTION_RE = re.compile(r"---(\w+)---") LAYER_RE = re.compile(r"//\sLAYER\s(\d+)") -COMBINATOR_RE = re.compile(r"^([\w.]+)#([0-9a-f]+)\s(?:.*)=\s([\w<>.]+);(?: // Docs: (.+))?$", re.MULTILINE) +COMBINATOR_RE = re.compile(r"^([\w.]+)#([0-9a-f]+)\s(?:.*)=\s([\w<>.]+);$", re.MULTILINE) ARGS_RE = re.compile(r"[^{](\w+):([\w?!.<>#]+)") FLAGS_RE = re.compile(r"flags\.(\d+)\?") FLAGS_RE_2 = re.compile(r"flags\.(\d+)\?([\w<>.]+)") FLAGS_RE_3 = re.compile(r"flags:#") INT_RE = re.compile(r"int(\d+)") -core_types = ["int", "long", "int128", "int256", "double", "bytes", "string", "Bool"] +CORE_TYPES = ["int", "long", "int128", "int256", "double", "bytes", "string", "Bool", "true"] + +WARNING = """ +# # # # # # # # # # # # # # # # # # # # # # # # +# !!! WARNING !!! # +# This is a generated file! # +# All changes made in this file will be lost! # +# # # # # # # # # # # # # # # # # # # # # # # # +""".strip() + +# noinspection PyShadowingBuiltins +open = partial(open, encoding="utf-8") + types_to_constructors = {} types_to_functions = {} constructors_to_functions = {} +namespaces_to_types = {} +namespaces_to_constructors = {} +namespaces_to_functions = {} -def get_docstring_arg_type(t: str, is_list: bool = False, is_pyrogram_type: bool = False): - if t in core_types: - if t == "long": - return "``int`` ``64-bit``" - elif "int" in t: - size = INT_RE.match(t) - return "``int`` ``{}-bit``".format(size.group(1)) if size else "``int`` ``32-bit``" - elif t == "double": - return "``float`` ``64-bit``" - elif t == "string": - return "``str``" - else: - return "``{}``".format(t.lower()) - elif t == "true": - return "``bool``" - elif t == "TLObject" or t == "X": - return "Any object from :obj:`~pyrogram.api.types`" - elif t == "!X": - return "Any method from :obj:`~pyrogram.api.functions`" - elif t.startswith("Vector"): - return "List of " + get_docstring_arg_type(t.split("<", 1)[1][:-1], True, is_pyrogram_type) - else: - if is_pyrogram_type: - t = "pyrogram." + t - - t = types_to_constructors.get(t, [t]) - n = len(t) - 1 - - t = (("e" if is_list else "E") + "ither " if n else "") + ", ".join( - ":obj:`{1} <{0}.{1}>`".format( - "pyrogram.types" if is_pyrogram_type else "pyrogram.api.types", - i.replace("pyrogram.", "") - ) - for i in t - ) - - if n: - t = t.split(", ") - t = ", ".join(t[:-1]) + " or " + t[-1] - - return t +class Combinator(NamedTuple): + section: str + qualname: str + namespace: str + name: str + id: str + has_flags: bool + args: List[Tuple[str, str]] + qualtype: str + typespace: str + type: str -def get_references(t: str): - t = constructors_to_functions.get(t) - - if t: - n = len(t) - 1 - - t = ", ".join( - ":obj:`{0} `".format(i) - for i in t - ) - - if n: - t = t.split(", ") - t = ", ".join(t[:-1]) + " and " + t[-1] - - return t - - -def get_argument_type(arg): - is_flag = FLAGS_RE.match(arg[1]) - name, t = arg - - if is_flag: - t = t.split("?")[1] - - if t in core_types: - if t == "long" or "int" in t: - t = ": int" - elif t == "double": - t = ": float" - elif t == "string": - t = ": str" - else: - t = ": {}".format(t.lower()) - elif t == "true": - t = ": bool" - elif t.startswith("Vector"): - t = ": list" - else: - return name + ("=None" if is_flag else "") - - return name + t + (" = None" if is_flag else "") - - -class Combinator: - def __init__(self, - section: str, - namespace: str, - name: str, - id: str, - args: list, - has_flags: bool, - return_type: str, - docs: str): - self.section = section - self.namespace = namespace - self.name = name - self.id = id - self.args = args - self.has_flags = has_flags - self.return_type = return_type - self.docs = docs - - -def snek(s: str): - # https://stackoverflow.com/questions/1175208/elegant-python-function-to-convert-camelcase-to-snake-case +def snake(s: str): + # https://stackoverflow.com/q/1175208 s = re.sub(r"(.)([A-Z][a-z]+)", r"\1_\2", s) return re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", s).lower() -def capit(s: str): +def camel(s: str): return "".join([i[0].upper() + i[1:] for i in s.split("_")]) +# noinspection PyShadowingBuiltins, PyShadowingNames +def get_type_hint(type: str) -> str: + is_flag = FLAGS_RE.match(type) + is_core = False + + if is_flag: + type = type.split("?")[1] + + if type in CORE_TYPES: + is_core = True + + if type == "long" or "int" in type: + type = "int" + elif type == "double": + type = "float" + elif type == "string": + type = "str" + elif type in ["Bool", "true"]: + type = "bool" + else: # bytes and object + type = "bytes" + + if type in ["Object", "!X"]: + return "TLObject" + + if re.match("^vector", type, re.I): + is_core = True + + sub_type = type.split("<")[1][:-1] + type = f"List[{get_type_hint(sub_type)}]" + + if is_core: + return f"Union[None, {type}] = None" if is_flag else type + else: + ns, name = type.split(".") if "." in type else ("", type) + type = f'"raw.base.' + ".".join([ns, name]).strip(".") + '"' + + return f'{type}{" = None" if is_flag else ""}' + + def sort_args(args): """Put flags at the end""" args = args.copy() @@ -163,99 +131,167 @@ def sort_args(args): for i in flags: args.remove(i) + try: + args.remove(("flags", "#")) + except ValueError: + pass + return args + flags -def start(): - shutil.rmtree("{}/types".format(DESTINATION), ignore_errors=True) - shutil.rmtree("{}/functions".format(DESTINATION), ignore_errors=True) +def remove_whitespaces(source: str) -> str: + """Remove whitespaces from blank lines""" + lines = source.split("\n") - with open("{}/source/auth_key.tl".format(HOME), encoding="utf-8") as auth, \ - open("{}/source/sys_msgs.tl".format(HOME), encoding="utf-8") as system, \ - open("{}/source/main_api.tl".format(HOME), encoding="utf-8") as api: - schema = (auth.read() + system.read() + api.read()).splitlines() + for i, _ in enumerate(lines): + if re.match(r"^\s+$", lines[i]): + lines[i] = "" - with open("{}/template/mtproto.txt".format(HOME), encoding="utf-8") as f: - mtproto_template = f.read() + return "\n".join(lines) - with open("{}/template/pyrogram.txt".format(HOME), encoding="utf-8") as f: - pyrogram_template = f.read() + +def get_docstring_arg_type(t: str, is_list: bool = False, is_pyrogram_type: bool = False): + if t in CORE_TYPES: + if t == "long": + return "``int`` ``64-bit``" + elif "int" in t: + size = INT_RE.match(t) + return f"``int`` ``{size.group(1)}-bit``" if size else "``int`` ``32-bit``" + elif t == "double": + return "``float`` ``64-bit``" + elif t == "string": + return "``str``" + elif t == "true": + return "``bool``" + else: + return f"``{t.lower()}``" + elif t == "TLObject" or t == "X": + return "Any object from :obj:`~pyrogram.raw.types`" + elif t == "!X": + return "Any method from :obj:`~pyrogram.raw.functions`" + elif t.lower().startswith("vector"): + return "List of " + get_docstring_arg_type(t.split("<", 1)[1][:-1], True) + else: + return f":obj:`{t} `" + + +def get_references(t: str, kind: str): + if kind == "constructors": + t = constructors_to_functions.get(t) + elif kind == "types": + t = types_to_functions.get(t) + else: + raise ValueError("Invalid kind") + + if t: + return "\n ".join( + f"- :obj:`{i} `" + for i in t + ), len(t) + + return None, 0 + + +# noinspection PyShadowingBuiltins +def start(format: bool = False): + shutil.rmtree(DESTINATION_PATH / "types", ignore_errors=True) + shutil.rmtree(DESTINATION_PATH / "functions", ignore_errors=True) + shutil.rmtree(DESTINATION_PATH / "base", ignore_errors=True) + + with open(HOME_PATH / "source/auth_key.tl") as f1, \ + open(HOME_PATH / "source/sys_msgs.tl") as f2, \ + open(HOME_PATH / "source/main_api.tl") as f3: + schema = (f1.read() + f2.read() + f3.read()).splitlines() + + with open(HOME_PATH / "template/type.txt") as f1, \ + open(HOME_PATH / "template/combinator.txt") as f2: + type_tmpl = f1.read() + combinator_tmpl = f2.read() with open(NOTICE_PATH, encoding="utf-8") as f: notice = [] for line in f.readlines(): - notice.append("# {}".format(line).strip()) + notice.append(f"# {line}".strip()) notice = "\n".join(notice) section = None layer = None - namespaces = {"types": set(), "functions": set()} combinators = [] for line in schema: # Check for section changer lines - s = SECTION_RE.match(line) - if s: - section = s.group(1) + section_match = SECTION_RE.match(line) + if section_match: + section = section_match.group(1) continue # Save the layer version - l = LAYER_RE.match(line) - if l: - layer = l.group(1) + layer_match = LAYER_RE.match(line) + if layer_match: + layer = layer_match.group(1) continue - combinator = COMBINATOR_RE.match(line) - if combinator: - name, id, return_type, docs = combinator.groups() - namespace, name = name.split(".") if "." in name else ("", name) - args = ARGS_RE.findall(line.split(" //")[0]) + combinator_match = COMBINATOR_RE.match(line) + if combinator_match: + # noinspection PyShadowingBuiltins + qualname, id, qualtype = combinator_match.groups() + + namespace, name = qualname.split(".") if "." in qualname else ("", qualname) + name = camel(name) + qualname = ".".join([namespace, name]).lstrip(".") + + typespace, type = qualtype.split(".") if "." in qualtype else ("", qualtype) + type = camel(type) + qualtype = ".".join([typespace, type]).lstrip(".") # Pingu! has_flags = not not FLAGS_RE_3.findall(line) - # Fix file and folder name collision - if name == "updates": - name = "update" + args = ARGS_RE.findall(line) - # Fix arg name being "self" (reserved keyword) + # Fix arg name being "self" (reserved python keyword) for i, item in enumerate(args): if item[0] == "self": args[i] = ("is_self", item[1]) - if namespace: - namespaces[section].add(namespace) - - combinators.append( - Combinator( - section, - namespace, - capit(name), - "0x{}".format(id.zfill(8)), - args, - has_flags, - ".".join( - return_type.split(".")[:-1] - + [capit(return_type.split(".")[-1])] - ), - docs - ) + combinator = Combinator( + section=section, + qualname=qualname, + namespace=namespace, + name=name, + id=f"0x{id}", + has_flags=has_flags, + args=args, + qualtype=qualtype, + typespace=typespace, + type=type ) - for c in combinators: - return_type = c.return_type + combinators.append(combinator) - if return_type.startswith("Vector"): - return_type = return_type.split("<")[1][:-1] + for c in combinators: + qualtype = c.qualtype + + if qualtype.startswith("Vector"): + qualtype = qualtype.split("<")[1][:-1] d = types_to_constructors if c.section == "types" else types_to_functions - if return_type not in d: - d[return_type] = [] + if qualtype not in d: + d[qualtype] = [] - d[return_type].append(".".join(filter(None, [c.namespace, c.name]))) + d[qualtype].append(c.qualname) + + if c.section == "types": + key = c.namespace + + if key not in namespaces_to_types: + namespaces_to_types[key] = [] + + if c.type not in namespaces_to_types[key]: + namespaces_to_types[key].append(c.type) for k, v in types_to_constructors.items(): for i in v: @@ -264,85 +300,100 @@ def start(): except KeyError: pass - total = len(combinators) - current = 0 - for c in combinators: # type: Combinator - print("Compiling APIs... [{}%] {}".format( - str(round(current * 100 / total)).rjust(3), - ".".join(filter(None, [c.section, c.namespace, c.name])) - ), end=" \r", flush=True) - current += 1 + # import json + # print(json.dumps(namespaces_to_types, indent=2)) - path = "{}/{}/{}".format(DESTINATION, c.section, c.namespace) - os.makedirs(path, exist_ok=True) + for qualtype in types_to_constructors: + typespace, type = qualtype.split(".") if "." in qualtype else ("", qualtype) + dir_path = DESTINATION_PATH / "base" / typespace - init = "{}/__init__.py".format(path) + module = type - if not os.path.exists(init): - with open(init, "w", encoding="utf-8") as f: - f.write(notice + "\n\n") + if module == "Updates": + module = "UpdatesT" - with open(init, "a", encoding="utf-8") as f: - f.write("from .{} import {}\n".format(snek(c.name), capit(c.name))) + os.makedirs(dir_path, exist_ok=True) + constructors = sorted(types_to_constructors[qualtype]) + constr_count = len(constructors) + items = "\n ".join([f"- :obj:`{c} `" for c in constructors]) + + docstring = f"This base type has {constr_count} constructor{'s' if constr_count > 1 else ''} available.\n\n" + docstring += f" Constructors:\n .. hlist::\n :columns: 2\n\n {items}" + + references, ref_count = get_references(qualtype, "types") + + if references: + docstring += f"\n\n See Also:\n This object can be returned by " \ + f"{ref_count} method{'s' if ref_count > 1 else ''}:" \ + f"\n\n .. hlist::\n :columns: 2\n\n " + references + + with open(dir_path / f"{snake(module)}.py", "w") as f: + f.write( + type_tmpl.format( + notice=notice, + warning=WARNING, + docstring=docstring, + name=type, + qualname=qualtype, + types=", ".join([f"raw.types.{c}" for c in constructors]) + ) + ) + + for c in combinators: sorted_args = sort_args(c.args) arguments = ( - ", " - + ("*, " if c.args else "") - + (", ".join([get_argument_type(i) for i in sorted_args if i != ("flags", "#")]) if c.args else "") + (", *, " if c.args else "") + + (", ".join( + [f"{i[0]}: {get_type_hint(i[1])}" + for i in sorted_args] + ) if sorted_args else "") ) fields = "\n ".join( - ["self.{0} = {0} # {1}".format(i[0], i[1]) for i in c.args if i != ("flags", "#")] - ) if c.args else "pass" + [f"self.{i[0]} = {i[0]} # {i[1]}" + for i in sorted_args] + ) if sorted_args else "pass" + docstring = "" docstring_args = [] - docs = c.docs.split("|")[1:] if c.docs else None for i, arg in enumerate(sorted_args): - if arg == ("flags", "#"): - continue - arg_name, arg_type = arg is_optional = FLAGS_RE.match(arg_type) flag_number = is_optional.group(1) if is_optional else -1 arg_type = arg_type.split("?")[-1] - if docs: - docstring_args.append( - "{} ({}{}):\n {}\n".format( - arg_name, - get_docstring_arg_type(arg_type, is_pyrogram_type=True), - ", optional" if "Optional" in docs[i] else "", - re.sub("Optional\. ", "", docs[i].split("§")[1].rstrip(".") + ".") - ) - ) - else: - docstring_args.append( - "{}{}: {}".format( - arg_name, - " (optional)".format(flag_number) if is_optional else "", - get_docstring_arg_type(arg_type, is_pyrogram_type=c.namespace == "pyrogram") - ) + docstring_args.append( + "{}{}: {}".format( + arg_name, + " (optional)".format(flag_number) if is_optional else "", + get_docstring_arg_type(arg_type, is_pyrogram_type=c.namespace == "pyrogram") ) + ) + + if c.section == "types": + docstring += f"This object is a constructor of the base type :obj:`~pyrogram.raw.base.{c.qualtype}`.\n\n" + else: + docstring += f"Telegram API method.\n\n" + + docstring += f" Details:\n - Layer: ``{layer}``\n - ID: ``{c.id}``\n\n" if docstring_args: - docstring_args = "Parameters:\n " + "\n ".join(docstring_args) + docstring += " Parameters:\n " + "\n ".join(docstring_args) else: - docstring_args = "No parameters required." - - docstring_args = "Attributes:\n ID: ``{}``\n\n ".format(c.id) + docstring_args - docstring_args = "Attributes:\n LAYER: ``{}``\n\n ".format(layer) + docstring_args + docstring += " **No parameters required.**" if c.section == "functions": - docstring_args += "\n\n Returns:\n " + get_docstring_arg_type(c.return_type) - + docstring += "\n\n Returns:\n " + get_docstring_arg_type(c.qualtype) else: - references = get_references(".".join(filter(None, [c.namespace, c.name]))) + references, count = get_references(c.qualname, "constructors") if references: - docstring_args += "\n\n See Also:\n This object can be returned by " + references + "." + docstring += f"\n\n See Also:\n This object can be returned by " \ + f"{count} method{'s' if count > 1 else ''}:" \ + f"\n\n .. hlist::\n :columns: 2\n\n " + references write_types = read_types = "" if c.has_flags else "# No flags\n " @@ -355,17 +406,16 @@ def start(): for i in c.args: flag = FLAGS_RE.match(i[1]) if flag: - write_flags.append( - "flags |= (1 << {}) if self.{} is not None else 0".format(flag.group(1), i[0])) + write_flags.append(f"flags |= (1 << {flag.group(1)}) if self.{i[0]} is not None else 0") write_flags = "\n ".join([ "flags = 0", "\n ".join(write_flags), - "b.write(Int(flags))\n " + "data.write(Int(flags))\n " ]) write_types += write_flags - read_types += "flags = Int.read(b)\n " + read_types += "flags = Int.read(data)\n " continue @@ -374,126 +424,171 @@ def start(): if flag_type == "true": read_types += "\n " - read_types += "{} = True if flags & (1 << {}) else False".format(arg_name, index) - elif flag_type in core_types: + read_types += f"{arg_name} = True if flags & (1 << {index}) else False" + elif flag_type in CORE_TYPES: write_types += "\n " - write_types += "if self.{} is not None:\n ".format(arg_name) - write_types += "b.write({}(self.{}))\n ".format(flag_type.title(), arg_name) + write_types += f"if self.{arg_name} is not None:\n " + write_types += f"data.write({flag_type.title()}(self.{arg_name}))\n " read_types += "\n " - read_types += "{} = {}.read(b) if flags & (1 << {}) else None".format( - arg_name, flag_type.title(), index - ) + read_types += f"{arg_name} = {flag_type.title()}.read(data) if flags & (1 << {index}) else None" elif "vector" in flag_type.lower(): sub_type = arg_type.split("<")[1][:-1] write_types += "\n " - write_types += "if self.{} is not None:\n ".format(arg_name) - write_types += "b.write(Vector(self.{}{}))\n ".format( - arg_name, ", {}".format(sub_type.title()) if sub_type in core_types else "" + write_types += f"if self.{arg_name} is not None:\n " + write_types += "data.write(Vector(self.{}{}))\n ".format( + arg_name, f", {sub_type.title()}" if sub_type in CORE_TYPES else "" ) read_types += "\n " - read_types += "{} = TLObject.read(b{}) if flags & (1 << {}) else []\n ".format( - arg_name, ", {}".format(sub_type.title()) if sub_type in core_types else "", index + read_types += "{} = TLObject.read(data{}) if flags & (1 << {}) else []\n ".format( + arg_name, f", {sub_type.title()}" if sub_type in CORE_TYPES else "", index ) else: write_types += "\n " - write_types += "if self.{} is not None:\n ".format(arg_name) - write_types += "b.write(self.{}.write())\n ".format(arg_name) + write_types += f"if self.{arg_name} is not None:\n " + write_types += f"data.write(self.{arg_name}.write())\n " read_types += "\n " - read_types += "{} = TLObject.read(b) if flags & (1 << {}) else None\n ".format( - arg_name, index - ) + read_types += f"{arg_name} = TLObject.read(data) if flags & (1 << {index}) else None\n " else: - if arg_type in core_types: + if arg_type in CORE_TYPES: write_types += "\n " - write_types += "b.write({}(self.{}))\n ".format(arg_type.title(), arg_name) + write_types += f"data.write({arg_type.title()}(self.{arg_name}))\n " read_types += "\n " - read_types += "{} = {}.read(b)\n ".format(arg_name, arg_type.title()) + read_types += f"{arg_name} = {arg_type.title()}.read(data)\n " elif "vector" in arg_type.lower(): sub_type = arg_type.split("<")[1][:-1] write_types += "\n " - write_types += "b.write(Vector(self.{}{}))\n ".format( - arg_name, ", {}".format(sub_type.title()) if sub_type in core_types else "" + write_types += "data.write(Vector(self.{}{}))\n ".format( + arg_name, f", {sub_type.title()}" if sub_type in CORE_TYPES else "" ) read_types += "\n " - read_types += "{} = TLObject.read(b{})\n ".format( - arg_name, ", {}".format(sub_type.title()) if sub_type in core_types else "" + read_types += "{} = TLObject.read(data{})\n ".format( + arg_name, f", {sub_type.title()}" if sub_type in CORE_TYPES else "" ) else: write_types += "\n " - write_types += "b.write(self.{}.write())\n ".format(arg_name) + write_types += f"data.write(self.{arg_name}.write())\n " read_types += "\n " - read_types += "{} = TLObject.read(b)\n ".format(arg_name) + read_types += f"{arg_name} = TLObject.read(data)\n " - if c.docs: - description = c.docs.split("|")[0].split("§")[1] - docstring_args = description + "\n\n " + docstring_args + slots = ", ".join([f'"{i[0]}"' for i in sorted_args]) + return_arguments = ", ".join([f"{i[0]}={i[0]}" for i in sorted_args]) - with open("{}/{}.py".format(path, snek(c.name)), "w", encoding="utf-8") as f: - if c.docs: - f.write( - pyrogram_template.format( - notice=notice, - class_name=capit(c.name), - docstring_args=docstring_args, - object_id=c.id, - arguments=arguments, - fields=fields - ) - ) - else: - f.write( - mtproto_template.format( - notice=notice, - class_name=capit(c.name), - docstring_args=docstring_args, - object_id=c.id, - arguments=arguments, - fields=fields, - read_types=read_types, - write_types=write_types, - return_arguments=", ".join( - ["{0}={0}".format(i[0]) for i in sorted_args if i != ("flags", "#")] - ), - slots=", ".join(['"{}"'.format(i[0]) for i in sorted_args if i != ("flags", "#")]), - qualname="{}.{}{}".format(c.section, "{}.".format(c.namespace) if c.namespace else "", c.name) - ) - ) + compiled_combinator = combinator_tmpl.format( + notice=notice, + warning=WARNING, + name=c.name, + docstring=docstring, + slots=slots, + id=c.id, + qualname=f"pyrogram.raw.{c.section}.{c.qualname}", + arguments=arguments, + fields=fields, + read_types=read_types, + write_types=write_types, + return_arguments=return_arguments + ) - with open("{}/all.py".format(DESTINATION), "w", encoding="utf-8") as f: + directory = "types" if c.section == "types" else c.section + + dir_path = DESTINATION_PATH / directory / c.namespace + + os.makedirs(dir_path, exist_ok=True) + + module = c.name + + if module == "Updates": + module = "UpdatesT" + + with open(dir_path / f"{snake(module)}.py", "w") as f: + f.write(compiled_combinator) + + d = namespaces_to_constructors if c.section == "types" else namespaces_to_functions + + if c.namespace not in d: + d[c.namespace] = [] + + d[c.namespace].append(c.name) + + for namespace, types in namespaces_to_types.items(): + with open(DESTINATION_PATH / "base" / namespace / "__init__.py", "w") as f: + f.write(f"{notice}\n\n") + f.write(f"{WARNING}\n\n") + + for t in types: + module = t + + if module == "Updates": + module = "UpdatesT" + + f.write(f"from .{snake(module)} import {t}\n") + + if not namespace: + f.write(f"from . import {', '.join(filter(bool, namespaces_to_types))}") + + for namespace, types in namespaces_to_constructors.items(): + with open(DESTINATION_PATH / "types" / namespace / "__init__.py", "w") as f: + f.write(f"{notice}\n\n") + f.write(f"{WARNING}\n\n") + + for t in types: + module = t + + if module == "Updates": + module = "UpdatesT" + + f.write(f"from .{snake(module)} import {t}\n") + + if not namespace: + f.write(f"from . import {', '.join(filter(bool, namespaces_to_constructors))}\n") + + for namespace, types in namespaces_to_functions.items(): + with open(DESTINATION_PATH / "functions" / namespace / "__init__.py", "w") as f: + f.write(f"{notice}\n\n") + f.write(f"{WARNING}\n\n") + + for t in types: + module = t + + if module == "Updates": + module = "UpdatesT" + + f.write(f"from .{snake(module)} import {t}\n") + + if not namespace: + f.write(f"from . import {', '.join(filter(bool, namespaces_to_functions))}") + + with open(DESTINATION_PATH / "all.py", "w", encoding="utf-8") as f: f.write(notice + "\n\n") - f.write("layer = {}\n\n".format(layer)) + f.write(WARNING + "\n\n") + f.write(f"layer = {layer}\n\n") f.write("objects = {") for c in combinators: - path = ".".join(filter(None, [c.section, c.namespace, capit(c.name)])) - f.write("\n {}: \"pyrogram.api.{}\",".format(c.id, path)) + f.write(f'\n {c.id}: "pyrogram.raw.{c.section}.{c.qualname}",') - f.write("\n 0xbc799737: \"pyrogram.api.core.BoolFalse\",") - f.write("\n 0x997275b5: \"pyrogram.api.core.BoolTrue\",") - f.write("\n 0x1cb5c415: \"pyrogram.api.core.Vector\",") - f.write("\n 0x73f1f8dc: \"pyrogram.api.core.MsgContainer\",") - f.write("\n 0xae500895: \"pyrogram.api.core.FutureSalts\",") - f.write("\n 0x0949d9dc: \"pyrogram.api.core.FutureSalt\",") - f.write("\n 0x3072cfa1: \"pyrogram.api.core.GzipPacked\",") - f.write("\n 0x5bb8e511: \"pyrogram.api.core.Message\",") + f.write('\n 0xbc799737: "pyrogram.raw.core.BoolFalse",') + f.write('\n 0x997275b5: "pyrogram.raw.core.BoolTrue",') + f.write('\n 0x1cb5c415: "pyrogram.raw.core.Vector",') + f.write('\n 0x73f1f8dc: "pyrogram.raw.core.MsgContainer",') + f.write('\n 0xae500895: "pyrogram.raw.core.FutureSalts",') + f.write('\n 0x0949d9dc: "pyrogram.raw.core.FutureSalt",') + f.write('\n 0x3072cfa1: "pyrogram.raw.core.GzipPacked",') + f.write('\n 0x5bb8e511: "pyrogram.raw.core.Message",') f.write("\n}\n") - for k, v in namespaces.items(): - with open("{}/{}/__init__.py".format(DESTINATION, k), "a", encoding="utf-8") as f: - f.write("from . import {}\n".format(", ".join([i for i in v])) if v else "") - if "__main__" == __name__: - HOME = "." - DESTINATION = "../../pyrogram/api" - NOTICE_PATH = "../../NOTICE" - start() + HOME_PATH = Path(".") + DESTINATION_PATH = Path("../../pyrogram/raw") + NOTICE_PATH = Path("../../NOTICE") + + start(format=False) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index 3c073c43..9b50b802 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -87,7 +87,7 @@ storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType; userEmpty#200250ba id:int = User; -user#938458c1 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; +user#938458c1 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string = User; userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; userProfilePhoto#69d3ab26 flags:# has_video:flags.0?true photo_id:long photo_small:FileLocation photo_big:FileLocation dc_id:int = UserProfilePhoto; @@ -106,7 +106,7 @@ channel#d31a961e flags:# creator:flags.0?true left:flags.2?true broadcast:flags. channelForbidden#289da732 flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string until_date:flags.16?int = Chat; chatFull#1b7c9db3 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true id:int about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int = ChatFull; -channelFull#f0e6672a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_view_stats:flags.12?true can_set_location:flags.16?true has_scheduled:flags.19?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int = ChatFull; +channelFull#f0e6672a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?int location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int = ChatFull; chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant; chatParticipantCreator#da13538a user_id:int = ChatParticipant; @@ -203,7 +203,7 @@ inputReportReasonOther#e1746d0a text:string = ReportReason; inputReportReasonCopyright#9b89f93a = ReportReason; inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; -userFull#edf17c12 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int = UserFull; +userFull#edf17c12 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true user:User about:flags.1?string settings:PeerSettings profile_photo:flags.2?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int = UserFull; contact#f911c994 user_id:int mutual:Bool = Contact; @@ -796,13 +796,14 @@ inputStickerSetItem#ffa0a496 flags:# document:InputDocument emoji:string mask_co inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; phoneCallEmpty#5366c915 id:long = PhoneCall; -phoneCallWaiting#1b8f4ad1 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; -phoneCallRequested#87eabb53 flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCallAccepted#997c454a flags:# video:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int = PhoneCall; -phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.5?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; +phoneCallWaiting#1b8f4ad1 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; +phoneCallRequested#87eabb53 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; +phoneCallAccepted#997c454a flags:# video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int g_b:bytes protocol:PhoneCallProtocol = PhoneCall; +phoneCall#8742ae7f flags:# p2p_allowed:flags.5?true video:flags.6?true id:long access_hash:long date:int admin_id:int participant_id:int g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int = PhoneCall; +phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; phoneConnection#9d4c17c0 id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; +phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection; phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector = PhoneCallProtocol; @@ -1376,7 +1377,7 @@ updates.getState#edd4882a = updates.State; updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference; updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; -photos.updateProfilePhoto#f0bb5152 id:InputPhoto = UserProfilePhoto; +photos.updateProfilePhoto#72d4742c id:InputPhoto = photos.Photo; photos.uploadProfilePhoto#89f30f69 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double = photos.Photo; photos.deletePhotos#87cf7f2f id:Vector = Vector; photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; @@ -1489,4 +1490,4 @@ stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph; stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats; -// LAYER 116 \ No newline at end of file +// LAYER 117 \ No newline at end of file diff --git a/compiler/api/template/combinator.txt b/compiler/api/template/combinator.txt new file mode 100644 index 00000000..318052a7 --- /dev/null +++ b/compiler/api/template/combinator.txt @@ -0,0 +1,35 @@ +{notice} + +from io import BytesIO + +from pyrogram.raw.core.primitives import Int, Long, Int128, Int256, Bool, Bytes, String, Double, Vector +from pyrogram.raw.core import TLObject +from pyrogram import raw +from typing import List, Union, Any + +{warning} + + +class {name}(TLObject): # type: ignore + """{docstring} + """ + + __slots__: List[str] = [{slots}] + + ID = {id} + QUALNAME = "{qualname}" + + def __init__(self{arguments}) -> None: + {fields} + + @staticmethod + def read(data: BytesIO, *args: Any) -> "{name}": + {read_types} + return {name}({return_arguments}) + + def write(self) -> bytes: + data = BytesIO() + data.write(Int(self.ID, False)) + + {write_types} + return data.getvalue() diff --git a/compiler/api/template/mtproto.txt b/compiler/api/template/mtproto.txt deleted file mode 100644 index d7d3c7b7..00000000 --- a/compiler/api/template/mtproto.txt +++ /dev/null @@ -1,30 +0,0 @@ -{notice} - -from io import BytesIO - -from pyrogram.api.core import * - - -class {class_name}(TLObject): - """{docstring_args} - """ - - __slots__ = [{slots}] - - ID = {object_id} - QUALNAME = "{qualname}" - - def __init__(self{arguments}): - {fields} - - @staticmethod - def read(b: BytesIO, *args) -> "{class_name}": - {read_types} - return {class_name}({return_arguments}) - - def write(self) -> bytes: - b = BytesIO() - b.write(Int(self.ID, False)) - - {write_types} - return b.getvalue() diff --git a/compiler/api/template/pyrogram.txt b/compiler/api/template/pyrogram.txt deleted file mode 100644 index 00ad8e33..00000000 --- a/compiler/api/template/pyrogram.txt +++ /dev/null @@ -1,12 +0,0 @@ -{notice} - -from pyrogram.api.core import Object - - -class {class_name}(Object): - """{docstring_args} - """ - ID = {object_id} - - def __init__(self{arguments}): - {fields} diff --git a/compiler/api/template/type.txt b/compiler/api/template/type.txt new file mode 100644 index 00000000..4dd6a250 --- /dev/null +++ b/compiler/api/template/type.txt @@ -0,0 +1,17 @@ +{notice} + +{warning} + +from typing import Union +from pyrogram import raw +from pyrogram.raw.core import TLObject + +{name} = Union[{types}] + + +# noinspection PyRedeclaration +class {name}(TLObject): # type: ignore + """{docstring} + """ + + QUALNAME = "pyrogram.raw.base.{qualname}" diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 8afd99f8..315c6b73 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -25,11 +25,13 @@ HOME = "compiler/docs" DESTINATION = "docs/source/telegram" PYROGRAM_API_DEST = "docs/source/api" -FUNCTIONS_PATH = "pyrogram/api/functions" -TYPES_PATH = "pyrogram/api/types" +FUNCTIONS_PATH = "pyrogram/raw/functions" +TYPES_PATH = "pyrogram/raw/types" +BASE_PATH = "pyrogram/raw/base" FUNCTIONS_BASE = "functions" TYPES_BASE = "types" +BASE_BASE = "base" def snek(s: str): @@ -70,7 +72,7 @@ def generate(source_path, base): page_template.format( title=name, title_markup="=" * len(name), - full_class_path="pyrogram.api.{}".format( + full_class_path="pyrogram.raw.{}".format( ".".join(full_path.split("/")[:-1]) + "." + name ) ) @@ -92,14 +94,14 @@ def generate(source_path, base): if k != base: inner_path = base + "/" + k + "/index" + ".rst" - module = "pyrogram.api.{}.{}".format(base, k) + module = "pyrogram.raw.{}.{}".format(base, k) else: for i in sorted(list(all_entities), reverse=True): if i != base: entities.insert(0, "{0}/index".format(i)) inner_path = base + "/index" + ".rst" - module = "pyrogram.api.{}".format(base) + module = "pyrogram.raw.{}".format(base) with open(DESTINATION + "/" + inner_path, "w", encoding="utf-8") as f: if k == base: @@ -128,7 +130,6 @@ def pyrogram_api(): utilities=""" Utilities start - idle stop run restart @@ -264,6 +265,7 @@ def pyrogram_api(): send_code resend_code sign_in + sign_in_bot sign_up get_password_hint check_password @@ -302,6 +304,15 @@ def pyrogram_api(): f2.write(title + "\n" + "=" * len(title) + "\n\n") f2.write(".. automethod:: pyrogram.Client.{}()".format(method)) + functions = ["idle"] + + for func in functions: + with open(root + "/{}.rst".format(func), "w") as f2: + title = "{}()".format(func) + + f2.write(title + "\n" + "=" * len(title) + "\n\n") + f2.write(".. autofunction:: pyrogram.{}()".format(func)) + f.write(template.format(**fmt_keys)) # Types @@ -405,7 +416,7 @@ def pyrogram_api(): title = "{}".format(type) f2.write(title + "\n" + "=" * len(title) + "\n\n") - f2.write(".. autoclass:: pyrogram.{}()".format(type)) + f2.write(".. autoclass:: pyrogram.types.{}()".format(type)) f.write(template.format(**fmt_keys)) @@ -506,7 +517,7 @@ def pyrogram_api(): title = "{}()".format(bm) f2.write(title + "\n" + "=" * len(title) + "\n\n") - f2.write(".. automethod:: pyrogram.{}()".format(bm)) + f2.write(".. automethod:: pyrogram.types.{}()".format(bm)) f.write(template.format(**fmt_keys)) @@ -525,12 +536,14 @@ def start(): generate(TYPES_PATH, TYPES_BASE) generate(FUNCTIONS_PATH, FUNCTIONS_BASE) + generate(BASE_PATH, BASE_BASE) pyrogram_api() if "__main__" == __name__: - FUNCTIONS_PATH = "../../pyrogram/api/functions" - TYPES_PATH = "../../pyrogram/api/types" + FUNCTIONS_PATH = "../../pyrogram/raw/functions" + TYPES_PATH = "../../pyrogram/raw/types" + BASE_PATH = "../../pyrogram/raw/base" HOME = "." DESTINATION = "../../docs/source/telegram" PYROGRAM_API_DEST = "../../docs/source/api" diff --git a/compiler/docs/template/bound-methods.rst b/compiler/docs/template/bound-methods.rst index 4238df52..963b5251 100644 --- a/compiler/docs/template/bound-methods.rst +++ b/compiler/docs/template/bound-methods.rst @@ -26,7 +26,7 @@ some of the required arguments. ----- -.. currentmodule:: pyrogram +.. currentmodule:: pyrogram.types Message ------- diff --git a/compiler/docs/template/methods.rst b/compiler/docs/template/methods.rst index 5a287f87..f99605ca 100644 --- a/compiler/docs/template/methods.rst +++ b/compiler/docs/template/methods.rst @@ -1,7 +1,8 @@ Available Methods ================= -This page is about Pyrogram methods. All the methods listed here are bound to a :class:`~pyrogram.Client` instance. +This page is about Pyrogram methods. All the methods listed here are bound to a :class:`~pyrogram.Client` instance, +except for :meth:`~pyrogram.idle()`, which is a special function that can be found in the main package directly. .. code-block:: python :emphasize-lines: 6 @@ -34,6 +35,20 @@ Utilities {utilities} +.. currentmodule:: pyrogram + +.. autosummary:: + :nosignatures: + + idle + +.. toctree:: + :hidden: + + idle + +.. currentmodule:: pyrogram.Client + Messages -------- diff --git a/compiler/docs/template/types.rst b/compiler/docs/template/types.rst index 2c79c11d..4cc0cf92 100644 --- a/compiler/docs/template/types.rst +++ b/compiler/docs/template/types.rst @@ -19,7 +19,7 @@ This page is about Pyrogram types. All types listed here are accessible through ----- -.. currentmodule:: pyrogram +.. currentmodule:: pyrogram.types Users & Chats ------------- diff --git a/compiler/error/source/400_BAD_REQUEST.tsv b/compiler/error/source/400_BAD_REQUEST.tsv index 608bcc9d..fadbbb49 100644 --- a/compiler/error/source/400_BAD_REQUEST.tsv +++ b/compiler/error/source/400_BAD_REQUEST.tsv @@ -28,7 +28,7 @@ PASSWORD_HASH_INVALID Two-step verification password is invalid USERNAME_NOT_OCCUPIED The username is not occupied by anyone USERNAME_INVALID The username is invalid MESSAGE_ID_INVALID The message id is invalid -MESSAGE_NOT_MODIFIED The message was not modified +MESSAGE_NOT_MODIFIED The message was not modified because you tried to edit it using the same content ENTITY_MENTION_USER_INVALID The mentioned entity is not an user MESSAGE_TOO_LONG The message text is over 4096 characters ACCESS_TOKEN_EXPIRED The bot token is invalid diff --git a/docs/Makefile b/docs/Makefile index c647eb13..cabe3ecb 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -2,7 +2,7 @@ # # You can set these variables from the command line. -SPHINXOPTS = +SPHINXOPTS = -j $(shell nproc --all) SPHINXBUILD = sphinx-build SPHINXPROJ = Pyrogram SOURCEDIR = source @@ -17,4 +17,7 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +lhtml: # live html + sphinx-autobuild -H $(shell ipconfig getifaddr en3) -b html "$(SOURCEDIR)" "$(BUILDDIR)/html" $(SPHINXOPTS) diff --git a/docs/requirements.txt b/docs/requirements.txt index 0e754f9f..995cfe8c 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,4 +3,5 @@ sphinx_rtd_theme sphinx_copybutton sphinx_tabs pypandoc -requests \ No newline at end of file +requests +sphinx-autobuild \ No newline at end of file diff --git a/docs/scripts/sitemap.py b/docs/scripts/sitemap.py index cc3da354..8e9bdded 100644 --- a/docs/scripts/sitemap.py +++ b/docs/scripts/sitemap.py @@ -46,7 +46,7 @@ with open("sitemap.xml", "w") as f: def search(path): try: for j in os.listdir(path): - search("{}/{}".format(path, j)) + search(f"{path}/{j}") except NotADirectoryError: if not path.endswith(".rst"): return @@ -58,7 +58,7 @@ with open("sitemap.xml", "w") as f: else: folder = path[0] - path = "{}{}".format(canonical, "/".join(path))[:-len(".rst")] + path = f"{canonical}{'/'.join(path)}"[:-len(".rst")] if path.endswith("index"): path = path[:-len("index")] @@ -71,11 +71,11 @@ with open("sitemap.xml", "w") as f: urls.sort(key=lambda x: x[3], reverse=True) for i in urls: - f.write(" \n") - f.write(" {}\n".format(i[0])) - f.write(" {}\n".format(i[1])) - f.write(" {}\n".format(i[2])) - f.write(" {}\n".format(i[3])) - f.write(" \n\n") + f.write(f" \n") + f.write(f" {i[0]}\n") + f.write(f" {i[1]}\n") + f.write(f" {i[2]}\n") + f.write(f" {i[3]}\n") + f.write(f" \n\n") f.write("") diff --git a/docs/source/api/decorators.rst b/docs/source/api/decorators.rst index cacb43b1..13bfc9e4 100644 --- a/docs/source/api/decorators.rst +++ b/docs/source/api/decorators.rst @@ -26,6 +26,7 @@ functions. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/api/errors.rst b/docs/source/api/errors.rst deleted file mode 100644 index 5c443cf3..00000000 --- a/docs/source/api/errors.rst +++ /dev/null @@ -1,78 +0,0 @@ -RPC Errors -========== - -All Pyrogram API errors live inside the ``errors`` sub-package: ``pyrogram.errors``. -The errors ids listed here are shown as *UPPER_SNAKE_CASE*, but the actual exception names to import from Pyrogram -follow the usual *PascalCase* convention. - -.. code-block:: python - :emphasize-lines: 1, 5 - - from pyrogram.errors import FloodWait - - try: - ... - except FloodWait as e: - ... - -.. contents:: Contents - :backlinks: none - :local: - ------ - -303 - SeeOther --------------- - -.. csv-table:: - :file: ../../../compiler/error/source/303_SEE_OTHER.tsv - :delim: tab - :header-rows: 1 - -400 - BadRequest ----------------- - -.. csv-table:: - :file: ../../../compiler/error/source/400_BAD_REQUEST.tsv - :delim: tab - :header-rows: 1 - -401 - Unauthorized ------------------- - -.. csv-table:: - :file: ../../../compiler/error/source/401_UNAUTHORIZED.tsv - :delim: tab - :header-rows: 1 - -403 - Forbidden ---------------- - -.. csv-table:: - :file: ../../../compiler/error/source/403_FORBIDDEN.tsv - :delim: tab - :header-rows: 1 - -406 - NotAcceptable -------------------- - -.. csv-table:: - :file: ../../../compiler/error/source/406_NOT_ACCEPTABLE.tsv - :delim: tab - :header-rows: 1 - -420 - Flood ------------ - -.. csv-table:: - :file: ../../../compiler/error/source/420_FLOOD.tsv - :delim: tab - :header-rows: 1 - -500 - InternalServerError -------------------------- - -.. csv-table:: - :file: ../../../compiler/error/source/500_INTERNAL_SERVER_ERROR.tsv - :delim: tab - :header-rows: 1 diff --git a/docs/source/api/errors/bad-request.rst b/docs/source/api/errors/bad-request.rst new file mode 100644 index 00000000..130cc574 --- /dev/null +++ b/docs/source/api/errors/bad-request.rst @@ -0,0 +1,7 @@ +400 - BadRequest +---------------- + +.. csv-table:: + :file: ../../../../compiler/error/source/400_BAD_REQUEST.tsv + :delim: tab + :header-rows: 1 diff --git a/docs/source/api/errors/flood.rst b/docs/source/api/errors/flood.rst new file mode 100644 index 00000000..eae33591 --- /dev/null +++ b/docs/source/api/errors/flood.rst @@ -0,0 +1,7 @@ +420 - Flood +----------- + +.. csv-table:: + :file: ../../../../compiler/error/source/420_FLOOD.tsv + :delim: tab + :header-rows: 1 \ No newline at end of file diff --git a/docs/source/api/errors/forbidden.rst b/docs/source/api/errors/forbidden.rst new file mode 100644 index 00000000..280adf40 --- /dev/null +++ b/docs/source/api/errors/forbidden.rst @@ -0,0 +1,7 @@ +403 - Forbidden +--------------- + +.. csv-table:: + :file: ../../../../compiler/error/source/403_FORBIDDEN.tsv + :delim: tab + :header-rows: 1 \ No newline at end of file diff --git a/docs/source/api/errors/index.rst b/docs/source/api/errors/index.rst new file mode 100644 index 00000000..be2b80d4 --- /dev/null +++ b/docs/source/api/errors/index.rst @@ -0,0 +1,37 @@ +RPC Errors +========== + +All Pyrogram API errors live inside the ``errors`` sub-package: ``pyrogram.errors``. +The errors ids listed here are shown as *UPPER_SNAKE_CASE*, but the actual exception names to import from Pyrogram +follow the usual *PascalCase* convention. + +.. code-block:: python + + from pyrogram.errors import FloodWait + + try: + ... + except FloodWait as e: + ... + +.. hlist:: + :columns: 1 + + - :doc:`see-other` + - :doc:`bad-request` + - :doc:`unauthorized` + - :doc:`forbidden` + - :doc:`not-acceptable` + - :doc:`flood` + - :doc:`internal-server-error` + +.. toctree:: + :hidden: + + see-other + bad-request + unauthorized + forbidden + not-acceptable + flood + internal-server-error \ No newline at end of file diff --git a/docs/source/api/errors/internal-server-error.rst b/docs/source/api/errors/internal-server-error.rst new file mode 100644 index 00000000..bbc9177a --- /dev/null +++ b/docs/source/api/errors/internal-server-error.rst @@ -0,0 +1,7 @@ +500 - InternalServerError +------------------------- + +.. csv-table:: + :file: ../../../../compiler/error/source/500_INTERNAL_SERVER_ERROR.tsv + :delim: tab + :header-rows: 1 \ No newline at end of file diff --git a/docs/source/api/errors/not-acceptable.rst b/docs/source/api/errors/not-acceptable.rst new file mode 100644 index 00000000..cfe0383e --- /dev/null +++ b/docs/source/api/errors/not-acceptable.rst @@ -0,0 +1,7 @@ +406 - NotAcceptable +------------------- + +.. csv-table:: + :file: ../../../../compiler/error/source/406_NOT_ACCEPTABLE.tsv + :delim: tab + :header-rows: 1 \ No newline at end of file diff --git a/docs/source/api/errors/see-other.rst b/docs/source/api/errors/see-other.rst new file mode 100644 index 00000000..f2cde9cf --- /dev/null +++ b/docs/source/api/errors/see-other.rst @@ -0,0 +1,7 @@ +303 - SeeOther +-------------- + +.. csv-table:: + :file: ../../../../compiler/error/source/303_SEE_OTHER.tsv + :delim: tab + :header-rows: 1 \ No newline at end of file diff --git a/docs/source/api/errors/unauthorized.rst b/docs/source/api/errors/unauthorized.rst new file mode 100644 index 00000000..4f2b24a5 --- /dev/null +++ b/docs/source/api/errors/unauthorized.rst @@ -0,0 +1,7 @@ +401 - Unauthorized +------------------ + +.. csv-table:: + :file: ../../../../compiler/error/source/401_UNAUTHORIZED.tsv + :delim: tab + :header-rows: 1 diff --git a/docs/source/api/filters.rst b/docs/source/api/filters.rst index 6cb01cda..eb3c9522 100644 --- a/docs/source/api/filters.rst +++ b/docs/source/api/filters.rst @@ -1,8 +1,11 @@ Update Filters ============== +Filters are objects that can be used to filter the content of incoming updates. +:doc:`Read more about how filters work <../topics/use-filters>`. + Details ------- -.. autoclass:: pyrogram.Filters +.. automodule:: pyrogram.filters :members: diff --git a/docs/source/api/handlers.rst b/docs/source/api/handlers.rst index 4fdc511e..80d2cf73 100644 --- a/docs/source/api/handlers.rst +++ b/docs/source/api/handlers.rst @@ -7,7 +7,8 @@ For a much more convenient way of registering callback functions have a look at .. code-block:: python :emphasize-lines: 1, 10 - from pyrogram import Client, MessageHandler + from pyrogram import Client + from pyrogram.handlers import MessageHandler app = Client("my_account") @@ -22,11 +23,12 @@ For a much more convenient way of registering callback functions have a look at .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- -.. currentmodule:: pyrogram +.. currentmodule:: pyrogram.handlers Index ----- diff --git a/docs/source/faq.rst b/docs/source/faq.rst index e56736d8..a8386732 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -12,6 +12,7 @@ This FAQ page provides answers to common questions about Pyrogram and, to some e .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst index a0e970ae..fa6086ce 100644 --- a/docs/source/glossary.rst +++ b/docs/source/glossary.rst @@ -10,6 +10,7 @@ general. Some words may as well link to dedicated articles in case the topic is .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/index.rst b/docs/source/index.rst index fd227079..0fda6da6 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,6 +1,95 @@ Welcome to Pyrogram =================== +.. raw:: html + +
+ +
Pyrogram Logo
+
+
+ +

+ Telegram MTProto API Framework for Python + +
+ + Source Code + + • + + Releases + + • + + Community + +

+ +.. code-block:: python + + from pyrogram import Client, filters + + app = Client("my_account") + + + @app.on_message(filters.private) + async def hello(client, message): + await message.reply_text(f"Hello {message.from_user.mention}") + + + app.run() + +**Pyrogram** is a modern, elegant and easy-to-use Telegram_ framework written from the ground up in Python and C. +It enables you to easily create custom apps for both user and bot identities (bot API alternative) via the +:doc:`MTProto API `. + +.. _Telegram: https://telegram.org + +How the Documentation is Organized +---------------------------------- + +Contents are organized into sections composed of self-contained topics which can be all accessed from the sidebar, or by +following them in order using the :guilabel:`Next` button at the end of each page. Here below you can, instead, find a +list of the most relevant pages for a quick access. + +First Steps +^^^^^^^^^^^ + +.. hlist:: + :columns: 2 + + - :doc:`Quick Start `: Overview to get you started quickly. + - :doc:`Calling Methods `: How to call Pyrogram's methods. + - :doc:`Handling Updates `: How to handle Telegram updates. + - :doc:`Error Handling `: How to handle API errors correctly. + +API Reference +^^^^^^^^^^^^^ + +.. hlist:: + :columns: 2 + + - :doc:`Pyrogram Client `: Reference details about the Client class. + - :doc:`Available Methods `: List of available high-level methods. + - :doc:`Available Types `: List of available high-level types. + - :doc:`Bound Methods `: List of convenient bound methods. + +Meta +^^^^ + +.. hlist:: + :columns: 2 + + - :doc:`Pyrogram FAQ `: Answers to common Pyrogram questions. + - :doc:`Pyrogram Glossary `: List of words with brief explanations. + - :doc:`Powered by Pyrogram `: Collection of Pyrogram Projects. + - :doc:`Support Pyrogram `: Ways to show your appreciation. + - :doc:`About the License `: Information about the Project license. + - :doc:`Release Notes `: Release notes for Pyrogram releases. + +Last updated on |today| + .. toctree:: :hidden: :caption: Introduction @@ -17,6 +106,7 @@ Welcome to Pyrogram start/invoking start/updates start/errors + start/examples/index .. toctree:: :hidden: @@ -28,7 +118,7 @@ Welcome to Pyrogram api/bound-methods/index api/handlers api/decorators - api/errors + api/errors/index api/filters .. toctree:: @@ -71,92 +161,4 @@ Welcome to Pyrogram telegram/functions/index telegram/types/index - -.. raw:: html - -
- -
Pyrogram Logo
-
-
- -

- Telegram MTProto API Framework for Python - -
- - Source Code - - • - - Releases - - • - - Community - -

- -.. code-block:: python - - from pyrogram import Client, Filters - - app = Client("my_account") - - - @app.on_message(Filters.private) - def hello(client, message): - message.reply_text(f"Hello {message.from_user.first_name}") - - - app.run() - -**Pyrogram** is an elegant, easy-to-use Telegram_ client library and framework written from the ground up in Python and -C. It enables you to easily create custom apps for both user and bot identities (bot API alternative) via the -:doc:`MTProto API `. - -.. _Telegram: https://telegram.org - -How the Documentation is Organized ----------------------------------- - -Contents are organized into self-contained topics and can be all accessed from the sidebar, or by following them in -order using the :guilabel:`Next` button at the end of each page. Here below you can, instead, find a list of the most -relevant pages for a quick access. - -First Steps -^^^^^^^^^^^ - -.. hlist:: - :columns: 2 - - - :doc:`Quick Start `: Overview to get you started quickly. - - :doc:`Calling Methods `: How to call Pyrogram's methods. - - :doc:`Handling Updates `: How to handle Telegram updates. - - :doc:`Error Handling `: How to handle API errors correctly. - -API Reference -^^^^^^^^^^^^^ - -.. hlist:: - :columns: 2 - - - :doc:`Pyrogram Client `: Reference details about the Client class. - - :doc:`Available Methods `: List of available high-level methods. - - :doc:`Available Types `: List of available high-level types. - - :doc:`Bound Methods `: List of convenient bound methods. - -Meta -^^^^ - -.. hlist:: - :columns: 2 - - - :doc:`Pyrogram FAQ `: Answers to common Pyrogram questions. - - :doc:`Pyrogram Glossary `: List of words with brief explanations. - - :doc:`Powered by Pyrogram `: Collection of Pyrogram Projects. - - :doc:`Support Pyrogram `: Ways to show your appreciation. - - :doc:`About the License `: Information about the Project license. - - :doc:`Release Notes `: Release notes for Pyrogram releases. - -Last updated on |today| \ No newline at end of file + telegram/base/index \ No newline at end of file diff --git a/docs/source/intro/install.rst b/docs/source/intro/install.rst index 5312e44a..9056d1f5 100644 --- a/docs/source/intro/install.rst +++ b/docs/source/intro/install.rst @@ -1,18 +1,19 @@ Install Guide ============= -Being a Python library, **Pyrogram** requires Python to be installed in your system. +Being a modern Python library, **Pyrogram** requires Python 3.6+ to be installed in your system. We recommend using the latest versions of both Python 3 and pip. -- Get **Python 3** from https://www.python.org/downloads/ (or with your package manager) +- Get **Python 3** from https://www.python.org/downloads/ (or with your package manager). - Get **pip** by following the instructions at https://pip.pypa.io/en/latest/installing/. .. important:: - Pyrogram supports **Python 3** only, starting from version 3.5.3. **PyPy** is supported too. + Pyrogram supports **Python 3** only, starting from version 3.6. **PyPy** is supported too. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- @@ -46,43 +47,6 @@ the link): $ pip3 install -U https://github.com/pyrogram/pyrogram/archive/develop.zip -Asynchronous ------------- - -Pyrogram heavily depends on IO-bound network code (it's a cloud-based messaging framework after all), and here's -where asyncio shines the most by providing extra performance and efficiency while running on a single OS-level thread -only. - -**A fully asynchronous variant of Pyrogram is therefore available** (Python 3.5.3 or higher is required). -Use this command to install (note "asyncio.zip" in the link): - -.. code-block:: text - - $ pip3 install -U https://github.com/pyrogram/pyrogram/archive/asyncio.zip - - -Pyrogram's API remains the same and features are kept up to date from the non-async, default develop branch, but you -are obviously required Python asyncio knowledge in order to take full advantage of it. - - -.. tip:: - - The idea to turn Pyrogram fully asynchronous is still under consideration, but is wise to expect that in future this - would be the one and only way to work with Pyrogram. - - You can start using Pyrogram Async variant right now as an excuse to learn more about asynchronous programming and - do experiments with it! - -.. raw:: html - - - -.. centered:: Subscribe to `@Pyrogram `_ for news and announcements - Verifying --------- diff --git a/docs/source/intro/quickstart.rst b/docs/source/intro/quickstart.rst index 13f646d1..593403b9 100644 --- a/docs/source/intro/quickstart.rst +++ b/docs/source/intro/quickstart.rst @@ -1,8 +1,8 @@ Quick Start =========== -The next few steps serve as a quick start for all new Pyrogrammers that want to get something done as fast as possible. -Let's go! +The next few steps serve as a quick start for all new Pyrogrammers that want to see Pyrogram in action as fast as +possible. Let's go! Get Pyrogram Real Fast ---------------------- diff --git a/docs/source/intro/setup.rst b/docs/source/intro/setup.rst index f5bf607b..e4c6e640 100644 --- a/docs/source/intro/setup.rst +++ b/docs/source/intro/setup.rst @@ -6,6 +6,7 @@ project with the library. Let's see how it's done. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/powered-by.rst b/docs/source/powered-by.rst index 77e593e7..6fee50b2 100644 --- a/docs/source/powered-by.rst +++ b/docs/source/powered-by.rst @@ -11,6 +11,7 @@ This is a collection of remarkable projects made with Pyrogram. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/start/auth.rst b/docs/source/start/auth.rst index 0bbd4c5e..23ff9fe2 100644 --- a/docs/source/start/auth.rst +++ b/docs/source/start/auth.rst @@ -6,6 +6,7 @@ API calls. This section provides all the information you need in order to author .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- @@ -41,7 +42,7 @@ keep the session alive, Pyrogram won't ask you again to enter your phone number. .. important:: - Your ``*.session`` files are personal and must be kept secret. + Your ``*.session`` file is personal and must be kept secret. .. note:: diff --git a/docs/source/start/errors.rst b/docs/source/start/errors.rst index a9707d08..ff9ccf5b 100644 --- a/docs/source/start/errors.rst +++ b/docs/source/start/errors.rst @@ -10,6 +10,7 @@ to control the behaviour of your application. Pyrogram errors all live inside th .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- @@ -17,9 +18,8 @@ to control the behaviour of your application. Pyrogram errors all live inside th RPCError -------- -The father of all errors is named ``RPCError``. This error exists in form of a Python exception which is directly -subclass-ed from Python's main ``Exception`` and is able to catch all Telegram API related errors. This error is raised -every time a method call against Telegram's API was unsuccessful. +The father of all errors is named ``RPCError`` and is able to catch all Telegram API related errors. +This error is raised every time a method call against Telegram's API was unsuccessful. .. code-block:: python @@ -34,19 +34,19 @@ Error Categories ---------------- The ``RPCError`` packs together all the possible errors Telegram could raise, but to make things tidier, Pyrogram -provides categories of errors, which are named after the common HTTP errors and are subclass-ed from the RPCError: +provides categories of errors, which are named after the common HTTP errors and are subclass-ed from the ``RPCError``: .. code-block:: python from pyrogram.errors import BadRequest, Forbidden, ... -- `303 - SeeOther <../api/errors#seeother>`_ -- `400 - BadRequest <../api/errors#badrequest>`_ -- `401 - Unauthorized <../api/errors#unauthorized>`_ -- `403 - Forbidden <../api/errors#forbidden>`_ -- `406 - NotAcceptable <../api/errors#notacceptable>`_ -- `420 - Flood <../api/errors#flood>`_ -- `500 - InternalServerError <../api/errors#internalservererror>`_ +- :doc:`303 - SeeOther <../api/errors/see-other>` +- :doc:`400 - BadRequest <../api/errors/bad-request>` +- :doc:`401 - Unauthorized <../api/errors/unauthorized>` +- :doc:`403 - Forbidden <../api/errors/forbidden>` +- :doc:`406 - NotAcceptable <../api/errors/not-acceptable>` +- :doc:`420 - Flood <../api/errors/flood>` +- :doc:`500 - InternalServerError <../api/errors/internal-server-error>` Single Errors ------------- @@ -59,7 +59,7 @@ issue. For example: from pyrogram.errors import FloodWait These errors subclass directly from the category of errors they belong to, which in turn subclass from the father -RPCError, thus building a class of error hierarchy such as this: +``RPCError``, thus building a class of error hierarchy such as this: - RPCError - BadRequest diff --git a/docs/source/start/examples/bot_keyboards.rst b/docs/source/start/examples/bot_keyboards.rst new file mode 100644 index 00000000..343e22c9 --- /dev/null +++ b/docs/source/start/examples/bot_keyboards.rst @@ -0,0 +1,61 @@ +bot_keyboards +============= + +This example will show you how to send normal and inline keyboards (as bot). + +You must log-in as a regular bot in order to send keyboards (use the token from @BotFather). +Any attempt in sending keyboards with a user account will be simply ignored by the server. + +send_message() is used as example, but a keyboard can be sent with any other send_* methods, +like send_audio(), send_document(), send_location(), etc... + +.. code-block:: python + + from pyrogram import Client, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton + + # Create a client using your bot token + app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11") + + with app: + app.send_message( + "haskell", # Edit this + "This is a ReplyKeyboardMarkup example", + reply_markup=ReplyKeyboardMarkup( + [ + ["A", "B", "C", "D"], # First row + ["E", "F", "G"], # Second row + ["H", "I"], # Third row + ["J"] # Fourth row + ], + resize_keyboard=True # Make the keyboard smaller + ) + ) + + app.send_message( + "haskell", # Edit this + "This is a InlineKeyboardMarkup example", + reply_markup=InlineKeyboardMarkup( + [ + [ # First row + InlineKeyboardButton( # Generates a callback query when pressed + "Button", + callback_data="data" + ), + InlineKeyboardButton( # Opens a web URL + "URL", + url="https://docs.pyrogram.org" + ), + ], + [ # Second row + InlineKeyboardButton( # Opens the inline interface + "Choose chat", + switch_inline_query="pyrogram" + ), + InlineKeyboardButton( # Opens the inline interface in the current chat + "Inline here", + switch_inline_query_current_chat="pyrogram" + ) + ] + ] + ) + ) diff --git a/docs/source/start/examples/callback_queries.rst b/docs/source/start/examples/callback_queries.rst new file mode 100644 index 00000000..73273058 --- /dev/null +++ b/docs/source/start/examples/callback_queries.rst @@ -0,0 +1,19 @@ +callback_queries +================ + +This example shows how to handle callback queries, i.e.: queries coming from inline button presses. +It uses the @on_callback_query decorator to register a CallbackQueryHandler. + +.. code-block:: python + + from pyrogram import Client + + app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11") + + + @app.on_callback_query() + def answer(client, callback_query): + callback_query.answer(f"Button contains: '{callback_query.data}'", show_alert=True) + + + app.run() # Automatically start() and idle() \ No newline at end of file diff --git a/docs/source/start/examples/echobot.rst b/docs/source/start/examples/echobot.rst new file mode 100644 index 00000000..a751a2cd --- /dev/null +++ b/docs/source/start/examples/echobot.rst @@ -0,0 +1,21 @@ +echobot +======= + +This simple echo bot replies to every private text message. + +It uses the @on_message decorator to register a MessageHandler and applies two filters on it: +Filters.text and Filters.private to make sure it will reply to private text messages only. + +.. code-block:: python + + from pyrogram import Client, Filters + + app = Client("my_account") + + + @app.on_message(Filters.text & Filters.private) + def echo(client, message): + message.reply(message.text) + + + app.run() # Automatically start() and idle() \ No newline at end of file diff --git a/docs/source/start/examples/get_chat_members.rst b/docs/source/start/examples/get_chat_members.rst new file mode 100644 index 00000000..8d477976 --- /dev/null +++ b/docs/source/start/examples/get_chat_members.rst @@ -0,0 +1,15 @@ +get_chat_members +================ + +This example shows how to get all the members of a chat. + +.. code-block:: python + + from pyrogram import Client + + app = Client("my_account") + target = "pyrogramchat" # Target channel/supergroup + + with app: + for member in app.iter_chat_members(target): + print(member.user.first_name) \ No newline at end of file diff --git a/docs/source/start/examples/get_dialogs.rst b/docs/source/start/examples/get_dialogs.rst new file mode 100644 index 00000000..b1a48064 --- /dev/null +++ b/docs/source/start/examples/get_dialogs.rst @@ -0,0 +1,14 @@ +get_dialogs +=========== + +This example shows how to get the full dialogs list (as user). + +.. code-block:: python + + from pyrogram import Client + + app = Client("my_account") + + with app: + for dialog in app.iter_dialogs(): + print(dialog.chat.title or dialog.chat.first_name) \ No newline at end of file diff --git a/docs/source/start/examples/get_history.rst b/docs/source/start/examples/get_history.rst new file mode 100644 index 00000000..01433d91 --- /dev/null +++ b/docs/source/start/examples/get_history.rst @@ -0,0 +1,15 @@ +get_history +=========== + +This example shows how to get the full message history of a chat, starting from the latest message. + +.. code-block:: python + + from pyrogram import Client + + app = Client("my_account") + target = "me" # "me" refers to your own chat (Saved Messages) + + with app: + for message in app.iter_history(target): + print(message.text) \ No newline at end of file diff --git a/docs/source/start/examples/hello_world.rst b/docs/source/start/examples/hello_world.rst new file mode 100644 index 00000000..e6884779 --- /dev/null +++ b/docs/source/start/examples/hello_world.rst @@ -0,0 +1,21 @@ +hello_world +=========== + +This example demonstrates a basic API usage + +.. code-block:: python + + from pyrogram import Client + + # Create a new Client instance + app = Client("my_account") + + with app: + # Send a message, Markdown is enabled by default + app.send_message("me", "Hi there! I'm using **Pyrogram**") + + # Send a location + app.send_location("me", 51.500729, -0.124583) + + # Send a sticker + app.send_sticker("me", "CAADBAADzg4AAvLQYAEz_x2EOgdRwBYE") \ No newline at end of file diff --git a/docs/source/start/examples/index.rst b/docs/source/start/examples/index.rst new file mode 100644 index 00000000..7d8a69a4 --- /dev/null +++ b/docs/source/start/examples/index.rst @@ -0,0 +1,46 @@ +Examples +======== + +This page contains example scripts to show you how Pyrogram looks like. + +Every script is working right away (provided you correctly set up your credentials), meaning you can simply copy-paste +and run. The only things you have to change are session names and target chats, where applicable. + +The examples listed below can be treated as building blocks for your own applications and are meant to be simple enough +to give you a basic idea. + +----- + +.. csv-table:: + :header: Example, Description + :widths: auto + :align: center + + :doc:`hello_world`, "Demonstration of basic API usage" + :doc:`echobot`, "Echo every private text message" + :doc:`welcomebot`, "The Welcome Bot in @PyrogramChat" + :doc:`get_history`, "Get the full message history of a chat" + :doc:`get_chat_members`, "Get all the members of a chat" + :doc:`get_dialogs`, "Get all of your dialog chats" + :doc:`callback_queries`, "Handle callback queries (as bot) coming from inline button presses" + :doc:`inline_queries`, "Handle inline queries (as bot) and answer with results" + :doc:`use_inline_bots`, "Query an inline bot (as user) and send a result to a chat" + :doc:`bot_keyboards`, "Send normal and inline keyboards using regular bots" + :doc:`raw_updates`, "Handle raw updates (old, should be avoided)" + +For more advanced examples, see https://snippets.pyrogram.org. + +.. toctree:: + :hidden: + + hello_world + echobot + welcomebot + get_history + get_chat_members + get_dialogs + callback_queries + inline_queries + use_inline_bots + bot_keyboards + raw_updates diff --git a/docs/source/start/examples/inline_queries.rst b/docs/source/start/examples/inline_queries.rst new file mode 100644 index 00000000..158394e8 --- /dev/null +++ b/docs/source/start/examples/inline_queries.rst @@ -0,0 +1,61 @@ +inline_queries +============== + +This example shows how to handle inline queries. + +Two results are generated when users invoke the bot inline mode, e.g.: @pyrogrambot hi. +It uses the @on_inline_query decorator to register an InlineQueryHandler. + +.. code-block:: python + + from pyrogram import ( + Client, InlineQueryResultArticle, InputTextMessageContent, InlineKeyboardMarkup, InlineKeyboardButton + ) + + app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11") + + + @app.on_inline_query() + def answer(client, inline_query): + inline_query.answer( + results=[ + InlineQueryResultArticle( + title="Installation", + input_message_content=InputTextMessageContent( + "Here's how to install **Pyrogram**" + ), + url="https://docs.pyrogram.org/intro/install", + description="How to install Pyrogram", + thumb_url="https://i.imgur.com/JyxrStE.png", + reply_markup=InlineKeyboardMarkup( + [ + [InlineKeyboardButton( + "Open website", + url="https://docs.pyrogram.org/intro/install" + )] + ] + ) + ), + InlineQueryResultArticle( + title="Usage", + input_message_content=InputTextMessageContent( + "Here's how to use **Pyrogram**" + ), + url="https://docs.pyrogram.org/start/invoking", + description="How to use Pyrogram", + thumb_url="https://i.imgur.com/JyxrStE.png", + reply_markup=InlineKeyboardMarkup( + [ + [InlineKeyboardButton( + "Open website", + url="https://docs.pyrogram.org/start/invoking" + )] + ] + ) + ) + ], + cache_time=1 + ) + + + app.run() # Automatically start() and idle() \ No newline at end of file diff --git a/docs/source/start/examples/raw_updates.rst b/docs/source/start/examples/raw_updates.rst new file mode 100644 index 00000000..6086a968 --- /dev/null +++ b/docs/source/start/examples/raw_updates.rst @@ -0,0 +1,18 @@ +raw_updates +=========== + +This example shows how to handle raw updates. + +.. code-block:: python + + from pyrogram import Client + + app = Client("my_account") + + + @app.on_raw_update() + def raw(client, update, users, chats): + print(update) + + + app.run() # Automatically start() and idle() diff --git a/docs/source/start/examples/use_inline_bots.rst b/docs/source/start/examples/use_inline_bots.rst new file mode 100644 index 00000000..284432d8 --- /dev/null +++ b/docs/source/start/examples/use_inline_bots.rst @@ -0,0 +1,18 @@ +use_inline_bots +=============== + +This example shows how to query an inline bot (as user). + +.. code-block:: python + + from pyrogram import Client + + # Create a new Client + app = Client("my_account") + + with app: + # Get bot results for "Fuzz Universe" from the inline bot @vid + bot_results = app.get_inline_bot_results("vid", "Fuzz Universe") + + # Send the first result (bot_results.results[0]) to your own chat (Saved Messages) + app.send_inline_bot_result("me", bot_results.query_id, bot_results.results[0].id) \ No newline at end of file diff --git a/docs/source/start/examples/welcomebot.rst b/docs/source/start/examples/welcomebot.rst new file mode 100644 index 00000000..a3bb3299 --- /dev/null +++ b/docs/source/start/examples/welcomebot.rst @@ -0,0 +1,33 @@ +welcomebot +========== + +This is the Welcome Bot in @PyrogramChat. + +It uses the Emoji module to easily add emojis in your text messages and Filters +to make it only work for specific messages in a specific chat. + +.. code-block:: python + + from pyrogram import Client, Emoji, Filters + + TARGET = "PyrogramChat" # Target chat. Can also be a list of multiple chat ids/usernames + MENTION = "[{}](tg://user?id={})" # User mention markup + MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.org/)'s group chat {}!" # Welcome message + + app = Client("my_account") + + + # Filter in only new_chat_members updates generated in TARGET chat + @app.on_message(Filters.chat(TARGET) & Filters.new_chat_members) + def welcome(client, message): + # Build the new members list (with mentions) by using their first_name + new_members = [MENTION.format(i.first_name, i.id) for i in message.new_chat_members] + + # Build the welcome message by using an emoji and the list we built above + text = MESSAGE.format(Emoji.SPARKLES, ", ".join(new_members)) + + # Send the welcome message, without the web page preview + message.reply(text, disable_web_page_preview=True) + + + app.run() # Automatically start() and idle() \ No newline at end of file diff --git a/docs/source/start/invoking.rst b/docs/source/start/invoking.rst index 74b313e4..0abea089 100644 --- a/docs/source/start/invoking.rst +++ b/docs/source/start/invoking.rst @@ -6,6 +6,7 @@ account; we are now aiming towards the core of the library. It's time to start p .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- @@ -13,7 +14,8 @@ account; we are now aiming towards the core of the library. It's time to start p Basic Usage ----------- -Making API method calls with Pyrogram is very simple. Here's an example we are going to examine: +Making API method calls with Pyrogram is very simple. Here's a basic example we are going to examine step by step and +then expand to explain what happens underneath: .. code-block:: python @@ -21,16 +23,13 @@ Making API method calls with Pyrogram is very simple. Here's an example we are g app = Client("my_account") - app.start() + with app: + app.send_message("me", "Hi!") - print(app.get_me()) - app.send_message("me", "Hi, it's me!") - app.send_location("me", 51.500729, -0.124583) - app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") +Basic step-by-step +^^^^^^^^^^^^^^^^^^ - app.stop() - -#. Let's begin by importing the Client class from the Pyrogram package: +#. Let's begin by importing the Client class: .. code-block:: python @@ -42,35 +41,26 @@ Making API method calls with Pyrogram is very simple. Here's an example we are g app = Client("my_account") -#. To actually make use of any method, the client has to be started first: +#. The ``with`` context manager is a shortcut for starting, executing and stopping the Client: .. code-block:: python - app.start() + with app: #. Now, you can call any method you like: .. code-block:: python - print(app.get_me()) # Print information about yourself - - # Send messages to yourself: - app.send_message("me", "Hi!") # Text message - app.send_location("me", 51.500729, -0.124583) # Location - app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") # Sticker - -#. Finally, when done, simply stop the client: - - .. code-block:: python - - app.stop() + app.send_message("me", "Hi!") Context Manager --------------- -You can also use Pyrogram's Client in a context manager with the ``with`` statement. The client will automatically -:meth:`~pyrogram.Client.start` and :meth:`~pyrogram.Client.stop` gracefully, even in case of unhandled exceptions in -your code. The example above can be therefore rewritten in a much nicer way: +The ``with`` statement starts a context manager, which is used as a shortcut to automatically call +:meth:`~pyrogram.Client.start` and :meth:`~pyrogram.Client.stop`, which are methods required for Pyrogram to work +properly. The context manager does also gracefully stop the client, even in case of unhandled exceptions in your code. + +This is how Pyrogram looks without the context manager: .. code-block:: python @@ -78,10 +68,53 @@ your code. The example above can be therefore rewritten in a much nicer way: app = Client("my_account") - with app: - print(app.get_me()) - app.send_message("me", "Hi there! I'm using **Pyrogram**") - app.send_location("me", 51.500729, -0.124583) - app.send_sticker("me", "CAADBAADyg4AAvLQYAEYD4F7vcZ43AI") + app.start() + app.send_message("me", "Hi!") + app.stop() -More examples can be found on `GitHub `_. +Asynchronous Calls +------------------ + +In case you want Pyrogram to run asynchronously (e.g.: if you are using third party libraries that require you to call +them with ``await``), use the asynchronous context manager: + +.. code-block:: python + + from pyrogram import Client + + app = Client("my_account") + + async def main(): + async with app: + await app.send_message("me", "Hi!") + + app.run(main()) + +Asynchronous step-by-step +^^^^^^^^^^^^^^^^^^^^^^^^^ + +#. Import the Client class and create an instance: + + .. code-block:: python + + from pyrogram import Client + + app = Client("my_account") + +#. Async methods can't normally be executed at the top level, because they must be inside an async-defined function; + here we define one and put our code inside; the context manager is also being used differently in asyncio and + method calls require the await keyword: + + .. code-block:: python + + async def main(): + async with app: + await app.send_message("me", "Hi!") + +#. Finally, we tell Python to schedule our ``main()`` async function, which in turn will execute Pyrogram's code. Using + :meth:`~pyrogram.Client.run` this way is a friendly alternative for the much more verbose + ``asyncio.get_event_loop().run_until_complete(main())``: + + .. code-block:: python + + app.run(main()) diff --git a/docs/source/start/updates.rst b/docs/source/start/updates.rst index 4f010e27..ef569bf9 100644 --- a/docs/source/start/updates.rst +++ b/docs/source/start/updates.rst @@ -6,6 +6,7 @@ This page deals with updates and how to handle such events in Pyrogram. Let's ha .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- @@ -24,72 +25,14 @@ function will be called back by the framework and its body executed. Registering a Handler --------------------- -To explain how handlers work let's have a look at the most used one, the :class:`~pyrogram.MessageHandler`, which will -be in charge for handling :class:`~pyrogram.Message` updates coming from all around your chats. Every other handler shares -the same setup logic; you should not have troubles settings them up once you learn from this section. - -Using add_handler() -------------------- - -The :meth:`~pyrogram.Client.add_handler` method takes any handler instance that wraps around your defined callback -function and registers it in your Client. Here's a full example that prints out the content of a message as soon as it -arrives: - -.. code-block:: python - - from pyrogram import Client, MessageHandler - - - def my_function(client, message): - print(message) - - - app = Client("my_account") - - my_handler = MessageHandler(my_function) - app.add_handler(my_handler) - - app.run() - -Let's examine these four new pieces. - -#. A callback function we defined which accepts two arguments - - *(client, message)*. This will be the function that gets executed every time a new message arrives and Pyrogram will - call that function by passing the client instance and the new message instance as argument. - - .. code-block:: python - - def my_function(client, message): - print(message) - -#. The :class:`~pyrogram.MessageHandler`. This object tells Pyrogram the function we defined above must only handle - updates that are in form of a :class:`~pyrogram.Message`: - - .. code-block:: python - - my_handler = MessageHandler(my_function) - -#. The method :meth:`~pyrogram.Client.add_handler`. This method is used to actually register the handler and let - Pyrogram know it needs to be taken into consideration when new updates arrive and the internal dispatching phase - begins. - - .. code-block:: python - - app.add_handler(my_handler) - -#. The :meth:`~pyrogram.Client.run` method. What this does is simply call :meth:`~pyrogram.Client.start` and - a special method :meth:`~pyrogram.Client.idle` that keeps your main scripts alive until you press ``CTRL+C``; the - client will be automatically stopped after that. - - .. code-block:: python - - app.run() +To explain how handlers work let's examine the one which will be in charge for handling :class:`~pyrogram.types.Message` +updates coming from all around your chats. Every other handler shares the same setup logic; you should not have +troubles settings them up once you learn from this section. Using Decorators ----------------- +^^^^^^^^^^^^^^^^ -All of the above will become quite verbose, especially in case you have lots of handlers to register. A much nicer way -to do so is by decorating your callback function with the :meth:`~pyrogram.Client.on_message` decorator. +The most elegant way to register a message handler is by using the :meth:`~pyrogram.Client.on_message` decorator: .. code-block:: python @@ -100,7 +43,58 @@ to do so is by decorating your callback function with the :meth:`~pyrogram.Clien @app.on_message() def my_handler(client, message): - print(message) + message.forward("me") app.run() + +The defined function ``my_handler``, which accepts the two arguments *(client, message)*, will be the function that gets +executed every time a new message arrives. + +Asynchronous handlers +^^^^^^^^^^^^^^^^^^^^^ + +You can also have asynchronous handlers; you only need to define the callback function using ``async def`` and call API +methods by placing ``await`` in front of them: + +.. code-block:: python + + @app.on_message() + async def my_handler(client, message): + await message.forward("me") + +.. note:: + + You can mix ``def`` and ``async def`` handlers as much as you need, Pyrogram will still work concurrently and + efficiently regardless of what you choose. + +Using add_handler() +^^^^^^^^^^^^^^^^^^^ + +The :meth:`~pyrogram.Client.add_handler` method takes any handler instance that wraps around your defined callback +function and registers it in your Client. It us useful in case you want to programmatically add handlers (or in case, +for some reason, you don't like to use decorators). + +.. code-block:: python + + from pyrogram import Client + from pyrogram.handlers import MessageHandler + + + def my_function(client, message): + message.forward("me") + + + app = Client("my_account") + + my_handler = MessageHandler(my_function) + app.add_handler(my_handler) + + app.run() + +The same about asynchronous handlers applies for :meth:`~pyrogram.Client.add_handler`: + +.. code-block:: python + + async def my_function(client, message): + await message.forward("me") diff --git a/docs/source/topics/advanced-usage.rst b/docs/source/topics/advanced-usage.rst index a56e0da1..9df028ad 100644 --- a/docs/source/topics/advanced-usage.rst +++ b/docs/source/topics/advanced-usage.rst @@ -10,6 +10,7 @@ Telegram API with its functions and types. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- @@ -18,7 +19,7 @@ Telegram Raw API ---------------- If you can't find a high-level method for your needs or if you want complete, low-level access to the whole -Telegram API, you have to use the raw :mod:`~pyrogram.api.functions` and :mod:`~pyrogram.api.types`. +Telegram API, you have to use the raw :mod:`~pyrogram.raw.functions` and :mod:`~pyrogram.raw.types`. As already hinted, raw functions and types can be really confusing, mainly because people don't realize soon enough they accept *only* the right types and that all required parameters must be filled in. This section will therefore explain @@ -41,7 +42,7 @@ Unlike the :doc:`methods <../api/methods/index>` found in Pyrogram's API, which functions to be invoked from the raw Telegram API have a different way of usage and are more complex. First of all, both :doc:`raw functions <../telegram/functions/index>` and :doc:`raw types <../telegram/types/index>` -live in their respective packages (and sub-packages): ``pyrogram.api.functions``, ``pyrogram.api.types``. They all exist +live in their respective packages (and sub-packages): ``pyrogram.raw.functions``, ``pyrogram.raw.types``. They all exist as Python classes, meaning you need to create an instance of each every time you need them and fill them in with the correct values using named arguments. @@ -55,7 +56,7 @@ Here's some examples: .. code-block:: python from pyrogram import Client - from pyrogram.api import functions + from pyrogram.raw import functions with Client("my_account") as app: app.send( @@ -70,7 +71,7 @@ Here's some examples: .. code-block:: python from pyrogram import Client - from pyrogram.api import functions, types + from pyrogram.raw import functions, types with Client("my_account") as app: app.send( @@ -85,7 +86,7 @@ Here's some examples: .. code-block:: python from pyrogram import Client - from pyrogram.api import functions, types + from pyrogram.raw import functions, types with Client("my_account") as app: app.send( @@ -109,9 +110,9 @@ sending messages with IDs only thanks to cached access hashes. There are three different InputPeer types, one for each kind of Telegram entity. Whenever an InputPeer is needed you must pass one of these: -- :class:`~pyrogram.api.types.InputPeerUser` - Users -- :class:`~pyrogram.api.types.InputPeerChat` - Basic Chats -- :class:`~pyrogram.api.types.InputPeerChannel` - Either Channels or Supergroups +- :class:`~pyrogram.raw.types.InputPeerUser` - Users +- :class:`~pyrogram.raw.types.InputPeerChat` - Basic Chats +- :class:`~pyrogram.raw.types.InputPeerChannel` - Either Channels or Supergroups But you don't necessarily have to manually instantiate each object because, luckily for you, Pyrogram already provides :meth:`~pyrogram.Client.resolve_peer` as a convenience utility method that returns the correct InputPeer diff --git a/docs/source/topics/bots-interaction.rst b/docs/source/topics/bots-interaction.rst index 97a72e05..1fad2069 100644 --- a/docs/source/topics/bots-interaction.rst +++ b/docs/source/topics/bots-interaction.rst @@ -5,6 +5,7 @@ Users can interact with other bots via plain text messages as well as inline que .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/topics/config-file.rst b/docs/source/topics/config-file.rst index b6faee05..38bb9e33 100644 --- a/docs/source/topics/config-file.rst +++ b/docs/source/topics/config-file.rst @@ -6,6 +6,7 @@ This page explains how this file is structured, how to use it and why. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/topics/create-filters.rst b/docs/source/topics/create-filters.rst index 060357de..3e87a3de 100644 --- a/docs/source/topics/create-filters.rst +++ b/docs/source/topics/create-filters.rst @@ -1,16 +1,12 @@ Creating Filters ================ -Pyrogram already provides lots of built-in :class:`~pyrogram.Filters` to work with, but in case you can't find -a specific one for your needs or want to build a custom filter by yourself (to be used in a different kind of handler, -for example) you can use :meth:`~pyrogram.Filters.create`. - -.. note:: - - At the moment, the built-in filters are intended to be used with the :class:`~pyrogram.MessageHandler` only. +Pyrogram already provides lots of built-in :class:`~pyrogram.filters` to work with, but in case you can't find a +specific one for your needs or want to build a custom filter by yourself you can use :meth:`~pyrogram.filters.create`. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- @@ -19,14 +15,14 @@ Custom Filters -------------- An example to demonstrate how custom filters work is to show how to create and use one for the -:class:`~pyrogram.CallbackQueryHandler`. Note that callback queries updates are only received by bots as result of a -user pressing an inline button attached to the bot's message; create and :doc:`authorize your bot <../start/auth>`, +:class:`~pyrogram.handlers.CallbackQueryHandler`. Note that callback queries updates are only received by bots as result +of a user pressing an inline button attached to the bot's message; create and :doc:`authorize your bot <../start/auth>`, then send a message with an inline keyboard to yourself. This allows you to test your filter by pressing the inline button: .. code-block:: python - from pyrogram import InlineKeyboardMarkup, InlineKeyboardButton + from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton app.send_message( "username", # Change this to your username or id @@ -39,7 +35,7 @@ button: Basic Filters ------------- -For this basic filter we will be using only the first parameter of :meth:`~pyrogram.Filters.create`. +For this basic filter we will be using only the first parameter of :meth:`~pyrogram.filters.create`. The code below creates a simple filter for hardcoded, static callback data. This filter will only allow callback queries containing "pyrogram" as data, that is, the function *func* you pass returns True in case the callback query data @@ -47,17 +43,21 @@ equals to ``"pyrogram"``. .. code-block:: python - static_data_filter = Filters.create(lambda _, query: query.data == "pyrogram") + from pyrogram import filters + + static_data_filter = filters.create(lambda _, query: query.data == "pyrogram") The ``lambda`` operator in python is used to create small anonymous functions and is perfect for this example, the same -could be achieved with a normal function, but we don't really need it as it makes sense only inside the filter scope: +could be achieved with a normal function, but we don't really need it as it makes sense only inside the filter's scope: .. code-block:: python + from pyrogram import filters + def func(_, query): return query.data == "pyrogram" - static_data_filter = Filters.create(func) + static_data_filter = filters.create(func) The filter usage remains the same: @@ -71,14 +71,16 @@ Filters with Arguments ---------------------- A much cooler filter would be one that accepts "pyrogram" or any other data as argument at usage time. -A dynamic filter like this will make use of named arguments for the :meth:`~pyrogram.Filters.create` method. +A dynamic filter like this will make use of named arguments for the :meth:`~pyrogram.filters.create` method. This is how a dynamic custom filter looks like: .. code-block:: python + from pyrogram import filters + def dynamic_data_filter(data): - return Filters.create( + return filters.create( lambda flt, query: flt.data == query.data, data=data # "data" kwarg is accessed with "flt.data" above ) diff --git a/docs/source/topics/debugging.rst b/docs/source/topics/debugging.rst index 7284884a..995ce9e5 100644 --- a/docs/source/topics/debugging.rst +++ b/docs/source/topics/debugging.rst @@ -6,6 +6,7 @@ to actually worry about -- that's normal -- and luckily for you, Pyrogram provid .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/topics/more-on-updates.rst b/docs/source/topics/more-on-updates.rst index 1bffaeef..a636008a 100644 --- a/docs/source/topics/more-on-updates.rst +++ b/docs/source/topics/more-on-updates.rst @@ -6,6 +6,7 @@ Here we'll show some advanced usages when working with :doc:`update handlers <.. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- @@ -25,21 +26,21 @@ For example, take these two handlers: .. code-block:: python :emphasize-lines: 1, 6 - @app.on_message(Filters.text | Filters.sticker) + @app.on_message(filters.text | filters.sticker) def text_or_sticker(client, message): print("Text or Sticker") - @app.on_message(Filters.text) + @app.on_message(filters.text) def just_text(client, message): print("Just Text") Here, ``just_text`` is never executed because ``text_or_sticker``, which has been registered first, already handles -texts (``Filters.text`` is shared and conflicting). To enable it, register the handler using a different group: +texts (``filters.text`` is shared and conflicting). To enable it, register the handler using a different group: .. code-block:: python - @app.on_message(Filters.text, group=1) + @app.on_message(filters.text, group=1) def just_text(client, message): print("Just Text") @@ -47,7 +48,7 @@ Or, if you want ``just_text`` to be executed *before* ``text_or_sticker`` (note .. code-block:: python - @app.on_message(Filters.text, group=-1) + @app.on_message(filters.text, group=-1) def just_text(client, message): print("Just Text") @@ -55,7 +56,7 @@ With :meth:`~pyrogram.Client.add_handler` (without decorators) the same can be a .. code-block:: python - app.add_handler(MessageHandler(just_text, Filters.text), -1) + app.add_handler(MessageHandler(just_text, filters.text), -1) Update propagation ------------------ @@ -67,17 +68,17 @@ continue to propagate the same update to the next groups until all the handlers .. code-block:: python - @app.on_message(Filters.private) + @app.on_message(filters.private) def _(client, message): print(0) - @app.on_message(Filters.private, group=1) + @app.on_message(filters.private, group=1) def _(client, message): raise Exception("Unhandled exception!") # Simulate an unhandled exception - @app.on_message(Filters.private, group=2) + @app.on_message(filters.private, group=2) def _(client, message): print(2) @@ -109,18 +110,18 @@ Example with ``stop_propagation()``: .. code-block:: python - @app.on_message(Filters.private) + @app.on_message(filters.private) def _(client, message): print(0) - @app.on_message(Filters.private, group=1) + @app.on_message(filters.private, group=1) def _(client, message): print(1) message.stop_propagation() - @app.on_message(Filters.private, group=2) + @app.on_message(filters.private, group=2) def _(client, message): print(2) @@ -130,18 +131,18 @@ Example with ``raise StopPropagation``: from pyrogram import StopPropagation - @app.on_message(Filters.private) + @app.on_message(filters.private) def _(client, message): print(0) - @app.on_message(Filters.private, group=1) + @app.on_message(filters.private, group=1) def _(client, message): print(1) raise StopPropagation - @app.on_message(Filters.private, group=2) + @app.on_message(filters.private, group=2) def _(client, message): print(2) @@ -177,19 +178,19 @@ Example with ``continue_propagation()``: .. code-block:: python - @app.on_message(Filters.private) + @app.on_message(filters.private) def _(client, message): print(0) message.continue_propagation() - @app.on_message(Filters.private) + @app.on_message(filters.private) def _(client, message): print(1) message.continue_propagation() - @app.on_message(Filters.private) + @app.on_message(filters.private) def _(client, message): print(2) @@ -199,19 +200,19 @@ Example with ``raise ContinuePropagation``: from pyrogram import ContinuePropagation - @app.on_message(Filters.private) + @app.on_message(filters.private) def _(client, message): print(0) raise ContinuePropagation - @app.on_message(Filters.private) + @app.on_message(filters.private) def _(client, message): print(1) raise ContinuePropagation - @app.on_message(Filters.private) + @app.on_message(filters.private) def _(client, message): print(2) diff --git a/docs/source/topics/mtproto-vs-botapi.rst b/docs/source/topics/mtproto-vs-botapi.rst index aab3525e..c73d6692 100644 --- a/docs/source/topics/mtproto-vs-botapi.rst +++ b/docs/source/topics/mtproto-vs-botapi.rst @@ -8,6 +8,7 @@ actually is the MTProto and the Bot API. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/topics/proxy.rst b/docs/source/topics/proxy.rst index cde55cc7..7d7e2c88 100644 --- a/docs/source/topics/proxy.rst +++ b/docs/source/topics/proxy.rst @@ -6,6 +6,7 @@ through an intermediate SOCKS5 proxy server. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/topics/scheduling.rst b/docs/source/topics/scheduling.rst index c5f410bb..0776d601 100644 --- a/docs/source/topics/scheduling.rst +++ b/docs/source/topics/scheduling.rst @@ -10,6 +10,7 @@ visit and learn from each library documentation. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- @@ -69,8 +70,7 @@ Using ``apscheduler`` scheduler.start() app.run() -``apscheduler`` does also support async code, here's an example with -`Pyrogram Asyncio `_: +``apscheduler`` does also support async code, here's an example: .. code-block:: python diff --git a/docs/source/topics/serializing.rst b/docs/source/topics/serializing.rst index 8e6f29de..7e013573 100644 --- a/docs/source/topics/serializing.rst +++ b/docs/source/topics/serializing.rst @@ -7,6 +7,7 @@ humans and another more compact for machines that is able to recover the origina .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/topics/session-settings.rst b/docs/source/topics/session-settings.rst index a97dbc06..847427cf 100644 --- a/docs/source/topics/session-settings.rst +++ b/docs/source/topics/session-settings.rst @@ -22,6 +22,7 @@ That's how a session looks like on the Android app, showing the three main piece .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/topics/smart-plugins.rst b/docs/source/topics/smart-plugins.rst index 7ffe1cb2..fece6366 100644 --- a/docs/source/topics/smart-plugins.rst +++ b/docs/source/topics/smart-plugins.rst @@ -11,6 +11,7 @@ different Pyrogram applications with **minimal boilerplate code**. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- @@ -51,7 +52,8 @@ after importing your modules, like this: .. code-block:: python - from pyrogram import Client, MessageHandler, Filters + from pyrogram import Client, filters + from pyrogram.handlers import MessageHandler from handlers import echo, echo_reversed @@ -60,19 +62,19 @@ after importing your modules, like this: app.add_handler( MessageHandler( echo, - Filters.text & Filters.private)) + filters.text & filters.private)) app.add_handler( MessageHandler( echo_reversed, - Filters.text & Filters.private), + filters.text & filters.private), group=1) app.run() This is already nice and doesn't add *too much* boilerplate code, but things can get boring still; you have to manually ``import``, manually :meth:`~pyrogram.Client.add_handler` and manually instantiate each -:class:`~pyrogram.MessageHandler` object because **you can't use those cool decorators** for your +:class:`~pyrogram.handlers.MessageHandler` object because **you can't use those cool decorators** for your functions. So, what if you could? Smart Plugins solve this issue by taking care of handlers registration automatically. Using Smart Plugins @@ -102,15 +104,15 @@ Setting up your Pyrogram project to accommodate Smart Plugins is pretty straight .. code-block:: python :emphasize-lines: 4, 9 - from pyrogram import Client, Filters + from pyrogram import Client, filters - @Client.on_message(Filters.text & Filters.private) + @Client.on_message(filters.text & filters.private) def echo(client, message): message.reply(message.text) - @Client.on_message(Filters.text & Filters.private, group=1) + @Client.on_message(filters.text & filters.private, group=1) def echo_reversed(client, message): message.reply(message.text[::-1]) @@ -306,7 +308,7 @@ updates) will be modified in such a way that a special ``handler`` attribute poi .. code-block:: python :emphasize-lines: 5, 6 - @Client.on_message(Filters.text & Filters.private) + @Client.on_message(filters.text & filters.private) def echo(client, message): message.reply(message.text) diff --git a/docs/source/topics/storage-engines.rst b/docs/source/topics/storage-engines.rst index e7494e2b..1a86cad8 100644 --- a/docs/source/topics/storage-engines.rst +++ b/docs/source/topics/storage-engines.rst @@ -7,6 +7,7 @@ decide to manually terminate it) and is used to authorize a client to execute AP .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/topics/test-servers.rst b/docs/source/topics/test-servers.rst index 1906c2f1..3ed996ee 100644 --- a/docs/source/topics/test-servers.rst +++ b/docs/source/topics/test-servers.rst @@ -20,6 +20,7 @@ Telegram's test servers without hassle. All you need to do is start a new sessio .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/topics/text-formatting.rst b/docs/source/topics/text-formatting.rst index f4ac23e1..5d9a9376 100644 --- a/docs/source/topics/text-formatting.rst +++ b/docs/source/topics/text-formatting.rst @@ -19,6 +19,7 @@ variety of decorations that can also be nested in order to combine multiple styl .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- diff --git a/docs/source/topics/use-filters.rst b/docs/source/topics/use-filters.rst index 8806052e..7e5219e1 100644 --- a/docs/source/topics/use-filters.rst +++ b/docs/source/topics/use-filters.rst @@ -1,14 +1,15 @@ Using Filters ============= -So far we've seen :doc:`how to register a callback function <../start/updates>` that executes every time a specific update -comes from the server, but there's much more than that to come. +So far we've seen :doc:`how to register a callback function <../start/updates>` that executes every time an update comes +from the server, but there's much more than that to come. -Here we'll discuss about :class:`~pyrogram.Filters`. Filters enable a fine-grain control over what kind of +Here we'll discuss about :obj:`~pyrogram.filters`. Filters enable a fine-grain control over what kind of updates are allowed or not to be passed in your callback functions, based on their inner details. .. contents:: Contents :backlinks: none + :depth: 1 :local: ----- @@ -24,10 +25,10 @@ Let's start right away with a simple example: .. code-block:: python :emphasize-lines: 4 - from pyrogram import Filters + from pyrogram import filters - @app.on_message(Filters.audio) + @app.on_message(filters.audio) def my_handler(client, message): print(message) @@ -35,16 +36,17 @@ Let's start right away with a simple example: callback function itself: .. code-block:: python - :emphasize-lines: 8 + :emphasize-lines: 9 - from pyrogram import Filters, MessageHandler + from pyrogram import filters + from pyrogram.handlers import MessageHandler def my_handler(client, message): print(message) - app.add_handler(MessageHandler(my_handler, Filters.audio)) + app.add_handler(MessageHandler(my_handler, filters.audio)) Combining Filters ----------------- @@ -61,7 +63,7 @@ Here are some examples: .. code-block:: python - @app.on_message(Filters.text & ~Filters.edited) + @app.on_message(filters.text & ~filters.edited) def my_handler(client, message): print(message) @@ -69,21 +71,21 @@ Here are some examples: .. code-block:: python - @app.on_message(Filters.sticker & (Filters.channel | Filters.private)) + @app.on_message(filters.sticker & (filters.channel | filters.private)) def my_handler(client, message): print(message) Advanced Filters ---------------- -Some filters, like :meth:`~pyrogram.Filters.command` or :meth:`~pyrogram.Filters.regex` +Some filters, like :meth:`~pyrogram.filters.command` or :meth:`~pyrogram.filters.regex` can also accept arguments: - Message is either a */start* or */help* **command**. .. code-block:: python - @app.on_message(Filters.command(["start", "help"])) + @app.on_message(filters.command(["start", "help"])) def my_handler(client, message): print(message) @@ -91,7 +93,7 @@ can also accept arguments: .. code-block:: python - @app.on_message(Filters.regex("pyrogram")) + @app.on_message(filters.regex("pyrogram")) def my_handler(client, message): print(message) @@ -99,16 +101,16 @@ More handlers using different filters can also live together. .. code-block:: python - @app.on_message(Filters.command("start")) + @app.on_message(filters.command("start")) def start_command(client, message): print("This is the /start command") - @app.on_message(Filters.command("help")) + @app.on_message(filters.command("help")) def help_command(client, message): print("This is the /help command") - @app.on_message(Filters.chat("PyrogramChat")) + @app.on_message(filters.chat("PyrogramChat")) def from_pyrogramchat(client, message): print("New message in @PyrogramChat") diff --git a/examples/LICENSE b/examples/LICENSE deleted file mode 100644 index 1625c179..00000000 --- a/examples/LICENSE +++ /dev/null @@ -1,121 +0,0 @@ -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. \ No newline at end of file diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index b8898a71..00000000 --- a/examples/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Examples - -This folder contains example scripts to show you how **Pyrogram** looks like. - -Every script is working right away (provided you correctly set up your credentials), meaning you can simply copy-paste -and run. The only things you have to change are session names and target chats. - -All the examples listed in this directory are licensed under the terms of the [CC0 1.0 Universal](LICENSE) license and -can be freely used as basic building blocks for your own applications without worrying about copyrights. - -Example | Description ----: | :--- -[**hello_world**](hello_world.py) | Demonstration of basic API usage -[**echobot**](echobot.py) | Echo every private text message -[**welcomebot**](welcomebot.py) | The Welcome Bot in [@PyrogramChat](https://t.me/pyrogramchat) -[**get_history**](get_history.py) | Get the full message history of a chat -[**get_chat_members**](get_chat_members.py) | Get all the members of a chat -[**get_dialogs**](get_dialogs.py) | Get all of your dialog chats -[**callback_queries**](callback_queries.py) | Handle callback queries (as bot) coming from inline button presses -[**inline_queries**](inline_queries.py) | Handle inline queries (as bot) and answer with results -[**use_inline_bots**](use_inline_bots.py) | Query an inline bot (as user) and send a result to a chat -[**bot_keyboards**](bot_keyboards.py) | Send normal and inline keyboards using regular bots -[**raw_updates**](raw_updates.py) | Handle raw updates (old, should be avoided) diff --git a/examples/bot_keyboards.py b/examples/bot_keyboards.py deleted file mode 100644 index e1ff1e7e..00000000 --- a/examples/bot_keyboards.py +++ /dev/null @@ -1,57 +0,0 @@ -"""This example will show you how to send normal and inline keyboards (as bot). - -You must log-in as a regular bot in order to send keyboards (use the token from @BotFather). -Any attempt in sending keyboards with a user account will be simply ignored by the server. - -send_message() is used as example, but a keyboard can be sent with any other send_* methods, -like send_audio(), send_document(), send_location(), etc... -""" - -from pyrogram import Client, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton - -# Create a client using your bot token -app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11") - -with app: - app.send_message( - "haskell", # Edit this - "This is a ReplyKeyboardMarkup example", - reply_markup=ReplyKeyboardMarkup( - [ - ["A", "B", "C", "D"], # First row - ["E", "F", "G"], # Second row - ["H", "I"], # Third row - ["J"] # Fourth row - ], - resize_keyboard=True # Make the keyboard smaller - ) - ) - - app.send_message( - "haskell", # Edit this - "This is a InlineKeyboardMarkup example", - reply_markup=InlineKeyboardMarkup( - [ - [ # First row - InlineKeyboardButton( # Generates a callback query when pressed - "Button", - callback_data=b"data" # Note how callback_data must be bytes - ), - InlineKeyboardButton( # Opens a web URL - "URL", - url="https://docs.pyrogram.org" - ), - ], - [ # Second row - InlineKeyboardButton( # Opens the inline interface - "Choose chat", - switch_inline_query="pyrogram" - ), - InlineKeyboardButton( # Opens the inline interface in the current chat - "Inline here", - switch_inline_query_current_chat="pyrogram" - ) - ] - ] - ) - ) diff --git a/examples/callback_queries.py b/examples/callback_queries.py deleted file mode 100644 index f4a87b00..00000000 --- a/examples/callback_queries.py +++ /dev/null @@ -1,16 +0,0 @@ -"""This example shows how to handle callback queries, i.e.: queries coming from inline button presses. - -It uses the @on_callback_query decorator to register a CallbackQueryHandler. -""" - -from pyrogram import Client - -app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11") - - -@app.on_callback_query() -def answer(client, callback_query): - callback_query.answer("Button contains: '{}'".format(callback_query.data), show_alert=True) - - -app.run() # Automatically start() and idle() diff --git a/examples/echobot.py b/examples/echobot.py deleted file mode 100644 index c60ae291..00000000 --- a/examples/echobot.py +++ /dev/null @@ -1,17 +0,0 @@ -"""This simple echo bot replies to every private text message. - -It uses the @on_message decorator to register a MessageHandler and applies two filters on it: -Filters.text and Filters.private to make sure it will reply to private text messages only. -""" - -from pyrogram import Client, Filters - -app = Client("my_account") - - -@app.on_message(Filters.text & Filters.private) -def echo(client, message): - message.reply(message.text) - - -app.run() # Automatically start() and idle() diff --git a/examples/get_chat_members.py b/examples/get_chat_members.py deleted file mode 100644 index 468ac7de..00000000 --- a/examples/get_chat_members.py +++ /dev/null @@ -1,10 +0,0 @@ -"""This example shows how to get all the members of a chat.""" - -from pyrogram import Client - -app = Client("my_account") -target = "pyrogramchat" # Target channel/supergroup - -with app: - for member in app.iter_chat_members(target): - print(member.user.first_name) diff --git a/examples/get_dialogs.py b/examples/get_dialogs.py deleted file mode 100644 index 92da8834..00000000 --- a/examples/get_dialogs.py +++ /dev/null @@ -1,9 +0,0 @@ -"""This example shows how to get the full dialogs list (as user).""" - -from pyrogram import Client - -app = Client("my_account") - -with app: - for dialog in app.iter_dialogs(): - print(dialog.chat.title or dialog.chat.first_name) diff --git a/examples/get_history.py b/examples/get_history.py deleted file mode 100644 index e8bb14e3..00000000 --- a/examples/get_history.py +++ /dev/null @@ -1,10 +0,0 @@ -"""This example shows how to get the full message history of a chat, starting from the latest message""" - -from pyrogram import Client - -app = Client("my_account") -target = "me" # "me" refers to your own chat (Saved Messages) - -with app: - for message in app.iter_history(target): - print(message.text) diff --git a/examples/hello_world.py b/examples/hello_world.py deleted file mode 100644 index 5764e979..00000000 --- a/examples/hello_world.py +++ /dev/null @@ -1,16 +0,0 @@ -"""This example demonstrates a basic API usage""" - -from pyrogram import Client - -# Create a new Client instance -app = Client("my_account") - -with app: - # Send a message, Markdown is enabled by default - app.send_message("me", "Hi there! I'm using **Pyrogram**") - - # Send a location - app.send_location("me", 51.500729, -0.124583) - - # Send a sticker - app.send_sticker("me", "CAADBAADzg4AAvLQYAEz_x2EOgdRwBYE") diff --git a/examples/inline_queries.py b/examples/inline_queries.py deleted file mode 100644 index d86d90d5..00000000 --- a/examples/inline_queries.py +++ /dev/null @@ -1,54 +0,0 @@ -"""This example shows how to handle inline queries. -Two results are generated when users invoke the bot inline mode, e.g.: @pyrogrambot hi. -It uses the @on_inline_query decorator to register an InlineQueryHandler. -""" - -from uuid import uuid4 - -from pyrogram import ( - Client, InlineQueryResultArticle, InputTextMessageContent, InlineKeyboardMarkup, InlineKeyboardButton -) - -app = Client("my_bot", bot_token="123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11") - - -@app.on_inline_query() -def answer(client, inline_query): - inline_query.answer( - results=[ - InlineQueryResultArticle( - id=uuid4(), - title="Installation", - input_message_content=InputTextMessageContent( - "Here's how to install **Pyrogram**" - ), - url="https://docs.pyrogram.org/intro/install", - description="How to install Pyrogram", - thumb_url="https://i.imgur.com/JyxrStE.png", - reply_markup=InlineKeyboardMarkup( - [ - [InlineKeyboardButton("Open website", url="https://docs.pyrogram.org/intro/install")] - ] - ) - ), - InlineQueryResultArticle( - id=uuid4(), - title="Usage", - input_message_content=InputTextMessageContent( - "Here's how to use **Pyrogram**" - ), - url="https://docs.pyrogram.org/start/invoking", - description="How to use Pyrogram", - thumb_url="https://i.imgur.com/JyxrStE.png", - reply_markup=InlineKeyboardMarkup( - [ - [InlineKeyboardButton("Open website", url="https://docs.pyrogram.org/start/invoking")] - ] - ) - ) - ], - cache_time=1 - ) - - -app.run() # Automatically start() and idle() diff --git a/examples/raw_updates.py b/examples/raw_updates.py deleted file mode 100644 index 27d87eb3..00000000 --- a/examples/raw_updates.py +++ /dev/null @@ -1,13 +0,0 @@ -"""This example shows how to handle raw updates""" - -from pyrogram import Client - -app = Client("my_account") - - -@app.on_raw_update() -def raw(client, update, users, chats): - print(update) - - -app.run() # Automatically start() and idle() diff --git a/examples/use_inline_bots.py b/examples/use_inline_bots.py deleted file mode 100644 index 5681df87..00000000 --- a/examples/use_inline_bots.py +++ /dev/null @@ -1,13 +0,0 @@ -"""This example shows how to query an inline bot (as user)""" - -from pyrogram import Client - -# Create a new Client -app = Client("my_account") - -with app: - # Get bot results for "Fuzz Universe" from the inline bot @vid - bot_results = app.get_inline_bot_results("vid", "Fuzz Universe") - - # Send the first result (bot_results.results[0]) to your own chat (Saved Messages) - app.send_inline_bot_result("me", bot_results.query_id, bot_results.results[0].id) diff --git a/examples/welcomebot.py b/examples/welcomebot.py deleted file mode 100644 index 35f72aff..00000000 --- a/examples/welcomebot.py +++ /dev/null @@ -1,29 +0,0 @@ -"""This is the Welcome Bot in @PyrogramChat. - -It uses the Emoji module to easily add emojis in your text messages and Filters -to make it only work for specific messages in a specific chat. -""" - -from pyrogram import Client, Emoji, Filters - -TARGET = "PyrogramChat" # Target chat. Can also be a list of multiple chat ids/usernames -MENTION = "[{}](tg://user?id={})" # User mention markup -MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.org/)'s group chat {}!" # Welcome message - -app = Client("my_account") - - -# Filter in only new_chat_members updates generated in TARGET chat -@app.on_message(Filters.chat(TARGET) & Filters.new_chat_members) -def welcome(client, message): - # Build the new members list (with mentions) by using their first_name - new_members = [MENTION.format(i.first_name, i.id) for i in message.new_chat_members] - - # Build the welcome message by using an emoji and the list we built above - text = MESSAGE.format(Emoji.SPARKLES, ", ".join(new_members)) - - # Send the welcome message, without the web page preview - message.reply(text, disable_web_page_preview=True) - - -app.run() # Automatically start() and idle() diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 053d3398..65ac3d71 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -16,10 +16,23 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -__version__ = "0.18.0-async" +__version__ = "1.0.0b1" __license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)" __copyright__ = "Copyright (C) 2017-2020 Dan " -from .client import * -from .client.handlers import * -from .client.types import * + +class StopTransmission(StopAsyncIteration): + pass + + +class StopPropagation(StopAsyncIteration): + pass + + +class ContinuePropagation(StopAsyncIteration): + pass + + +from . import types, filters, handlers, emoji +from .client import Client +from .sync import idle diff --git a/pyrogram/client.py b/pyrogram/client.py new file mode 100644 index 00000000..a293efd5 --- /dev/null +++ b/pyrogram/client.py @@ -0,0 +1,1069 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import asyncio +import functools +import logging +import os +import re +import shutil +import tempfile +from concurrent.futures.thread import ThreadPoolExecutor +from configparser import ConfigParser +from hashlib import sha256 +from importlib import import_module +from pathlib import Path +from typing import Union, List + +import pyrogram +from pyrogram import raw +from pyrogram import utils +from pyrogram.crypto import aes +from pyrogram.errors import ( + SessionPasswordNeeded, + VolumeLocNotFound, ChannelPrivate, + AuthBytesInvalid, BadRequest +) +from pyrogram.handlers.handler import Handler +from pyrogram.methods import Methods +from pyrogram.session import Auth, Session +from pyrogram.storage import Storage, FileStorage, MemoryStorage +from pyrogram.types import User, TermsOfService +from pyrogram.utils import ainput +from .dispatcher import Dispatcher +from .scaffold import Scaffold + +log = logging.getLogger(__name__) + + +class Client(Methods, Scaffold): + """Pyrogram Client, the main means for interacting with Telegram. + + Parameters: + session_name (``str``): + Pass a string of your choice to give a name to the client session, e.g.: "*my_account*". This name will be + used to save a file on disk that stores details needed to reconnect without asking again for credentials. + Alternatively, if you don't want a file to be saved on disk, pass the special name "**:memory:**" to start + an in-memory session that will be discarded as soon as you stop the Client. In order to reconnect again + using a memory storage without having to login again, you can use + :meth:`~pyrogram.Client.export_session_string` before stopping the client to get a session string you can + pass here as argument. + + api_id (``int`` | ``str``, *optional*): + The *api_id* part of your Telegram API Key, as integer. E.g.: "12345". + This is an alternative way to pass it if you don't want to use the *config.ini* file. + + api_hash (``str``, *optional*): + The *api_hash* part of your Telegram API Key, as string. E.g.: "0123456789abcdef0123456789abcdef". + This is an alternative way to set it if you don't want to use the *config.ini* file. + + app_version (``str``, *optional*): + Application version. Defaults to "Pyrogram |version|". + This is an alternative way to set it if you don't want to use the *config.ini* file. + + device_model (``str``, *optional*): + Device model. Defaults to *platform.python_implementation() + " " + platform.python_version()*. + This is an alternative way to set it if you don't want to use the *config.ini* file. + + system_version (``str``, *optional*): + Operating System version. Defaults to *platform.system() + " " + platform.release()*. + This is an alternative way to set it if you don't want to use the *config.ini* file. + + lang_code (``str``, *optional*): + Code of the language used on the client, in ISO 639-1 standard. Defaults to "en". + This is an alternative way to set it if you don't want to use the *config.ini* file. + + ipv6 (``bool``, *optional*): + Pass True to connect to Telegram using IPv6. + Defaults to False (IPv4). + + proxy (``dict``, *optional*): + Your SOCKS5 Proxy settings as dict, + e.g.: *dict(hostname="11.22.33.44", port=1080, username="user", password="pass")*. + The *username* and *password* can be omitted if your proxy doesn't require authorization. + This is an alternative way to setup a proxy if you don't want to use the *config.ini* file. + + test_mode (``bool``, *optional*): + Enable or disable login to the test servers. + Only applicable for new sessions and will be ignored in case previously created sessions are loaded. + Defaults to False. + + bot_token (``str``, *optional*): + Pass your Bot API token to create a bot session, e.g.: "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" + Only applicable for new sessions. + This is an alternative way to set it if you don't want to use the *config.ini* file. + + phone_number (``str``, *optional*): + Pass your phone number as string (with your Country Code prefix included) to avoid entering it manually. + Only applicable for new sessions. + + phone_code (``str``, *optional*): + Pass the phone code as string (for test numbers only) to avoid entering it manually. + Only applicable for new sessions. + + password (``str``, *optional*): + Pass your Two-Step Verification password as string (if you have one) to avoid entering it manually. + Only applicable for new sessions. + + force_sms (``bool``, *optional*): + Pass True to force Telegram sending the authorization code via SMS. + Only applicable for new sessions. + Defaults to False. + + workers (``int``, *optional*): + Number of maximum concurrent workers for handling incoming updates. + Defaults to ``min(32, os.cpu_count() + 4)``. + + workdir (``str``, *optional*): + Define a custom working directory. The working directory is the location in your filesystem where Pyrogram + will store your session files. + Defaults to the parent directory of the main script. + + config_file (``str``, *optional*): + Path of the configuration file. + Defaults to ./config.ini + + plugins (``dict``, *optional*): + Your Smart Plugins settings as dict, e.g.: *dict(root="plugins")*. + This is an alternative way to setup plugins if you don't want to use the *config.ini* file. + + parse_mode (``str``, *optional*): + The parse mode, can be any of: *"combined"*, for the default combined mode. *"markdown"* or *"md"* + to force Markdown-only styles. *"html"* to force HTML-only styles. *None* to disable the parser + completely. + + no_updates (``bool``, *optional*): + Pass True to completely disable incoming updates for the current session. + When updates are disabled your client can't receive any new message. + Useful for batch programs that don't need to deal with updates. + Defaults to False (updates enabled and always received). + + takeout (``bool``, *optional*): + Pass True to let the client use a takeout session instead of a normal one, implies *no_updates=True*. + Useful for exporting your Telegram data. Methods invoked inside a takeout session (such as get_history, + download_media, ...) are less prone to throw FloodWait exceptions. + Only available for users, bots will ignore this parameter. + Defaults to False (normal session). + + sleep_threshold (``int``, *optional*): + Set a sleep threshold for flood wait exceptions happening globally in this client instance, below which any + request that raises a flood wait will be automatically invoked again after sleeping for the required amount + of time. Flood wait exceptions requiring higher waiting times will be raised. + Defaults to 60 (seconds). + """ + + def __init__( + self, + session_name: Union[str, Storage], + api_id: Union[int, str] = None, + api_hash: str = None, + app_version: str = None, + device_model: str = None, + system_version: str = None, + lang_code: str = None, + ipv6: bool = False, + proxy: dict = None, + test_mode: bool = False, + bot_token: str = None, + phone_number: str = None, + phone_code: str = None, + password: str = None, + force_sms: bool = False, + workers: int = Scaffold.WORKERS, + workdir: str = Scaffold.WORKDIR, + config_file: str = Scaffold.CONFIG_FILE, + plugins: dict = None, + parse_mode: str = Scaffold.PARSE_MODES[0], + no_updates: bool = None, + takeout: bool = None, + sleep_threshold: int = Session.SLEEP_THRESHOLD + ): + super().__init__() + + self.session_name = session_name + self.api_id = int(api_id) if api_id else None + self.api_hash = api_hash + self.app_version = app_version + self.device_model = device_model + self.system_version = system_version + self.lang_code = lang_code + self.ipv6 = ipv6 + # TODO: Make code consistent, use underscore for private/protected fields + self._proxy = proxy + self.test_mode = test_mode + self.bot_token = bot_token + self.phone_number = phone_number + self.phone_code = phone_code + self.password = password + self.force_sms = force_sms + self.workers = workers + self.workdir = Path(workdir) + self.config_file = Path(config_file) + self.plugins = plugins + self.parse_mode = parse_mode + self.no_updates = no_updates + self.takeout = takeout + self.sleep_threshold = sleep_threshold + + self.executor = ThreadPoolExecutor(self.workers, thread_name_prefix="Handler") + + if isinstance(session_name, str): + if session_name == ":memory:" or len(session_name) >= MemoryStorage.SESSION_STRING_SIZE: + session_name = re.sub(r"[\n\s]+", "", session_name) + self.storage = MemoryStorage(session_name) + else: + self.storage = FileStorage(session_name, self.workdir) + elif isinstance(session_name, Storage): + self.storage = session_name + else: + raise ValueError("Unknown storage engine") + + self.dispatcher = Dispatcher(self) + self.loop = asyncio.get_event_loop() + + def __enter__(self): + return self.start() + + def __exit__(self, *args): + try: + self.stop() + except ConnectionError: + pass + + async def __aenter__(self): + return await self.start() + + async def __aexit__(self, *args): + await self.stop() + + @property + def proxy(self): + return self._proxy + + @proxy.setter + def proxy(self, value): + if value is None: + self._proxy = None + return + + if self._proxy is None: + self._proxy = {} + + self._proxy["enabled"] = bool(value.get("enabled", True)) + self._proxy.update(value) + + async def authorize(self) -> User: + if self.bot_token: + return await self.sign_in_bot(self.bot_token) + + while True: + try: + if not self.phone_number: + while True: + value = await ainput("Enter phone number or bot token: ") + + if not value: + continue + + confirm = (await ainput(f'Is "{value}" correct? (y/N): ')).lower() + + if confirm == "y": + break + + if ":" in value: + self.bot_token = value + return await self.sign_in_bot(value) + else: + self.phone_number = value + + sent_code = await self.send_code(self.phone_number) + except BadRequest as e: + print(e.MESSAGE) + self.phone_number = None + self.bot_token = None + else: + break + + if self.force_sms: + sent_code = await self.resend_code(self.phone_number, sent_code.phone_code_hash) + + print("The confirmation code has been sent via {}".format( + { + "app": "Telegram app", + "sms": "SMS", + "call": "phone call", + "flash_call": "phone flash call" + }[sent_code.type] + )) + + while True: + if not self.phone_code: + self.phone_code = await ainput("Enter confirmation code: ") + + try: + signed_in = await self.sign_in(self.phone_number, sent_code.phone_code_hash, self.phone_code) + except BadRequest as e: + print(e.MESSAGE) + self.phone_code = None + except SessionPasswordNeeded as e: + print(e.MESSAGE) + + while True: + print("Password hint: {}".format(await self.get_password_hint())) + + if not self.password: + self.password = await ainput("Enter password (empty to recover): ", hide=True) + + try: + if not self.password: + confirm = await ainput("Confirm password recovery (y/n): ") + + if confirm == "y": + email_pattern = await self.send_recovery_code() + print(f"The recovery code has been sent to {email_pattern}") + + while True: + recovery_code = await ainput("Enter recovery code: ") + + try: + return await self.recover_password(recovery_code) + except BadRequest as e: + print(e.MESSAGE) + except Exception as e: + log.error(e, exc_info=True) + raise + else: + self.password = None + else: + return await self.check_password(self.password) + except BadRequest as e: + print(e.MESSAGE) + self.password = None + else: + break + + if isinstance(signed_in, User): + return signed_in + + while True: + first_name = await ainput("Enter first name: ") + last_name = await ainput("Enter last name (empty to skip): ") + + try: + signed_up = await self.sign_up( + self.phone_number, + sent_code.phone_code_hash, + first_name, + last_name + ) + except BadRequest as e: + print(e.MESSAGE) + else: + break + + if isinstance(signed_in, TermsOfService): + print("\n" + signed_in.text + "\n") + await self.accept_terms_of_service(signed_in.id) + + return signed_up + + @property + def parse_mode(self): + return self._parse_mode + + @parse_mode.setter + def parse_mode(self, parse_mode: Union[str, None] = "combined"): + if parse_mode not in self.PARSE_MODES: + raise ValueError('parse_mode must be one of {} or None. Not "{}"'.format( + ", ".join(f'"{m}"' for m in self.PARSE_MODES[:-1]), + parse_mode + )) + + self._parse_mode = parse_mode + + # TODO: redundant, remove in next major version + def set_parse_mode(self, parse_mode: Union[str, None] = "combined"): + """Set the parse mode to be used globally by the client. + + When setting the parse mode with this method, all other methods having a *parse_mode* parameter will follow the + global value by default. The default value *"combined"* enables both Markdown and HTML styles to be used and + combined together. + + Parameters: + parse_mode (``str``): + The new parse mode, can be any of: *"combined"*, for the default combined mode. *"markdown"* or *"md"* + to force Markdown-only styles. *"html"* to force HTML-only styles. *None* to disable the parser + completely. + + Raises: + ValueError: In case the provided *parse_mode* is not a valid parse mode. + + Example: + .. code-block:: python + :emphasize-lines: 10,14,18,22 + + from pyrogram import Client + + app = Client("my_account") + + with app: + # Default combined mode: Markdown + HTML + app.send_message("haskell", "1. **markdown** and html") + + # Force Markdown-only, HTML is disabled + app.set_parse_mode("markdown") + app.send_message("haskell", "2. **markdown** and html") + + # Force HTML-only, Markdown is disabled + app.set_parse_mode("html") + app.send_message("haskell", "3. **markdown** and html") + + # Disable the parser completely + app.set_parse_mode(None) + app.send_message("haskell", "4. **markdown** and html") + + # Bring back the default combined mode + app.set_parse_mode() + app.send_message("haskell", "5. **markdown** and html") + """ + + self.parse_mode = parse_mode + + async def fetch_peers(self, peers: List[Union[raw.types.User, raw.types.Chat, raw.types.Channel]]) -> bool: + is_min = False + parsed_peers = [] + + for peer in peers: + if getattr(peer, "min", False): + is_min = True + continue + + username = None + phone_number = None + + if isinstance(peer, raw.types.User): + peer_id = peer.id + access_hash = peer.access_hash + username = (peer.username or "").lower() or None + phone_number = peer.phone + peer_type = "bot" if peer.bot else "user" + elif isinstance(peer, (raw.types.Chat, raw.types.ChatForbidden)): + peer_id = -peer.id + access_hash = 0 + peer_type = "group" + elif isinstance(peer, (raw.types.Channel, raw.types.ChannelForbidden)): + peer_id = utils.get_channel_id(peer.id) + access_hash = peer.access_hash + username = (getattr(peer, "username", None) or "").lower() or None + peer_type = "channel" if peer.broadcast else "supergroup" + else: + continue + + parsed_peers.append((peer_id, access_hash, peer_type, username, phone_number)) + + await self.storage.update_peers(parsed_peers) + + return is_min + + async def handle_download(self, packet): + temp_file_path = "" + final_file_path = "" + + try: + data, directory, file_name, progress, progress_args = packet + + temp_file_path = await self.get_file( + media_type=data.media_type, + dc_id=data.dc_id, + document_id=data.document_id, + access_hash=data.access_hash, + thumb_size=data.thumb_size, + peer_id=data.peer_id, + peer_type=data.peer_type, + peer_access_hash=data.peer_access_hash, + volume_id=data.volume_id, + local_id=data.local_id, + file_ref=data.file_ref, + file_size=data.file_size, + is_big=data.is_big, + progress=progress, + progress_args=progress_args + ) + + if temp_file_path: + final_file_path = os.path.abspath(re.sub("\\\\", "/", os.path.join(directory, file_name))) + os.makedirs(directory, exist_ok=True) + shutil.move(temp_file_path, final_file_path) + except Exception as e: + log.error(e, exc_info=True) + + try: + os.remove(temp_file_path) + except OSError: + pass + else: + return final_file_path or None + + async def handle_updates(self, updates): + if isinstance(updates, (raw.types.Updates, raw.types.UpdatesCombined)): + is_min = (await self.fetch_peers(updates.users)) or (await self.fetch_peers(updates.chats)) + + users = {u.id: u for u in updates.users} + chats = {c.id: c for c in updates.chats} + + for update in updates.updates: + channel_id = getattr( + getattr( + getattr( + update, "message", None + ), "to_id", None + ), "channel_id", None + ) or getattr(update, "channel_id", None) + + pts = getattr(update, "pts", None) + pts_count = getattr(update, "pts_count", None) + + if isinstance(update, raw.types.UpdateChannelTooLong): + log.warning(update) + + if isinstance(update, raw.types.UpdateNewChannelMessage) and is_min: + message = update.message + + if not isinstance(message, raw.types.MessageEmpty): + try: + diff = await self.send( + raw.functions.updates.GetChannelDifference( + channel=await self.resolve_peer(utils.get_channel_id(channel_id)), + filter=raw.types.ChannelMessagesFilter( + ranges=[raw.types.MessageRange( + min_id=update.message.id, + max_id=update.message.id + )] + ), + pts=pts - pts_count, + limit=pts + ) + ) + except ChannelPrivate: + pass + else: + if not isinstance(diff, raw.types.updates.ChannelDifferenceEmpty): + users.update({u.id: u for u in diff.users}) + chats.update({c.id: c for c in diff.chats}) + + self.dispatcher.updates_queue.put_nowait((update, users, chats)) + elif isinstance(updates, (raw.types.UpdateShortMessage, raw.types.UpdateShortChatMessage)): + diff = await self.send( + raw.functions.updates.GetDifference( + pts=updates.pts - updates.pts_count, + date=updates.date, + qts=-1 + ) + ) + + if diff.new_messages: + self.dispatcher.updates_queue.put_nowait(( + raw.types.UpdateNewMessage( + message=diff.new_messages[0], + pts=updates.pts, + pts_count=updates.pts_count + ), + {u.id: u for u in diff.users}, + {c.id: c for c in diff.chats} + )) + else: + self.dispatcher.updates_queue.put_nowait((diff.other_updates[0], {}, {})) + elif isinstance(updates, raw.types.UpdateShort): + self.dispatcher.updates_queue.put_nowait((updates.update, {}, {})) + elif isinstance(updates, raw.types.UpdatesTooLong): + log.info(updates) + + def load_config(self): + parser = ConfigParser() + parser.read(str(self.config_file)) + + if self.bot_token: + pass + else: + self.bot_token = parser.get("pyrogram", "bot_token", fallback=None) + + if self.api_id and self.api_hash: + pass + else: + if parser.has_section("pyrogram"): + self.api_id = parser.getint("pyrogram", "api_id") + self.api_hash = parser.get("pyrogram", "api_hash") + else: + raise AttributeError("No API Key found. More info: https://docs.pyrogram.org/intro/setup") + + for option in ["app_version", "device_model", "system_version", "lang_code"]: + if getattr(self, option): + pass + else: + if parser.has_section("pyrogram"): + setattr(self, option, parser.get( + "pyrogram", + option, + fallback=getattr(Client, option.upper()) + )) + else: + setattr(self, option, getattr(Client, option.upper())) + + if self._proxy: + self._proxy["enabled"] = bool(self._proxy.get("enabled", True)) + else: + self._proxy = {} + + if parser.has_section("proxy"): + self._proxy["enabled"] = parser.getboolean("proxy", "enabled", fallback=True) + self._proxy["hostname"] = parser.get("proxy", "hostname") + self._proxy["port"] = parser.getint("proxy", "port") + self._proxy["username"] = parser.get("proxy", "username", fallback=None) or None + self._proxy["password"] = parser.get("proxy", "password", fallback=None) or None + + if self.plugins: + self.plugins = { + "enabled": bool(self.plugins.get("enabled", True)), + "root": self.plugins.get("root", None), + "include": self.plugins.get("include", []), + "exclude": self.plugins.get("exclude", []) + } + else: + try: + section = parser["plugins"] + + self.plugins = { + "enabled": section.getboolean("enabled", True), + "root": section.get("root", None), + "include": section.get("include", []), + "exclude": section.get("exclude", []) + } + + include = self.plugins["include"] + exclude = self.plugins["exclude"] + + if include: + self.plugins["include"] = include.strip().split("\n") + + if exclude: + self.plugins["exclude"] = exclude.strip().split("\n") + + except KeyError: + self.plugins = None + + async def load_session(self): + await self.storage.open() + + session_empty = any([ + await self.storage.test_mode() is None, + await self.storage.auth_key() is None, + await self.storage.user_id() is None, + await self.storage.is_bot() is None + ]) + + if session_empty: + await self.storage.dc_id(2) + await self.storage.date(0) + + await self.storage.test_mode(self.test_mode) + await self.storage.auth_key( + await Auth( + self, await self.storage.dc_id(), + await self.storage.test_mode() + ).create() + ) + await self.storage.user_id(None) + await self.storage.is_bot(None) + + def load_plugins(self): + if self.plugins: + plugins = self.plugins.copy() + + for option in ["include", "exclude"]: + if plugins[option]: + plugins[option] = [ + (i.split()[0], i.split()[1:] or None) + for i in self.plugins[option] + ] + else: + return + + if plugins.get("enabled", False): + root = plugins["root"] + include = plugins["include"] + exclude = plugins["exclude"] + + count = 0 + + if not include: + for path in sorted(Path(root.replace(".", "/")).rglob("*.py")): + module_path = '.'.join(path.parent.parts + (path.stem,)) + module = import_module(module_path) + + for name in vars(module).keys(): + # noinspection PyBroadException + try: + handler, group = getattr(module, name).handler + + if isinstance(handler, Handler) and isinstance(group, int): + self.add_handler(handler, group) + + log.info('[{}] [LOAD] {}("{}") in group {} from "{}"'.format( + self.session_name, type(handler).__name__, name, group, module_path)) + + count += 1 + except Exception: + pass + else: + for path, handlers in include: + module_path = root + "." + path + warn_non_existent_functions = True + + try: + module = import_module(module_path) + except ImportError: + log.warning(f'[{self.session_name}] [LOAD] Ignoring non-existent module "{module_path}"') + continue + + if "__path__" in dir(module): + log.warning(f'[{self.session_name}] [LOAD] Ignoring namespace "{module_path}"') + continue + + if handlers is None: + handlers = vars(module).keys() + warn_non_existent_functions = False + + for name in handlers: + # noinspection PyBroadException + try: + handler, group = getattr(module, name).handler + + if isinstance(handler, Handler) and isinstance(group, int): + self.add_handler(handler, group) + + log.info('[{}] [LOAD] {}("{}") in group {} from "{}"'.format( + self.session_name, type(handler).__name__, name, group, module_path)) + + count += 1 + except Exception: + if warn_non_existent_functions: + log.warning('[{}] [LOAD] Ignoring non-existent function "{}" from "{}"'.format( + self.session_name, name, module_path)) + + if exclude: + for path, handlers in exclude: + module_path = root + "." + path + warn_non_existent_functions = True + + try: + module = import_module(module_path) + except ImportError: + log.warning(f'[{self.session_name}] [UNLOAD] Ignoring non-existent module "{module_path}"') + continue + + if "__path__" in dir(module): + log.warning(f'[{self.session_name}] [UNLOAD] Ignoring namespace "{module_path}"') + continue + + if handlers is None: + handlers = vars(module).keys() + warn_non_existent_functions = False + + for name in handlers: + # noinspection PyBroadException + try: + handler, group = getattr(module, name).handler + + if isinstance(handler, Handler) and isinstance(group, int): + self.remove_handler(handler, group) + + log.info('[{}] [UNLOAD] {}("{}") from group {} in "{}"'.format( + self.session_name, type(handler).__name__, name, group, module_path)) + + count -= 1 + except Exception: + if warn_non_existent_functions: + log.warning('[{}] [UNLOAD] Ignoring non-existent function "{}" from "{}"'.format( + self.session_name, name, module_path)) + + if count > 0: + log.info('[{}] Successfully loaded {} plugin{} from "{}"'.format( + self.session_name, count, "s" if count > 1 else "", root)) + else: + log.warning(f'[{self.session_name}] No plugin loaded from "{root}"') + + async def get_file( + self, + media_type: int, + dc_id: int, + document_id: int, + access_hash: int, + thumb_size: str, + peer_id: int, + peer_type: str, + peer_access_hash: int, + volume_id: int, + local_id: int, + file_ref: str, + file_size: int, + is_big: bool, + progress: callable, + progress_args: tuple = () + ) -> str: + async with self.media_sessions_lock: + session = self.media_sessions.get(dc_id, None) + + if session is None: + if dc_id != await self.storage.dc_id(): + session = Session( + self, dc_id, await Auth(self, dc_id, await self.storage.test_mode()).create(), + await self.storage.test_mode(), is_media=True + ) + await session.start() + + for _ in range(3): + exported_auth = await self.send( + raw.functions.auth.ExportAuthorization( + dc_id=dc_id + ) + ) + + try: + await session.send( + raw.functions.auth.ImportAuthorization( + id=exported_auth.id, + bytes=exported_auth.bytes + ) + ) + except AuthBytesInvalid: + continue + else: + break + else: + await session.stop() + raise AuthBytesInvalid + else: + session = Session( + self, dc_id, await self.storage.auth_key(), + await self.storage.test_mode(), is_media=True + ) + await session.start() + + self.media_sessions[dc_id] = session + + file_ref = utils.decode_file_ref(file_ref) + + if media_type == 1: + if peer_type == "user": + peer = raw.types.InputPeerUser( + user_id=peer_id, + access_hash=peer_access_hash + ) + elif peer_type == "chat": + peer = raw.types.InputPeerChat( + chat_id=peer_id + ) + else: + peer = raw.types.InputPeerChannel( + channel_id=peer_id, + access_hash=peer_access_hash + ) + + location = raw.types.InputPeerPhotoFileLocation( + peer=peer, + volume_id=volume_id, + local_id=local_id, + big=is_big or None + ) + elif media_type in (0, 2): + location = raw.types.InputPhotoFileLocation( + id=document_id, + access_hash=access_hash, + file_reference=file_ref, + thumb_size=thumb_size + ) + elif media_type == 14: + location = raw.types.InputDocumentFileLocation( + id=document_id, + access_hash=access_hash, + file_reference=file_ref, + thumb_size=thumb_size + ) + else: + location = raw.types.InputDocumentFileLocation( + id=document_id, + access_hash=access_hash, + file_reference=file_ref, + thumb_size="" + ) + + limit = 1024 * 1024 + offset = 0 + file_name = "" + + try: + r = await session.send( + raw.functions.upload.GetFile( + location=location, + offset=offset, + limit=limit + ) + ) + + if isinstance(r, raw.types.upload.File): + with tempfile.NamedTemporaryFile("wb", delete=False) as f: + file_name = f.name + + while True: + chunk = r.bytes + + if not chunk: + break + + f.write(chunk) + + offset += limit + + if progress: + await progress( + min(offset, file_size) + if file_size != 0 + else offset, + file_size, + *progress_args + ) + + r = await session.send( + raw.functions.upload.GetFile( + location=location, + offset=offset, + limit=limit + ) + ) + + elif isinstance(r, raw.types.upload.FileCdnRedirect): + async with self.media_sessions_lock: + cdn_session = self.media_sessions.get(r.dc_id, None) + + if cdn_session is None: + cdn_session = Session( + self, r.dc_id, await Auth(self, r.dc_id, await self.storage.test_mode()).create(), + await self.storage.test_mode(), is_media=True, is_cdn=True + ) + + await cdn_session.start() + + self.media_sessions[r.dc_id] = cdn_session + + try: + with tempfile.NamedTemporaryFile("wb", delete=False) as f: + file_name = f.name + + while True: + r2 = await cdn_session.send( + raw.functions.upload.GetCdnFile( + file_token=r.file_token, + offset=offset, + limit=limit + ) + ) + + if isinstance(r2, raw.types.upload.CdnFileReuploadNeeded): + try: + await session.send( + raw.functions.upload.ReuploadCdnFile( + file_token=r.file_token, + request_token=r2.request_token + ) + ) + except VolumeLocNotFound: + break + else: + continue + + chunk = r2.bytes + + # https://core.telegram.org/cdn#decrypting-files + decrypted_chunk = aes.ctr256_decrypt( + chunk, + r.encryption_key, + bytearray( + r.encryption_iv[:-4] + + (offset // 16).to_bytes(4, "big") + ) + ) + + hashes = await session.send( + raw.functions.upload.GetCdnFileHashes( + file_token=r.file_token, + offset=offset + ) + ) + + # https://core.telegram.org/cdn#verifying-files + for i, h in enumerate(hashes): + cdn_chunk = decrypted_chunk[h.limit * i: h.limit * (i + 1)] + assert h.hash == sha256(cdn_chunk).digest(), f"Invalid CDN hash part {i}" + + f.write(decrypted_chunk) + + offset += limit + + if progress: + if asyncio.iscoroutinefunction(progress): + await progress( + min(offset, file_size) if file_size != 0 else offset, + file_size, + *progress_args + ) + else: + func = functools.partial( + progress, + min(offset, file_size) if file_size != 0 else offset, + file_size, + *progress_args + ) + + await self.loop.run_in_executor(self.executor, func) + + if len(chunk) < limit: + break + except Exception as e: + raise e + except Exception as e: + if not isinstance(e, pyrogram.StopTransmission): + log.error(e, exc_info=True) + + try: + os.remove(file_name) + except OSError: + pass + + return "" + else: + return file_name + + def guess_mime_type(self, filename: str): + extension = os.path.splitext(filename)[1] + return self.extensions_to_mime_types.get(extension) + + def guess_extension(self, mime_type: str): + extensions = self.mime_types_to_extensions.get(mime_type) + + if extensions: + return extensions.split(" ")[0] diff --git a/pyrogram/client/__init__.py b/pyrogram/client/__init__.py deleted file mode 100644 index d0b82f91..00000000 --- a/pyrogram/client/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2020 Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -from .client import Client -from .ext import BaseClient, Emoji -from .filters import Filters - -__all__ = [ - "Client", "BaseClient", "Emoji", "Filters", -] diff --git a/pyrogram/client/client.py b/pyrogram/client/client.py deleted file mode 100644 index 624c98c6..00000000 --- a/pyrogram/client/client.py +++ /dev/null @@ -1,2151 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2020 Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -import asyncio -import io -import logging -import math -import os -import re -import shutil -import tempfile -from configparser import ConfigParser -from hashlib import sha256, md5 -from importlib import import_module -from pathlib import Path, Pureapath -from signal import signal, SIGINT, SIGTERM, SIGABRT -from typing import Union, List, BinaryIO - -from pyrogram.api import functions, types -from pyrogram.api.core import TLObject -from pyrogram.client.handlers import DisconnectHandler -from pyrogram.client.handlers.handler import Handler -from pyrogram.client.methods.password.utils import compute_check -from pyrogram.crypto import AES -from pyrogram.errors import ( - PhoneMigrate, NetworkMigrate, SessionPasswordNeeded, - PeerIdInvalid, VolumeLocNotFound, UserMigrate, ChannelPrivate, - AuthBytesInvalid, BadRequest -) -from pyrogram.session import Auth, Session -from .ext import utils, Syncer, BaseClient, Dispatcher -from .ext.utils import ainput -from .methods import Methods -from .storage import Storage, FileStorage, MemoryStorage -from .types import User, SentCode, TermsOfService - -log = logging.getLogger(__name__) - - -class Client(Methods, BaseClient): - """Pyrogram Client, the main means for interacting with Telegram. - - Parameters: - session_name (``str``): - Pass a string of your choice to give a name to the client session, e.g.: "*my_account*". This name will be - used to save a file on disk that stores details needed to reconnect without asking again for credentials. - Alternatively, if you don't want a file to be saved on disk, pass the special name "**:memory:**" to start - an in-memory session that will be discarded as soon as you stop the Client. In order to reconnect again - using a memory storage without having to login again, you can use - :meth:`~pyrogram.Client.export_session_string` before stopping the client to get a session string you can - pass here as argument. - - api_id (``int`` | ``str``, *optional*): - The *api_id* part of your Telegram API Key, as integer. E.g.: "12345". - This is an alternative way to pass it if you don't want to use the *config.ini* file. - - api_hash (``str``, *optional*): - The *api_hash* part of your Telegram API Key, as string. E.g.: "0123456789abcdef0123456789abcdef". - This is an alternative way to set it if you don't want to use the *config.ini* file. - - app_version (``str``, *optional*): - Application version. Defaults to "Pyrogram |version|". - This is an alternative way to set it if you don't want to use the *config.ini* file. - - device_model (``str``, *optional*): - Device model. Defaults to *platform.python_implementation() + " " + platform.python_version()*. - This is an alternative way to set it if you don't want to use the *config.ini* file. - - system_version (``str``, *optional*): - Operating System version. Defaults to *platform.system() + " " + platform.release()*. - This is an alternative way to set it if you don't want to use the *config.ini* file. - - lang_code (``str``, *optional*): - Code of the language used on the client, in ISO 639-1 standard. Defaults to "en". - This is an alternative way to set it if you don't want to use the *config.ini* file. - - ipv6 (``bool``, *optional*): - Pass True to connect to Telegram using IPv6. - Defaults to False (IPv4). - - proxy (``dict``, *optional*): - Your SOCKS5 Proxy settings as dict, - e.g.: *dict(hostname="11.22.33.44", port=1080, username="user", password="pass")*. - The *username* and *password* can be omitted if your proxy doesn't require authorization. - This is an alternative way to setup a proxy if you don't want to use the *config.ini* file. - - test_mode (``bool``, *optional*): - Enable or disable login to the test servers. - Only applicable for new sessions and will be ignored in case previously created sessions are loaded. - Defaults to False. - - bot_token (``str``, *optional*): - Pass your Bot API token to create a bot session, e.g.: "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" - Only applicable for new sessions. - This is an alternative way to set it if you don't want to use the *config.ini* file. - - phone_number (``str``, *optional*): - Pass your phone number as string (with your Country Code prefix included) to avoid entering it manually. - Only applicable for new sessions. - - phone_code (``str``, *optional*): - Pass the phone code as string (for test numbers only) to avoid entering it manually. - Only applicable for new sessions. - - password (``str``, *optional*): - Pass your Two-Step Verification password as string (if you have one) to avoid entering it manually. - Only applicable for new sessions. - - force_sms (``bool``, *optional*): - Pass True to force Telegram sending the authorization code via SMS. - Only applicable for new sessions. - Defaults to False. - - workers (``int``, *optional*): - Number of maximum concurrent workers for handling incoming updates. - Defaults to 4. - - workdir (``str``, *optional*): - Define a custom working directory. The working directory is the location in your filesystem where Pyrogram - will store your session files. - Defaults to the parent directory of the main script. - - config_file (``str``, *optional*): - Path of the configuration file. - Defaults to ./config.ini - - plugins (``dict``, *optional*): - Your Smart Plugins settings as dict, e.g.: *dict(root="plugins")*. - This is an alternative way to setup plugins if you don't want to use the *config.ini* file. - - parse_mode (``str``, *optional*): - The parse mode, can be any of: *"combined"*, for the default combined mode. *"markdown"* or *"md"* - to force Markdown-only styles. *"html"* to force HTML-only styles. *None* to disable the parser - completely. - - no_updates (``bool``, *optional*): - Pass True to completely disable incoming updates for the current session. - When updates are disabled your client can't receive any new message. - Useful for batch programs that don't need to deal with updates. - Defaults to False (updates enabled and always received). - - takeout (``bool``, *optional*): - Pass True to let the client use a takeout session instead of a normal one, implies *no_updates=True*. - Useful for exporting your Telegram data. Methods invoked inside a takeout session (such as get_history, - download_media, ...) are less prone to throw FloodWait exceptions. - Only available for users, bots will ignore this parameter. - Defaults to False (normal session). - - sleep_threshold (``int``, *optional*): - Set a sleep threshold for flood wait exceptions happening globally in this client instance, below which any - request that raises a flood wait will be automatically invoked again after sleeping for the required amount - of time. Flood wait exceptions requiring higher waiting times will be raised. - Defaults to 60 (seconds). - """ - - def __init__( - self, - session_name: Union[str, Storage], - api_id: Union[int, str] = None, - api_hash: str = None, - app_version: str = None, - device_model: str = None, - system_version: str = None, - lang_code: str = None, - ipv6: bool = False, - proxy: dict = None, - test_mode: bool = False, - bot_token: str = None, - phone_number: str = None, - phone_code: str = None, - password: str = None, - force_sms: bool = False, - workers: int = BaseClient.WORKERS, - workdir: str = BaseClient.WORKDIR, - config_file: str = BaseClient.CONFIG_FILE, - plugins: dict = None, - parse_mode: str = BaseClient.PARSE_MODES[0], - no_updates: bool = None, - takeout: bool = None, - sleep_threshold: int = Session.SLEEP_THRESHOLD - ): - super().__init__() - - self.session_name = session_name - self.api_id = int(api_id) if api_id else None - self.api_hash = api_hash - self.app_version = app_version - self.device_model = device_model - self.system_version = system_version - self.lang_code = lang_code - self.ipv6 = ipv6 - # TODO: Make code consistent, use underscore for private/protected fields - self._proxy = proxy - self.test_mode = test_mode - self.bot_token = bot_token - self.phone_number = phone_number - self.phone_code = phone_code - self.password = password - self.force_sms = force_sms - self.workers = workers - self.workdir = Path(workdir) - self.config_file = Path(config_file) - self.plugins = plugins - self.parse_mode = parse_mode - self.no_updates = no_updates - self.takeout = takeout - self.sleep_threshold = sleep_threshold - - if isinstance(session_name, str): - if session_name == ":memory:" or len(session_name) >= MemoryStorage.SESSION_STRING_SIZE: - session_name = re.sub(r"[\n\s]+", "", session_name) - self.storage = MemoryStorage(session_name) - else: - self.storage = FileStorage(session_name, self.workdir) - elif isinstance(session_name, Storage): - self.storage = session_name - else: - raise ValueError("Unknown storage engine") - - self.dispatcher = Dispatcher(self, 0 if no_updates else workers) - - def __enter__(self): - return self.start() - - def __exit__(self, *args): - try: - self.stop() - except ConnectionError: - pass - - async def __aenter__(self): - return await self.start() - - async def __aexit__(self, *args): - await self.stop() - - @property - def proxy(self): - return self._proxy - - @proxy.setter - def proxy(self, value): - if value is None: - self._proxy = None - return - - if self._proxy is None: - self._proxy = {} - - self._proxy["enabled"] = bool(value.get("enabled", True)) - self._proxy.update(value) - - async def connect(self) -> bool: - """ - Connect the client to Telegram servers. - - Returns: - ``bool``: On success, in case the passed-in session is authorized, True is returned. Otherwise, in case - the session needs to be authorized, False is returned. - - Raises: - ConnectionError: In case you try to connect an already connected client. - """ - if self.is_connected: - raise ConnectionError("Client is already connected") - - self.load_config() - await self.load_session() - - self.session = Session(self, self.storage.dc_id(), self.storage.auth_key()) - - await self.session.start() - - self.is_connected = True - - return bool(self.storage.user_id()) - - async def disconnect(self): - """Disconnect the client from Telegram servers. - - Raises: - ConnectionError: In case you try to disconnect an already disconnected client or in case you try to - disconnect a client that needs to be terminated first. - """ - if not self.is_connected: - raise ConnectionError("Client is already disconnected") - - if self.is_initialized: - raise ConnectionError("Can't disconnect an initialized client") - - await self.session.stop() - self.storage.close() - self.is_connected = False - - async def initialize(self): - """Initialize the client by starting up workers. - - This method will start updates and download workers. - It will also load plugins and start the internal dispatcher. - - Raises: - ConnectionError: In case you try to initialize a disconnected client or in case you try to initialize an - already initialized client. - """ - if not self.is_connected: - raise ConnectionError("Can't initialize a disconnected client") - - if self.is_initialized: - raise ConnectionError("Client is already initialized") - - self.load_plugins() - - if not self.no_updates: - for _ in range(Client.UPDATES_WORKERS): - self.updates_worker_tasks.append( - asyncio.ensure_future(self.updates_worker()) - ) - - logging.info("Started {} UpdatesWorkerTasks".format(Client.UPDATES_WORKERS)) - - for _ in range(Client.DOWNLOAD_WORKERS): - self.download_worker_tasks.append( - asyncio.ensure_future(self.download_worker()) - ) - - logging.info("Started {} DownloadWorkerTasks".format(Client.DOWNLOAD_WORKERS)) - - await self.dispatcher.start() - await Syncer.add(self) - - self.is_initialized = True - - async def terminate(self): - """Terminate the client by shutting down workers. - - This method does the opposite of :meth:`~Client.initialize`. - It will stop the dispatcher and shut down updates and download workers. - - Raises: - ConnectionError: In case you try to terminate a client that is already terminated. - """ - if not self.is_initialized: - raise ConnectionError("Client is already terminated") - - if self.takeout_id: - await self.send(functions.account.FinishTakeoutSession()) - log.warning("Takeout session {} finished".format(self.takeout_id)) - - await Syncer.remove(self) - await self.dispatcher.stop() - - for _ in range(Client.DOWNLOAD_WORKERS): - self.download_queue.put_nowait(None) - - for task in self.download_worker_tasks: - await task - - self.download_worker_tasks.clear() - - logging.info("Stopped {} DownloadWorkerTasks".format(Client.DOWNLOAD_WORKERS)) - - if not self.no_updates: - for _ in range(Client.UPDATES_WORKERS): - self.updates_queue.put_nowait(None) - - for task in self.updates_worker_tasks: - await task - - self.updates_worker_tasks.clear() - - logging.info("Stopped {} UpdatesWorkerTasks".format(Client.UPDATES_WORKERS)) - - for media_session in self.media_sessions.values(): - await media_session.stop() - - self.media_sessions.clear() - - self.is_initialized = False - - async def send_code(self, phone_number: str) -> SentCode: - """Send the confirmation code to the given phone number. - - Parameters: - phone_number (``str``): - Phone number in international format (includes the country prefix). - - Returns: - :obj:`SentCode`: On success, an object containing information on the sent confirmation code is returned. - - Raises: - BadRequest: In case the phone number is invalid. - """ - phone_number = phone_number.strip(" +") - - while True: - try: - r = await self.send( - functions.auth.SendCode( - phone_number=phone_number, - api_id=self.api_id, - api_hash=self.api_hash, - settings=types.CodeSettings() - ) - ) - except (PhoneMigrate, NetworkMigrate) as e: - await self.session.stop() - - self.storage.dc_id(e.x) - self.storage.auth_key(await Auth(self, self.storage.dc_id()).create()) - self.session = Session(self, self.storage.dc_id(), self.storage.auth_key()) - - await self.session.start() - else: - return SentCode._parse(r) - - async def resend_code(self, phone_number: str, phone_code_hash: str) -> SentCode: - """Re-send the confirmation code using a different type. - - The type of the code to be re-sent is specified in the *next_type* attribute of the :obj:`SentCode` object - returned by :meth:`send_code`. - - Parameters: - phone_number (``str``): - Phone number in international format (includes the country prefix). - - phone_code_hash (``str``): - Confirmation code identifier. - - Returns: - :obj:`SentCode`: On success, an object containing information on the re-sent confirmation code is returned. - - Raises: - BadRequest: In case the arguments are invalid. - """ - phone_number = phone_number.strip(" +") - - r = await self.send( - functions.auth.ResendCode( - phone_number=phone_number, - phone_code_hash=phone_code_hash - ) - ) - - return SentCode._parse(r) - - async def sign_in(self, phone_number: str, phone_code_hash: str, phone_code: str) -> Union[ - User, TermsOfService, bool]: - """Authorize a user in Telegram with a valid confirmation code. - - Parameters: - phone_number (``str``): - Phone number in international format (includes the country prefix). - - phone_code_hash (``str``): - Code identifier taken from the result of :meth:`~Client.send_code`. - - phone_code (``str``): - The valid confirmation code you received (either as Telegram message or as SMS in your phone number). - - Returns: - :obj:`User` | :obj:`TermsOfService` | bool: On success, in case the authorization completed, the user is - returned. In case the phone number needs to be registered first AND the terms of services accepted (with - :meth:`~Client.accept_terms_of_service`), an object containing them is returned. In case the phone number - needs to be registered, but the terms of services don't need to be accepted, False is returned instead. - - Raises: - BadRequest: In case the arguments are invalid. - SessionPasswordNeeded: In case a password is needed to sign in. - """ - phone_number = phone_number.strip(" +") - - r = await self.send( - functions.auth.SignIn( - phone_number=phone_number, - phone_code_hash=phone_code_hash, - phone_code=phone_code - ) - ) - - if isinstance(r, types.auth.AuthorizationSignUpRequired): - if r.terms_of_service: - return TermsOfService._parse(terms_of_service=r.terms_of_service) - - return False - else: - self.storage.user_id(r.user.id) - self.storage.is_bot(False) - - return User._parse(self, r.user) - - async def sign_up(self, phone_number: str, phone_code_hash: str, first_name: str, last_name: str = "") -> User: - """Register a new user in Telegram. - - Parameters: - phone_number (``str``): - Phone number in international format (includes the country prefix). - - phone_code_hash (``str``): - Code identifier taken from the result of :meth:`~Client.send_code`. - - first_name (``str``): - New user first name. - - last_name (``str``, *optional*): - New user last name. Defaults to "" (empty string, no last name). - - Returns: - :obj:`User`: On success, the new registered user is returned. - - Raises: - BadRequest: In case the arguments are invalid. - """ - phone_number = phone_number.strip(" +") - - r = await self.send( - functions.auth.SignUp( - phone_number=phone_number, - first_name=first_name, - last_name=last_name, - phone_code_hash=phone_code_hash - ) - ) - - self.storage.user_id(r.user.id) - self.storage.is_bot(False) - - return User._parse(self, r.user) - - async def sign_in_bot(self, bot_token: str) -> User: - """Authorize a bot using its bot token generated by BotFather. - - Parameters: - bot_token (``str``): - The bot token generated by BotFather - - Returns: - :obj:`User`: On success, the bot identity is return in form of a user object. - - Raises: - BadRequest: In case the bot token is invalid. - """ - while True: - try: - r = await self.send( - functions.auth.ImportBotAuthorization( - flags=0, - api_id=self.api_id, - api_hash=self.api_hash, - bot_auth_token=bot_token - ) - ) - except UserMigrate as e: - await self.session.stop() - - self.storage.dc_id(e.x) - self.storage.auth_key(await Auth(self, self.storage.dc_id()).create()) - self.session = Session(self, self.storage.dc_id(), self.storage.auth_key()) - - await self.session.start() - else: - self.storage.user_id(r.user.id) - self.storage.is_bot(True) - - return User._parse(self, r.user) - - async def get_password_hint(self) -> str: - """Get your Two-Step Verification password hint. - - Returns: - ``str``: On success, the password hint as string is returned. - """ - return (await self.send(functions.account.GetPassword())).hint - - async def check_password(self, password: str) -> User: - """Check your Two-Step Verification password and log in. - - Parameters: - password (``str``): - Your Two-Step Verification password. - - Returns: - :obj:`User`: On success, the authorized user is returned. - - Raises: - BadRequest: In case the password is invalid. - """ - r = await self.send( - functions.auth.CheckPassword( - password=compute_check( - await self.send(functions.account.GetPassword()), - password - ) - ) - ) - - self.storage.user_id(r.user.id) - self.storage.is_bot(False) - - return User._parse(self, r.user) - - async def send_recovery_code(self) -> str: - """Send a code to your email to recover your password. - - Returns: - ``str``: On success, the hidden email pattern is returned and a recovery code is sent to that email. - - Raises: - BadRequest: In case no recovery email was set up. - """ - return (await self.send( - functions.auth.RequestPasswordRecovery() - )).email_pattern - - async def recover_password(self, recovery_code: str) -> User: - """Recover your password with a recovery code and log in. - - Parameters: - recovery_code (``str``): - The recovery code sent via email. - - Returns: - :obj:`User`: On success, the authorized user is returned and the Two-Step Verification password reset. - - Raises: - BadRequest: In case the recovery code is invalid. - """ - r = await self.send( - functions.auth.RecoverPassword( - code=recovery_code - ) - ) - - self.storage.user_id(r.user.id) - self.storage.is_bot(False) - - return User._parse(self, r.user) - - async def accept_terms_of_service(self, terms_of_service_id: str) -> bool: - """Accept the given terms of service. - - Parameters: - terms_of_service_id (``str``): - The terms of service identifier. - """ - r = await self.send( - functions.help.AcceptTermsOfService( - id=types.DataJSON( - data=terms_of_service_id - ) - ) - ) - - assert r - - return True - - async def authorize(self) -> User: - if self.bot_token: - return await self.sign_in_bot(self.bot_token) - - while True: - try: - if not self.phone_number: - while True: - value = await ainput("Enter phone number or bot token: ") - - if not value: - continue - - confirm = input("Is \"{}\" correct? (y/N): ".format(value)).lower() - - if confirm == "y": - break - - if ":" in value: - self.bot_token = value - return await self.sign_in_bot(value) - else: - self.phone_number = value - - sent_code = await self.send_code(self.phone_number) - except BadRequest as e: - print(e.MESSAGE) - self.phone_number = None - self.bot_token = None - else: - break - - if self.force_sms: - sent_code = await self.resend_code(self.phone_number, sent_code.phone_code_hash) - - print("The confirmation code has been sent via {}".format( - { - "app": "Telegram app", - "sms": "SMS", - "call": "phone call", - "flash_call": "phone flash call" - }[sent_code.type] - )) - - while True: - if not self.phone_code: - self.phone_code = await ainput("Enter confirmation code: ") - - try: - signed_in = await self.sign_in(self.phone_number, sent_code.phone_code_hash, self.phone_code) - except BadRequest as e: - print(e.MESSAGE) - self.phone_code = None - except SessionPasswordNeeded as e: - print(e.MESSAGE) - - while True: - print("Password hint: {}".format(await self.get_password_hint())) - - if not self.password: - self.password = await ainput("Enter password (empty to recover): ") - - try: - if not self.password: - confirm = await ainput("Confirm password recovery (y/n): ") - - if confirm == "y": - email_pattern = await self.send_recovery_code() - print("The recovery code has been sent to {}".format(email_pattern)) - - while True: - recovery_code = await ainput("Enter recovery code: ") - - try: - return await self.recover_password(recovery_code) - except BadRequest as e: - print(e.MESSAGE) - except Exception as e: - log.error(e, exc_info=True) - raise - else: - self.password = None - else: - return await self.check_password(self.password) - except BadRequest as e: - print(e.MESSAGE) - self.password = None - else: - break - - if isinstance(signed_in, User): - return signed_in - - while True: - first_name = await ainput("Enter first name: ") - last_name = await ainput("Enter last name (empty to skip): ") - - try: - signed_up = await self.sign_up( - self.phone_number, - sent_code.phone_code_hash, - first_name, - last_name - ) - except BadRequest as e: - print(e.MESSAGE) - else: - break - - if isinstance(signed_in, TermsOfService): - print("\n" + signed_in.text + "\n") - await self.accept_terms_of_service(signed_in.id) - - return signed_up - - async def log_out(self): - """Log out from Telegram and delete the *\\*.session* file. - - When you log out, the current client is stopped and the storage session deleted. - No more API calls can be made until you start the client and re-authorize again. - - Returns: - ``bool``: On success, True is returned. - - Example: - .. code-block:: python - - # Log out. - app.log_out() - """ - await self.send(functions.auth.LogOut()) - await self.stop() - self.storage.delete() - - return True - - async def start(self): - """Start the client. - - This method connects the client to Telegram and, in case of new sessions, automatically manages the full - authorization process using an interactive prompt. - - Returns: - :obj:`Client`: The started client itself. - - Raises: - ConnectionError: In case you try to start an already started client. - - Example: - .. code-block:: python - :emphasize-lines: 4 - - from pyrogram import Client - - app = Client("my_account") - app.start() - - ... # Call API methods - - app.stop() - """ - is_authorized = await self.connect() - - try: - if not is_authorized: - await self.authorize() - - if not self.storage.is_bot() and self.takeout: - self.takeout_id = (await self.send(functions.account.InitTakeoutSession())).id - log.warning("Takeout session {} initiated".format(self.takeout_id)) - - await self.send(functions.updates.GetState()) - except (Exception, KeyboardInterrupt): - await self.disconnect() - raise - else: - await self.initialize() - return self - - async def stop(self, block: bool = True): - """Stop the Client. - - This method disconnects the client from Telegram and stops the underlying tasks. - - Parameters: - block (``bool``, *optional*): - Blocks the code execution until the client has been restarted. It is useful with ``block=False`` in case - you want to stop the own client *within* an handler in order not to cause a deadlock. - Defaults to True. - - Returns: - :obj:`Client`: The stopped client itself. - - Raises: - ConnectionError: In case you try to stop an already stopped client. - - Example: - .. code-block:: python - :emphasize-lines: 8 - - from pyrogram import Client - - app = Client("my_account") - app.start() - - ... # Call API methods - - app.stop() - """ - - async def do_it(): - await self.terminate() - await self.disconnect() - - if block: - await do_it() - else: - asyncio.ensure_future(do_it()) - - return self - - async def restart(self, block: bool = True): - """Restart the Client. - - This method will first call :meth:`~Client.stop` and then :meth:`~Client.start` in a row in order to restart - a client using a single method. - - Parameters: - block (``bool``, *optional*): - Blocks the code execution until the client has been restarted. It is useful with ``block=False`` in case - you want to restart the own client *within* an handler in order not to cause a deadlock. - Defaults to True. - - Returns: - :obj:`Client`: The restarted client itself. - - Raises: - ConnectionError: In case you try to restart a stopped Client. - - Example: - .. code-block:: python - :emphasize-lines: 8 - - from pyrogram import Client - - app = Client("my_account") - app.start() - - ... # Call API methods - - app.restart() - - ... # Call other API methods - - app.stop() - """ - - async def do_it(): - await self.stop() - await self.start() - - if block: - await do_it() - else: - asyncio.ensure_future(do_it()) - - return self - - @staticmethod - async def idle(stop_signals: tuple = (SIGINT, SIGTERM, SIGABRT)): - """Block the main script execution until a signal is received. - - This static method will run an infinite loop in order to block the main script execution and prevent it from - exiting while having client(s) that are still running in the background. - - It is useful for event-driven application only, that are, applications which react upon incoming Telegram - updates through handlers, rather than executing a set of methods sequentially. - - The way Pyrogram works, it will keep your handlers in a pool of worker threads, which are executed concurrently - outside the main thread; calling idle() will ensure the client(s) will be kept alive by not letting the main - script to end, until you decide to quit. - - Once a signal is received (e.g.: from CTRL+C) the inner infinite loop will break and your main script will - continue. Don't forget to call :meth:`~Client.stop` for each running client before the script ends. - - Parameters: - stop_signals (``tuple``, *optional*): - Iterable containing signals the signal handler will listen to. - Defaults to *(SIGINT, SIGTERM, SIGABRT)*. - - Example: - .. code-block:: python - :emphasize-lines: 13 - - from pyrogram import Client - - app1 = Client("account1") - app2 = Client("account2") - app3 = Client("account3") - - ... # Set handlers up - - app1.start() - app2.start() - app3.start() - - Client.idle() - - app1.stop() - app2.stop() - app3.stop() - """ - - def signal_handler(_, __): - logging.info("Stop signal received ({}). Exiting...".format(_)) - Client.is_idling = False - - for s in stop_signals: - signal(s, signal_handler) - - Client.is_idling = True - - while Client.is_idling: - await asyncio.sleep(1) - - def run(self, coroutine=None): - """Start the client, idle the main script and finally stop the client. - - This is a convenience method that calls :meth:`~Client.start`, :meth:`~Client.idle` and :meth:`~Client.stop` in - sequence. It makes running a client less verbose, but is not suitable in case you want to run more than one - client in a single main script, since idle() will block after starting the own client. - - Raises: - ConnectionError: In case you try to run an already started client. - - Example: - .. code-block:: python - :emphasize-lines: 7 - - from pyrogram import Client - - app = Client("my_account") - - ... # Set handlers up - - app.run() - """ - loop = asyncio.get_event_loop() - run = loop.run_until_complete - - if coroutine is not None: - run(coroutine) - else: - run(self.start()) - run(Client.idle()) - run(self.stop()) - - loop.close() - - def add_handler(self, handler: Handler, group: int = 0): - """Register an update handler. - - You can register multiple handlers, but at most one handler within a group will be used for a single update. - To handle the same update more than once, register your handler using a different group id (lower group id - == higher priority). This mechanism is explained in greater details at - :doc:`More on Updates <../../topics/more-on-updates>`. - - Parameters: - handler (``Handler``): - The handler to be registered. - - group (``int``, *optional*): - The group identifier, defaults to 0. - - Returns: - ``tuple``: A tuple consisting of *(handler, group)*. - - Example: - .. code-block:: python - :emphasize-lines: 8 - - from pyrogram import Client, MessageHandler - - def dump(client, message): - print(message) - - app = Client("my_account") - - app.add_handler(MessageHandler(dump)) - - app.run() - """ - if isinstance(handler, DisconnectHandler): - self.disconnect_handler = handler.callback - else: - self.dispatcher.add_handler(handler, group) - - return handler, group - - def remove_handler(self, handler: Handler, group: int = 0): - """Remove a previously-registered update handler. - - Make sure to provide the right group where the handler was added in. You can use the return value of the - :meth:`~Client.add_handler` method, a tuple of *(handler, group)*, and pass it directly. - - Parameters: - handler (``Handler``): - The handler to be removed. - - group (``int``, *optional*): - The group identifier, defaults to 0. - - Example: - .. code-block:: python - :emphasize-lines: 11 - - from pyrogram import Client, MessageHandler - - def dump(client, message): - print(message) - - app = Client("my_account") - - handler = app.add_handler(MessageHandler(dump)) - - # Starred expression to unpack (handler, group) - app.remove_handler(*handler) - - app.run() - """ - if isinstance(handler, DisconnectHandler): - self.disconnect_handler = None - else: - self.dispatcher.remove_handler(handler, group) - - def stop_transmission(self): - """Stop downloading or uploading a file. - - This method must be called inside a progress callback function in order to stop the transmission at the - desired time. The progress callback is called every time a file chunk is uploaded/downloaded. - - Example: - .. code-block:: python - :emphasize-lines: 9 - - from pyrogram import Client - - app = Client("my_account") - - # Example to stop transmission once the upload progress reaches 50% - # Useless in practice, but shows how to stop on command - def progress(current, total, client): - if (current * 100 / total) > 50: - client.stop_transmission() - - with app: - app.send_document("me", "files.zip", progress=progress, progress_args=(app,)) - """ - raise Client.StopTransmission - - def export_session_string(self): - """Export the current authorized session as a serialized string. - - Session strings are useful for storing in-memory authorized sessions in a portable, serialized string. - More detailed information about session strings can be found at the dedicated page of - :doc:`Storage Engines <../../topics/storage-engines>`. - - Returns: - ``str``: The session serialized into a printable, url-safe string. - - Example: - .. code-block:: python - :emphasize-lines: 6 - - from pyrogram import Client - - app = Client("my_account") - - with app: - print(app.export_session_string()) - """ - return self.storage.export_session_string() - - @property - def parse_mode(self): - return self._parse_mode - - @parse_mode.setter - def parse_mode(self, parse_mode: Union[str, None] = "combined"): - if parse_mode not in self.PARSE_MODES: - raise ValueError('parse_mode must be one of {} or None. Not "{}"'.format( - ", ".join('"{}"'.format(m) for m in self.PARSE_MODES[:-1]), - parse_mode - )) - - self._parse_mode = parse_mode - - # TODO: redundant, remove in next major version - def set_parse_mode(self, parse_mode: Union[str, None] = "combined"): - """Set the parse mode to be used globally by the client. - - When setting the parse mode with this method, all other methods having a *parse_mode* parameter will follow the - global value by default. The default value *"combined"* enables both Markdown and HTML styles to be used and - combined together. - - Parameters: - parse_mode (``str``): - The new parse mode, can be any of: *"combined"*, for the default combined mode. *"markdown"* or *"md"* - to force Markdown-only styles. *"html"* to force HTML-only styles. *None* to disable the parser - completely. - - Raises: - ValueError: In case the provided *parse_mode* is not a valid parse mode. - - Example: - .. code-block:: python - :emphasize-lines: 10,14,18,22 - - from pyrogram import Client - - app = Client("my_account") - - with app: - # Default combined mode: Markdown + HTML - app.send_message("haskell", "1. **markdown** and html") - - # Force Markdown-only, HTML is disabled - app.set_parse_mode("markdown") - app.send_message("haskell", "2. **markdown** and html") - - # Force HTML-only, Markdown is disabled - app.set_parse_mode("html") - app.send_message("haskell", "3. **markdown** and html") - - # Disable the parser completely - app.set_parse_mode(None) - app.send_message("haskell", "4. **markdown** and html") - - # Bring back the default combined mode - app.set_parse_mode() - app.send_message("haskell", "5. **markdown** and html") - """ - - self.parse_mode = parse_mode - - def fetch_peers(self, peers: List[Union[types.User, types.Chat, types.Channel]]) -> bool: - is_min = False - parsed_peers = [] - - for peer in peers: - if getattr(peer, "min", False): - is_min = True - continue - - username = None - phone_number = None - - if isinstance(peer, types.User): - peer_id = peer.id - access_hash = peer.access_hash - username = (peer.username or "").lower() or None - phone_number = peer.phone - peer_type = "bot" if peer.bot else "user" - elif isinstance(peer, (types.Chat, types.ChatForbidden)): - peer_id = -peer.id - access_hash = 0 - peer_type = "group" - elif isinstance(peer, (types.Channel, types.ChannelForbidden)): - peer_id = utils.get_channel_id(peer.id) - access_hash = peer.access_hash - username = (getattr(peer, "username", None) or "").lower() or None - peer_type = "channel" if peer.broadcast else "supergroup" - else: - continue - - parsed_peers.append((peer_id, access_hash, peer_type, username, phone_number)) - - self.storage.update_peers(parsed_peers) - - return is_min - - async def download_worker(self): - while True: - packet = await self.download_queue.get() - - if packet is None: - break - - temp_file_path = "" - final_file_path = "" - - try: - data, directory, file_name, done, progress, progress_args, path = packet - - temp_file_path = await self.get_file( - media_type=data.media_type, - dc_id=data.dc_id, - document_id=data.document_id, - access_hash=data.access_hash, - thumb_size=data.thumb_size, - peer_id=data.peer_id, - peer_type=data.peer_type, - peer_access_hash=data.peer_access_hash, - volume_id=data.volume_id, - local_id=data.local_id, - file_ref=data.file_ref, - file_size=data.file_size, - is_big=data.is_big, - progress=progress, - progress_args=progress_args - ) - - if temp_file_path: - final_file_path = os.path.abspath(re.sub("\\\\", "/", os.path.join(directory, file_name))) - os.makedirs(directory, exist_ok=True) - shutil.move(temp_file_path, final_file_path) - except Exception as e: - log.error(e, exc_info=True) - - try: - os.remove(temp_file_path) - except OSError: - pass - else: - # TODO: "" or None for faulty download, which is better? - # os.path methods return "" in case something does not exist, I prefer this. - # For now let's keep None - path[0] = final_file_path or None - finally: - done.set() - - async def updates_worker(self): - while True: - updates = await self.updates_queue.get() - - if updates is None: - break - - try: - if isinstance(updates, (types.Update, types.UpdatesCombined)): - is_min = self.fetch_peers(updates.users) or self.fetch_peers(updates.chats) - - users = {u.id: u for u in updates.users} - chats = {c.id: c for c in updates.chats} - - for update in updates.updates: - channel_id = getattr( - getattr( - getattr( - update, "message", None - ), "to_id", None - ), "channel_id", None - ) or getattr(update, "channel_id", None) - - pts = getattr(update, "pts", None) - pts_count = getattr(update, "pts_count", None) - - if isinstance(update, types.UpdateChannelTooLong): - log.warning(update) - - if isinstance(update, types.UpdateNewChannelMessage) and is_min: - message = update.message - - if not isinstance(message, types.MessageEmpty): - try: - diff = await self.send( - functions.updates.GetChannelDifference( - channel=await self.resolve_peer(utils.get_channel_id(channel_id)), - filter=types.ChannelMessagesFilter( - ranges=[types.MessageRange( - min_id=update.message.id, - max_id=update.message.id - )] - ), - pts=pts - pts_count, - limit=pts - ) - ) - except ChannelPrivate: - pass - else: - if not isinstance(diff, types.updates.ChannelDifferenceEmpty): - users.update({u.id: u for u in diff.users}) - chats.update({c.id: c for c in diff.chats}) - - self.dispatcher.updates_queue.put_nowait((update, users, chats)) - elif isinstance(updates, (types.UpdateShortMessage, types.UpdateShortChatMessage)): - diff = await self.send( - functions.updates.GetDifference( - pts=updates.pts - updates.pts_count, - date=updates.date, - qts=-1 - ) - ) - - if diff.new_messages: - self.dispatcher.updates_queue.put_nowait(( - types.UpdateNewMessage( - message=diff.new_messages[0], - pts=updates.pts, - pts_count=updates.pts_count - ), - {u.id: u for u in diff.users}, - {c.id: c for c in diff.chats} - )) - else: - self.dispatcher.updates_queue.put_nowait((diff.other_updates[0], {}, {})) - elif isinstance(updates, types.UpdateShort): - self.dispatcher.updates_queue.put_nowait((updates.update, {}, {})) - elif isinstance(updates, types.UpdatesTooLong): - log.info(updates) - except Exception as e: - log.error(e, exc_info=True) - - async def send(self, data: TLObject, retries: int = Session.MAX_RETRIES, timeout: float = Session.WAIT_TIMEOUT): - """Send raw Telegram queries. - - This method makes it possible to manually call every single Telegram API method in a low-level manner. - Available functions are listed in the :obj:`functions ` package and may accept compound - data types from :obj:`types ` as well as bare types such as ``int``, ``str``, etc... - - .. note:: - - This is a utility method intended to be used **only** when working with raw - :obj:`functions ` (i.e: a Telegram API method you wish to use which is not - available yet in the Client class as an easy-to-use method). - - Parameters: - data (``RawFunction``): - The API Schema function filled with proper arguments. - - retries (``int``): - Number of retries. - - timeout (``float``): - Timeout in seconds. - - Returns: - ``RawType``: The raw type response generated by the query. - - Raises: - RPCError: In case of a Telegram RPC error. - """ - if not self.is_connected: - raise ConnectionError("Client has not been started yet") - - if self.no_updates: - data = functions.InvokeWithoutUpdates(query=data) - - if self.takeout_id: - data = functions.InvokeWithTakeout(takeout_id=self.takeout_id, query=data) - - r = await self.session.send(data, retries, timeout, self.sleep_threshold) - - self.fetch_peers(getattr(r, "users", [])) - self.fetch_peers(getattr(r, "chats", [])) - - return r - - def load_config(self): - parser = ConfigParser() - parser.read(str(self.config_file)) - - if self.bot_token: - pass - else: - self.bot_token = parser.get("pyrogram", "bot_token", fallback=None) - - if self.api_id and self.api_hash: - pass - else: - if parser.has_section("pyrogram"): - self.api_id = parser.getint("pyrogram", "api_id") - self.api_hash = parser.get("pyrogram", "api_hash") - else: - raise AttributeError("No API Key found. More info: https://docs.pyrogram.org/intro/setup") - - for option in ["app_version", "device_model", "system_version", "lang_code"]: - if getattr(self, option): - pass - else: - if parser.has_section("pyrogram"): - setattr(self, option, parser.get( - "pyrogram", - option, - fallback=getattr(Client, option.upper()) - )) - else: - setattr(self, option, getattr(Client, option.upper())) - - if self._proxy: - self._proxy["enabled"] = bool(self._proxy.get("enabled", True)) - else: - self._proxy = {} - - if parser.has_section("proxy"): - self._proxy["enabled"] = parser.getboolean("proxy", "enabled", fallback=True) - self._proxy["hostname"] = parser.get("proxy", "hostname") - self._proxy["port"] = parser.getint("proxy", "port") - self._proxy["username"] = parser.get("proxy", "username", fallback=None) or None - self._proxy["password"] = parser.get("proxy", "password", fallback=None) or None - - if self.plugins: - self.plugins = { - "enabled": bool(self.plugins.get("enabled", True)), - "root": self.plugins.get("root", None), - "include": self.plugins.get("include", []), - "exclude": self.plugins.get("exclude", []) - } - else: - try: - section = parser["plugins"] - - self.plugins = { - "enabled": section.getboolean("enabled", True), - "root": section.get("root", None), - "include": section.get("include", []), - "exclude": section.get("exclude", []) - } - - include = self.plugins["include"] - exclude = self.plugins["exclude"] - - if include: - self.plugins["include"] = include.strip().split("\n") - - if exclude: - self.plugins["exclude"] = exclude.strip().split("\n") - - except KeyError: - self.plugins = None - - async def load_session(self): - self.storage.open() - - session_empty = any([ - self.storage.test_mode() is None, - self.storage.auth_key() is None, - self.storage.user_id() is None, - self.storage.is_bot() is None - ]) - - if session_empty: - self.storage.dc_id(2) - self.storage.date(0) - - self.storage.test_mode(self.test_mode) - self.storage.auth_key(await Auth(self, self.storage.dc_id()).create()) - self.storage.user_id(None) - self.storage.is_bot(None) - - def load_plugins(self): - if self.plugins: - plugins = self.plugins.copy() - - for option in ["include", "exclude"]: - if plugins[option]: - plugins[option] = [ - (i.split()[0], i.split()[1:] or None) - for i in self.plugins[option] - ] - else: - return - - if plugins.get("enabled", False): - root = plugins["root"] - include = plugins["include"] - exclude = plugins["exclude"] - - count = 0 - - if not include: - for path in sorted(Path(root.replace(".", "/")).rglob("*.py")): - module_path = '.'.join(path.parent.parts + (path.stem,)) - module = import_module(module_path) - - for name in vars(module).keys(): - # noinspection PyBroadException - try: - handler, group = getattr(module, name).handler - - if isinstance(handler, Handler) and isinstance(group, int): - self.add_handler(handler, group) - - log.info('[{}] [LOAD] {}("{}") in group {} from "{}"'.format( - self.session_name, type(handler).__name__, name, group, module_path)) - - count += 1 - except Exception: - pass - else: - for path, handlers in include: - module_path = root + "." + path - warn_non_existent_functions = True - - try: - module = import_module(module_path) - except ImportError: - log.warning('[{}] [LOAD] Ignoring non-existent module "{}"'.format( - self.session_name, module_path)) - continue - - if "__path__" in dir(module): - log.warning('[{}] [LOAD] Ignoring namespace "{}"'.format( - self.session_name, module_path)) - continue - - if handlers is None: - handlers = vars(module).keys() - warn_non_existent_functions = False - - for name in handlers: - # noinspection PyBroadException - try: - handler, group = getattr(module, name).handler - - if isinstance(handler, Handler) and isinstance(group, int): - self.add_handler(handler, group) - - log.info('[{}] [LOAD] {}("{}") in group {} from "{}"'.format( - self.session_name, type(handler).__name__, name, group, module_path)) - - count += 1 - except Exception: - if warn_non_existent_functions: - log.warning('[{}] [LOAD] Ignoring non-existent function "{}" from "{}"'.format( - self.session_name, name, module_path)) - - if exclude: - for path, handlers in exclude: - module_path = root + "." + path - warn_non_existent_functions = True - - try: - module = import_module(module_path) - except ImportError: - log.warning('[{}] [UNLOAD] Ignoring non-existent module "{}"'.format( - self.session_name, module_path)) - continue - - if "__path__" in dir(module): - log.warning('[{}] [UNLOAD] Ignoring namespace "{}"'.format( - self.session_name, module_path)) - continue - - if handlers is None: - handlers = vars(module).keys() - warn_non_existent_functions = False - - for name in handlers: - # noinspection PyBroadException - try: - handler, group = getattr(module, name).handler - - if isinstance(handler, Handler) and isinstance(group, int): - self.remove_handler(handler, group) - - log.info('[{}] [UNLOAD] {}("{}") from group {} in "{}"'.format( - self.session_name, type(handler).__name__, name, group, module_path)) - - count -= 1 - except Exception: - if warn_non_existent_functions: - log.warning('[{}] [UNLOAD] Ignoring non-existent function "{}" from "{}"'.format( - self.session_name, name, module_path)) - - if count > 0: - log.info('[{}] Successfully loaded {} plugin{} from "{}"'.format( - self.session_name, count, "s" if count > 1 else "", root)) - else: - log.warning('[{}] No plugin loaded from "{}"'.format( - self.session_name, root)) - - async def resolve_peer(self, peer_id: Union[int, str]): - """Get the InputPeer of a known peer id. - Useful whenever an InputPeer type is required. - - .. note:: - - This is a utility method intended to be used **only** when working with raw - :obj:`functions ` (i.e: a Telegram API method you wish to use which is not - available yet in the Client class as an easy-to-use method). - - Parameters: - peer_id (``int`` | ``str``): - The peer id you want to extract the InputPeer from. - Can be a direct id (int), a username (str) or a phone number (str). - - Returns: - ``InputPeer``: On success, the resolved peer id is returned in form of an InputPeer object. - - Raises: - KeyError: In case the peer doesn't exist in the internal database. - """ - if not self.is_connected: - raise ConnectionError("Client has not been started yet") - - try: - return self.storage.get_peer_by_id(peer_id) - except KeyError: - if isinstance(peer_id, str): - if peer_id in ("self", "me"): - return types.InputPeerSelf() - - peer_id = re.sub(r"[@+\s]", "", peer_id.lower()) - - try: - int(peer_id) - except ValueError: - try: - return self.storage.get_peer_by_username(peer_id) - except KeyError: - await self.send( - functions.contacts.ResolveUsername( - username=peer_id - ) - ) - - return self.storage.get_peer_by_username(peer_id) - else: - try: - return self.storage.get_peer_by_phone_number(peer_id) - except KeyError: - raise PeerIdInvalid - - peer_type = utils.get_peer_type(peer_id) - - if peer_type == "user": - self.fetch_peers( - await self.send( - functions.users.GetUsers( - id=[ - types.InputUser( - user_id=peer_id, - access_hash=0 - ) - ] - ) - ) - ) - elif peer_type == "chat": - await self.send( - functions.messages.GetChats( - id=[-peer_id] - ) - ) - else: - await self.send( - functions.channels.GetChannels( - id=[ - types.InputChannel( - channel_id=utils.get_channel_id(peer_id), - access_hash=0 - ) - ] - ) - ) - - try: - return self.storage.get_peer_by_id(peer_id) - except KeyError: - raise PeerIdInvalid - - async def save_file( - self, - path: Union[str, BinaryIO], - file_id: int = None, - file_part: int = 0, - progress: callable = None, - progress_args: tuple = () - ): - """Upload a file onto Telegram servers, without actually sending the message to anyone. - Useful whenever an InputFile type is required. - - .. note:: - - This is a utility method intended to be used **only** when working with raw - :obj:`functions ` (i.e: a Telegram API method you wish to use which is not - available yet in the Client class as an easy-to-use method). - - Parameters: - path (``str``): - The path of the file you want to upload that exists on your local machine. - - file_id (``int``, *optional*): - In case a file part expired, pass the file_id and the file_part to retry uploading that specific chunk. - - file_part (``int``, *optional*): - In case a file part expired, pass the file_id and the file_part to retry uploading that specific chunk. - - progress (``callable``, *optional*): - Pass a callback function to view the file transmission progress. - The function must take *(current, total)* as positional arguments (look at Other Parameters below for a - detailed description) and will be called back each time a new file chunk has been successfully - transmitted. - - progress_args (``tuple``, *optional*): - Extra custom arguments for the progress callback function. - You can pass anything you need to be available in the progress callback scope; for example, a Message - object or a Client instance in order to edit the message with the updated progress status. - - Other Parameters: - current (``int``): - The amount of bytes transmitted so far. - - total (``int``): - The total size of the file. - - *args (``tuple``, *optional*): - Extra custom arguments as defined in the *progress_args* parameter. - You can either keep *\*args* or add every single extra argument in your function signature. - - Returns: - ``InputFile``: On success, the uploaded file is returned in form of an InputFile object. - - Raises: - RPCError: In case of a Telegram RPC error. - """ - if path is None: - return None - - async def worker(session): - while True: - data = await queue.get() - - if data is None: - return - - try: - await asyncio.ensure_future(session.send(data)) - except Exception as e: - logging.error(e) - - part_size = 512 * 1024 - - if isinstance(path, (str, PurePath)): - fp = open(path, "rb") - elif isinstance(path, io.IOBase): - fp = path - else: - raise ValueError("Invalid file. Expected a file path as string or a binary (not text) file pointer") - - file_name = fp.name - - fp.seek(0, os.SEEK_END) - file_size = fp.tell() - fp.seek(0) - - if file_size == 0: - raise ValueError("File size equals to 0 B") - - if file_size > 2000 * 1024 * 1024: - raise ValueError("Telegram doesn't support uploading files bigger than 2000 MiB") - - file_total_parts = int(math.ceil(file_size / part_size)) - is_big = file_size > 10 * 1024 * 1024 - pool_size = 3 if is_big else 1 - workers_count = 4 if is_big else 1 - is_missing_part = file_id is not None - file_id = file_id or self.rnd_id() - md5_sum = md5() if not is_big and not is_missing_part else None - pool = [Session(self, self.storage.dc_id(), self.storage.auth_key(), is_media=True) for _ in range(pool_size)] - workers = [asyncio.ensure_future(worker(session)) for session in pool for _ in range(workers_count)] - queue = asyncio.Queue(16) - - try: - for session in pool: - await session.start() - - with fp: - fp.seek(part_size * file_part) - - while True: - chunk = fp.read(part_size) - - if not chunk: - if not is_big: - md5_sum = "".join([hex(i)[2:].zfill(2) for i in md5_sum.digest()]) - break - - if is_big: - rpc = functions.upload.SaveBigFilePart( - file_id=file_id, - file_part=file_part, - file_total_parts=file_total_parts, - bytes=chunk - ) - else: - rpc = functions.upload.SaveFilePart( - file_id=file_id, - file_part=file_part, - bytes=chunk - ) - - await queue.put(rpc) - - if is_missing_part: - return - - if not is_big: - md5_sum.update(chunk) - - file_part += 1 - - if progress: - await progress(min(file_part * part_size, file_size), file_size, *progress_args) - except Client.StopTransmission: - raise - except Exception as e: - log.error(e, exc_info=True) - else: - if is_big: - return types.InputFileBig( - id=file_id, - parts=file_total_parts, - name=file_name, - - ) - else: - return types.InputFile( - id=file_id, - parts=file_total_parts, - name=file_name, - md5_checksum=md5_sum - ) - finally: - for _ in workers: - await queue.put(None) - - await asyncio.gather(*workers) - - for session in pool: - await session.stop() - - async def get_file( - self, - media_type: int, - dc_id: int, - document_id: int, - access_hash: int, - thumb_size: str, - peer_id: int, - peer_type: str, - peer_access_hash: int, - volume_id: int, - local_id: int, - file_ref: str, - file_size: int, - is_big: bool, - progress: callable, - progress_args: tuple = () - ) -> str: - async with self.media_sessions_lock: - session = self.media_sessions.get(dc_id, None) - - if session is None: - if dc_id != self.storage.dc_id(): - session = Session(self, dc_id, await Auth(self, dc_id).create(), is_media=True) - await session.start() - - for _ in range(3): - exported_auth = await self.send( - functions.auth.ExportAuthorization( - dc_id=dc_id - ) - ) - - try: - await session.send( - functions.auth.ImportAuthorization( - id=exported_auth.id, - bytes=exported_auth.bytes - ) - ) - except AuthBytesInvalid: - continue - else: - break - else: - await session.stop() - raise AuthBytesInvalid - else: - session = Session(self, dc_id, self.storage.auth_key(), is_media=True) - await session.start() - - self.media_sessions[dc_id] = session - - file_ref = utils.decode_file_ref(file_ref) - - if media_type == 1: - if peer_type == "user": - peer = types.InputPeerUser( - user_id=peer_id, - access_hash=peer_access_hash - ) - elif peer_type == "chat": - peer = types.InputPeerChat( - chat_id=peer_id - ) - else: - peer = types.InputPeerChannel( - channel_id=peer_id, - access_hash=peer_access_hash - ) - - location = types.InputPeerPhotoFileLocation( - peer=peer, - volume_id=volume_id, - local_id=local_id, - big=is_big or None - ) - elif media_type in (0, 2): - location = types.InputPhotoFileLocation( - id=document_id, - access_hash=access_hash, - file_reference=file_ref, - thumb_size=thumb_size - ) - elif media_type == 14: - location = types.InputDocumentFileLocation( - id=document_id, - access_hash=access_hash, - file_reference=file_ref, - thumb_size=thumb_size - ) - else: - location = types.InputDocumentFileLocation( - id=document_id, - access_hash=access_hash, - file_reference=file_ref, - thumb_size="" - ) - - limit = 1024 * 1024 - offset = 0 - file_name = "" - - try: - r = await session.send( - functions.upload.GetFile( - location=location, - offset=offset, - limit=limit - ) - ) - - if isinstance(r, types.upload.File): - with tempfile.NamedTemporaryFile("wb", delete=False) as f: - file_name = f.name - - while True: - chunk = r.bytes - - if not chunk: - break - - f.write(chunk) - - offset += limit - - if progress: - await progress( - min(offset, file_size) - if file_size != 0 - else offset, - file_size, - *progress_args - ) - - r = await session.send( - functions.upload.GetFile( - location=location, - offset=offset, - limit=limit - ) - ) - - elif isinstance(r, types.upload.FileCdnRedirect): - async with self.media_sessions_lock: - cdn_session = self.media_sessions.get(r.dc_id, None) - - if cdn_session is None: - cdn_session = Session( - self, - r.dc_id, - await Auth(self, r.dc_id).create(), is_media=True, is_cdn=True) - - await cdn_session.start() - - self.media_sessions[r.dc_id] = cdn_session - - try: - with tempfile.NamedTemporaryFile("wb", delete=False) as f: - file_name = f.name - - while True: - r2 = await cdn_session.send( - functions.upload.GetCdnFile( - file_token=r.file_token, - offset=offset, - limit=limit - ) - ) - - if isinstance(r2, types.upload.CdnFileReuploadNeeded): - try: - await session.send( - functions.upload.ReuploadCdnFile( - file_token=r.file_token, - request_token=r2.request_token - ) - ) - except VolumeLocNotFound: - break - else: - continue - - chunk = r2.bytes - - # https://core.telegram.org/cdn#decrypting-files - decrypted_chunk = AES.ctr256_decrypt( - chunk, - r.encryption_key, - bytearray( - r.encryption_iv[:-4] - + (offset // 16).to_bytes(4, "big") - ) - ) - - hashes = await session.send( - functions.upload.GetCdnFileHashes( - file_token=r.file_token, - offset=offset - ) - ) - - # https://core.telegram.org/cdn#verifying-files - for i, h in enumerate(hashes): - cdn_chunk = decrypted_chunk[h.limit * i: h.limit * (i + 1)] - assert h.hash == sha256(cdn_chunk).digest(), "Invalid CDN hash part {}".format(i) - - f.write(decrypted_chunk) - - offset += limit - - if progress: - await progress( - min(offset, file_size) - if file_size != 0 - else offset, - file_size, - *progress_args - ) - - if len(chunk) < limit: - break - except Exception as e: - raise e - except Exception as e: - if not isinstance(e, Client.StopTransmission): - log.error(e, exc_info=True) - - try: - os.remove(file_name) - except OSError: - pass - - return "" - else: - return file_name - - def guess_mime_type(self, filename: str): - extension = os.path.splitext(filename)[1] - return self.extensions_to_mime_types.get(extension) - - def guess_extension(self, mime_type: str): - extensions = self.mime_types_to_extensions.get(mime_type) - - if extensions: - return extensions.split(" ")[0] diff --git a/pyrogram/client/ext/__init__.py b/pyrogram/client/ext/__init__.py deleted file mode 100644 index e363d3d4..00000000 --- a/pyrogram/client/ext/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2020 Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -from .base_client import BaseClient -from .dispatcher import Dispatcher -from .emoji import Emoji -from .file_data import FileData -from .link import Link -from .syncer import Syncer diff --git a/pyrogram/client/ext/emoji.py b/pyrogram/client/ext/emoji.py deleted file mode 100644 index 97bfc529..00000000 --- a/pyrogram/client/ext/emoji.py +++ /dev/null @@ -1,7850 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2020 Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -class Emoji: - HELMET_WITH_WHITE_CROSS_TYPE_1_2 = "\u26d1\U0001f3fb" - HELMET_WITH_WHITE_CROSS_TYPE_3 = "\u26d1\U0001f3fc" - HELMET_WITH_WHITE_CROSS_TYPE_4 = "\u26d1\U0001f3fd" - HELMET_WITH_WHITE_CROSS_TYPE_5 = "\u26d1\U0001f3fe" - HELMET_WITH_WHITE_CROSS_TYPE_6 = "\u26d1\U0001f3ff" - KISS_TYPE_1_2 = "\U0001f48f\U0001f3fb" - KISS_TYPE_3 = "\U0001f48f\U0001f3fc" - KISS_TYPE_4 = "\U0001f48f\U0001f3fd" - KISS_TYPE_5 = "\U0001f48f\U0001f3fe" - KISS_TYPE_6 = "\U0001f48f\U0001f3ff" - COUPLE_WITH_HEART_TYPE_1_2 = "\U0001f491\U0001f3fb" - COUPLE_WITH_HEART_TYPE_3 = "\U0001f491\U0001f3fc" - COUPLE_WITH_HEART_TYPE_4 = "\U0001f491\U0001f3fd" - COUPLE_WITH_HEART_TYPE_5 = "\U0001f491\U0001f3fe" - COUPLE_WITH_HEART_TYPE_6 = "\U0001f491\U0001f3ff" - SKIER_TYPE_1_2 = "\u26f7\U0001f3fb" - SKIER_TYPE_3 = "\u26f7\U0001f3fc" - SKIER_TYPE_4 = "\u26f7\U0001f3fd" - SKIER_TYPE_5 = "\u26f7\U0001f3fe" - SKIER_TYPE_6 = "\u26f7\U0001f3ff" - GRINNING_FACE = "\U0001f600" - BEAMING_FACE_WITH_SMILING_EYES = "\U0001f601" - FACE_WITH_TEARS_OF_JOY = "\U0001f602" - ROLLING_ON_THE_FLOOR_LAUGHING = "\U0001f923" - GRINNING_FACE_WITH_BIG_EYES = "\U0001f603" - GRINNING_FACE_WITH_SMILING_EYES = "\U0001f604" - GRINNING_FACE_WITH_SWEAT = "\U0001f605" - GRINNING_SQUINTING_FACE = "\U0001f606" - WINKING_FACE = "\U0001f609" - SMILING_FACE_WITH_SMILING_EYES = "\U0001f60a" - FACE_SAVORING_FOOD = "\U0001f60b" - SMILING_FACE_WITH_SUNGLASSES = "\U0001f60e" - SMILING_FACE_WITH_HEART_EYES = "\U0001f60d" - FACE_BLOWING_A_KISS = "\U0001f618" - SMILING_FACE_WITH_3_HEARTS = "\U0001f970" - KISSING_FACE = "\U0001f617" - KISSING_FACE_WITH_SMILING_EYES = "\U0001f619" - KISSING_FACE_WITH_CLOSED_EYES = "\U0001f61a" - SMILING_FACE = "\u263a\ufe0f" - SLIGHTLY_SMILING_FACE = "\U0001f642" - HUGGING_FACE = "\U0001f917" - STAR_STRUCK = "\U0001f929" - THINKING_FACE = "\U0001f914" - FACE_WITH_RAISED_EYEBROW = "\U0001f928" - NEUTRAL_FACE = "\U0001f610" - EXPRESSIONLESS_FACE = "\U0001f611" - FACE_WITHOUT_MOUTH = "\U0001f636" - FACE_WITH_ROLLING_EYES = "\U0001f644" - SMIRKING_FACE = "\U0001f60f" - PERSEVERING_FACE = "\U0001f623" - SAD_BUT_RELIEVED_FACE = "\U0001f625" - FACE_WITH_OPEN_MOUTH = "\U0001f62e" - ZIPPER_MOUTH_FACE = "\U0001f910" - HUSHED_FACE = "\U0001f62f" - SLEEPY_FACE = "\U0001f62a" - TIRED_FACE = "\U0001f62b" - SLEEPING_FACE = "\U0001f634" - RELIEVED_FACE = "\U0001f60c" - FACE_WITH_TONGUE = "\U0001f61b" - WINKING_FACE_WITH_TONGUE = "\U0001f61c" - SQUINTING_FACE_WITH_TONGUE = "\U0001f61d" - DROOLING_FACE = "\U0001f924" - UNAMUSED_FACE = "\U0001f612" - DOWNCAST_FACE_WITH_SWEAT = "\U0001f613" - PENSIVE_FACE = "\U0001f614" - CONFUSED_FACE = "\U0001f615" - UPSIDE_DOWN_FACE = "\U0001f643" - MONEY_MOUTH_FACE = "\U0001f911" - ASTONISHED_FACE = "\U0001f632" - FROWNING_FACE = "\u2639\ufe0f" - SLIGHTLY_FROWNING_FACE = "\U0001f641" - CONFOUNDED_FACE = "\U0001f616" - DISAPPOINTED_FACE = "\U0001f61e" - WORRIED_FACE = "\U0001f61f" - FACE_WITH_STEAM_FROM_NOSE = "\U0001f624" - CRYING_FACE = "\U0001f622" - LOUDLY_CRYING_FACE = "\U0001f62d" - FROWNING_FACE_WITH_OPEN_MOUTH = "\U0001f626" - ANGUISHED_FACE = "\U0001f627" - FEARFUL_FACE = "\U0001f628" - WEARY_FACE = "\U0001f629" - EXPLODING_HEAD = "\U0001f92f" - GRIMACING_FACE = "\U0001f62c" - ANXIOUS_FACE_WITH_SWEAT = "\U0001f630" - FACE_SCREAMING_IN_FEAR = "\U0001f631" - HOT_FACE = "\U0001f975" - COLD_FACE = "\U0001f976" - FLUSHED_FACE = "\U0001f633" - ZANY_FACE = "\U0001f92a" - DIZZY_FACE = "\U0001f635" - POUTING_FACE = "\U0001f621" - ANGRY_FACE = "\U0001f620" - FACE_WITH_SYMBOLS_ON_MOUTH = "\U0001f92c" - FACE_WITH_MEDICAL_MASK = "\U0001f637" - FACE_WITH_THERMOMETER = "\U0001f912" - FACE_WITH_HEAD_BANDAGE = "\U0001f915" - NAUSEATED_FACE = "\U0001f922" - FACE_VOMITING = "\U0001f92e" - SNEEZING_FACE = "\U0001f927" - SMILING_FACE_WITH_HALO = "\U0001f607" - COWBOY_HAT_FACE = "\U0001f920" - CLOWN_FACE = "\U0001f921" - PARTYING_FACE = "\U0001f973" - WOOZY_FACE = "\U0001f974" - PLEADING_FACE = "\U0001f97a" - LYING_FACE = "\U0001f925" - SHUSHING_FACE = "\U0001f92b" - FACE_WITH_HAND_OVER_MOUTH = "\U0001f92d" - FACE_WITH_MONOCLE = "\U0001f9d0" - NERD_FACE = "\U0001f913" - SMILING_FACE_WITH_HORNS = "\U0001f608" - ANGRY_FACE_WITH_HORNS = "\U0001f47f" - OGRE = "\U0001f479" - GOBLIN = "\U0001f47a" - SKULL = "\U0001f480" - SKULL_AND_CROSSBONES = "\u2620\ufe0f" - GHOST = "\U0001f47b" - ALIEN = "\U0001f47d" - ALIEN_MONSTER = "\U0001f47e" - ROBOT_FACE = "\U0001f916" - PILE_OF_POO = "\U0001f4a9" - GRINNING_CAT_FACE = "\U0001f63a" - GRINNING_CAT_FACE_WITH_SMILING_EYES = "\U0001f638" - CAT_FACE_WITH_TEARS_OF_JOY = "\U0001f639" - SMILING_CAT_FACE_WITH_HEART_EYES = "\U0001f63b" - CAT_FACE_WITH_WRY_SMILE = "\U0001f63c" - KISSING_CAT_FACE = "\U0001f63d" - WEARY_CAT_FACE = "\U0001f640" - CRYING_CAT_FACE = "\U0001f63f" - POUTING_CAT_FACE = "\U0001f63e" - SEE_NO_EVIL_MONKEY = "\U0001f648" - HEAR_NO_EVIL_MONKEY = "\U0001f649" - SPEAK_NO_EVIL_MONKEY = "\U0001f64a" - LIGHT_SKIN_TONE = "\U0001f3fb" - MEDIUM_LIGHT_SKIN_TONE = "\U0001f3fc" - MEDIUM_SKIN_TONE = "\U0001f3fd" - MEDIUM_DARK_SKIN_TONE = "\U0001f3fe" - DARK_SKIN_TONE = "\U0001f3ff" - BABY = "\U0001f476" - BABY_LIGHT_SKIN_TONE = "\U0001f476\U0001f3fb" - BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f476\U0001f3fc" - BABY_MEDIUM_SKIN_TONE = "\U0001f476\U0001f3fd" - BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f476\U0001f3fe" - BABY_DARK_SKIN_TONE = "\U0001f476\U0001f3ff" - CHILD = "\U0001f9d2" - CHILD_LIGHT_SKIN_TONE = "\U0001f9d2\U0001f3fb" - CHILD_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d2\U0001f3fc" - CHILD_MEDIUM_SKIN_TONE = "\U0001f9d2\U0001f3fd" - CHILD_MEDIUM_DARK_SKIN_TONE = "\U0001f9d2\U0001f3fe" - CHILD_DARK_SKIN_TONE = "\U0001f9d2\U0001f3ff" - BOY = "\U0001f466" - BOY_LIGHT_SKIN_TONE = "\U0001f466\U0001f3fb" - BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f466\U0001f3fc" - BOY_MEDIUM_SKIN_TONE = "\U0001f466\U0001f3fd" - BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f466\U0001f3fe" - BOY_DARK_SKIN_TONE = "\U0001f466\U0001f3ff" - GIRL = "\U0001f467" - GIRL_LIGHT_SKIN_TONE = "\U0001f467\U0001f3fb" - GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f467\U0001f3fc" - GIRL_MEDIUM_SKIN_TONE = "\U0001f467\U0001f3fd" - GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f467\U0001f3fe" - GIRL_DARK_SKIN_TONE = "\U0001f467\U0001f3ff" - PERSON = "\U0001f9d1" - ADULT_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb" - ADULT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc" - ADULT_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd" - ADULT_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe" - ADULT_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff" - MAN = "\U0001f468" - MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb" - MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc" - MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd" - MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe" - MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3ff" - WOMAN = "\U0001f469" - WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb" - WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc" - WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd" - WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe" - WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3ff" - OLDER_PERSON = "\U0001f9d3" - OLDER_ADULT_LIGHT_SKIN_TONE = "\U0001f9d3\U0001f3fb" - OLDER_ADULT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d3\U0001f3fc" - OLDER_ADULT_MEDIUM_SKIN_TONE = "\U0001f9d3\U0001f3fd" - OLDER_ADULT_MEDIUM_DARK_SKIN_TONE = "\U0001f9d3\U0001f3fe" - OLDER_ADULT_DARK_SKIN_TONE = "\U0001f9d3\U0001f3ff" - OLD_MAN = "\U0001f474" - OLD_MAN_LIGHT_SKIN_TONE = "\U0001f474\U0001f3fb" - OLD_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f474\U0001f3fc" - OLD_MAN_MEDIUM_SKIN_TONE = "\U0001f474\U0001f3fd" - OLD_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f474\U0001f3fe" - OLD_MAN_DARK_SKIN_TONE = "\U0001f474\U0001f3ff" - OLD_WOMAN = "\U0001f475" - OLD_WOMAN_LIGHT_SKIN_TONE = "\U0001f475\U0001f3fb" - OLD_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f475\U0001f3fc" - OLD_WOMAN_MEDIUM_SKIN_TONE = "\U0001f475\U0001f3fd" - OLD_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f475\U0001f3fe" - OLD_WOMAN_DARK_SKIN_TONE = "\U0001f475\U0001f3ff" - MAN_HEALTH_WORKER = "\U0001f468\u200d\u2695\ufe0f" - MAN_HEALTH_WORKER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2695\ufe0f" - MAN_HEALTH_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2695\ufe0f" - MAN_HEALTH_WORKER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2695\ufe0f" - MAN_HEALTH_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2695\ufe0f" - MAN_HEALTH_WORKER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2695\ufe0f" - WOMAN_HEALTH_WORKER = "\U0001f469\u200d\u2695\ufe0f" - WOMAN_HEALTH_WORKER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2695\ufe0f" - WOMAN_HEALTH_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2695\ufe0f" - WOMAN_HEALTH_WORKER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2695\ufe0f" - WOMAN_HEALTH_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2695\ufe0f" - WOMAN_HEALTH_WORKER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2695\ufe0f" - MAN_STUDENT = "\U0001f468\u200d\U0001f393" - MAN_STUDENT_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f393" - MAN_STUDENT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f393" - MAN_STUDENT_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f393" - MAN_STUDENT_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f393" - MAN_STUDENT_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f393" - WOMAN_STUDENT = "\U0001f469\u200d\U0001f393" - WOMAN_STUDENT_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f393" - WOMAN_STUDENT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f393" - WOMAN_STUDENT_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f393" - WOMAN_STUDENT_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f393" - WOMAN_STUDENT_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f393" - MAN_TEACHER = "\U0001f468\u200d\U0001f3eb" - MAN_TEACHER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f3eb" - MAN_TEACHER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f3eb" - MAN_TEACHER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f3eb" - MAN_TEACHER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f3eb" - MAN_TEACHER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f3eb" - WOMAN_TEACHER = "\U0001f469\u200d\U0001f3eb" - WOMAN_TEACHER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f3eb" - WOMAN_TEACHER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f3eb" - WOMAN_TEACHER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f3eb" - WOMAN_TEACHER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f3eb" - WOMAN_TEACHER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f3eb" - MAN_JUDGE = "\U0001f468\u200d\u2696\ufe0f" - MAN_JUDGE_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2696\ufe0f" - MAN_JUDGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2696\ufe0f" - MAN_JUDGE_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2696\ufe0f" - MAN_JUDGE_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2696\ufe0f" - MAN_JUDGE_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2696\ufe0f" - WOMAN_JUDGE = "\U0001f469\u200d\u2696\ufe0f" - WOMAN_JUDGE_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2696\ufe0f" - WOMAN_JUDGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2696\ufe0f" - WOMAN_JUDGE_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2696\ufe0f" - WOMAN_JUDGE_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2696\ufe0f" - WOMAN_JUDGE_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2696\ufe0f" - MAN_FARMER = "\U0001f468\u200d\U0001f33e" - MAN_FARMER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f33e" - MAN_FARMER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f33e" - MAN_FARMER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f33e" - MAN_FARMER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f33e" - MAN_FARMER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f33e" - WOMAN_FARMER = "\U0001f469\u200d\U0001f33e" - WOMAN_FARMER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f33e" - WOMAN_FARMER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f33e" - WOMAN_FARMER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f33e" - WOMAN_FARMER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f33e" - WOMAN_FARMER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f33e" - MAN_COOK = "\U0001f468\u200d\U0001f373" - MAN_COOK_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f373" - MAN_COOK_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f373" - MAN_COOK_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f373" - MAN_COOK_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f373" - MAN_COOK_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f373" - WOMAN_COOK = "\U0001f469\u200d\U0001f373" - WOMAN_COOK_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f373" - WOMAN_COOK_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f373" - WOMAN_COOK_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f373" - WOMAN_COOK_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f373" - WOMAN_COOK_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f373" - MAN_MECHANIC = "\U0001f468\u200d\U0001f527" - MAN_MECHANIC_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f527" - MAN_MECHANIC_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f527" - MAN_MECHANIC_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f527" - MAN_MECHANIC_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f527" - MAN_MECHANIC_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f527" - WOMAN_MECHANIC = "\U0001f469\u200d\U0001f527" - WOMAN_MECHANIC_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f527" - WOMAN_MECHANIC_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f527" - WOMAN_MECHANIC_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f527" - WOMAN_MECHANIC_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f527" - WOMAN_MECHANIC_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f527" - MAN_FACTORY_WORKER = "\U0001f468\u200d\U0001f3ed" - MAN_FACTORY_WORKER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f3ed" - MAN_FACTORY_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f3ed" - MAN_FACTORY_WORKER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f3ed" - MAN_FACTORY_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f3ed" - MAN_FACTORY_WORKER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f3ed" - WOMAN_FACTORY_WORKER = "\U0001f469\u200d\U0001f3ed" - WOMAN_FACTORY_WORKER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f3ed" - WOMAN_FACTORY_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f3ed" - WOMAN_FACTORY_WORKER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f3ed" - WOMAN_FACTORY_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f3ed" - WOMAN_FACTORY_WORKER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f3ed" - MAN_OFFICE_WORKER = "\U0001f468\u200d\U0001f4bc" - MAN_OFFICE_WORKER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f4bc" - MAN_OFFICE_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f4bc" - MAN_OFFICE_WORKER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f4bc" - MAN_OFFICE_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f4bc" - MAN_OFFICE_WORKER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f4bc" - WOMAN_OFFICE_WORKER = "\U0001f469\u200d\U0001f4bc" - WOMAN_OFFICE_WORKER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f4bc" - WOMAN_OFFICE_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f4bc" - WOMAN_OFFICE_WORKER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f4bc" - WOMAN_OFFICE_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f4bc" - WOMAN_OFFICE_WORKER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f4bc" - MAN_SCIENTIST = "\U0001f468\u200d\U0001f52c" - MAN_SCIENTIST_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f52c" - MAN_SCIENTIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f52c" - MAN_SCIENTIST_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f52c" - MAN_SCIENTIST_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f52c" - MAN_SCIENTIST_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f52c" - WOMAN_SCIENTIST = "\U0001f469\u200d\U0001f52c" - WOMAN_SCIENTIST_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f52c" - WOMAN_SCIENTIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f52c" - WOMAN_SCIENTIST_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f52c" - WOMAN_SCIENTIST_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f52c" - WOMAN_SCIENTIST_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f52c" - MAN_TECHNOLOGIST = "\U0001f468\u200d\U0001f4bb" - MAN_TECHNOLOGIST_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f4bb" - MAN_TECHNOLOGIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f4bb" - MAN_TECHNOLOGIST_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f4bb" - MAN_TECHNOLOGIST_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f4bb" - MAN_TECHNOLOGIST_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f4bb" - WOMAN_TECHNOLOGIST = "\U0001f469\u200d\U0001f4bb" - WOMAN_TECHNOLOGIST_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f4bb" - WOMAN_TECHNOLOGIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f4bb" - WOMAN_TECHNOLOGIST_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f4bb" - WOMAN_TECHNOLOGIST_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f4bb" - WOMAN_TECHNOLOGIST_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f4bb" - MAN_SINGER = "\U0001f468\u200d\U0001f3a4" - MAN_SINGER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f3a4" - MAN_SINGER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f3a4" - MAN_SINGER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f3a4" - MAN_SINGER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f3a4" - MAN_SINGER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f3a4" - WOMAN_SINGER = "\U0001f469\u200d\U0001f3a4" - WOMAN_SINGER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f3a4" - WOMAN_SINGER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f3a4" - WOMAN_SINGER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f3a4" - WOMAN_SINGER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f3a4" - WOMAN_SINGER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f3a4" - MAN_ARTIST = "\U0001f468\u200d\U0001f3a8" - MAN_ARTIST_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f3a8" - MAN_ARTIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f3a8" - MAN_ARTIST_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f3a8" - MAN_ARTIST_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f3a8" - MAN_ARTIST_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f3a8" - WOMAN_ARTIST = "\U0001f469\u200d\U0001f3a8" - WOMAN_ARTIST_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f3a8" - WOMAN_ARTIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f3a8" - WOMAN_ARTIST_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f3a8" - WOMAN_ARTIST_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f3a8" - WOMAN_ARTIST_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f3a8" - MAN_PILOT = "\U0001f468\u200d\u2708\ufe0f" - MAN_PILOT_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2708\ufe0f" - MAN_PILOT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2708\ufe0f" - MAN_PILOT_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2708\ufe0f" - MAN_PILOT_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2708\ufe0f" - MAN_PILOT_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2708\ufe0f" - WOMAN_PILOT = "\U0001f469\u200d\u2708\ufe0f" - WOMAN_PILOT_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2708\ufe0f" - WOMAN_PILOT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2708\ufe0f" - WOMAN_PILOT_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2708\ufe0f" - WOMAN_PILOT_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2708\ufe0f" - WOMAN_PILOT_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2708\ufe0f" - MAN_ASTRONAUT = "\U0001f468\u200d\U0001f680" - MAN_ASTRONAUT_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f680" - MAN_ASTRONAUT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f680" - MAN_ASTRONAUT_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f680" - MAN_ASTRONAUT_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f680" - MAN_ASTRONAUT_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f680" - WOMAN_ASTRONAUT = "\U0001f469\u200d\U0001f680" - WOMAN_ASTRONAUT_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f680" - WOMAN_ASTRONAUT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f680" - WOMAN_ASTRONAUT_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f680" - WOMAN_ASTRONAUT_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f680" - WOMAN_ASTRONAUT_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f680" - MAN_FIREFIGHTER = "\U0001f468\u200d\U0001f692" - MAN_FIREFIGHTER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f692" - MAN_FIREFIGHTER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f692" - MAN_FIREFIGHTER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f692" - MAN_FIREFIGHTER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f692" - MAN_FIREFIGHTER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f692" - WOMAN_FIREFIGHTER = "\U0001f469\u200d\U0001f692" - WOMAN_FIREFIGHTER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f692" - WOMAN_FIREFIGHTER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f692" - WOMAN_FIREFIGHTER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f692" - WOMAN_FIREFIGHTER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f692" - WOMAN_FIREFIGHTER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f692" - POLICE_OFFICER = "\U0001f46e" - POLICE_OFFICER_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fb" - POLICE_OFFICER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fc" - POLICE_OFFICER_MEDIUM_SKIN_TONE = "\U0001f46e\U0001f3fd" - POLICE_OFFICER_MEDIUM_DARK_SKIN_TONE = "\U0001f46e\U0001f3fe" - POLICE_OFFICER_DARK_SKIN_TONE = "\U0001f46e\U0001f3ff" - MAN_POLICE_OFFICER = "\U0001f46e\u200d\u2642\ufe0f" - MAN_POLICE_OFFICER_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fb\u200d\u2642\ufe0f" - MAN_POLICE_OFFICER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fc\u200d\u2642\ufe0f" - MAN_POLICE_OFFICER_MEDIUM_SKIN_TONE = "\U0001f46e\U0001f3fd\u200d\u2642\ufe0f" - MAN_POLICE_OFFICER_MEDIUM_DARK_SKIN_TONE = "\U0001f46e\U0001f3fe\u200d\u2642\ufe0f" - MAN_POLICE_OFFICER_DARK_SKIN_TONE = "\U0001f46e\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_POLICE_OFFICER = "\U0001f46e\u200d\u2640\ufe0f" - WOMAN_POLICE_OFFICER_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_POLICE_OFFICER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_POLICE_OFFICER_MEDIUM_SKIN_TONE = "\U0001f46e\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_POLICE_OFFICER_MEDIUM_DARK_SKIN_TONE = "\U0001f46e\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_POLICE_OFFICER_DARK_SKIN_TONE = "\U0001f46e\U0001f3ff\u200d\u2640\ufe0f" - DETECTIVE = "\U0001f575\ufe0f" - DETECTIVE_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fb" - DETECTIVE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fc" - DETECTIVE_MEDIUM_SKIN_TONE = "\U0001f575\U0001f3fd" - DETECTIVE_MEDIUM_DARK_SKIN_TONE = "\U0001f575\U0001f3fe" - DETECTIVE_DARK_SKIN_TONE = "\U0001f575\U0001f3ff" - MAN_DETECTIVE = "\U0001f575\ufe0f\u200d\u2642\ufe0f" - MAN_DETECTIVE_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fb\u200d\u2642\ufe0f" - MAN_DETECTIVE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fc\u200d\u2642\ufe0f" - MAN_DETECTIVE_MEDIUM_SKIN_TONE = "\U0001f575\U0001f3fd\u200d\u2642\ufe0f" - MAN_DETECTIVE_MEDIUM_DARK_SKIN_TONE = "\U0001f575\U0001f3fe\u200d\u2642\ufe0f" - MAN_DETECTIVE_DARK_SKIN_TONE = "\U0001f575\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_DETECTIVE = "\U0001f575\ufe0f\u200d\u2640\ufe0f" - WOMAN_DETECTIVE_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_DETECTIVE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_DETECTIVE_MEDIUM_SKIN_TONE = "\U0001f575\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_DETECTIVE_MEDIUM_DARK_SKIN_TONE = "\U0001f575\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_DETECTIVE_DARK_SKIN_TONE = "\U0001f575\U0001f3ff\u200d\u2640\ufe0f" - GUARD = "\U0001f482" - GUARD_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fb" - GUARD_MEDIUM_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fc" - GUARD_MEDIUM_SKIN_TONE = "\U0001f482\U0001f3fd" - GUARD_MEDIUM_DARK_SKIN_TONE = "\U0001f482\U0001f3fe" - GUARD_DARK_SKIN_TONE = "\U0001f482\U0001f3ff" - MAN_GUARD = "\U0001f482\u200d\u2642\ufe0f" - MAN_GUARD_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fb\u200d\u2642\ufe0f" - MAN_GUARD_MEDIUM_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fc\u200d\u2642\ufe0f" - MAN_GUARD_MEDIUM_SKIN_TONE = "\U0001f482\U0001f3fd\u200d\u2642\ufe0f" - MAN_GUARD_MEDIUM_DARK_SKIN_TONE = "\U0001f482\U0001f3fe\u200d\u2642\ufe0f" - MAN_GUARD_DARK_SKIN_TONE = "\U0001f482\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_GUARD = "\U0001f482\u200d\u2640\ufe0f" - WOMAN_GUARD_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_GUARD_MEDIUM_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_GUARD_MEDIUM_SKIN_TONE = "\U0001f482\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_GUARD_MEDIUM_DARK_SKIN_TONE = "\U0001f482\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_GUARD_DARK_SKIN_TONE = "\U0001f482\U0001f3ff\u200d\u2640\ufe0f" - CONSTRUCTION_WORKER = "\U0001f477" - CONSTRUCTION_WORKER_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fb" - CONSTRUCTION_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fc" - CONSTRUCTION_WORKER_MEDIUM_SKIN_TONE = "\U0001f477\U0001f3fd" - CONSTRUCTION_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f477\U0001f3fe" - CONSTRUCTION_WORKER_DARK_SKIN_TONE = "\U0001f477\U0001f3ff" - MAN_CONSTRUCTION_WORKER = "\U0001f477\u200d\u2642\ufe0f" - MAN_CONSTRUCTION_WORKER_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fb\u200d\u2642\ufe0f" - MAN_CONSTRUCTION_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fc\u200d\u2642\ufe0f" - MAN_CONSTRUCTION_WORKER_MEDIUM_SKIN_TONE = "\U0001f477\U0001f3fd\u200d\u2642\ufe0f" - MAN_CONSTRUCTION_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f477\U0001f3fe\u200d\u2642\ufe0f" - MAN_CONSTRUCTION_WORKER_DARK_SKIN_TONE = "\U0001f477\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_CONSTRUCTION_WORKER = "\U0001f477\u200d\u2640\ufe0f" - WOMAN_CONSTRUCTION_WORKER_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_CONSTRUCTION_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_CONSTRUCTION_WORKER_MEDIUM_SKIN_TONE = "\U0001f477\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_CONSTRUCTION_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f477\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_CONSTRUCTION_WORKER_DARK_SKIN_TONE = "\U0001f477\U0001f3ff\u200d\u2640\ufe0f" - PRINCE = "\U0001f934" - PRINCE_LIGHT_SKIN_TONE = "\U0001f934\U0001f3fb" - PRINCE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f934\U0001f3fc" - PRINCE_MEDIUM_SKIN_TONE = "\U0001f934\U0001f3fd" - PRINCE_MEDIUM_DARK_SKIN_TONE = "\U0001f934\U0001f3fe" - PRINCE_DARK_SKIN_TONE = "\U0001f934\U0001f3ff" - PRINCESS = "\U0001f478" - PRINCESS_LIGHT_SKIN_TONE = "\U0001f478\U0001f3fb" - PRINCESS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f478\U0001f3fc" - PRINCESS_MEDIUM_SKIN_TONE = "\U0001f478\U0001f3fd" - PRINCESS_MEDIUM_DARK_SKIN_TONE = "\U0001f478\U0001f3fe" - PRINCESS_DARK_SKIN_TONE = "\U0001f478\U0001f3ff" - PERSON_WEARING_TURBAN = "\U0001f473" - PERSON_WEARING_TURBAN_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fb" - PERSON_WEARING_TURBAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fc" - PERSON_WEARING_TURBAN_MEDIUM_SKIN_TONE = "\U0001f473\U0001f3fd" - PERSON_WEARING_TURBAN_MEDIUM_DARK_SKIN_TONE = "\U0001f473\U0001f3fe" - PERSON_WEARING_TURBAN_DARK_SKIN_TONE = "\U0001f473\U0001f3ff" - MAN_WEARING_TURBAN = "\U0001f473\u200d\u2642\ufe0f" - MAN_WEARING_TURBAN_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fb\u200d\u2642\ufe0f" - MAN_WEARING_TURBAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fc\u200d\u2642\ufe0f" - MAN_WEARING_TURBAN_MEDIUM_SKIN_TONE = "\U0001f473\U0001f3fd\u200d\u2642\ufe0f" - MAN_WEARING_TURBAN_MEDIUM_DARK_SKIN_TONE = "\U0001f473\U0001f3fe\u200d\u2642\ufe0f" - MAN_WEARING_TURBAN_DARK_SKIN_TONE = "\U0001f473\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_WEARING_TURBAN = "\U0001f473\u200d\u2640\ufe0f" - WOMAN_WEARING_TURBAN_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_WEARING_TURBAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_WEARING_TURBAN_MEDIUM_SKIN_TONE = "\U0001f473\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_WEARING_TURBAN_MEDIUM_DARK_SKIN_TONE = "\U0001f473\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_WEARING_TURBAN_DARK_SKIN_TONE = "\U0001f473\U0001f3ff\u200d\u2640\ufe0f" - MAN_WITH_CHINESE_CAP = "\U0001f472" - MAN_WITH_CHINESE_CAP_LIGHT_SKIN_TONE = "\U0001f472\U0001f3fb" - MAN_WITH_CHINESE_CAP_MEDIUM_LIGHT_SKIN_TONE = "\U0001f472\U0001f3fc" - MAN_WITH_CHINESE_CAP_MEDIUM_SKIN_TONE = "\U0001f472\U0001f3fd" - MAN_WITH_CHINESE_CAP_MEDIUM_DARK_SKIN_TONE = "\U0001f472\U0001f3fe" - MAN_WITH_CHINESE_CAP_DARK_SKIN_TONE = "\U0001f472\U0001f3ff" - WOMAN_WITH_HEADSCARF = "\U0001f9d5" - PERSON_WITH_HEADSCARF_LIGHT_SKIN_TONE = "\U0001f9d5\U0001f3fb" - PERSON_WITH_HEADSCARF_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d5\U0001f3fc" - PERSON_WITH_HEADSCARF_MEDIUM_SKIN_TONE = "\U0001f9d5\U0001f3fd" - PERSON_WITH_HEADSCARF_MEDIUM_DARK_SKIN_TONE = "\U0001f9d5\U0001f3fe" - PERSON_WITH_HEADSCARF_DARK_SKIN_TONE = "\U0001f9d5\U0001f3ff" - MAN_BEARD = "\U0001f9d4" - BEARDED_PERSON_LIGHT_SKIN_TONE = "\U0001f9d4\U0001f3fb" - BEARDED_PERSON_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d4\U0001f3fc" - BEARDED_PERSON_MEDIUM_SKIN_TONE = "\U0001f9d4\U0001f3fd" - BEARDED_PERSON_MEDIUM_DARK_SKIN_TONE = "\U0001f9d4\U0001f3fe" - BEARDED_PERSON_DARK_SKIN_TONE = "\U0001f9d4\U0001f3ff" - PERSON_BLOND_HAIR = "\U0001f471" - BLOND_HAIRED_PERSON_LIGHT_SKIN_TONE = "\U0001f471\U0001f3fb" - BLOND_HAIRED_PERSON_MEDIUM_LIGHT_SKIN_TONE = "\U0001f471\U0001f3fc" - BLOND_HAIRED_PERSON_MEDIUM_SKIN_TONE = "\U0001f471\U0001f3fd" - BLOND_HAIRED_PERSON_MEDIUM_DARK_SKIN_TONE = "\U0001f471\U0001f3fe" - BLOND_HAIRED_PERSON_DARK_SKIN_TONE = "\U0001f471\U0001f3ff" - MAN_BLOND_HAIR = "\U0001f471\u200d\u2642\ufe0f" - BLOND_HAIRED_MAN_LIGHT_SKIN_TONE = "\U0001f471\U0001f3fb\u200d\u2642\ufe0f" - BLOND_HAIRED_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f471\U0001f3fc\u200d\u2642\ufe0f" - BLOND_HAIRED_MAN_MEDIUM_SKIN_TONE = "\U0001f471\U0001f3fd\u200d\u2642\ufe0f" - BLOND_HAIRED_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f471\U0001f3fe\u200d\u2642\ufe0f" - BLOND_HAIRED_MAN_DARK_SKIN_TONE = "\U0001f471\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_BLOND_HAIR = "\U0001f471\u200d\u2640\ufe0f" - BLOND_HAIRED_WOMAN_LIGHT_SKIN_TONE = "\U0001f471\U0001f3fb\u200d\u2640\ufe0f" - BLOND_HAIRED_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f471\U0001f3fc\u200d\u2640\ufe0f" - BLOND_HAIRED_WOMAN_MEDIUM_SKIN_TONE = "\U0001f471\U0001f3fd\u200d\u2640\ufe0f" - BLOND_HAIRED_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f471\U0001f3fe\u200d\u2640\ufe0f" - BLOND_HAIRED_WOMAN_DARK_SKIN_TONE = "\U0001f471\U0001f3ff\u200d\u2640\ufe0f" - MAN_RED_HAIRED = "\U0001f468\u200d\U0001f9b0" - MAN_RED_HAIRED_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f9b0" - MAN_RED_HAIRED_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f9b0" - MAN_RED_HAIRED_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f9b0" - MAN_RED_HAIRED_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f9b0" - MAN_RED_HAIRED_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f9b0" - WOMAN_RED_HAIRED = "\U0001f469\u200d\U0001f9b0" - WOMAN_RED_HAIRED_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f9b0" - WOMAN_RED_HAIRED_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f9b0" - WOMAN_RED_HAIRED_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f9b0" - WOMAN_RED_HAIRED_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f9b0" - WOMAN_RED_HAIRED_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f9b0" - MAN_CURLY_HAIRED = "\U0001f468\u200d\U0001f9b1" - MAN_CURLY_HAIRED_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f9b1" - MAN_CURLY_HAIRED_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f9b1" - MAN_CURLY_HAIRED_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f9b1" - MAN_CURLY_HAIRED_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f9b1" - MAN_CURLY_HAIRED_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f9b1" - WOMAN_CURLY_HAIRED = "\U0001f469\u200d\U0001f9b1" - WOMAN_CURLY_HAIRED_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f9b1" - WOMAN_CURLY_HAIRED_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f9b1" - WOMAN_CURLY_HAIRED_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f9b1" - WOMAN_CURLY_HAIRED_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f9b1" - WOMAN_CURLY_HAIRED_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f9b1" - MAN_BALD = "\U0001f468\u200d\U0001f9b2" - MAN_BALD_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f9b2" - MAN_BALD_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f9b2" - MAN_BALD_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f9b2" - MAN_BALD_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f9b2" - MAN_BALD_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f9b2" - WOMAN_BALD = "\U0001f469\u200d\U0001f9b2" - WOMAN_BALD_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f9b2" - WOMAN_BALD_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f9b2" - WOMAN_BALD_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f9b2" - WOMAN_BALD_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f9b2" - WOMAN_BALD_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f9b2" - MAN_WHITE_HAIRED = "\U0001f468\u200d\U0001f9b3" - MAN_WHITE_HAIRED_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f9b3" - MAN_WHITE_HAIRED_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f9b3" - MAN_WHITE_HAIRED_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f9b3" - MAN_WHITE_HAIRED_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f9b3" - MAN_WHITE_HAIRED_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f9b3" - WOMAN_WHITE_HAIRED = "\U0001f469\u200d\U0001f9b3" - WOMAN_WHITE_HAIRED_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f9b3" - WOMAN_WHITE_HAIRED_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f9b3" - WOMAN_WHITE_HAIRED_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f9b3" - WOMAN_WHITE_HAIRED_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f9b3" - WOMAN_WHITE_HAIRED_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f9b3" - MAN_IN_TUXEDO = "\U0001f935" - MAN_IN_TUXEDO_LIGHT_SKIN_TONE = "\U0001f935\U0001f3fb" - MAN_IN_TUXEDO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f935\U0001f3fc" - MAN_IN_TUXEDO_MEDIUM_SKIN_TONE = "\U0001f935\U0001f3fd" - MAN_IN_TUXEDO_MEDIUM_DARK_SKIN_TONE = "\U0001f935\U0001f3fe" - MAN_IN_TUXEDO_DARK_SKIN_TONE = "\U0001f935\U0001f3ff" - BRIDE_WITH_VEIL = "\U0001f470" - BRIDE_WITH_VEIL_LIGHT_SKIN_TONE = "\U0001f470\U0001f3fb" - BRIDE_WITH_VEIL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f470\U0001f3fc" - BRIDE_WITH_VEIL_MEDIUM_SKIN_TONE = "\U0001f470\U0001f3fd" - BRIDE_WITH_VEIL_MEDIUM_DARK_SKIN_TONE = "\U0001f470\U0001f3fe" - BRIDE_WITH_VEIL_DARK_SKIN_TONE = "\U0001f470\U0001f3ff" - PREGNANT_WOMAN = "\U0001f930" - PREGNANT_WOMAN_LIGHT_SKIN_TONE = "\U0001f930\U0001f3fb" - PREGNANT_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f930\U0001f3fc" - PREGNANT_WOMAN_MEDIUM_SKIN_TONE = "\U0001f930\U0001f3fd" - PREGNANT_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f930\U0001f3fe" - PREGNANT_WOMAN_DARK_SKIN_TONE = "\U0001f930\U0001f3ff" - BREAST_FEEDING = "\U0001f931" - BREAST_FEEDING_LIGHT_SKIN_TONE = "\U0001f931\U0001f3fb" - BREAST_FEEDING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f931\U0001f3fc" - BREAST_FEEDING_MEDIUM_SKIN_TONE = "\U0001f931\U0001f3fd" - BREAST_FEEDING_MEDIUM_DARK_SKIN_TONE = "\U0001f931\U0001f3fe" - BREAST_FEEDING_DARK_SKIN_TONE = "\U0001f931\U0001f3ff" - BABY_ANGEL = "\U0001f47c" - BABY_ANGEL_LIGHT_SKIN_TONE = "\U0001f47c\U0001f3fb" - BABY_ANGEL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f47c\U0001f3fc" - BABY_ANGEL_MEDIUM_SKIN_TONE = "\U0001f47c\U0001f3fd" - BABY_ANGEL_MEDIUM_DARK_SKIN_TONE = "\U0001f47c\U0001f3fe" - BABY_ANGEL_DARK_SKIN_TONE = "\U0001f47c\U0001f3ff" - SANTA_CLAUS = "\U0001f385" - SANTA_CLAUS_LIGHT_SKIN_TONE = "\U0001f385\U0001f3fb" - SANTA_CLAUS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f385\U0001f3fc" - SANTA_CLAUS_MEDIUM_SKIN_TONE = "\U0001f385\U0001f3fd" - SANTA_CLAUS_MEDIUM_DARK_SKIN_TONE = "\U0001f385\U0001f3fe" - SANTA_CLAUS_DARK_SKIN_TONE = "\U0001f385\U0001f3ff" - MRS_CLAUS = "\U0001f936" - MRS_CLAUS_LIGHT_SKIN_TONE = "\U0001f936\U0001f3fb" - MRS_CLAUS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f936\U0001f3fc" - MRS_CLAUS_MEDIUM_SKIN_TONE = "\U0001f936\U0001f3fd" - MRS_CLAUS_MEDIUM_DARK_SKIN_TONE = "\U0001f936\U0001f3fe" - MRS_CLAUS_DARK_SKIN_TONE = "\U0001f936\U0001f3ff" - SUPERHERO = "\U0001f9b8" - SUPERHERO_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fb" - SUPERHERO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fc" - SUPERHERO_MEDIUM_SKIN_TONE = "\U0001f9b8\U0001f3fd" - SUPERHERO_MEDIUM_DARK_SKIN_TONE = "\U0001f9b8\U0001f3fe" - SUPERHERO_DARK_SKIN_TONE = "\U0001f9b8\U0001f3ff" - WOMAN_SUPERHERO = "\U0001f9b8\u200d\u2640\ufe0f" - WOMAN_SUPERHERO_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_SUPERHERO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_SUPERHERO_MEDIUM_SKIN_TONE = "\U0001f9b8\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_SUPERHERO_MEDIUM_DARK_SKIN_TONE = "\U0001f9b8\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_SUPERHERO_DARK_SKIN_TONE = "\U0001f9b8\U0001f3ff\u200d\u2640\ufe0f" - MAN_SUPERHERO = "\U0001f9b8\u200d\u2642\ufe0f" - MAN_SUPERHERO_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fb\u200d\u2642\ufe0f" - MAN_SUPERHERO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fc\u200d\u2642\ufe0f" - MAN_SUPERHERO_MEDIUM_SKIN_TONE = "\U0001f9b8\U0001f3fd\u200d\u2642\ufe0f" - MAN_SUPERHERO_MEDIUM_DARK_SKIN_TONE = "\U0001f9b8\U0001f3fe\u200d\u2642\ufe0f" - WOMAN_WITH_BUNNY_EARS_TYPE_1_2 = "\U0001f46f\U0001f3fb" - MAN_SUPERHERO_DARK_SKIN_TONE = "\U0001f9b8\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_WITH_BUNNY_EARS_TYPE_3 = "\U0001f46f\U0001f3fc" - WOMAN_WITH_BUNNY_EARS_TYPE_4 = "\U0001f46f\U0001f3fd" - SUPERVILLAIN = "\U0001f9b9" - WOMAN_WITH_BUNNY_EARS_TYPE_5 = "\U0001f46f\U0001f3fe" - WOMAN_WITH_BUNNY_EARS_TYPE_6 = "\U0001f46f\U0001f3ff" - SUPERVILLAIN_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fb" - SUPERVILLAIN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fc" - MEN_WITH_BUNNY_EARS_PARTYING_TYPE_1_2 = "\U0001f46f\U0001f3fb\u200d\u2642\ufe0f" - SUPERVILLAIN_MEDIUM_SKIN_TONE = "\U0001f9b9\U0001f3fd" - MEN_WITH_BUNNY_EARS_PARTYING_TYPE_3 = "\U0001f46f\U0001f3fc\u200d\u2642\ufe0f" - SUPERVILLAIN_MEDIUM_DARK_SKIN_TONE = "\U0001f9b9\U0001f3fe" - MEN_WITH_BUNNY_EARS_PARTYING_TYPE_4 = "\U0001f46f\U0001f3fd\u200d\u2642\ufe0f" - SUPERVILLAIN_DARK_SKIN_TONE = "\U0001f9b9\U0001f3ff" - MEN_WITH_BUNNY_EARS_PARTYING_TYPE_5 = "\U0001f46f\U0001f3fe\u200d\u2642\ufe0f" - WOMAN_SUPERVILLAIN = "\U0001f9b9\u200d\u2640\ufe0f" - MEN_WITH_BUNNY_EARS_PARTYING_TYPE_6 = "\U0001f46f\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_SUPERVILLAIN_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fb\u200d\u2640\ufe0f" - WOMEN_WITH_BUNNY_EARS_PARTYING_TYPE_1_2 = "\U0001f46f\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_SUPERVILLAIN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fc\u200d\u2640\ufe0f" - WOMEN_WITH_BUNNY_EARS_PARTYING_TYPE_3 = "\U0001f46f\U0001f3fc\u200d\u2640\ufe0f" - WOMEN_WITH_BUNNY_EARS_PARTYING_TYPE_4 = "\U0001f46f\U0001f3fd\u200d\u2640\ufe0f" - WOMEN_WITH_BUNNY_EARS_PARTYING_TYPE_5 = "\U0001f46f\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_SUPERVILLAIN_MEDIUM_SKIN_TONE = "\U0001f9b9\U0001f3fd\u200d\u2640\ufe0f" - WOMEN_WITH_BUNNY_EARS_PARTYING_TYPE_6 = "\U0001f46f\U0001f3ff\u200d\u2640\ufe0f" - WOMAN_SUPERVILLAIN_MEDIUM_DARK_SKIN_TONE = "\U0001f9b9\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_SUPERVILLAIN_DARK_SKIN_TONE = "\U0001f9b9\U0001f3ff\u200d\u2640\ufe0f" - MAN_SUPERVILLAIN = "\U0001f9b9\u200d\u2642\ufe0f" - MAN_SUPERVILLAIN_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fb\u200d\u2642\ufe0f" - MAN_SUPERVILLAIN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fc\u200d\u2642\ufe0f" - MAN_SUPERVILLAIN_MEDIUM_SKIN_TONE = "\U0001f9b9\U0001f3fd\u200d\u2642\ufe0f" - MAN_AND_WOMAN_HOLDING_HANDS_TYPE_1_2 = "\U0001f46b\U0001f3fb" - MAN_AND_WOMAN_HOLDING_HANDS_TYPE_3 = "\U0001f46b\U0001f3fc" - MAN_SUPERVILLAIN_MEDIUM_DARK_SKIN_TONE = "\U0001f9b9\U0001f3fe\u200d\u2642\ufe0f" - MAN_AND_WOMAN_HOLDING_HANDS_TYPE_4 = "\U0001f46b\U0001f3fd" - MAN_AND_WOMAN_HOLDING_HANDS_TYPE_5 = "\U0001f46b\U0001f3fe" - MAN_SUPERVILLAIN_DARK_SKIN_TONE = "\U0001f9b9\U0001f3ff\u200d\u2642\ufe0f" - MAN_AND_WOMAN_HOLDING_HANDS_TYPE_6 = "\U0001f46b\U0001f3ff" - MAGE = "\U0001f9d9" - TWO_MEN_HOLDING_HANDS_TYPE_1_2 = "\U0001f46c\U0001f3fb" - TWO_MEN_HOLDING_HANDS_TYPE_3 = "\U0001f46c\U0001f3fc" - MAGE_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fb" - TWO_MEN_HOLDING_HANDS_TYPE_4 = "\U0001f46c\U0001f3fd" - MAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fc" - TWO_MEN_HOLDING_HANDS_TYPE_5 = "\U0001f46c\U0001f3fe" - MAGE_MEDIUM_SKIN_TONE = "\U0001f9d9\U0001f3fd" - TWO_MEN_HOLDING_HANDS_TYPE_6 = "\U0001f46c\U0001f3ff" - MAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f9d9\U0001f3fe" - MAGE_DARK_SKIN_TONE = "\U0001f9d9\U0001f3ff" - WOMAN_MAGE = "\U0001f9d9\u200d\u2640\ufe0f" - TWO_WOMEN_HOLDING_HANDS_TYPE_1_2 = "\U0001f46d\U0001f3fb" - TWO_WOMEN_HOLDING_HANDS_TYPE_3 = "\U0001f46d\U0001f3fc" - WOMAN_MAGE_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fb\u200d\u2640\ufe0f" - TWO_WOMEN_HOLDING_HANDS_TYPE_4 = "\U0001f46d\U0001f3fd" - TWO_WOMEN_HOLDING_HANDS_TYPE_5 = "\U0001f46d\U0001f3fe" - WOMAN_MAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fc\u200d\u2640\ufe0f" - TWO_WOMEN_HOLDING_HANDS_TYPE_6 = "\U0001f46d\U0001f3ff" - WOMAN_MAGE_MEDIUM_SKIN_TONE = "\U0001f9d9\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_MAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f9d9\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_MAGE_DARK_SKIN_TONE = "\U0001f9d9\U0001f3ff\u200d\u2640\ufe0f" - MAN_MAGE = "\U0001f9d9\u200d\u2642\ufe0f" - MAN_MAGE_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fb\u200d\u2642\ufe0f" - FAMILY_TYPE_1_2 = "\U0001f46a\U0001f3fb" - FAMILY_TYPE_3 = "\U0001f46a\U0001f3fc" - MAN_MAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fc\u200d\u2642\ufe0f" - FAMILY_TYPE_4 = "\U0001f46a\U0001f3fd" - FAMILY_TYPE_5 = "\U0001f46a\U0001f3fe" - MAN_MAGE_MEDIUM_SKIN_TONE = "\U0001f9d9\U0001f3fd\u200d\u2642\ufe0f" - FAMILY_TYPE_6 = "\U0001f46a\U0001f3ff" - MAN_MAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f9d9\U0001f3fe\u200d\u2642\ufe0f" - MAN_MAGE_DARK_SKIN_TONE = "\U0001f9d9\U0001f3ff\u200d\u2642\ufe0f" - FAIRY = "\U0001f9da" - FAIRY_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fb" - FAIRY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fc" - FAIRY_MEDIUM_SKIN_TONE = "\U0001f9da\U0001f3fd" - FAIRY_MEDIUM_DARK_SKIN_TONE = "\U0001f9da\U0001f3fe" - FAIRY_DARK_SKIN_TONE = "\U0001f9da\U0001f3ff" - WOMAN_FAIRY = "\U0001f9da\u200d\u2640\ufe0f" - WOMAN_FAIRY_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_FAIRY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_FAIRY_MEDIUM_SKIN_TONE = "\U0001f9da\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_FAIRY_MEDIUM_DARK_SKIN_TONE = "\U0001f9da\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_FAIRY_DARK_SKIN_TONE = "\U0001f9da\U0001f3ff\u200d\u2640\ufe0f" - MAN_FAIRY = "\U0001f9da\u200d\u2642\ufe0f" - MAN_FAIRY_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fb\u200d\u2642\ufe0f" - MAN_FAIRY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fc\u200d\u2642\ufe0f" - MAN_FAIRY_MEDIUM_SKIN_TONE = "\U0001f9da\U0001f3fd\u200d\u2642\ufe0f" - MAN_FAIRY_MEDIUM_DARK_SKIN_TONE = "\U0001f9da\U0001f3fe\u200d\u2642\ufe0f" - MAN_FAIRY_DARK_SKIN_TONE = "\U0001f9da\U0001f3ff\u200d\u2642\ufe0f" - VAMPIRE = "\U0001f9db" - VAMPIRE_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fb" - VAMPIRE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fc" - VAMPIRE_MEDIUM_SKIN_TONE = "\U0001f9db\U0001f3fd" - VAMPIRE_MEDIUM_DARK_SKIN_TONE = "\U0001f9db\U0001f3fe" - VAMPIRE_DARK_SKIN_TONE = "\U0001f9db\U0001f3ff" - WOMAN_VAMPIRE = "\U0001f9db\u200d\u2640\ufe0f" - WOMAN_VAMPIRE_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_VAMPIRE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_VAMPIRE_MEDIUM_SKIN_TONE = "\U0001f9db\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_VAMPIRE_MEDIUM_DARK_SKIN_TONE = "\U0001f9db\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_VAMPIRE_DARK_SKIN_TONE = "\U0001f9db\U0001f3ff\u200d\u2640\ufe0f" - MAN_VAMPIRE = "\U0001f9db\u200d\u2642\ufe0f" - MAN_VAMPIRE_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fb\u200d\u2642\ufe0f" - MAN_VAMPIRE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fc\u200d\u2642\ufe0f" - MAN_VAMPIRE_MEDIUM_SKIN_TONE = "\U0001f9db\U0001f3fd\u200d\u2642\ufe0f" - MAN_VAMPIRE_MEDIUM_DARK_SKIN_TONE = "\U0001f9db\U0001f3fe\u200d\u2642\ufe0f" - MAN_VAMPIRE_DARK_SKIN_TONE = "\U0001f9db\U0001f3ff\u200d\u2642\ufe0f" - MERPERSON = "\U0001f9dc" - MERPERSON_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fb" - MERPERSON_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fc" - MERPERSON_MEDIUM_SKIN_TONE = "\U0001f9dc\U0001f3fd" - MERPERSON_MEDIUM_DARK_SKIN_TONE = "\U0001f9dc\U0001f3fe" - MERPERSON_DARK_SKIN_TONE = "\U0001f9dc\U0001f3ff" - MERMAID = "\U0001f9dc\u200d\u2640\ufe0f" - MERMAID_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fb\u200d\u2640\ufe0f" - MERMAID_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fc\u200d\u2640\ufe0f" - MERMAID_MEDIUM_SKIN_TONE = "\U0001f9dc\U0001f3fd\u200d\u2640\ufe0f" - MERMAID_MEDIUM_DARK_SKIN_TONE = "\U0001f9dc\U0001f3fe\u200d\u2640\ufe0f" - MERMAID_DARK_SKIN_TONE = "\U0001f9dc\U0001f3ff\u200d\u2640\ufe0f" - MERMAN = "\U0001f9dc\u200d\u2642\ufe0f" - MERMAN_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fb\u200d\u2642\ufe0f" - MERMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fc\u200d\u2642\ufe0f" - MERMAN_MEDIUM_SKIN_TONE = "\U0001f9dc\U0001f3fd\u200d\u2642\ufe0f" - MERMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f9dc\U0001f3fe\u200d\u2642\ufe0f" - MERMAN_DARK_SKIN_TONE = "\U0001f9dc\U0001f3ff\u200d\u2642\ufe0f" - ELF = "\U0001f9dd" - ELF_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fb" - ELF_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fc" - ELF_MEDIUM_SKIN_TONE = "\U0001f9dd\U0001f3fd" - ELF_MEDIUM_DARK_SKIN_TONE = "\U0001f9dd\U0001f3fe" - ELF_DARK_SKIN_TONE = "\U0001f9dd\U0001f3ff" - WOMAN_ELF = "\U0001f9dd\u200d\u2640\ufe0f" - WOMAN_ELF_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_ELF_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_ELF_MEDIUM_SKIN_TONE = "\U0001f9dd\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_ELF_MEDIUM_DARK_SKIN_TONE = "\U0001f9dd\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_ELF_DARK_SKIN_TONE = "\U0001f9dd\U0001f3ff\u200d\u2640\ufe0f" - MAN_ELF = "\U0001f9dd\u200d\u2642\ufe0f" - MAN_ELF_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fb\u200d\u2642\ufe0f" - MAN_ELF_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fc\u200d\u2642\ufe0f" - MAN_ELF_MEDIUM_SKIN_TONE = "\U0001f9dd\U0001f3fd\u200d\u2642\ufe0f" - MAN_ELF_MEDIUM_DARK_SKIN_TONE = "\U0001f9dd\U0001f3fe\u200d\u2642\ufe0f" - MAN_ELF_DARK_SKIN_TONE = "\U0001f9dd\U0001f3ff\u200d\u2642\ufe0f" - GENIE = "\U0001f9de" - WOMAN_GENIE = "\U0001f9de\u200d\u2640\ufe0f" - MAN_GENIE = "\U0001f9de\u200d\u2642\ufe0f" - ZOMBIE = "\U0001f9df" - ZOMBIE_LIGHT_SKIN_TONE = "\U0001f9df\U0001f3fb" - ZOMBIE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9df\U0001f3fc" - ZOMBIE_MEDIUM_SKIN_TONE = "\U0001f9df\U0001f3fd" - ZOMBIE_MEDIUM_DARK_SKIN_TONE = "\U0001f9df\U0001f3fe" - ZOMBIE_DARK_SKIN_TONE = "\U0001f9df\U0001f3ff" - WOMAN_ZOMBIE = "\U0001f9df\u200d\u2640\ufe0f" - MAN_ZOMBIE = "\U0001f9df\u200d\u2642\ufe0f" - PERSON_FROWNING = "\U0001f64d" - PERSON_FROWNING_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fb" - PERSON_FROWNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fc" - PERSON_FROWNING_MEDIUM_SKIN_TONE = "\U0001f64d\U0001f3fd" - PERSON_FROWNING_MEDIUM_DARK_SKIN_TONE = "\U0001f64d\U0001f3fe" - PERSON_FROWNING_DARK_SKIN_TONE = "\U0001f64d\U0001f3ff" - MAN_FROWNING = "\U0001f64d\u200d\u2642\ufe0f" - MAN_FROWNING_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fb\u200d\u2642\ufe0f" - MAN_FROWNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fc\u200d\u2642\ufe0f" - MAN_FROWNING_MEDIUM_SKIN_TONE = "\U0001f64d\U0001f3fd\u200d\u2642\ufe0f" - MAN_FROWNING_MEDIUM_DARK_SKIN_TONE = "\U0001f64d\U0001f3fe\u200d\u2642\ufe0f" - MAN_FROWNING_DARK_SKIN_TONE = "\U0001f64d\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_FROWNING = "\U0001f64d\u200d\u2640\ufe0f" - WOMAN_FROWNING_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_FROWNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_FROWNING_MEDIUM_SKIN_TONE = "\U0001f64d\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_FROWNING_MEDIUM_DARK_SKIN_TONE = "\U0001f64d\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_FROWNING_DARK_SKIN_TONE = "\U0001f64d\U0001f3ff\u200d\u2640\ufe0f" - PERSON_POUTING = "\U0001f64e" - PERSON_POUTING_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fb" - PERSON_POUTING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fc" - PERSON_POUTING_MEDIUM_SKIN_TONE = "\U0001f64e\U0001f3fd" - PERSON_POUTING_MEDIUM_DARK_SKIN_TONE = "\U0001f64e\U0001f3fe" - PERSON_POUTING_DARK_SKIN_TONE = "\U0001f64e\U0001f3ff" - MAN_POUTING = "\U0001f64e\u200d\u2642\ufe0f" - MAN_POUTING_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fb\u200d\u2642\ufe0f" - MAN_POUTING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fc\u200d\u2642\ufe0f" - MAN_POUTING_MEDIUM_SKIN_TONE = "\U0001f64e\U0001f3fd\u200d\u2642\ufe0f" - MAN_POUTING_MEDIUM_DARK_SKIN_TONE = "\U0001f64e\U0001f3fe\u200d\u2642\ufe0f" - MAN_POUTING_DARK_SKIN_TONE = "\U0001f64e\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_POUTING = "\U0001f64e\u200d\u2640\ufe0f" - WOMAN_POUTING_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_POUTING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_POUTING_MEDIUM_SKIN_TONE = "\U0001f64e\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_POUTING_MEDIUM_DARK_SKIN_TONE = "\U0001f64e\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_POUTING_DARK_SKIN_TONE = "\U0001f64e\U0001f3ff\u200d\u2640\ufe0f" - PERSON_GESTURING_NO = "\U0001f645" - PERSON_GESTURING_NO_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fb" - PERSON_GESTURING_NO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fc" - PERSON_GESTURING_NO_MEDIUM_SKIN_TONE = "\U0001f645\U0001f3fd" - PERSON_GESTURING_NO_MEDIUM_DARK_SKIN_TONE = "\U0001f645\U0001f3fe" - PERSON_GESTURING_NO_DARK_SKIN_TONE = "\U0001f645\U0001f3ff" - MAN_GESTURING_NO = "\U0001f645\u200d\u2642\ufe0f" - MAN_GESTURING_NO_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fb\u200d\u2642\ufe0f" - MAN_GESTURING_NO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fc\u200d\u2642\ufe0f" - HANDSHAKE_TYPE_1_2 = "\U0001f91d\U0001f3fb" - HANDSHAKE_TYPE_3 = "\U0001f91d\U0001f3fc" - MAN_GESTURING_NO_MEDIUM_SKIN_TONE = "\U0001f645\U0001f3fd\u200d\u2642\ufe0f" - HANDSHAKE_TYPE_4 = "\U0001f91d\U0001f3fd" - HANDSHAKE_TYPE_5 = "\U0001f91d\U0001f3fe" - MAN_GESTURING_NO_MEDIUM_DARK_SKIN_TONE = "\U0001f645\U0001f3fe\u200d\u2642\ufe0f" - HANDSHAKE_TYPE_6 = "\U0001f91d\U0001f3ff" - MAN_GESTURING_NO_DARK_SKIN_TONE = "\U0001f645\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_GESTURING_NO = "\U0001f645\u200d\u2640\ufe0f" - WOMAN_GESTURING_NO_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_GESTURING_NO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_GESTURING_NO_MEDIUM_SKIN_TONE = "\U0001f645\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_GESTURING_NO_MEDIUM_DARK_SKIN_TONE = "\U0001f645\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_GESTURING_NO_DARK_SKIN_TONE = "\U0001f645\U0001f3ff\u200d\u2640\ufe0f" - PERSON_GESTURING_OK = "\U0001f646" - PERSON_GESTURING_OK_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fb" - PERSON_GESTURING_OK_MEDIUM_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fc" - PERSON_GESTURING_OK_MEDIUM_SKIN_TONE = "\U0001f646\U0001f3fd" - PERSON_GESTURING_OK_MEDIUM_DARK_SKIN_TONE = "\U0001f646\U0001f3fe" - PERSON_GESTURING_OK_DARK_SKIN_TONE = "\U0001f646\U0001f3ff" - MAN_GESTURING_OK = "\U0001f646\u200d\u2642\ufe0f" - MAN_GESTURING_OK_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fb\u200d\u2642\ufe0f" - MAN_GESTURING_OK_MEDIUM_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fc\u200d\u2642\ufe0f" - MAN_GESTURING_OK_MEDIUM_SKIN_TONE = "\U0001f646\U0001f3fd\u200d\u2642\ufe0f" - MAN_GESTURING_OK_MEDIUM_DARK_SKIN_TONE = "\U0001f646\U0001f3fe\u200d\u2642\ufe0f" - MAN_GESTURING_OK_DARK_SKIN_TONE = "\U0001f646\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_GESTURING_OK = "\U0001f646\u200d\u2640\ufe0f" - WOMAN_GESTURING_OK_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_GESTURING_OK_MEDIUM_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_GESTURING_OK_MEDIUM_SKIN_TONE = "\U0001f646\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_GESTURING_OK_MEDIUM_DARK_SKIN_TONE = "\U0001f646\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_GESTURING_OK_DARK_SKIN_TONE = "\U0001f646\U0001f3ff\u200d\u2640\ufe0f" - PERSON_TIPPING_HAND = "\U0001f481" - PERSON_TIPPING_HAND_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fb" - PERSON_TIPPING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fc" - PERSON_TIPPING_HAND_MEDIUM_SKIN_TONE = "\U0001f481\U0001f3fd" - PERSON_TIPPING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f481\U0001f3fe" - PERSON_TIPPING_HAND_DARK_SKIN_TONE = "\U0001f481\U0001f3ff" - MAN_TIPPING_HAND = "\U0001f481\u200d\u2642\ufe0f" - MAN_TIPPING_HAND_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fb\u200d\u2642\ufe0f" - MAN_TIPPING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fc\u200d\u2642\ufe0f" - MAN_TIPPING_HAND_MEDIUM_SKIN_TONE = "\U0001f481\U0001f3fd\u200d\u2642\ufe0f" - MAN_TIPPING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f481\U0001f3fe\u200d\u2642\ufe0f" - MAN_TIPPING_HAND_DARK_SKIN_TONE = "\U0001f481\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_TIPPING_HAND = "\U0001f481\u200d\u2640\ufe0f" - WOMAN_TIPPING_HAND_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_TIPPING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_TIPPING_HAND_MEDIUM_SKIN_TONE = "\U0001f481\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_TIPPING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f481\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_TIPPING_HAND_DARK_SKIN_TONE = "\U0001f481\U0001f3ff\u200d\u2640\ufe0f" - PERSON_RAISING_HAND = "\U0001f64b" - PERSON_RAISING_HAND_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fb" - PERSON_RAISING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fc" - PERSON_RAISING_HAND_MEDIUM_SKIN_TONE = "\U0001f64b\U0001f3fd" - PERSON_RAISING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f64b\U0001f3fe" - PERSON_RAISING_HAND_DARK_SKIN_TONE = "\U0001f64b\U0001f3ff" - MAN_RAISING_HAND = "\U0001f64b\u200d\u2642\ufe0f" - MAN_RAISING_HAND_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fb\u200d\u2642\ufe0f" - MAN_RAISING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fc\u200d\u2642\ufe0f" - MAN_RAISING_HAND_MEDIUM_SKIN_TONE = "\U0001f64b\U0001f3fd\u200d\u2642\ufe0f" - MAN_RAISING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f64b\U0001f3fe\u200d\u2642\ufe0f" - MAN_RAISING_HAND_DARK_SKIN_TONE = "\U0001f64b\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_RAISING_HAND = "\U0001f64b\u200d\u2640\ufe0f" - WOMAN_RAISING_HAND_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_RAISING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_RAISING_HAND_MEDIUM_SKIN_TONE = "\U0001f64b\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_RAISING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f64b\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_RAISING_HAND_DARK_SKIN_TONE = "\U0001f64b\U0001f3ff\u200d\u2640\ufe0f" - PERSON_BOWING = "\U0001f647" - PERSON_BOWING_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fb" - PERSON_BOWING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fc" - PERSON_BOWING_MEDIUM_SKIN_TONE = "\U0001f647\U0001f3fd" - PERSON_BOWING_MEDIUM_DARK_SKIN_TONE = "\U0001f647\U0001f3fe" - PERSON_BOWING_DARK_SKIN_TONE = "\U0001f647\U0001f3ff" - MAN_BOWING = "\U0001f647\u200d\u2642\ufe0f" - MAN_BOWING_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fb\u200d\u2642\ufe0f" - MAN_BOWING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fc\u200d\u2642\ufe0f" - MAN_BOWING_MEDIUM_SKIN_TONE = "\U0001f647\U0001f3fd\u200d\u2642\ufe0f" - MAN_BOWING_MEDIUM_DARK_SKIN_TONE = "\U0001f647\U0001f3fe\u200d\u2642\ufe0f" - MAN_BOWING_DARK_SKIN_TONE = "\U0001f647\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_BOWING = "\U0001f647\u200d\u2640\ufe0f" - WOMAN_BOWING_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_BOWING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_BOWING_MEDIUM_SKIN_TONE = "\U0001f647\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_BOWING_MEDIUM_DARK_SKIN_TONE = "\U0001f647\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_BOWING_DARK_SKIN_TONE = "\U0001f647\U0001f3ff\u200d\u2640\ufe0f" - PERSON_FACEPALMING = "\U0001f926" - PERSON_FACEPALMING_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fb" - PERSON_FACEPALMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fc" - PERSON_FACEPALMING_MEDIUM_SKIN_TONE = "\U0001f926\U0001f3fd" - PERSON_FACEPALMING_MEDIUM_DARK_SKIN_TONE = "\U0001f926\U0001f3fe" - PERSON_FACEPALMING_DARK_SKIN_TONE = "\U0001f926\U0001f3ff" - MAN_FACEPALMING = "\U0001f926\u200d\u2642\ufe0f" - MAN_FACEPALMING_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fb\u200d\u2642\ufe0f" - MAN_FACEPALMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fc\u200d\u2642\ufe0f" - MAN_FACEPALMING_MEDIUM_SKIN_TONE = "\U0001f926\U0001f3fd\u200d\u2642\ufe0f" - MAN_FACEPALMING_MEDIUM_DARK_SKIN_TONE = "\U0001f926\U0001f3fe\u200d\u2642\ufe0f" - MAN_FACEPALMING_DARK_SKIN_TONE = "\U0001f926\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_FACEPALMING = "\U0001f926\u200d\u2640\ufe0f" - WOMAN_FACEPALMING_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_FACEPALMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_FACEPALMING_MEDIUM_SKIN_TONE = "\U0001f926\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_FACEPALMING_MEDIUM_DARK_SKIN_TONE = "\U0001f926\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_FACEPALMING_DARK_SKIN_TONE = "\U0001f926\U0001f3ff\u200d\u2640\ufe0f" - PERSON_SHRUGGING = "\U0001f937" - PERSON_SHRUGGING_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fb" - PERSON_SHRUGGING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fc" - PERSON_SHRUGGING_MEDIUM_SKIN_TONE = "\U0001f937\U0001f3fd" - PERSON_SHRUGGING_MEDIUM_DARK_SKIN_TONE = "\U0001f937\U0001f3fe" - PERSON_SHRUGGING_DARK_SKIN_TONE = "\U0001f937\U0001f3ff" - MAN_SHRUGGING = "\U0001f937\u200d\u2642\ufe0f" - MAN_SHRUGGING_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fb\u200d\u2642\ufe0f" - MAN_SHRUGGING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fc\u200d\u2642\ufe0f" - MAN_SHRUGGING_MEDIUM_SKIN_TONE = "\U0001f937\U0001f3fd\u200d\u2642\ufe0f" - MAN_SHRUGGING_MEDIUM_DARK_SKIN_TONE = "\U0001f937\U0001f3fe\u200d\u2642\ufe0f" - MAN_SHRUGGING_DARK_SKIN_TONE = "\U0001f937\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_SHRUGGING = "\U0001f937\u200d\u2640\ufe0f" - WOMAN_SHRUGGING_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_SHRUGGING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_SHRUGGING_MEDIUM_SKIN_TONE = "\U0001f937\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_SHRUGGING_MEDIUM_DARK_SKIN_TONE = "\U0001f937\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_SHRUGGING_DARK_SKIN_TONE = "\U0001f937\U0001f3ff\u200d\u2640\ufe0f" - PERSON_GETTING_MASSAGE = "\U0001f486" - PERSON_GETTING_MASSAGE_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fb" - PERSON_GETTING_MASSAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fc" - PERSON_GETTING_MASSAGE_MEDIUM_SKIN_TONE = "\U0001f486\U0001f3fd" - PERSON_GETTING_MASSAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f486\U0001f3fe" - PERSON_GETTING_MASSAGE_DARK_SKIN_TONE = "\U0001f486\U0001f3ff" - MAN_GETTING_MASSAGE = "\U0001f486\u200d\u2642\ufe0f" - MAN_GETTING_MASSAGE_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fb\u200d\u2642\ufe0f" - MAN_GETTING_MASSAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fc\u200d\u2642\ufe0f" - MAN_GETTING_MASSAGE_MEDIUM_SKIN_TONE = "\U0001f486\U0001f3fd\u200d\u2642\ufe0f" - MAN_GETTING_MASSAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f486\U0001f3fe\u200d\u2642\ufe0f" - MAN_GETTING_MASSAGE_DARK_SKIN_TONE = "\U0001f486\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_GETTING_MASSAGE = "\U0001f486\u200d\u2640\ufe0f" - WOMAN_GETTING_MASSAGE_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_GETTING_MASSAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_GETTING_MASSAGE_MEDIUM_SKIN_TONE = "\U0001f486\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_GETTING_MASSAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f486\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_GETTING_MASSAGE_DARK_SKIN_TONE = "\U0001f486\U0001f3ff\u200d\u2640\ufe0f" - PERSON_GETTING_HAIRCUT = "\U0001f487" - PERSON_GETTING_HAIRCUT_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fb" - PERSON_GETTING_HAIRCUT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fc" - PERSON_GETTING_HAIRCUT_MEDIUM_SKIN_TONE = "\U0001f487\U0001f3fd" - PERSON_GETTING_HAIRCUT_MEDIUM_DARK_SKIN_TONE = "\U0001f487\U0001f3fe" - PERSON_GETTING_HAIRCUT_DARK_SKIN_TONE = "\U0001f487\U0001f3ff" - MAN_GETTING_HAIRCUT = "\U0001f487\u200d\u2642\ufe0f" - MAN_GETTING_HAIRCUT_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fb\u200d\u2642\ufe0f" - MAN_GETTING_HAIRCUT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fc\u200d\u2642\ufe0f" - MAN_GETTING_HAIRCUT_MEDIUM_SKIN_TONE = "\U0001f487\U0001f3fd\u200d\u2642\ufe0f" - MAN_GETTING_HAIRCUT_MEDIUM_DARK_SKIN_TONE = "\U0001f487\U0001f3fe\u200d\u2642\ufe0f" - MAN_GETTING_HAIRCUT_DARK_SKIN_TONE = "\U0001f487\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_GETTING_HAIRCUT = "\U0001f487\u200d\u2640\ufe0f" - WOMAN_GETTING_HAIRCUT_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_GETTING_HAIRCUT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_GETTING_HAIRCUT_MEDIUM_SKIN_TONE = "\U0001f487\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_GETTING_HAIRCUT_MEDIUM_DARK_SKIN_TONE = "\U0001f487\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_GETTING_HAIRCUT_DARK_SKIN_TONE = "\U0001f487\U0001f3ff\u200d\u2640\ufe0f" - PERSON_WALKING = "\U0001f6b6" - PERSON_WALKING_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fb" - PERSON_WALKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fc" - PERSON_WALKING_MEDIUM_SKIN_TONE = "\U0001f6b6\U0001f3fd" - PERSON_WALKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b6\U0001f3fe" - PERSON_WALKING_DARK_SKIN_TONE = "\U0001f6b6\U0001f3ff" - MAN_WALKING = "\U0001f6b6\u200d\u2642\ufe0f" - MAN_WALKING_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fb\u200d\u2642\ufe0f" - MAN_WALKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fc\u200d\u2642\ufe0f" - MAN_WALKING_MEDIUM_SKIN_TONE = "\U0001f6b6\U0001f3fd\u200d\u2642\ufe0f" - MAN_WALKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b6\U0001f3fe\u200d\u2642\ufe0f" - MAN_WALKING_DARK_SKIN_TONE = "\U0001f6b6\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_WALKING = "\U0001f6b6\u200d\u2640\ufe0f" - WOMAN_WALKING_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_WALKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_WALKING_MEDIUM_SKIN_TONE = "\U0001f6b6\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_WALKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b6\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_WALKING_DARK_SKIN_TONE = "\U0001f6b6\U0001f3ff\u200d\u2640\ufe0f" - PERSON_RUNNING = "\U0001f3c3" - PERSON_RUNNING_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fb" - PERSON_RUNNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fc" - PERSON_RUNNING_MEDIUM_SKIN_TONE = "\U0001f3c3\U0001f3fd" - PERSON_RUNNING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c3\U0001f3fe" - PERSON_RUNNING_DARK_SKIN_TONE = "\U0001f3c3\U0001f3ff" - MAN_RUNNING = "\U0001f3c3\u200d\u2642\ufe0f" - MAN_RUNNING_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fb\u200d\u2642\ufe0f" - MAN_RUNNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fc\u200d\u2642\ufe0f" - MAN_RUNNING_MEDIUM_SKIN_TONE = "\U0001f3c3\U0001f3fd\u200d\u2642\ufe0f" - MAN_RUNNING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c3\U0001f3fe\u200d\u2642\ufe0f" - MAN_RUNNING_DARK_SKIN_TONE = "\U0001f3c3\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_RUNNING = "\U0001f3c3\u200d\u2640\ufe0f" - WOMAN_RUNNING_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_RUNNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_RUNNING_MEDIUM_SKIN_TONE = "\U0001f3c3\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_RUNNING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c3\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_RUNNING_DARK_SKIN_TONE = "\U0001f3c3\U0001f3ff\u200d\u2640\ufe0f" - WOMAN_DANCING = "\U0001f483" - WOMAN_DANCING_LIGHT_SKIN_TONE = "\U0001f483\U0001f3fb" - WOMAN_DANCING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f483\U0001f3fc" - WOMAN_DANCING_MEDIUM_SKIN_TONE = "\U0001f483\U0001f3fd" - WOMAN_DANCING_MEDIUM_DARK_SKIN_TONE = "\U0001f483\U0001f3fe" - WOMAN_DANCING_DARK_SKIN_TONE = "\U0001f483\U0001f3ff" - MAN_DANCING = "\U0001f57a" - MAN_DANCING_LIGHT_SKIN_TONE = "\U0001f57a\U0001f3fb" - MAN_DANCING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f57a\U0001f3fc" - MAN_DANCING_MEDIUM_SKIN_TONE = "\U0001f57a\U0001f3fd" - MAN_DANCING_MEDIUM_DARK_SKIN_TONE = "\U0001f57a\U0001f3fe" - MAN_DANCING_DARK_SKIN_TONE = "\U0001f57a\U0001f3ff" - PEOPLE_WITH_BUNNY_EARS = "\U0001f46f" - MEN_WITH_BUNNY_EARS = "\U0001f46f\u200d\u2642\ufe0f" - WOMEN_WITH_BUNNY_EARS = "\U0001f46f\u200d\u2640\ufe0f" - PERSON_IN_STEAMY_ROOM = "\U0001f9d6" - PERSON_IN_STEAMY_ROOM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fb" - PERSON_IN_STEAMY_ROOM_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fc" - PERSON_IN_STEAMY_ROOM_MEDIUM_SKIN_TONE = "\U0001f9d6\U0001f3fd" - PERSON_IN_STEAMY_ROOM_MEDIUM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3fe" - PERSON_IN_STEAMY_ROOM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3ff" - WOMAN_IN_STEAMY_ROOM = "\U0001f9d6\u200d\u2640\ufe0f" - WOMAN_IN_STEAMY_ROOM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_IN_STEAMY_ROOM_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_IN_STEAMY_ROOM_MEDIUM_SKIN_TONE = "\U0001f9d6\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_IN_STEAMY_ROOM_MEDIUM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_IN_STEAMY_ROOM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3ff\u200d\u2640\ufe0f" - MAN_IN_STEAMY_ROOM = "\U0001f9d6\u200d\u2642\ufe0f" - MAN_IN_STEAMY_ROOM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fb\u200d\u2642\ufe0f" - MAN_IN_STEAMY_ROOM_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fc\u200d\u2642\ufe0f" - MAN_IN_STEAMY_ROOM_MEDIUM_SKIN_TONE = "\U0001f9d6\U0001f3fd\u200d\u2642\ufe0f" - MAN_IN_STEAMY_ROOM_MEDIUM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3fe\u200d\u2642\ufe0f" - MAN_IN_STEAMY_ROOM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3ff\u200d\u2642\ufe0f" - PERSON_CLIMBING = "\U0001f9d7" - PERSON_CLIMBING_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fb" - PERSON_CLIMBING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fc" - PERSON_CLIMBING_MEDIUM_SKIN_TONE = "\U0001f9d7\U0001f3fd" - PERSON_CLIMBING_MEDIUM_DARK_SKIN_TONE = "\U0001f9d7\U0001f3fe" - PERSON_CLIMBING_DARK_SKIN_TONE = "\U0001f9d7\U0001f3ff" - WOMAN_CLIMBING = "\U0001f9d7\u200d\u2640\ufe0f" - WOMAN_CLIMBING_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_CLIMBING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_CLIMBING_MEDIUM_SKIN_TONE = "\U0001f9d7\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_CLIMBING_MEDIUM_DARK_SKIN_TONE = "\U0001f9d7\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_CLIMBING_DARK_SKIN_TONE = "\U0001f9d7\U0001f3ff\u200d\u2640\ufe0f" - MAN_CLIMBING = "\U0001f9d7\u200d\u2642\ufe0f" - MAN_CLIMBING_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fb\u200d\u2642\ufe0f" - MAN_CLIMBING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fc\u200d\u2642\ufe0f" - MAN_CLIMBING_MEDIUM_SKIN_TONE = "\U0001f9d7\U0001f3fd\u200d\u2642\ufe0f" - MAN_CLIMBING_MEDIUM_DARK_SKIN_TONE = "\U0001f9d7\U0001f3fe\u200d\u2642\ufe0f" - MAN_CLIMBING_DARK_SKIN_TONE = "\U0001f9d7\U0001f3ff\u200d\u2642\ufe0f" - PERSON_IN_LOTUS_POSITION = "\U0001f9d8" - PERSON_IN_LOTUS_POSITION_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fb" - PERSON_IN_LOTUS_POSITION_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fc" - PERSON_IN_LOTUS_POSITION_MEDIUM_SKIN_TONE = "\U0001f9d8\U0001f3fd" - PERSON_IN_LOTUS_POSITION_MEDIUM_DARK_SKIN_TONE = "\U0001f9d8\U0001f3fe" - PERSON_IN_LOTUS_POSITION_DARK_SKIN_TONE = "\U0001f9d8\U0001f3ff" - WOMAN_IN_LOTUS_POSITION = "\U0001f9d8\u200d\u2640\ufe0f" - WOMAN_IN_LOTUS_POSITION_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_IN_LOTUS_POSITION_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_IN_LOTUS_POSITION_MEDIUM_SKIN_TONE = "\U0001f9d8\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_IN_LOTUS_POSITION_MEDIUM_DARK_SKIN_TONE = "\U0001f9d8\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_IN_LOTUS_POSITION_DARK_SKIN_TONE = "\U0001f9d8\U0001f3ff\u200d\u2640\ufe0f" - MAN_IN_LOTUS_POSITION = "\U0001f9d8\u200d\u2642\ufe0f" - MAN_IN_LOTUS_POSITION_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fb\u200d\u2642\ufe0f" - MAN_IN_LOTUS_POSITION_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fc\u200d\u2642\ufe0f" - MAN_IN_LOTUS_POSITION_MEDIUM_SKIN_TONE = "\U0001f9d8\U0001f3fd\u200d\u2642\ufe0f" - MAN_IN_LOTUS_POSITION_MEDIUM_DARK_SKIN_TONE = "\U0001f9d8\U0001f3fe\u200d\u2642\ufe0f" - MAN_IN_LOTUS_POSITION_DARK_SKIN_TONE = "\U0001f9d8\U0001f3ff\u200d\u2642\ufe0f" - PERSON_TAKING_BATH = "\U0001f6c0" - PERSON_TAKING_BATH_LIGHT_SKIN_TONE = "\U0001f6c0\U0001f3fb" - PERSON_TAKING_BATH_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6c0\U0001f3fc" - PERSON_TAKING_BATH_MEDIUM_SKIN_TONE = "\U0001f6c0\U0001f3fd" - PERSON_TAKING_BATH_MEDIUM_DARK_SKIN_TONE = "\U0001f6c0\U0001f3fe" - PERSON_TAKING_BATH_DARK_SKIN_TONE = "\U0001f6c0\U0001f3ff" - PERSON_IN_BED = "\U0001f6cc" - PERSON_IN_BED_LIGHT_SKIN_TONE = "\U0001f6cc\U0001f3fb" - PERSON_IN_BED_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6cc\U0001f3fc" - PERSON_IN_BED_MEDIUM_SKIN_TONE = "\U0001f6cc\U0001f3fd" - PERSON_IN_BED_MEDIUM_DARK_SKIN_TONE = "\U0001f6cc\U0001f3fe" - PERSON_IN_BED_DARK_SKIN_TONE = "\U0001f6cc\U0001f3ff" - MAN_IN_SUIT_LEVITATING = "\U0001f574\ufe0f" - MAN_IN_SUIT_LEVITATING_LIGHT_SKIN_TONE = "\U0001f574\U0001f3fb" - MAN_IN_SUIT_LEVITATING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f574\U0001f3fc" - MAN_IN_SUIT_LEVITATING_MEDIUM_SKIN_TONE = "\U0001f574\U0001f3fd" - MAN_IN_SUIT_LEVITATING_MEDIUM_DARK_SKIN_TONE = "\U0001f574\U0001f3fe" - MAN_IN_SUIT_LEVITATING_DARK_SKIN_TONE = "\U0001f574\U0001f3ff" - SPEAKING_HEAD = "\U0001f5e3\ufe0f" - BUST_IN_SILHOUETTE = "\U0001f464" - BUSTS_IN_SILHOUETTE = "\U0001f465" - PERSON_FENCING = "\U0001f93a" - HORSE_RACING = "\U0001f3c7" - HORSE_RACING_LIGHT_SKIN_TONE = "\U0001f3c7\U0001f3fb" - HORSE_RACING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c7\U0001f3fc" - HORSE_RACING_MEDIUM_SKIN_TONE = "\U0001f3c7\U0001f3fd" - HORSE_RACING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c7\U0001f3fe" - HORSE_RACING_DARK_SKIN_TONE = "\U0001f3c7\U0001f3ff" - SKIER = "\u26f7\ufe0f" - SNOWBOARDER = "\U0001f3c2" - SNOWBOARDER_LIGHT_SKIN_TONE = "\U0001f3c2\U0001f3fb" - SNOWBOARDER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c2\U0001f3fc" - SNOWBOARDER_MEDIUM_SKIN_TONE = "\U0001f3c2\U0001f3fd" - SNOWBOARDER_MEDIUM_DARK_SKIN_TONE = "\U0001f3c2\U0001f3fe" - SNOWBOARDER_DARK_SKIN_TONE = "\U0001f3c2\U0001f3ff" - PERSON_GOLFING = "\U0001f3cc\ufe0f" - PERSON_GOLFING_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fb" - PERSON_GOLFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fc" - PERSON_GOLFING_MEDIUM_SKIN_TONE = "\U0001f3cc\U0001f3fd" - PERSON_GOLFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3cc\U0001f3fe" - PERSON_GOLFING_DARK_SKIN_TONE = "\U0001f3cc\U0001f3ff" - MAN_GOLFING = "\U0001f3cc\ufe0f\u200d\u2642\ufe0f" - MAN_GOLFING_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fb\u200d\u2642\ufe0f" - MAN_GOLFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fc\u200d\u2642\ufe0f" - MAN_GOLFING_MEDIUM_SKIN_TONE = "\U0001f3cc\U0001f3fd\u200d\u2642\ufe0f" - MAN_GOLFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3cc\U0001f3fe\u200d\u2642\ufe0f" - MAN_GOLFING_DARK_SKIN_TONE = "\U0001f3cc\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_GOLFING = "\U0001f3cc\ufe0f\u200d\u2640\ufe0f" - WOMAN_GOLFING_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_GOLFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_GOLFING_MEDIUM_SKIN_TONE = "\U0001f3cc\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_GOLFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3cc\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_GOLFING_DARK_SKIN_TONE = "\U0001f3cc\U0001f3ff\u200d\u2640\ufe0f" - PERSON_SURFING = "\U0001f3c4" - PERSON_SURFING_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fb" - PERSON_SURFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fc" - PERSON_SURFING_MEDIUM_SKIN_TONE = "\U0001f3c4\U0001f3fd" - PERSON_SURFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c4\U0001f3fe" - PERSON_SURFING_DARK_SKIN_TONE = "\U0001f3c4\U0001f3ff" - MAN_SURFING = "\U0001f3c4\u200d\u2642\ufe0f" - MAN_SURFING_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fb\u200d\u2642\ufe0f" - MAN_SURFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fc\u200d\u2642\ufe0f" - MAN_SURFING_MEDIUM_SKIN_TONE = "\U0001f3c4\U0001f3fd\u200d\u2642\ufe0f" - MAN_SURFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c4\U0001f3fe\u200d\u2642\ufe0f" - MAN_SURFING_DARK_SKIN_TONE = "\U0001f3c4\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_SURFING = "\U0001f3c4\u200d\u2640\ufe0f" - WOMAN_SURFING_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_SURFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_SURFING_MEDIUM_SKIN_TONE = "\U0001f3c4\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_SURFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c4\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_SURFING_DARK_SKIN_TONE = "\U0001f3c4\U0001f3ff\u200d\u2640\ufe0f" - PERSON_ROWING_BOAT = "\U0001f6a3" - PERSON_ROWING_BOAT_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fb" - PERSON_ROWING_BOAT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fc" - PERSON_ROWING_BOAT_MEDIUM_SKIN_TONE = "\U0001f6a3\U0001f3fd" - PERSON_ROWING_BOAT_MEDIUM_DARK_SKIN_TONE = "\U0001f6a3\U0001f3fe" - PERSON_ROWING_BOAT_DARK_SKIN_TONE = "\U0001f6a3\U0001f3ff" - MAN_ROWING_BOAT = "\U0001f6a3\u200d\u2642\ufe0f" - MAN_ROWING_BOAT_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fb\u200d\u2642\ufe0f" - MAN_ROWING_BOAT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fc\u200d\u2642\ufe0f" - MAN_ROWING_BOAT_MEDIUM_SKIN_TONE = "\U0001f6a3\U0001f3fd\u200d\u2642\ufe0f" - MAN_ROWING_BOAT_MEDIUM_DARK_SKIN_TONE = "\U0001f6a3\U0001f3fe\u200d\u2642\ufe0f" - MAN_ROWING_BOAT_DARK_SKIN_TONE = "\U0001f6a3\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_ROWING_BOAT = "\U0001f6a3\u200d\u2640\ufe0f" - WOMAN_ROWING_BOAT_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_ROWING_BOAT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_ROWING_BOAT_MEDIUM_SKIN_TONE = "\U0001f6a3\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_ROWING_BOAT_MEDIUM_DARK_SKIN_TONE = "\U0001f6a3\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_ROWING_BOAT_DARK_SKIN_TONE = "\U0001f6a3\U0001f3ff\u200d\u2640\ufe0f" - PERSON_SWIMMING = "\U0001f3ca" - PERSON_SWIMMING_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fb" - PERSON_SWIMMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fc" - PERSON_SWIMMING_MEDIUM_SKIN_TONE = "\U0001f3ca\U0001f3fd" - PERSON_SWIMMING_MEDIUM_DARK_SKIN_TONE = "\U0001f3ca\U0001f3fe" - PERSON_SWIMMING_DARK_SKIN_TONE = "\U0001f3ca\U0001f3ff" - MAN_SWIMMING = "\U0001f3ca\u200d\u2642\ufe0f" - MAN_SWIMMING_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fb\u200d\u2642\ufe0f" - MAN_SWIMMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fc\u200d\u2642\ufe0f" - MAN_SWIMMING_MEDIUM_SKIN_TONE = "\U0001f3ca\U0001f3fd\u200d\u2642\ufe0f" - MAN_SWIMMING_MEDIUM_DARK_SKIN_TONE = "\U0001f3ca\U0001f3fe\u200d\u2642\ufe0f" - MAN_SWIMMING_DARK_SKIN_TONE = "\U0001f3ca\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_SWIMMING = "\U0001f3ca\u200d\u2640\ufe0f" - WOMAN_SWIMMING_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_SWIMMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_SWIMMING_MEDIUM_SKIN_TONE = "\U0001f3ca\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_SWIMMING_MEDIUM_DARK_SKIN_TONE = "\U0001f3ca\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_SWIMMING_DARK_SKIN_TONE = "\U0001f3ca\U0001f3ff\u200d\u2640\ufe0f" - PERSON_BOUNCING_BALL = "\u26f9\ufe0f" - PERSON_BOUNCING_BALL_LIGHT_SKIN_TONE = "\u26f9\U0001f3fb" - PERSON_BOUNCING_BALL_MEDIUM_LIGHT_SKIN_TONE = "\u26f9\U0001f3fc" - PERSON_BOUNCING_BALL_MEDIUM_SKIN_TONE = "\u26f9\U0001f3fd" - PERSON_BOUNCING_BALL_MEDIUM_DARK_SKIN_TONE = "\u26f9\U0001f3fe" - PERSON_BOUNCING_BALL_DARK_SKIN_TONE = "\u26f9\U0001f3ff" - MAN_BOUNCING_BALL = "\u26f9\ufe0f\u200d\u2642\ufe0f" - MAN_BOUNCING_BALL_LIGHT_SKIN_TONE = "\u26f9\U0001f3fb\u200d\u2642\ufe0f" - MAN_BOUNCING_BALL_MEDIUM_LIGHT_SKIN_TONE = "\u26f9\U0001f3fc\u200d\u2642\ufe0f" - MAN_BOUNCING_BALL_MEDIUM_SKIN_TONE = "\u26f9\U0001f3fd\u200d\u2642\ufe0f" - MAN_BOUNCING_BALL_MEDIUM_DARK_SKIN_TONE = "\u26f9\U0001f3fe\u200d\u2642\ufe0f" - MAN_BOUNCING_BALL_DARK_SKIN_TONE = "\u26f9\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_BOUNCING_BALL = "\u26f9\ufe0f\u200d\u2640\ufe0f" - WOMAN_BOUNCING_BALL_LIGHT_SKIN_TONE = "\u26f9\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_BOUNCING_BALL_MEDIUM_LIGHT_SKIN_TONE = "\u26f9\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_BOUNCING_BALL_MEDIUM_SKIN_TONE = "\u26f9\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_BOUNCING_BALL_MEDIUM_DARK_SKIN_TONE = "\u26f9\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_BOUNCING_BALL_DARK_SKIN_TONE = "\u26f9\U0001f3ff\u200d\u2640\ufe0f" - PERSON_LIFTING_WEIGHTS = "\U0001f3cb\ufe0f" - PERSON_LIFTING_WEIGHTS_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fb" - PERSON_LIFTING_WEIGHTS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fc" - PERSON_LIFTING_WEIGHTS_MEDIUM_SKIN_TONE = "\U0001f3cb\U0001f3fd" - PERSON_LIFTING_WEIGHTS_MEDIUM_DARK_SKIN_TONE = "\U0001f3cb\U0001f3fe" - PERSON_LIFTING_WEIGHTS_DARK_SKIN_TONE = "\U0001f3cb\U0001f3ff" - MAN_LIFTING_WEIGHTS = "\U0001f3cb\ufe0f\u200d\u2642\ufe0f" - MAN_LIFTING_WEIGHTS_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fb\u200d\u2642\ufe0f" - MAN_LIFTING_WEIGHTS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fc\u200d\u2642\ufe0f" - MAN_LIFTING_WEIGHTS_MEDIUM_SKIN_TONE = "\U0001f3cb\U0001f3fd\u200d\u2642\ufe0f" - MAN_LIFTING_WEIGHTS_MEDIUM_DARK_SKIN_TONE = "\U0001f3cb\U0001f3fe\u200d\u2642\ufe0f" - MAN_LIFTING_WEIGHTS_DARK_SKIN_TONE = "\U0001f3cb\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_LIFTING_WEIGHTS = "\U0001f3cb\ufe0f\u200d\u2640\ufe0f" - WOMAN_LIFTING_WEIGHTS_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_LIFTING_WEIGHTS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_LIFTING_WEIGHTS_MEDIUM_SKIN_TONE = "\U0001f3cb\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_LIFTING_WEIGHTS_MEDIUM_DARK_SKIN_TONE = "\U0001f3cb\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_LIFTING_WEIGHTS_DARK_SKIN_TONE = "\U0001f3cb\U0001f3ff\u200d\u2640\ufe0f" - PERSON_BIKING = "\U0001f6b4" - PERSON_BIKING_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fb" - PERSON_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fc" - PERSON_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b4\U0001f3fd" - PERSON_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b4\U0001f3fe" - PERSON_BIKING_DARK_SKIN_TONE = "\U0001f6b4\U0001f3ff" - MAN_BIKING = "\U0001f6b4\u200d\u2642\ufe0f" - MAN_BIKING_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fb\u200d\u2642\ufe0f" - MAN_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fc\u200d\u2642\ufe0f" - MAN_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b4\U0001f3fd\u200d\u2642\ufe0f" - MAN_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b4\U0001f3fe\u200d\u2642\ufe0f" - MAN_BIKING_DARK_SKIN_TONE = "\U0001f6b4\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_BIKING = "\U0001f6b4\u200d\u2640\ufe0f" - WOMAN_BIKING_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b4\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b4\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_BIKING_DARK_SKIN_TONE = "\U0001f6b4\U0001f3ff\u200d\u2640\ufe0f" - PERSON_MOUNTAIN_BIKING = "\U0001f6b5" - PERSON_MOUNTAIN_BIKING_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fb" - PERSON_MOUNTAIN_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fc" - PERSON_MOUNTAIN_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b5\U0001f3fd" - PERSON_MOUNTAIN_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b5\U0001f3fe" - PERSON_MOUNTAIN_BIKING_DARK_SKIN_TONE = "\U0001f6b5\U0001f3ff" - MAN_MOUNTAIN_BIKING = "\U0001f6b5\u200d\u2642\ufe0f" - MAN_MOUNTAIN_BIKING_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fb\u200d\u2642\ufe0f" - MAN_MOUNTAIN_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fc\u200d\u2642\ufe0f" - MAN_MOUNTAIN_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b5\U0001f3fd\u200d\u2642\ufe0f" - MAN_MOUNTAIN_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b5\U0001f3fe\u200d\u2642\ufe0f" - MAN_MOUNTAIN_BIKING_DARK_SKIN_TONE = "\U0001f6b5\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_MOUNTAIN_BIKING = "\U0001f6b5\u200d\u2640\ufe0f" - WOMAN_MOUNTAIN_BIKING_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_MOUNTAIN_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_MOUNTAIN_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b5\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_MOUNTAIN_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b5\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_MOUNTAIN_BIKING_DARK_SKIN_TONE = "\U0001f6b5\U0001f3ff\u200d\u2640\ufe0f" - RACING_CAR = "\U0001f3ce\ufe0f" - MOTORCYCLE = "\U0001f3cd\ufe0f" - PERSON_CARTWHEELING = "\U0001f938" - PERSON_CARTWHEELING_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fb" - PERSON_CARTWHEELING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fc" - PERSON_CARTWHEELING_MEDIUM_SKIN_TONE = "\U0001f938\U0001f3fd" - WRESTLERS_TYPE_1_2 = "\U0001f93c\U0001f3fb" - PERSON_CARTWHEELING_MEDIUM_DARK_SKIN_TONE = "\U0001f938\U0001f3fe" - WRESTLERS_TYPE_3 = "\U0001f93c\U0001f3fc" - PERSON_CARTWHEELING_DARK_SKIN_TONE = "\U0001f938\U0001f3ff" - MAN_CARTWHEELING = "\U0001f938\u200d\u2642\ufe0f" - WRESTLERS_TYPE_4 = "\U0001f93c\U0001f3fd" - WRESTLERS_TYPE_5 = "\U0001f93c\U0001f3fe" - MAN_CARTWHEELING_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fb\u200d\u2642\ufe0f" - WRESTLERS_TYPE_6 = "\U0001f93c\U0001f3ff" - MAN_CARTWHEELING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fc\u200d\u2642\ufe0f" - MEN_WRESTLING_TYPE_1_2 = "\U0001f93c\U0001f3fb\u200d\u2642\ufe0f" - MEN_WRESTLING_TYPE_3 = "\U0001f93c\U0001f3fc\u200d\u2642\ufe0f" - MEN_WRESTLING_TYPE_4 = "\U0001f93c\U0001f3fd\u200d\u2642\ufe0f" - MAN_CARTWHEELING_MEDIUM_SKIN_TONE = "\U0001f938\U0001f3fd\u200d\u2642\ufe0f" - MEN_WRESTLING_TYPE_5 = "\U0001f93c\U0001f3fe\u200d\u2642\ufe0f" - MEN_WRESTLING_TYPE_6 = "\U0001f93c\U0001f3ff\u200d\u2642\ufe0f" - MAN_CARTWHEELING_MEDIUM_DARK_SKIN_TONE = "\U0001f938\U0001f3fe\u200d\u2642\ufe0f" - WOMEN_WRESTLING_TYPE_1_2 = "\U0001f93c\U0001f3fb\u200d\u2640\ufe0f" - MAN_CARTWHEELING_DARK_SKIN_TONE = "\U0001f938\U0001f3ff\u200d\u2642\ufe0f" - WOMEN_WRESTLING_TYPE_3 = "\U0001f93c\U0001f3fc\u200d\u2640\ufe0f" - WOMEN_WRESTLING_TYPE_4 = "\U0001f93c\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_CARTWHEELING = "\U0001f938\u200d\u2640\ufe0f" - WOMEN_WRESTLING_TYPE_5 = "\U0001f93c\U0001f3fe\u200d\u2640\ufe0f" - WOMEN_WRESTLING_TYPE_6 = "\U0001f93c\U0001f3ff\u200d\u2640\ufe0f" - WOMAN_CARTWHEELING_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_CARTWHEELING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_CARTWHEELING_MEDIUM_SKIN_TONE = "\U0001f938\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_CARTWHEELING_MEDIUM_DARK_SKIN_TONE = "\U0001f938\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_CARTWHEELING_DARK_SKIN_TONE = "\U0001f938\U0001f3ff\u200d\u2640\ufe0f" - PEOPLE_WRESTLING = "\U0001f93c" - MEN_WRESTLING = "\U0001f93c\u200d\u2642\ufe0f" - WOMEN_WRESTLING = "\U0001f93c\u200d\u2640\ufe0f" - PERSON_PLAYING_WATER_POLO = "\U0001f93d" - PERSON_PLAYING_WATER_POLO_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fb" - PERSON_PLAYING_WATER_POLO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fc" - PERSON_PLAYING_WATER_POLO_MEDIUM_SKIN_TONE = "\U0001f93d\U0001f3fd" - PERSON_PLAYING_WATER_POLO_MEDIUM_DARK_SKIN_TONE = "\U0001f93d\U0001f3fe" - PERSON_PLAYING_WATER_POLO_DARK_SKIN_TONE = "\U0001f93d\U0001f3ff" - MAN_PLAYING_WATER_POLO = "\U0001f93d\u200d\u2642\ufe0f" - MAN_PLAYING_WATER_POLO_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fb\u200d\u2642\ufe0f" - MAN_PLAYING_WATER_POLO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fc\u200d\u2642\ufe0f" - MAN_PLAYING_WATER_POLO_MEDIUM_SKIN_TONE = "\U0001f93d\U0001f3fd\u200d\u2642\ufe0f" - MAN_PLAYING_WATER_POLO_MEDIUM_DARK_SKIN_TONE = "\U0001f93d\U0001f3fe\u200d\u2642\ufe0f" - MAN_PLAYING_WATER_POLO_DARK_SKIN_TONE = "\U0001f93d\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_PLAYING_WATER_POLO = "\U0001f93d\u200d\u2640\ufe0f" - WOMAN_PLAYING_WATER_POLO_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_PLAYING_WATER_POLO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_PLAYING_WATER_POLO_MEDIUM_SKIN_TONE = "\U0001f93d\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_PLAYING_WATER_POLO_MEDIUM_DARK_SKIN_TONE = "\U0001f93d\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_PLAYING_WATER_POLO_DARK_SKIN_TONE = "\U0001f93d\U0001f3ff\u200d\u2640\ufe0f" - PERSON_PLAYING_HANDBALL = "\U0001f93e" - PERSON_PLAYING_HANDBALL_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fb" - PERSON_PLAYING_HANDBALL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fc" - PERSON_PLAYING_HANDBALL_MEDIUM_SKIN_TONE = "\U0001f93e\U0001f3fd" - PERSON_PLAYING_HANDBALL_MEDIUM_DARK_SKIN_TONE = "\U0001f93e\U0001f3fe" - PERSON_PLAYING_HANDBALL_DARK_SKIN_TONE = "\U0001f93e\U0001f3ff" - MAN_PLAYING_HANDBALL = "\U0001f93e\u200d\u2642\ufe0f" - MAN_PLAYING_HANDBALL_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fb\u200d\u2642\ufe0f" - MAN_PLAYING_HANDBALL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fc\u200d\u2642\ufe0f" - MAN_PLAYING_HANDBALL_MEDIUM_SKIN_TONE = "\U0001f93e\U0001f3fd\u200d\u2642\ufe0f" - MAN_PLAYING_HANDBALL_MEDIUM_DARK_SKIN_TONE = "\U0001f93e\U0001f3fe\u200d\u2642\ufe0f" - MAN_PLAYING_HANDBALL_DARK_SKIN_TONE = "\U0001f93e\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_PLAYING_HANDBALL = "\U0001f93e\u200d\u2640\ufe0f" - WOMAN_PLAYING_HANDBALL_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_PLAYING_HANDBALL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_PLAYING_HANDBALL_MEDIUM_SKIN_TONE = "\U0001f93e\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_PLAYING_HANDBALL_MEDIUM_DARK_SKIN_TONE = "\U0001f93e\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_PLAYING_HANDBALL_DARK_SKIN_TONE = "\U0001f93e\U0001f3ff\u200d\u2640\ufe0f" - PERSON_JUGGLING = "\U0001f939" - PERSON_JUGGLING_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fb" - PERSON_JUGGLING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fc" - PERSON_JUGGLING_MEDIUM_SKIN_TONE = "\U0001f939\U0001f3fd" - PERSON_JUGGLING_MEDIUM_DARK_SKIN_TONE = "\U0001f939\U0001f3fe" - PERSON_JUGGLING_DARK_SKIN_TONE = "\U0001f939\U0001f3ff" - MAN_JUGGLING = "\U0001f939\u200d\u2642\ufe0f" - MAN_JUGGLING_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fb\u200d\u2642\ufe0f" - MAN_JUGGLING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fc\u200d\u2642\ufe0f" - MAN_JUGGLING_MEDIUM_SKIN_TONE = "\U0001f939\U0001f3fd\u200d\u2642\ufe0f" - MAN_JUGGLING_MEDIUM_DARK_SKIN_TONE = "\U0001f939\U0001f3fe\u200d\u2642\ufe0f" - MAN_JUGGLING_DARK_SKIN_TONE = "\U0001f939\U0001f3ff\u200d\u2642\ufe0f" - WOMAN_JUGGLING = "\U0001f939\u200d\u2640\ufe0f" - WOMAN_JUGGLING_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fb\u200d\u2640\ufe0f" - WOMAN_JUGGLING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fc\u200d\u2640\ufe0f" - WOMAN_JUGGLING_MEDIUM_SKIN_TONE = "\U0001f939\U0001f3fd\u200d\u2640\ufe0f" - WOMAN_JUGGLING_MEDIUM_DARK_SKIN_TONE = "\U0001f939\U0001f3fe\u200d\u2640\ufe0f" - WOMAN_JUGGLING_DARK_SKIN_TONE = "\U0001f939\U0001f3ff\u200d\u2640\ufe0f" - MAN_AND_WOMAN_HOLDING_HANDS = "\U0001f46b" - TWO_MEN_HOLDING_HANDS = "\U0001f46c" - TWO_WOMEN_HOLDING_HANDS = "\U0001f46d" - KISS = "\U0001f48f" - KISS_WOMAN_MAN = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - KISS_MAN_MAN = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - KISS_WOMAN_WOMAN = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - COUPLE_WITH_HEART = "\U0001f491" - COUPLE_WITH_HEART_WOMAN_MAN = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f468" - COUPLE_WITH_HEART_MAN_MAN = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f468" - COUPLE_WITH_HEART_WOMAN_WOMAN = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f469" - FAMILY = "\U0001f46a" - FAMILY_MAN_WOMAN_BOY = "\U0001f468\u200d\U0001f469\u200d\U0001f466" - FAMILY_MAN_WOMAN_GIRL = "\U0001f468\u200d\U0001f469\u200d\U0001f467" - FAMILY_MAN_WOMAN_GIRL_BOY = "\U0001f468\u200d\U0001f469\u200d\U0001f467\u200d\U0001f466" - FAMILY_MAN_WOMAN_BOY_BOY = "\U0001f468\u200d\U0001f469\u200d\U0001f466\u200d\U0001f466" - FAMILY_MAN_WOMAN_GIRL_GIRL = "\U0001f468\u200d\U0001f469\u200d\U0001f467\u200d\U0001f467" - FAMILY_MAN_MAN_BOY = "\U0001f468\u200d\U0001f468\u200d\U0001f466" - FAMILY_MAN_MAN_GIRL = "\U0001f468\u200d\U0001f468\u200d\U0001f467" - FAMILY_MAN_MAN_GIRL_BOY = "\U0001f468\u200d\U0001f468\u200d\U0001f467\u200d\U0001f466" - FAMILY_MAN_MAN_BOY_BOY = "\U0001f468\u200d\U0001f468\u200d\U0001f466\u200d\U0001f466" - FAMILY_MAN_MAN_GIRL_GIRL = "\U0001f468\u200d\U0001f468\u200d\U0001f467\u200d\U0001f467" - FAMILY_WOMAN_WOMAN_BOY = "\U0001f469\u200d\U0001f469\u200d\U0001f466" - FAMILY_WOMAN_WOMAN_GIRL = "\U0001f469\u200d\U0001f469\u200d\U0001f467" - FAMILY_WOMAN_WOMAN_GIRL_BOY = "\U0001f469\u200d\U0001f469\u200d\U0001f467\u200d\U0001f466" - FAMILY_WOMAN_WOMAN_BOY_BOY = "\U0001f469\u200d\U0001f469\u200d\U0001f466\u200d\U0001f466" - FAMILY_WOMAN_WOMAN_GIRL_GIRL = "\U0001f469\u200d\U0001f469\u200d\U0001f467\u200d\U0001f467" - FAMILY_MAN_BOY = "\U0001f468\u200d\U0001f466" - FAMILY_MAN_BOY_BOY = "\U0001f468\u200d\U0001f466\u200d\U0001f466" - FAMILY_MAN_GIRL = "\U0001f468\u200d\U0001f467" - FAMILY_MAN_GIRL_BOY = "\U0001f468\u200d\U0001f467\u200d\U0001f466" - FAMILY_MAN_GIRL_GIRL = "\U0001f468\u200d\U0001f467\u200d\U0001f467" - FAMILY_WOMAN_BOY = "\U0001f469\u200d\U0001f466" - FAMILY_WOMAN_BOY_BOY = "\U0001f469\u200d\U0001f466\u200d\U0001f466" - FAMILY_WOMAN_GIRL = "\U0001f469\u200d\U0001f467" - FAMILY_WOMAN_GIRL_BOY = "\U0001f469\u200d\U0001f467\u200d\U0001f466" - FAMILY_WOMAN_GIRL_GIRL = "\U0001f469\u200d\U0001f467\u200d\U0001f467" - SELFIE = "\U0001f933" - SELFIE_LIGHT_SKIN_TONE = "\U0001f933\U0001f3fb" - SELFIE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f933\U0001f3fc" - SELFIE_MEDIUM_SKIN_TONE = "\U0001f933\U0001f3fd" - SELFIE_MEDIUM_DARK_SKIN_TONE = "\U0001f933\U0001f3fe" - SELFIE_DARK_SKIN_TONE = "\U0001f933\U0001f3ff" - FLEXED_BICEPS = "\U0001f4aa" - FLEXED_BICEPS_LIGHT_SKIN_TONE = "\U0001f4aa\U0001f3fb" - FLEXED_BICEPS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f4aa\U0001f3fc" - FLEXED_BICEPS_MEDIUM_SKIN_TONE = "\U0001f4aa\U0001f3fd" - FLEXED_BICEPS_MEDIUM_DARK_SKIN_TONE = "\U0001f4aa\U0001f3fe" - FLEXED_BICEPS_DARK_SKIN_TONE = "\U0001f4aa\U0001f3ff" - LEG = "\U0001f9b5" - LEG_LIGHT_SKIN_TONE = "\U0001f9b5\U0001f3fb" - LEG_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b5\U0001f3fc" - LEG_MEDIUM_SKIN_TONE = "\U0001f9b5\U0001f3fd" - LEG_MEDIUM_DARK_SKIN_TONE = "\U0001f9b5\U0001f3fe" - LEG_DARK_SKIN_TONE = "\U0001f9b5\U0001f3ff" - FOOT = "\U0001f9b6" - FOOT_LIGHT_SKIN_TONE = "\U0001f9b6\U0001f3fb" - FOOT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b6\U0001f3fc" - FOOT_MEDIUM_SKIN_TONE = "\U0001f9b6\U0001f3fd" - FOOT_MEDIUM_DARK_SKIN_TONE = "\U0001f9b6\U0001f3fe" - FOOT_DARK_SKIN_TONE = "\U0001f9b6\U0001f3ff" - BACKHAND_INDEX_POINTING_LEFT = "\U0001f448" - BACKHAND_INDEX_POINTING_LEFT_LIGHT_SKIN_TONE = "\U0001f448\U0001f3fb" - BACKHAND_INDEX_POINTING_LEFT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f448\U0001f3fc" - BACKHAND_INDEX_POINTING_LEFT_MEDIUM_SKIN_TONE = "\U0001f448\U0001f3fd" - BACKHAND_INDEX_POINTING_LEFT_MEDIUM_DARK_SKIN_TONE = "\U0001f448\U0001f3fe" - BACKHAND_INDEX_POINTING_LEFT_DARK_SKIN_TONE = "\U0001f448\U0001f3ff" - BACKHAND_INDEX_POINTING_RIGHT = "\U0001f449" - BACKHAND_INDEX_POINTING_RIGHT_LIGHT_SKIN_TONE = "\U0001f449\U0001f3fb" - BACKHAND_INDEX_POINTING_RIGHT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f449\U0001f3fc" - BACKHAND_INDEX_POINTING_RIGHT_MEDIUM_SKIN_TONE = "\U0001f449\U0001f3fd" - BACKHAND_INDEX_POINTING_RIGHT_MEDIUM_DARK_SKIN_TONE = "\U0001f449\U0001f3fe" - BACKHAND_INDEX_POINTING_RIGHT_DARK_SKIN_TONE = "\U0001f449\U0001f3ff" - INDEX_POINTING_UP = "\u261d\ufe0f" - INDEX_POINTING_UP_LIGHT_SKIN_TONE = "\u261d\U0001f3fb" - INDEX_POINTING_UP_MEDIUM_LIGHT_SKIN_TONE = "\u261d\U0001f3fc" - INDEX_POINTING_UP_MEDIUM_SKIN_TONE = "\u261d\U0001f3fd" - INDEX_POINTING_UP_MEDIUM_DARK_SKIN_TONE = "\u261d\U0001f3fe" - INDEX_POINTING_UP_DARK_SKIN_TONE = "\u261d\U0001f3ff" - BACKHAND_INDEX_POINTING_UP = "\U0001f446" - BACKHAND_INDEX_POINTING_UP_LIGHT_SKIN_TONE = "\U0001f446\U0001f3fb" - BACKHAND_INDEX_POINTING_UP_MEDIUM_LIGHT_SKIN_TONE = "\U0001f446\U0001f3fc" - BACKHAND_INDEX_POINTING_UP_MEDIUM_SKIN_TONE = "\U0001f446\U0001f3fd" - BACKHAND_INDEX_POINTING_UP_MEDIUM_DARK_SKIN_TONE = "\U0001f446\U0001f3fe" - BACKHAND_INDEX_POINTING_UP_DARK_SKIN_TONE = "\U0001f446\U0001f3ff" - MIDDLE_FINGER = "\U0001f595" - MIDDLE_FINGER_LIGHT_SKIN_TONE = "\U0001f595\U0001f3fb" - MIDDLE_FINGER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f595\U0001f3fc" - MIDDLE_FINGER_MEDIUM_SKIN_TONE = "\U0001f595\U0001f3fd" - MIDDLE_FINGER_MEDIUM_DARK_SKIN_TONE = "\U0001f595\U0001f3fe" - MIDDLE_FINGER_DARK_SKIN_TONE = "\U0001f595\U0001f3ff" - BACKHAND_INDEX_POINTING_DOWN = "\U0001f447" - BACKHAND_INDEX_POINTING_DOWN_LIGHT_SKIN_TONE = "\U0001f447\U0001f3fb" - BACKHAND_INDEX_POINTING_DOWN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f447\U0001f3fc" - BACKHAND_INDEX_POINTING_DOWN_MEDIUM_SKIN_TONE = "\U0001f447\U0001f3fd" - BACKHAND_INDEX_POINTING_DOWN_MEDIUM_DARK_SKIN_TONE = "\U0001f447\U0001f3fe" - BACKHAND_INDEX_POINTING_DOWN_DARK_SKIN_TONE = "\U0001f447\U0001f3ff" - VICTORY_HAND = "\u270c\ufe0f" - VICTORY_HAND_LIGHT_SKIN_TONE = "\u270c\U0001f3fb" - VICTORY_HAND_MEDIUM_LIGHT_SKIN_TONE = "\u270c\U0001f3fc" - VICTORY_HAND_MEDIUM_SKIN_TONE = "\u270c\U0001f3fd" - VICTORY_HAND_MEDIUM_DARK_SKIN_TONE = "\u270c\U0001f3fe" - VICTORY_HAND_DARK_SKIN_TONE = "\u270c\U0001f3ff" - CROSSED_FINGERS = "\U0001f91e" - CROSSED_FINGERS_LIGHT_SKIN_TONE = "\U0001f91e\U0001f3fb" - CROSSED_FINGERS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f91e\U0001f3fc" - CROSSED_FINGERS_MEDIUM_SKIN_TONE = "\U0001f91e\U0001f3fd" - CROSSED_FINGERS_MEDIUM_DARK_SKIN_TONE = "\U0001f91e\U0001f3fe" - CROSSED_FINGERS_DARK_SKIN_TONE = "\U0001f91e\U0001f3ff" - VULCAN_SALUTE = "\U0001f596" - VULCAN_SALUTE_LIGHT_SKIN_TONE = "\U0001f596\U0001f3fb" - VULCAN_SALUTE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f596\U0001f3fc" - VULCAN_SALUTE_MEDIUM_SKIN_TONE = "\U0001f596\U0001f3fd" - VULCAN_SALUTE_MEDIUM_DARK_SKIN_TONE = "\U0001f596\U0001f3fe" - VULCAN_SALUTE_DARK_SKIN_TONE = "\U0001f596\U0001f3ff" - SIGN_OF_THE_HORNS = "\U0001f918" - SIGN_OF_THE_HORNS_LIGHT_SKIN_TONE = "\U0001f918\U0001f3fb" - SIGN_OF_THE_HORNS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f918\U0001f3fc" - SIGN_OF_THE_HORNS_MEDIUM_SKIN_TONE = "\U0001f918\U0001f3fd" - SIGN_OF_THE_HORNS_MEDIUM_DARK_SKIN_TONE = "\U0001f918\U0001f3fe" - SIGN_OF_THE_HORNS_DARK_SKIN_TONE = "\U0001f918\U0001f3ff" - CALL_ME_HAND = "\U0001f919" - CALL_ME_HAND_LIGHT_SKIN_TONE = "\U0001f919\U0001f3fb" - CALL_ME_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f919\U0001f3fc" - CALL_ME_HAND_MEDIUM_SKIN_TONE = "\U0001f919\U0001f3fd" - CALL_ME_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f919\U0001f3fe" - CALL_ME_HAND_DARK_SKIN_TONE = "\U0001f919\U0001f3ff" - HAND_WITH_FINGERS_SPLAYED = "\U0001f590\ufe0f" - HAND_WITH_FINGERS_SPLAYED_LIGHT_SKIN_TONE = "\U0001f590\U0001f3fb" - HAND_WITH_FINGERS_SPLAYED_MEDIUM_LIGHT_SKIN_TONE = "\U0001f590\U0001f3fc" - HAND_WITH_FINGERS_SPLAYED_MEDIUM_SKIN_TONE = "\U0001f590\U0001f3fd" - HAND_WITH_FINGERS_SPLAYED_MEDIUM_DARK_SKIN_TONE = "\U0001f590\U0001f3fe" - HAND_WITH_FINGERS_SPLAYED_DARK_SKIN_TONE = "\U0001f590\U0001f3ff" - RAISED_HAND = "\u270b" - RAISED_HAND_LIGHT_SKIN_TONE = "\u270b\U0001f3fb" - RAISED_HAND_MEDIUM_LIGHT_SKIN_TONE = "\u270b\U0001f3fc" - RAISED_HAND_MEDIUM_SKIN_TONE = "\u270b\U0001f3fd" - RAISED_HAND_MEDIUM_DARK_SKIN_TONE = "\u270b\U0001f3fe" - RAISED_HAND_DARK_SKIN_TONE = "\u270b\U0001f3ff" - OK_HAND = "\U0001f44c" - OK_HAND_LIGHT_SKIN_TONE = "\U0001f44c\U0001f3fb" - OK_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44c\U0001f3fc" - OK_HAND_MEDIUM_SKIN_TONE = "\U0001f44c\U0001f3fd" - OK_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f44c\U0001f3fe" - OK_HAND_DARK_SKIN_TONE = "\U0001f44c\U0001f3ff" - THUMBS_UP = "\U0001f44d" - THUMBS_UP_LIGHT_SKIN_TONE = "\U0001f44d\U0001f3fb" - THUMBS_UP_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44d\U0001f3fc" - THUMBS_UP_MEDIUM_SKIN_TONE = "\U0001f44d\U0001f3fd" - THUMBS_UP_MEDIUM_DARK_SKIN_TONE = "\U0001f44d\U0001f3fe" - THUMBS_UP_DARK_SKIN_TONE = "\U0001f44d\U0001f3ff" - THUMBS_DOWN = "\U0001f44e" - THUMBS_DOWN_LIGHT_SKIN_TONE = "\U0001f44e\U0001f3fb" - THUMBS_DOWN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44e\U0001f3fc" - THUMBS_DOWN_MEDIUM_SKIN_TONE = "\U0001f44e\U0001f3fd" - THUMBS_DOWN_MEDIUM_DARK_SKIN_TONE = "\U0001f44e\U0001f3fe" - THUMBS_DOWN_DARK_SKIN_TONE = "\U0001f44e\U0001f3ff" - RAISED_FIST = "\u270a" - RAISED_FIST_LIGHT_SKIN_TONE = "\u270a\U0001f3fb" - RAISED_FIST_MEDIUM_LIGHT_SKIN_TONE = "\u270a\U0001f3fc" - RAISED_FIST_MEDIUM_SKIN_TONE = "\u270a\U0001f3fd" - RAISED_FIST_MEDIUM_DARK_SKIN_TONE = "\u270a\U0001f3fe" - RAISED_FIST_DARK_SKIN_TONE = "\u270a\U0001f3ff" - ONCOMING_FIST = "\U0001f44a" - ONCOMING_FIST_LIGHT_SKIN_TONE = "\U0001f44a\U0001f3fb" - ONCOMING_FIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44a\U0001f3fc" - ONCOMING_FIST_MEDIUM_SKIN_TONE = "\U0001f44a\U0001f3fd" - ONCOMING_FIST_MEDIUM_DARK_SKIN_TONE = "\U0001f44a\U0001f3fe" - ONCOMING_FIST_DARK_SKIN_TONE = "\U0001f44a\U0001f3ff" - LEFT_FACING_FIST = "\U0001f91b" - LEFT_FACING_FIST_LIGHT_SKIN_TONE = "\U0001f91b\U0001f3fb" - LEFT_FACING_FIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f91b\U0001f3fc" - LEFT_FACING_FIST_MEDIUM_SKIN_TONE = "\U0001f91b\U0001f3fd" - LEFT_FACING_FIST_MEDIUM_DARK_SKIN_TONE = "\U0001f91b\U0001f3fe" - LEFT_FACING_FIST_DARK_SKIN_TONE = "\U0001f91b\U0001f3ff" - RIGHT_FACING_FIST = "\U0001f91c" - RIGHT_FACING_FIST_LIGHT_SKIN_TONE = "\U0001f91c\U0001f3fb" - RIGHT_FACING_FIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f91c\U0001f3fc" - RIGHT_FACING_FIST_MEDIUM_SKIN_TONE = "\U0001f91c\U0001f3fd" - RIGHT_FACING_FIST_MEDIUM_DARK_SKIN_TONE = "\U0001f91c\U0001f3fe" - RIGHT_FACING_FIST_DARK_SKIN_TONE = "\U0001f91c\U0001f3ff" - RAISED_BACK_OF_HAND = "\U0001f91a" - RAISED_BACK_OF_HAND_LIGHT_SKIN_TONE = "\U0001f91a\U0001f3fb" - RAISED_BACK_OF_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f91a\U0001f3fc" - RAISED_BACK_OF_HAND_MEDIUM_SKIN_TONE = "\U0001f91a\U0001f3fd" - RAISED_BACK_OF_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f91a\U0001f3fe" - RAISED_BACK_OF_HAND_DARK_SKIN_TONE = "\U0001f91a\U0001f3ff" - WAVING_HAND = "\U0001f44b" - WAVING_HAND_LIGHT_SKIN_TONE = "\U0001f44b\U0001f3fb" - WAVING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44b\U0001f3fc" - WAVING_HAND_MEDIUM_SKIN_TONE = "\U0001f44b\U0001f3fd" - WAVING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f44b\U0001f3fe" - WAVING_HAND_DARK_SKIN_TONE = "\U0001f44b\U0001f3ff" - LOVE_YOU_GESTURE = "\U0001f91f" - LOVE_YOU_GESTURE_LIGHT_SKIN_TONE = "\U0001f91f\U0001f3fb" - LOVE_YOU_GESTURE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f91f\U0001f3fc" - LOVE_YOU_GESTURE_MEDIUM_SKIN_TONE = "\U0001f91f\U0001f3fd" - LOVE_YOU_GESTURE_MEDIUM_DARK_SKIN_TONE = "\U0001f91f\U0001f3fe" - LOVE_YOU_GESTURE_DARK_SKIN_TONE = "\U0001f91f\U0001f3ff" - WRITING_HAND = "\u270d\ufe0f" - WRITING_HAND_LIGHT_SKIN_TONE = "\u270d\U0001f3fb" - WRITING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\u270d\U0001f3fc" - WRITING_HAND_MEDIUM_SKIN_TONE = "\u270d\U0001f3fd" - WRITING_HAND_MEDIUM_DARK_SKIN_TONE = "\u270d\U0001f3fe" - WRITING_HAND_DARK_SKIN_TONE = "\u270d\U0001f3ff" - CLAPPING_HANDS = "\U0001f44f" - CLAPPING_HANDS_LIGHT_SKIN_TONE = "\U0001f44f\U0001f3fb" - CLAPPING_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44f\U0001f3fc" - CLAPPING_HANDS_MEDIUM_SKIN_TONE = "\U0001f44f\U0001f3fd" - CLAPPING_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f44f\U0001f3fe" - CLAPPING_HANDS_DARK_SKIN_TONE = "\U0001f44f\U0001f3ff" - OPEN_HANDS = "\U0001f450" - OPEN_HANDS_LIGHT_SKIN_TONE = "\U0001f450\U0001f3fb" - OPEN_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f450\U0001f3fc" - OPEN_HANDS_MEDIUM_SKIN_TONE = "\U0001f450\U0001f3fd" - OPEN_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f450\U0001f3fe" - OPEN_HANDS_DARK_SKIN_TONE = "\U0001f450\U0001f3ff" - RAISING_HANDS = "\U0001f64c" - RAISING_HANDS_LIGHT_SKIN_TONE = "\U0001f64c\U0001f3fb" - RAISING_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64c\U0001f3fc" - RAISING_HANDS_MEDIUM_SKIN_TONE = "\U0001f64c\U0001f3fd" - RAISING_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f64c\U0001f3fe" - RAISING_HANDS_DARK_SKIN_TONE = "\U0001f64c\U0001f3ff" - PALMS_UP_TOGETHER = "\U0001f932" - PALMS_UP_TOGETHER_LIGHT_SKIN_TONE = "\U0001f932\U0001f3fb" - PALMS_UP_TOGETHER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f932\U0001f3fc" - PALMS_UP_TOGETHER_MEDIUM_SKIN_TONE = "\U0001f932\U0001f3fd" - PALMS_UP_TOGETHER_MEDIUM_DARK_SKIN_TONE = "\U0001f932\U0001f3fe" - PALMS_UP_TOGETHER_DARK_SKIN_TONE = "\U0001f932\U0001f3ff" - FOLDED_HANDS = "\U0001f64f" - FOLDED_HANDS_LIGHT_SKIN_TONE = "\U0001f64f\U0001f3fb" - FOLDED_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64f\U0001f3fc" - FOLDED_HANDS_MEDIUM_SKIN_TONE = "\U0001f64f\U0001f3fd" - FOLDED_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f64f\U0001f3fe" - FOLDED_HANDS_DARK_SKIN_TONE = "\U0001f64f\U0001f3ff" - HANDSHAKE = "\U0001f91d" - NAIL_POLISH = "\U0001f485" - NAIL_POLISH_LIGHT_SKIN_TONE = "\U0001f485\U0001f3fb" - NAIL_POLISH_MEDIUM_LIGHT_SKIN_TONE = "\U0001f485\U0001f3fc" - NAIL_POLISH_MEDIUM_SKIN_TONE = "\U0001f485\U0001f3fd" - NAIL_POLISH_MEDIUM_DARK_SKIN_TONE = "\U0001f485\U0001f3fe" - NAIL_POLISH_DARK_SKIN_TONE = "\U0001f485\U0001f3ff" - EAR = "\U0001f442" - EAR_LIGHT_SKIN_TONE = "\U0001f442\U0001f3fb" - EAR_MEDIUM_LIGHT_SKIN_TONE = "\U0001f442\U0001f3fc" - EAR_MEDIUM_SKIN_TONE = "\U0001f442\U0001f3fd" - EAR_MEDIUM_DARK_SKIN_TONE = "\U0001f442\U0001f3fe" - EAR_DARK_SKIN_TONE = "\U0001f442\U0001f3ff" - NOSE = "\U0001f443" - NOSE_LIGHT_SKIN_TONE = "\U0001f443\U0001f3fb" - NOSE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f443\U0001f3fc" - NOSE_MEDIUM_SKIN_TONE = "\U0001f443\U0001f3fd" - NOSE_MEDIUM_DARK_SKIN_TONE = "\U0001f443\U0001f3fe" - NOSE_DARK_SKIN_TONE = "\U0001f443\U0001f3ff" - RED_HAIR = "\U0001f9b0" - CURLY_HAIR = "\U0001f9b1" - BALD = "\U0001f9b2" - WHITE_HAIR = "\U0001f9b3" - FOOTPRINTS = "\U0001f463" - EYES = "\U0001f440" - EYE = "\U0001f441\ufe0f" - EYE_IN_SPEECH_BUBBLE = "\U0001f441\u200d\U0001f5e8" - BRAIN = "\U0001f9e0" - BONE = "\U0001f9b4" - TOOTH = "\U0001f9b7" - TONGUE = "\U0001f445" - MOUTH = "\U0001f444" - KISS_MARK = "\U0001f48b" - HEART_WITH_ARROW = "\U0001f498" - RED_HEART = "\u2764\ufe0f" - BEATING_HEART = "\U0001f493" - BROKEN_HEART = "\U0001f494" - TWO_HEARTS = "\U0001f495" - SPARKLING_HEART = "\U0001f496" - GROWING_HEART = "\U0001f497" - BLUE_HEART = "\U0001f499" - GREEN_HEART = "\U0001f49a" - YELLOW_HEART = "\U0001f49b" - ORANGE_HEART = "\U0001f9e1" - PURPLE_HEART = "\U0001f49c" - BLACK_HEART = "\U0001f5a4" - HEART_WITH_RIBBON = "\U0001f49d" - REVOLVING_HEARTS = "\U0001f49e" - HEART_DECORATION = "\U0001f49f" - HEAVY_HEART_EXCLAMATION = "\u2763\ufe0f" - LOVE_LETTER = "\U0001f48c" - ZZZ = "\U0001f4a4" - ANGER_SYMBOL = "\U0001f4a2" - BOMB = "\U0001f4a3" - COLLISION = "\U0001f4a5" - SWEAT_DROPLETS = "\U0001f4a6" - DASHING_AWAY = "\U0001f4a8" - DIZZY = "\U0001f4ab" - SPEECH_BALLOON = "\U0001f4ac" - LEFT_SPEECH_BUBBLE = "\U0001f5e8\ufe0f" - RIGHT_ANGER_BUBBLE = "\U0001f5ef\ufe0f" - THOUGHT_BALLOON = "\U0001f4ad" - HOLE = "\U0001f573\ufe0f" - GLASSES = "\U0001f453" - SUNGLASSES = "\U0001f576\ufe0f" - GOGGLES = "\U0001f97d" - LAB_COAT = "\U0001f97c" - NECKTIE = "\U0001f454" - T_SHIRT = "\U0001f455" - JEANS = "\U0001f456" - SCARF = "\U0001f9e3" - GLOVES = "\U0001f9e4" - COAT = "\U0001f9e5" - SOCKS = "\U0001f9e6" - DRESS = "\U0001f457" - KIMONO = "\U0001f458" - BIKINI = "\U0001f459" - WOMAN_S_CLOTHES = "\U0001f45a" - PURSE = "\U0001f45b" - HANDBAG = "\U0001f45c" - CLUTCH_BAG = "\U0001f45d" - SHOPPING_BAGS = "\U0001f6cd\ufe0f" - BACKPACK = "\U0001f392" - MAN_S_SHOE = "\U0001f45e" - RUNNING_SHOE = "\U0001f45f" - HIKING_BOOT = "\U0001f97e" - FLAT_SHOE = "\U0001f97f" - HIGH_HEELED_SHOE = "\U0001f460" - WOMAN_S_SANDAL = "\U0001f461" - WOMAN_S_BOOT = "\U0001f462" - CROWN = "\U0001f451" - WOMAN_S_HAT = "\U0001f452" - TOP_HAT = "\U0001f3a9" - GRADUATION_CAP = "\U0001f393" - BILLED_CAP = "\U0001f9e2" - RESCUE_WORKER_S_HELMET = "\u26d1\ufe0f" - PRAYER_BEADS = "\U0001f4ff" - LIPSTICK = "\U0001f484" - RING = "\U0001f48d" - GEM_STONE = "\U0001f48e" - MONKEY_FACE = "\U0001f435" - MONKEY = "\U0001f412" - GORILLA = "\U0001f98d" - DOG_FACE = "\U0001f436" - DOG = "\U0001f415" - POODLE = "\U0001f429" - WOLF_FACE = "\U0001f43a" - FOX_FACE = "\U0001f98a" - RACCOON = "\U0001f99d" - CAT_FACE = "\U0001f431" - CAT = "\U0001f408" - LION_FACE = "\U0001f981" - TIGER_FACE = "\U0001f42f" - TIGER = "\U0001f405" - LEOPARD = "\U0001f406" - HORSE_FACE = "\U0001f434" - HORSE = "\U0001f40e" - UNICORN_FACE = "\U0001f984" - ZEBRA = "\U0001f993" - DEER = "\U0001f98c" - COW_FACE = "\U0001f42e" - OX = "\U0001f402" - WATER_BUFFALO = "\U0001f403" - COW = "\U0001f404" - PIG_FACE = "\U0001f437" - PIG = "\U0001f416" - BOAR = "\U0001f417" - PIG_NOSE = "\U0001f43d" - RAM = "\U0001f40f" - EWE = "\U0001f411" - GOAT = "\U0001f410" - CAMEL = "\U0001f42a" - TWO_HUMP_CAMEL = "\U0001f42b" - LLAMA = "\U0001f999" - GIRAFFE = "\U0001f992" - ELEPHANT = "\U0001f418" - RHINOCEROS = "\U0001f98f" - HIPPOPOTAMUS = "\U0001f99b" - MOUSE_FACE = "\U0001f42d" - MOUSE = "\U0001f401" - RAT = "\U0001f400" - HAMSTER_FACE = "\U0001f439" - RABBIT_FACE = "\U0001f430" - RABBIT = "\U0001f407" - CHIPMUNK = "\U0001f43f\ufe0f" - HEDGEHOG = "\U0001f994" - BAT = "\U0001f987" - BEAR_FACE = "\U0001f43b" - KOALA = "\U0001f428" - PANDA_FACE = "\U0001f43c" - KANGAROO = "\U0001f998" - BADGER = "\U0001f9a1" - PAW_PRINTS = "\U0001f43e" - TURKEY_2 = "\U0001f983" - CHICKEN = "\U0001f414" - ROOSTER = "\U0001f413" - HATCHING_CHICK = "\U0001f423" - BABY_CHICK = "\U0001f424" - FRONT_FACING_BABY_CHICK = "\U0001f425" - BIRD = "\U0001f426" - PENGUIN = "\U0001f427" - DOVE = "\U0001f54a\ufe0f" - EAGLE = "\U0001f985" - DUCK = "\U0001f986" - SWAN = "\U0001f9a2" - OWL = "\U0001f989" - PEACOCK = "\U0001f99a" - PARROT = "\U0001f99c" - FROG_FACE = "\U0001f438" - CROCODILE = "\U0001f40a" - TURTLE = "\U0001f422" - LIZARD = "\U0001f98e" - SNAKE = "\U0001f40d" - DRAGON_FACE = "\U0001f432" - DRAGON = "\U0001f409" - SAUROPOD = "\U0001f995" - T_REX = "\U0001f996" - SPOUTING_WHALE = "\U0001f433" - WHALE = "\U0001f40b" - DOLPHIN = "\U0001f42c" - FISH = "\U0001f41f" - TROPICAL_FISH = "\U0001f420" - BLOWFISH = "\U0001f421" - SHARK = "\U0001f988" - OCTOPUS = "\U0001f419" - SPIRAL_SHELL = "\U0001f41a" - CRAB = "\U0001f980" - LOBSTER = "\U0001f99e" - SHRIMP = "\U0001f990" - SQUID = "\U0001f991" - SNAIL = "\U0001f40c" - BUTTERFLY = "\U0001f98b" - BUG = "\U0001f41b" - ANT = "\U0001f41c" - HONEYBEE = "\U0001f41d" - LADY_BEETLE = "\U0001f41e" - CRICKET = "\U0001f997" - SPIDER = "\U0001f577\ufe0f" - SPIDER_WEB = "\U0001f578\ufe0f" - SCORPION = "\U0001f982" - MOSQUITO = "\U0001f99f" - MICROBE = "\U0001f9a0" - BOUQUET = "\U0001f490" - CHERRY_BLOSSOM = "\U0001f338" - WHITE_FLOWER = "\U0001f4ae" - ROSETTE = "\U0001f3f5\ufe0f" - ROSE = "\U0001f339" - WILTED_FLOWER = "\U0001f940" - HIBISCUS = "\U0001f33a" - SUNFLOWER = "\U0001f33b" - BLOSSOM = "\U0001f33c" - TULIP = "\U0001f337" - SEEDLING = "\U0001f331" - EVERGREEN_TREE = "\U0001f332" - DECIDUOUS_TREE = "\U0001f333" - PALM_TREE = "\U0001f334" - CACTUS = "\U0001f335" - SHEAF_OF_RICE = "\U0001f33e" - HERB = "\U0001f33f" - SHAMROCK = "\u2618\ufe0f" - FOUR_LEAF_CLOVER = "\U0001f340" - MAPLE_LEAF = "\U0001f341" - FALLEN_LEAF = "\U0001f342" - LEAF_FLUTTERING_IN_WIND = "\U0001f343" - GRAPES = "\U0001f347" - MELON = "\U0001f348" - WATERMELON = "\U0001f349" - TANGERINE = "\U0001f34a" - LEMON = "\U0001f34b" - BANANA = "\U0001f34c" - PINEAPPLE = "\U0001f34d" - MANGO = "\U0001f96d" - RED_APPLE = "\U0001f34e" - GREEN_APPLE = "\U0001f34f" - PEAR = "\U0001f350" - PEACH = "\U0001f351" - CHERRIES = "\U0001f352" - STRAWBERRY = "\U0001f353" - KIWI_FRUIT = "\U0001f95d" - TOMATO = "\U0001f345" - COCONUT = "\U0001f965" - AVOCADO = "\U0001f951" - EGGPLANT = "\U0001f346" - POTATO = "\U0001f954" - CARROT = "\U0001f955" - EAR_OF_CORN = "\U0001f33d" - HOT_PEPPER = "\U0001f336\ufe0f" - CUCUMBER = "\U0001f952" - LEAFY_GREEN = "\U0001f96c" - BROCCOLI = "\U0001f966" - MUSHROOM = "\U0001f344" - PEANUTS = "\U0001f95c" - CHESTNUT = "\U0001f330" - BREAD = "\U0001f35e" - CROISSANT = "\U0001f950" - BAGUETTE_BREAD = "\U0001f956" - PRETZEL = "\U0001f968" - BAGEL = "\U0001f96f" - PANCAKES = "\U0001f95e" - CHEESE_WEDGE = "\U0001f9c0" - MEAT_ON_BONE = "\U0001f356" - POULTRY_LEG = "\U0001f357" - CUT_OF_MEAT = "\U0001f969" - BACON = "\U0001f953" - HAMBURGER = "\U0001f354" - FRENCH_FRIES = "\U0001f35f" - PIZZA = "\U0001f355" - HOT_DOG = "\U0001f32d" - SANDWICH = "\U0001f96a" - TACO = "\U0001f32e" - BURRITO = "\U0001f32f" - STUFFED_FLATBREAD = "\U0001f959" - EGG = "\U0001f95a" - COOKING = "\U0001f373" - SHALLOW_PAN_OF_FOOD = "\U0001f958" - POT_OF_FOOD = "\U0001f372" - BOWL_WITH_SPOON = "\U0001f963" - GREEN_SALAD = "\U0001f957" - POPCORN = "\U0001f37f" - SALT = "\U0001f9c2" - CANNED_FOOD = "\U0001f96b" - BENTO_BOX = "\U0001f371" - RICE_CRACKER = "\U0001f358" - RICE_BALL = "\U0001f359" - COOKED_RICE = "\U0001f35a" - CURRY_RICE = "\U0001f35b" - STEAMING_BOWL = "\U0001f35c" - SPAGHETTI = "\U0001f35d" - ROASTED_SWEET_POTATO = "\U0001f360" - ODEN = "\U0001f362" - SUSHI = "\U0001f363" - FRIED_SHRIMP = "\U0001f364" - FISH_CAKE_WITH_SWIRL = "\U0001f365" - MOON_CAKE = "\U0001f96e" - DANGO = "\U0001f361" - DUMPLING = "\U0001f95f" - FORTUNE_COOKIE = "\U0001f960" - TAKEOUT_BOX = "\U0001f961" - SOFT_ICE_CREAM = "\U0001f366" - SHAVED_ICE = "\U0001f367" - ICE_CREAM = "\U0001f368" - DOUGHNUT = "\U0001f369" - COOKIE = "\U0001f36a" - BIRTHDAY_CAKE = "\U0001f382" - SHORTCAKE = "\U0001f370" - CUPCAKE = "\U0001f9c1" - PIE = "\U0001f967" - CHOCOLATE_BAR = "\U0001f36b" - CANDY = "\U0001f36c" - LOLLIPOP = "\U0001f36d" - CUSTARD = "\U0001f36e" - HONEY_POT = "\U0001f36f" - BABY_BOTTLE = "\U0001f37c" - GLASS_OF_MILK = "\U0001f95b" - HOT_BEVERAGE = "\u2615" - TEACUP_WITHOUT_HANDLE = "\U0001f375" - SAKE = "\U0001f376" - BOTTLE_WITH_POPPING_CORK = "\U0001f37e" - WINE_GLASS = "\U0001f377" - COCKTAIL_GLASS = "\U0001f378" - TROPICAL_DRINK = "\U0001f379" - BEER_MUG = "\U0001f37a" - CLINKING_BEER_MUGS = "\U0001f37b" - CLINKING_GLASSES = "\U0001f942" - TUMBLER_GLASS = "\U0001f943" - CUP_WITH_STRAW = "\U0001f964" - CHOPSTICKS = "\U0001f962" - FORK_AND_KNIFE_WITH_PLATE = "\U0001f37d\ufe0f" - FORK_AND_KNIFE = "\U0001f374" - SPOON = "\U0001f944" - KITCHEN_KNIFE = "\U0001f52a" - AMPHORA = "\U0001f3fa" - GLOBE_SHOWING_EUROPE_AFRICA = "\U0001f30d" - GLOBE_SHOWING_AMERICAS = "\U0001f30e" - GLOBE_SHOWING_ASIA_AUSTRALIA = "\U0001f30f" - GLOBE_WITH_MERIDIANS = "\U0001f310" - WORLD_MAP = "\U0001f5fa\ufe0f" - MAP_OF_JAPAN = "\U0001f5fe" - COMPASS = "\U0001f9ed" - SNOW_CAPPED_MOUNTAIN = "\U0001f3d4\ufe0f" - MOUNTAIN = "\u26f0\ufe0f" - VOLCANO = "\U0001f30b" - MOUNT_FUJI = "\U0001f5fb" - CAMPING = "\U0001f3d5\ufe0f" - BEACH_WITH_UMBRELLA = "\U0001f3d6\ufe0f" - DESERT = "\U0001f3dc\ufe0f" - DESERT_ISLAND = "\U0001f3dd\ufe0f" - NATIONAL_PARK = "\U0001f3de\ufe0f" - STADIUM = "\U0001f3df\ufe0f" - CLASSICAL_BUILDING = "\U0001f3db\ufe0f" - BUILDING_CONSTRUCTION = "\U0001f3d7\ufe0f" - HOUSES = "\U0001f3d8\ufe0f" - DERELICT_HOUSE = "\U0001f3da\ufe0f" - HOUSE = "\U0001f3e0" - HOUSE_WITH_GARDEN = "\U0001f3e1" - BRICK = "\U0001f9f1" - OFFICE_BUILDING = "\U0001f3e2" - JAPANESE_POST_OFFICE = "\U0001f3e3" - POST_OFFICE = "\U0001f3e4" - HOSPITAL = "\U0001f3e5" - BANK = "\U0001f3e6" - HOTEL = "\U0001f3e8" - LOVE_HOTEL = "\U0001f3e9" - CONVENIENCE_STORE = "\U0001f3ea" - SCHOOL = "\U0001f3eb" - DEPARTMENT_STORE = "\U0001f3ec" - FACTORY = "\U0001f3ed" - JAPANESE_CASTLE = "\U0001f3ef" - CASTLE = "\U0001f3f0" - WEDDING = "\U0001f492" - TOKYO_TOWER = "\U0001f5fc" - STATUE_OF_LIBERTY = "\U0001f5fd" - CHURCH = "\u26ea" - MOSQUE = "\U0001f54c" - SYNAGOGUE = "\U0001f54d" - SHINTO_SHRINE = "\u26e9\ufe0f" - KAABA = "\U0001f54b" - FOUNTAIN = "\u26f2" - TENT = "\u26fa" - FOGGY = "\U0001f301" - NIGHT_WITH_STARS = "\U0001f303" - CITYSCAPE = "\U0001f3d9\ufe0f" - SUNRISE_OVER_MOUNTAINS = "\U0001f304" - SUNRISE = "\U0001f305" - CITYSCAPE_AT_DUSK = "\U0001f306" - SUNSET = "\U0001f307" - BRIDGE_AT_NIGHT = "\U0001f309" - HOT_SPRINGS = "\u2668\ufe0f" - MILKY_WAY = "\U0001f30c" - CAROUSEL_HORSE = "\U0001f3a0" - FERRIS_WHEEL = "\U0001f3a1" - ROLLER_COASTER = "\U0001f3a2" - BARBER_POLE = "\U0001f488" - CIRCUS_TENT = "\U0001f3aa" - LOCOMOTIVE = "\U0001f682" - RAILWAY_CAR = "\U0001f683" - HIGH_SPEED_TRAIN = "\U0001f684" - BULLET_TRAIN = "\U0001f685" - TRAIN = "\U0001f686" - METRO = "\U0001f687" - LIGHT_RAIL = "\U0001f688" - STATION = "\U0001f689" - TRAM = "\U0001f68a" - MONORAIL = "\U0001f69d" - MOUNTAIN_RAILWAY = "\U0001f69e" - TRAM_CAR = "\U0001f68b" - BUS = "\U0001f68c" - ONCOMING_BUS = "\U0001f68d" - TROLLEYBUS = "\U0001f68e" - MINIBUS = "\U0001f690" - AMBULANCE = "\U0001f691" - FIRE_ENGINE = "\U0001f692" - POLICE_CAR = "\U0001f693" - ONCOMING_POLICE_CAR = "\U0001f694" - TAXI = "\U0001f695" - ONCOMING_TAXI = "\U0001f696" - AUTOMOBILE = "\U0001f697" - ONCOMING_AUTOMOBILE = "\U0001f698" - SPORT_UTILITY_VEHICLE = "\U0001f699" - DELIVERY_TRUCK = "\U0001f69a" - ARTICULATED_LORRY = "\U0001f69b" - TRACTOR = "\U0001f69c" - BICYCLE = "\U0001f6b2" - KICK_SCOOTER = "\U0001f6f4" - SKATEBOARD = "\U0001f6f9" - MOTOR_SCOOTER = "\U0001f6f5" - BUS_STOP = "\U0001f68f" - MOTORWAY = "\U0001f6e3\ufe0f" - RAILWAY_TRACK = "\U0001f6e4\ufe0f" - OIL_DRUM = "\U0001f6e2\ufe0f" - FUEL_PUMP = "\u26fd" - POLICE_CAR_LIGHT = "\U0001f6a8" - HORIZONTAL_TRAFFIC_LIGHT = "\U0001f6a5" - VERTICAL_TRAFFIC_LIGHT = "\U0001f6a6" - STOP_SIGN = "\U0001f6d1" - CONSTRUCTION = "\U0001f6a7" - ANCHOR = "\u2693" - SAILBOAT = "\u26f5" - CANOE = "\U0001f6f6" - SPEEDBOAT = "\U0001f6a4" - PASSENGER_SHIP = "\U0001f6f3\ufe0f" - FERRY = "\u26f4\ufe0f" - MOTOR_BOAT = "\U0001f6e5\ufe0f" - SHIP = "\U0001f6a2" - AIRPLANE = "\u2708\ufe0f" - SMALL_AIRPLANE = "\U0001f6e9\ufe0f" - AIRPLANE_DEPARTURE = "\U0001f6eb" - AIRPLANE_ARRIVAL = "\U0001f6ec" - SEAT = "\U0001f4ba" - HELICOPTER = "\U0001f681" - SUSPENSION_RAILWAY = "\U0001f69f" - MOUNTAIN_CABLEWAY = "\U0001f6a0" - AERIAL_TRAMWAY = "\U0001f6a1" - SATELLITE = "\U0001f6f0\ufe0f" - ROCKET = "\U0001f680" - FLYING_SAUCER = "\U0001f6f8" - BELLHOP_BELL = "\U0001f6ce\ufe0f" - LUGGAGE = "\U0001f9f3" - HOURGLASS_DONE = "\u231b" - HOURGLASS_NOT_DONE = "\u23f3" - WATCH = "\u231a" - ALARM_CLOCK = "\u23f0" - STOPWATCH = "\u23f1\ufe0f" - TIMER_CLOCK = "\u23f2\ufe0f" - MANTELPIECE_CLOCK = "\U0001f570\ufe0f" - TWELVE_O_CLOCK = "\U0001f55b" - TWELVE_THIRTY = "\U0001f567" - ONE_O_CLOCK = "\U0001f550" - ONE_THIRTY = "\U0001f55c" - TWO_O_CLOCK = "\U0001f551" - TWO_THIRTY = "\U0001f55d" - THREE_O_CLOCK = "\U0001f552" - THREE_THIRTY = "\U0001f55e" - FOUR_O_CLOCK = "\U0001f553" - FOUR_THIRTY = "\U0001f55f" - FIVE_O_CLOCK = "\U0001f554" - FIVE_THIRTY = "\U0001f560" - SIX_O_CLOCK = "\U0001f555" - SIX_THIRTY = "\U0001f561" - SEVEN_O_CLOCK = "\U0001f556" - SEVEN_THIRTY = "\U0001f562" - EIGHT_O_CLOCK = "\U0001f557" - EIGHT_THIRTY = "\U0001f563" - NINE_O_CLOCK = "\U0001f558" - NINE_THIRTY = "\U0001f564" - TEN_O_CLOCK = "\U0001f559" - TEN_THIRTY = "\U0001f565" - ELEVEN_O_CLOCK = "\U0001f55a" - ELEVEN_THIRTY = "\U0001f566" - NEW_MOON = "\U0001f311" - WAXING_CRESCENT_MOON = "\U0001f312" - FIRST_QUARTER_MOON = "\U0001f313" - WAXING_GIBBOUS_MOON = "\U0001f314" - FULL_MOON = "\U0001f315" - WANING_GIBBOUS_MOON = "\U0001f316" - LAST_QUARTER_MOON = "\U0001f317" - WANING_CRESCENT_MOON = "\U0001f318" - CRESCENT_MOON = "\U0001f319" - NEW_MOON_FACE = "\U0001f31a" - FIRST_QUARTER_MOON_FACE = "\U0001f31b" - LAST_QUARTER_MOON_FACE = "\U0001f31c" - THERMOMETER = "\U0001f321\ufe0f" - SUN = "\u2600\ufe0f" - FULL_MOON_FACE = "\U0001f31d" - SUN_WITH_FACE = "\U0001f31e" - STAR = "\u2b50" - GLOWING_STAR = "\U0001f31f" - SHOOTING_STAR = "\U0001f320" - CLOUD = "\u2601\ufe0f" - SUN_BEHIND_CLOUD = "\u26c5" - CLOUD_WITH_LIGHTNING_AND_RAIN = "\u26c8\ufe0f" - SUN_BEHIND_SMALL_CLOUD = "\U0001f324\ufe0f" - SUN_BEHIND_LARGE_CLOUD = "\U0001f325\ufe0f" - SUN_BEHIND_RAIN_CLOUD = "\U0001f326\ufe0f" - CLOUD_WITH_RAIN = "\U0001f327\ufe0f" - CLOUD_WITH_SNOW = "\U0001f328\ufe0f" - CLOUD_WITH_LIGHTNING = "\U0001f329\ufe0f" - TORNADO = "\U0001f32a\ufe0f" - FOG = "\U0001f32b\ufe0f" - WIND_FACE = "\U0001f32c\ufe0f" - CYCLONE = "\U0001f300" - RAINBOW = "\U0001f308" - CLOSED_UMBRELLA = "\U0001f302" - UMBRELLA = "\u2602\ufe0f" - UMBRELLA_WITH_RAIN_DROPS = "\u2614" - UMBRELLA_ON_GROUND = "\u26f1\ufe0f" - HIGH_VOLTAGE = "\u26a1" - SNOWFLAKE = "\u2744\ufe0f" - SNOWMAN = "\u2603\ufe0f" - SNOWMAN_WITHOUT_SNOW = "\u26c4" - COMET = "\u2604\ufe0f" - FIRE = "\U0001f525" - DROPLET = "\U0001f4a7" - WATER_WAVE = "\U0001f30a" - JACK_O_LANTERN = "\U0001f383" - CHRISTMAS_TREE = "\U0001f384" - FIREWORKS = "\U0001f386" - SPARKLER = "\U0001f387" - FIRECRACKER = "\U0001f9e8" - SPARKLES = "\u2728" - BALLOON = "\U0001f388" - PARTY_POPPER = "\U0001f389" - CONFETTI_BALL = "\U0001f38a" - TANABATA_TREE = "\U0001f38b" - PINE_DECORATION = "\U0001f38d" - JAPANESE_DOLLS = "\U0001f38e" - CARP_STREAMER = "\U0001f38f" - WIND_CHIME = "\U0001f390" - MOON_VIEWING_CEREMONY = "\U0001f391" - RED_ENVELOPE = "\U0001f9e7" - RIBBON = "\U0001f380" - WRAPPED_GIFT = "\U0001f381" - REMINDER_RIBBON = "\U0001f397\ufe0f" - ADMISSION_TICKETS = "\U0001f39f\ufe0f" - TICKET = "\U0001f3ab" - MILITARY_MEDAL = "\U0001f396\ufe0f" - TROPHY = "\U0001f3c6" - SPORTS_MEDAL = "\U0001f3c5" - FIRST_PLACE_MEDAL = "\U0001f947" - SECOND_PLACE_MEDAL = "\U0001f948" - THIRD_PLACE_MEDAL = "\U0001f949" - SOCCER_BALL = "\u26bd" - BASEBALL = "\u26be" - SOFTBALL = "\U0001f94e" - BASKETBALL = "\U0001f3c0" - VOLLEYBALL = "\U0001f3d0" - AMERICAN_FOOTBALL = "\U0001f3c8" - RUGBY_FOOTBALL = "\U0001f3c9" - TENNIS = "\U0001f3be" - FLYING_DISC = "\U0001f94f" - BOWLING = "\U0001f3b3" - CRICKET_GAME = "\U0001f3cf" - FIELD_HOCKEY = "\U0001f3d1" - ICE_HOCKEY = "\U0001f3d2" - LACROSSE = "\U0001f94d" - PING_PONG = "\U0001f3d3" - BADMINTON = "\U0001f3f8" - BOXING_GLOVE = "\U0001f94a" - MARTIAL_ARTS_UNIFORM = "\U0001f94b" - GOAL_NET = "\U0001f945" - FLAG_IN_HOLE = "\u26f3" - ICE_SKATE = "\u26f8\ufe0f" - FISHING_POLE = "\U0001f3a3" - RUNNING_SHIRT = "\U0001f3bd" - SKIS = "\U0001f3bf" - SLED = "\U0001f6f7" - CURLING_STONE = "\U0001f94c" - DIRECT_HIT = "\U0001f3af" - POOL_8_BALL = "\U0001f3b1" - CRYSTAL_BALL = "\U0001f52e" - NAZAR_AMULET = "\U0001f9ff" - VIDEO_GAME = "\U0001f3ae" - JOYSTICK = "\U0001f579\ufe0f" - SLOT_MACHINE = "\U0001f3b0" - GAME_DIE = "\U0001f3b2" - JIGSAW = "\U0001f9e9" - TEDDY_BEAR = "\U0001f9f8" - SPADE_SUIT = "\u2660\ufe0f" - HEART_SUIT = "\u2665\ufe0f" - DIAMOND_SUIT = "\u2666\ufe0f" - CLUB_SUIT = "\u2663\ufe0f" - CHESS_PAWN = "\u265f\ufe0f" - JOKER = "\U0001f0cf" - MAHJONG_RED_DRAGON = "\U0001f004" - FLOWER_PLAYING_CARDS = "\U0001f3b4" - PERFORMING_ARTS = "\U0001f3ad" - FRAMED_PICTURE = "\U0001f5bc\ufe0f" - ARTIST_PALETTE = "\U0001f3a8" - MUTED_SPEAKER = "\U0001f507" - SPEAKER_LOW_VOLUME = "\U0001f508" - SPEAKER_MEDIUM_VOLUME = "\U0001f509" - SPEAKER_HIGH_VOLUME = "\U0001f50a" - LOUDSPEAKER = "\U0001f4e2" - MEGAPHONE = "\U0001f4e3" - POSTAL_HORN = "\U0001f4ef" - BELL = "\U0001f514" - BELL_WITH_SLASH = "\U0001f515" - MUSICAL_SCORE = "\U0001f3bc" - MUSICAL_NOTE = "\U0001f3b5" - MUSICAL_NOTES = "\U0001f3b6" - STUDIO_MICROPHONE = "\U0001f399\ufe0f" - LEVEL_SLIDER = "\U0001f39a\ufe0f" - CONTROL_KNOBS = "\U0001f39b\ufe0f" - MICROPHONE = "\U0001f3a4" - HEADPHONE = "\U0001f3a7" - RADIO = "\U0001f4fb" - SAXOPHONE = "\U0001f3b7" - GUITAR = "\U0001f3b8" - MUSICAL_KEYBOARD = "\U0001f3b9" - TRUMPET = "\U0001f3ba" - VIOLIN = "\U0001f3bb" - DRUM = "\U0001f941" - MOBILE_PHONE = "\U0001f4f1" - MOBILE_PHONE_WITH_ARROW = "\U0001f4f2" - TELEPHONE = "\u260e\ufe0f" - TELEPHONE_RECEIVER = "\U0001f4de" - PAGER = "\U0001f4df" - FAX_MACHINE = "\U0001f4e0" - BATTERY = "\U0001f50b" - ELECTRIC_PLUG = "\U0001f50c" - LAPTOP_COMPUTER = "\U0001f4bb" - DESKTOP_COMPUTER = "\U0001f5a5\ufe0f" - PRINTER = "\U0001f5a8\ufe0f" - KEYBOARD = "\u2328\ufe0f" - COMPUTER_MOUSE = "\U0001f5b1\ufe0f" - TRACKBALL = "\U0001f5b2\ufe0f" - COMPUTER_DISK = "\U0001f4bd" - FLOPPY_DISK = "\U0001f4be" - OPTICAL_DISK = "\U0001f4bf" - DVD = "\U0001f4c0" - ABACUS = "\U0001f9ee" - MOVIE_CAMERA = "\U0001f3a5" - FILM_FRAMES = "\U0001f39e\ufe0f" - FILM_PROJECTOR = "\U0001f4fd\ufe0f" - CLAPPER_BOARD = "\U0001f3ac" - TELEVISION = "\U0001f4fa" - CAMERA = "\U0001f4f7" - CAMERA_WITH_FLASH = "\U0001f4f8" - VIDEO_CAMERA = "\U0001f4f9" - VIDEOCASSETTE = "\U0001f4fc" - MAGNIFYING_GLASS_TILTED_LEFT = "\U0001f50d" - MAGNIFYING_GLASS_TILTED_RIGHT = "\U0001f50e" - CANDLE = "\U0001f56f\ufe0f" - LIGHT_BULB = "\U0001f4a1" - FLASHLIGHT = "\U0001f526" - RED_PAPER_LANTERN = "\U0001f3ee" - NOTEBOOK_WITH_DECORATIVE_COVER = "\U0001f4d4" - CLOSED_BOOK = "\U0001f4d5" - OPEN_BOOK = "\U0001f4d6" - GREEN_BOOK = "\U0001f4d7" - BLUE_BOOK = "\U0001f4d8" - ORANGE_BOOK = "\U0001f4d9" - BOOKS = "\U0001f4da" - NOTEBOOK = "\U0001f4d3" - LEDGER = "\U0001f4d2" - PAGE_WITH_CURL = "\U0001f4c3" - SCROLL = "\U0001f4dc" - PAGE_FACING_UP = "\U0001f4c4" - NEWSPAPER = "\U0001f4f0" - ROLLED_UP_NEWSPAPER = "\U0001f5de\ufe0f" - BOOKMARK_TABS = "\U0001f4d1" - BOOKMARK = "\U0001f516" - LABEL = "\U0001f3f7\ufe0f" - MONEY_BAG = "\U0001f4b0" - YEN_BANKNOTE = "\U0001f4b4" - DOLLAR_BANKNOTE = "\U0001f4b5" - EURO_BANKNOTE = "\U0001f4b6" - POUND_BANKNOTE = "\U0001f4b7" - MONEY_WITH_WINGS = "\U0001f4b8" - CREDIT_CARD = "\U0001f4b3" - RECEIPT = "\U0001f9fe" - CHART_INCREASING_WITH_YEN = "\U0001f4b9" - CURRENCY_EXCHANGE = "\U0001f4b1" - HEAVY_DOLLAR_SIGN = "\U0001f4b2" - ENVELOPE = "\u2709\ufe0f" - E_MAIL = "\U0001f4e7" - INCOMING_ENVELOPE = "\U0001f4e8" - ENVELOPE_WITH_ARROW = "\U0001f4e9" - OUTBOX_TRAY = "\U0001f4e4" - INBOX_TRAY = "\U0001f4e5" - PACKAGE = "\U0001f4e6" - CLOSED_MAILBOX_WITH_RAISED_FLAG = "\U0001f4eb" - CLOSED_MAILBOX_WITH_LOWERED_FLAG = "\U0001f4ea" - OPEN_MAILBOX_WITH_RAISED_FLAG = "\U0001f4ec" - OPEN_MAILBOX_WITH_LOWERED_FLAG = "\U0001f4ed" - POSTBOX = "\U0001f4ee" - BALLOT_BOX_WITH_BALLOT = "\U0001f5f3\ufe0f" - PENCIL = "\u270f\ufe0f" - BLACK_NIB = "\u2712\ufe0f" - FOUNTAIN_PEN = "\U0001f58b\ufe0f" - PEN = "\U0001f58a\ufe0f" - PAINTBRUSH = "\U0001f58c\ufe0f" - CRAYON = "\U0001f58d\ufe0f" - MEMO = "\U0001f4dd" - BRIEFCASE = "\U0001f4bc" - FILE_FOLDER = "\U0001f4c1" - OPEN_FILE_FOLDER = "\U0001f4c2" - CARD_INDEX_DIVIDERS = "\U0001f5c2\ufe0f" - CALENDAR = "\U0001f4c5" - TEAR_OFF_CALENDAR = "\U0001f4c6" - SPIRAL_NOTEPAD = "\U0001f5d2\ufe0f" - SPIRAL_CALENDAR = "\U0001f5d3\ufe0f" - CARD_INDEX = "\U0001f4c7" - CHART_INCREASING = "\U0001f4c8" - CHART_DECREASING = "\U0001f4c9" - BAR_CHART = "\U0001f4ca" - CLIPBOARD = "\U0001f4cb" - PUSHPIN = "\U0001f4cc" - ROUND_PUSHPIN = "\U0001f4cd" - PAPERCLIP = "\U0001f4ce" - LINKED_PAPERCLIPS = "\U0001f587\ufe0f" - STRAIGHT_RULER = "\U0001f4cf" - TRIANGULAR_RULER = "\U0001f4d0" - SCISSORS = "\u2702\ufe0f" - CARD_FILE_BOX = "\U0001f5c3\ufe0f" - FILE_CABINET = "\U0001f5c4\ufe0f" - WASTEBASKET = "\U0001f5d1\ufe0f" - LOCKED = "\U0001f512" - UNLOCKED = "\U0001f513" - LOCKED_WITH_PEN = "\U0001f50f" - LOCKED_WITH_KEY = "\U0001f510" - KEY = "\U0001f511" - OLD_KEY = "\U0001f5dd\ufe0f" - HAMMER = "\U0001f528" - PICK = "\u26cf\ufe0f" - HAMMER_AND_PICK = "\u2692\ufe0f" - HAMMER_AND_WRENCH = "\U0001f6e0\ufe0f" - DAGGER = "\U0001f5e1\ufe0f" - CROSSED_SWORDS = "\u2694\ufe0f" - PISTOL = "\U0001f52b" - BOW_AND_ARROW = "\U0001f3f9" - SHIELD = "\U0001f6e1\ufe0f" - WRENCH = "\U0001f527" - NUT_AND_BOLT = "\U0001f529" - GEAR = "\u2699\ufe0f" - CLAMP = "\U0001f5dc\ufe0f" - BALANCE_SCALE = "\u2696\ufe0f" - LINK = "\U0001f517" - CHAINS = "\u26d3\ufe0f" - TOOLBOX = "\U0001f9f0" - MAGNET = "\U0001f9f2" - ALEMBIC = "\u2697\ufe0f" - TEST_TUBE = "\U0001f9ea" - PETRI_DISH = "\U0001f9eb" - DNA = "\U0001f9ec" - FIRE_EXTINGUISHER = "\U0001f9ef" - MICROSCOPE = "\U0001f52c" - TELESCOPE = "\U0001f52d" - SATELLITE_ANTENNA = "\U0001f4e1" - SYRINGE = "\U0001f489" - PILL = "\U0001f48a" - DOOR = "\U0001f6aa" - BED = "\U0001f6cf\ufe0f" - COUCH_AND_LAMP = "\U0001f6cb\ufe0f" - TOILET = "\U0001f6bd" - SHOWER = "\U0001f6bf" - BATHTUB = "\U0001f6c1" - LOTION_BOTTLE = "\U0001f9f4" - THREAD = "\U0001f9f5" - YARN = "\U0001f9f6" - SAFETY_PIN = "\U0001f9f7" - BROOM = "\U0001f9f9" - BASKET = "\U0001f9fa" - ROLL_OF_PAPER = "\U0001f9fb" - SOAP = "\U0001f9fc" - SPONGE = "\U0001f9fd" - SHOPPING_CART = "\U0001f6d2" - CIGARETTE = "\U0001f6ac" - COFFIN = "\u26b0\ufe0f" - FUNERAL_URN = "\u26b1\ufe0f" - MOAI = "\U0001f5ff" - ATM_SIGN = "\U0001f3e7" - LITTER_IN_BIN_SIGN = "\U0001f6ae" - POTABLE_WATER = "\U0001f6b0" - WHEELCHAIR_SYMBOL = "\u267f" - MEN_S_ROOM = "\U0001f6b9" - WOMEN_S_ROOM = "\U0001f6ba" - RESTROOM = "\U0001f6bb" - BABY_SYMBOL = "\U0001f6bc" - WATER_CLOSET = "\U0001f6be" - PASSPORT_CONTROL = "\U0001f6c2" - CUSTOMS = "\U0001f6c3" - BAGGAGE_CLAIM = "\U0001f6c4" - LEFT_LUGGAGE = "\U0001f6c5" - WARNING = "\u26a0\ufe0f" - CHILDREN_CROSSING = "\U0001f6b8" - NO_ENTRY = "\u26d4" - PROHIBITED = "\U0001f6ab" - NO_BICYCLES = "\U0001f6b3" - NO_SMOKING = "\U0001f6ad" - NO_LITTERING = "\U0001f6af" - NON_POTABLE_WATER = "\U0001f6b1" - NO_PEDESTRIANS = "\U0001f6b7" - NO_MOBILE_PHONES = "\U0001f4f5" - NO_ONE_UNDER_EIGHTEEN = "\U0001f51e" - RADIOACTIVE = "\u2622\ufe0f" - BIOHAZARD = "\u2623\ufe0f" - UP_ARROW = "\u2b06\ufe0f" - UP_RIGHT_ARROW = "\u2197\ufe0f" - RIGHT_ARROW = "\u27a1\ufe0f" - DOWN_RIGHT_ARROW = "\u2198\ufe0f" - DOWN_ARROW = "\u2b07\ufe0f" - DOWN_LEFT_ARROW = "\u2199\ufe0f" - LEFT_ARROW = "\u2b05\ufe0f" - UP_LEFT_ARROW = "\u2196\ufe0f" - UP_DOWN_ARROW = "\u2195\ufe0f" - LEFT_RIGHT_ARROW = "\u2194\ufe0f" - RIGHT_ARROW_CURVING_LEFT = "\u21a9\ufe0f" - LEFT_ARROW_CURVING_RIGHT = "\u21aa\ufe0f" - RIGHT_ARROW_CURVING_UP = "\u2934\ufe0f" - RIGHT_ARROW_CURVING_DOWN = "\u2935\ufe0f" - CLOCKWISE_VERTICAL_ARROWS = "\U0001f503" - COUNTERCLOCKWISE_ARROWS_BUTTON = "\U0001f504" - BACK_ARROW = "\U0001f519" - END_ARROW = "\U0001f51a" - ON_ARROW = "\U0001f51b" - SOON_ARROW = "\U0001f51c" - TOP_ARROW = "\U0001f51d" - PLACE_OF_WORSHIP = "\U0001f6d0" - ATOM_SYMBOL = "\u269b\ufe0f" - INFINITY = "\u267e\ufe0f" - OM = "\U0001f549\ufe0f" - STAR_OF_DAVID = "\u2721\ufe0f" - WHEEL_OF_DHARMA = "\u2638\ufe0f" - YIN_YANG = "\u262f\ufe0f" - LATIN_CROSS = "\u271d\ufe0f" - ORTHODOX_CROSS = "\u2626\ufe0f" - STAR_AND_CRESCENT = "\u262a\ufe0f" - PEACE_SYMBOL = "\u262e\ufe0f" - MENORAH = "\U0001f54e" - DOTTED_SIX_POINTED_STAR = "\U0001f52f" - ARIES = "\u2648" - TAURUS = "\u2649" - GEMINI = "\u264a" - CANCER = "\u264b" - LEO = "\u264c" - VIRGO = "\u264d" - LIBRA = "\u264e" - SCORPIO = "\u264f" - SAGITTARIUS = "\u2650" - CAPRICORN = "\u2651" - AQUARIUS = "\u2652" - PISCES = "\u2653" - OPHIUCHUS = "\u26ce" - SHUFFLE_TRACKS_BUTTON = "\U0001f500" - REPEAT_BUTTON = "\U0001f501" - REPEAT_SINGLE_BUTTON = "\U0001f502" - PLAY_BUTTON = "\u25b6\ufe0f" - FAST_FORWARD_BUTTON = "\u23e9" - NEXT_TRACK_BUTTON = "\u23ed\ufe0f" - PLAY_OR_PAUSE_BUTTON = "\u23ef\ufe0f" - REVERSE_BUTTON = "\u25c0\ufe0f" - FAST_REVERSE_BUTTON = "\u23ea" - LAST_TRACK_BUTTON = "\u23ee\ufe0f" - UPWARDS_BUTTON = "\U0001f53c" - FAST_UP_BUTTON = "\u23eb" - DOWNWARDS_BUTTON = "\U0001f53d" - FAST_DOWN_BUTTON = "\u23ec" - PAUSE_BUTTON = "\u23f8\ufe0f" - STOP_BUTTON = "\u23f9\ufe0f" - RECORD_BUTTON = "\u23fa\ufe0f" - EJECT_BUTTON = "\u23cf\ufe0f" - CINEMA = "\U0001f3a6" - DIM_BUTTON = "\U0001f505" - BRIGHT_BUTTON = "\U0001f506" - ANTENNA_BARS = "\U0001f4f6" - VIBRATION_MODE = "\U0001f4f3" - MOBILE_PHONE_OFF = "\U0001f4f4" - FEMALE_SIGN = "\u2640\ufe0f" - MALE_SIGN = "\u2642\ufe0f" - MEDICAL_SYMBOL = "\u2695\ufe0f" - RECYCLING_SYMBOL = "\u267b\ufe0f" - FLEUR_DE_LIS = "\u269c\ufe0f" - TRIDENT_EMBLEM = "\U0001f531" - NAME_BADGE = "\U0001f4db" - JAPANESE_SYMBOL_FOR_BEGINNER = "\U0001f530" - HEAVY_LARGE_CIRCLE = "\u2b55" - WHITE_HEAVY_CHECK_MARK = "\u2705" - BALLOT_BOX_WITH_CHECK = "\u2611\ufe0f" - HEAVY_CHECK_MARK = "\u2714\ufe0f" - HEAVY_MULTIPLICATION_X = "\u2716\ufe0f" - CROSS_MARK = "\u274c" - CROSS_MARK_BUTTON = "\u274e" - HEAVY_PLUS_SIGN = "\u2795" - HEAVY_MINUS_SIGN = "\u2796" - HEAVY_DIVISION_SIGN = "\u2797" - CURLY_LOOP = "\u27b0" - DOUBLE_CURLY_LOOP = "\u27bf" - PART_ALTERNATION_MARK = "\u303d\ufe0f" - EIGHT_SPOKED_ASTERISK = "\u2733\ufe0f" - EIGHT_POINTED_STAR = "\u2734\ufe0f" - SPARKLE = "\u2747\ufe0f" - DOUBLE_EXCLAMATION_MARK = "\u203c\ufe0f" - EXCLAMATION_QUESTION_MARK = "\u2049\ufe0f" - QUESTION_MARK = "\u2753" - WHITE_QUESTION_MARK = "\u2754" - WHITE_EXCLAMATION_MARK = "\u2755" - EXCLAMATION_MARK = "\u2757" - WAVY_DASH = "\u3030\ufe0f" - COPYRIGHT = "\xa9\ufe0f" - REGISTERED = "\xae\ufe0f" - TRADE_MARK = "\u2122\ufe0f" - KEYCAP_NUMBER_SIGN = "#\ufe0f\u20e3" - KEYCAP_ASTERISK = "*\ufe0f\u20e3" - KEYCAP_DIGIT_ZERO = "0\ufe0f\u20e3" - KEYCAP_DIGIT_ONE = "1\ufe0f\u20e3" - KEYCAP_DIGIT_TWO = "2\ufe0f\u20e3" - KEYCAP_DIGIT_THREE = "3\ufe0f\u20e3" - KEYCAP_DIGIT_FOUR = "4\ufe0f\u20e3" - KEYCAP_DIGIT_FIVE = "5\ufe0f\u20e3" - KEYCAP_DIGIT_SIX = "6\ufe0f\u20e3" - KEYCAP_DIGIT_SEVEN = "7\ufe0f\u20e3" - KEYCAP_DIGIT_EIGHT = "8\ufe0f\u20e3" - KEYCAP_DIGIT_NINE = "9\ufe0f\u20e3" - KEYCAP_10 = "\U0001f51f" - HUNDRED_POINTS = "\U0001f4af" - INPUT_LATIN_UPPERCASE = "\U0001f520" - INPUT_LATIN_LOWERCASE = "\U0001f521" - INPUT_NUMBERS = "\U0001f522" - INPUT_SYMBOLS = "\U0001f523" - INPUT_LATIN_LETTERS = "\U0001f524" - A_BUTTON_BLOOD_TYPE = "\U0001f170\ufe0f" - AB_BUTTON_BLOOD_TYPE = "\U0001f18e" - B_BUTTON_BLOOD_TYPE = "\U0001f171\ufe0f" - CL_BUTTON = "\U0001f191" - COOL_BUTTON = "\U0001f192" - FREE_BUTTON = "\U0001f193" - INFORMATION = "\u2139\ufe0f" - ID_BUTTON = "\U0001f194" - CIRCLED_M = "\u24c2\ufe0f" - NEW_BUTTON = "\U0001f195" - NG_BUTTON = "\U0001f196" - O_BUTTON_BLOOD_TYPE = "\U0001f17e\ufe0f" - OK_BUTTON = "\U0001f197" - P_BUTTON = "\U0001f17f\ufe0f" - SOS_BUTTON = "\U0001f198" - UP_BUTTON = "\U0001f199" - VS_BUTTON = "\U0001f19a" - JAPANESE_HERE_BUTTON = "\U0001f201" - JAPANESE_SERVICE_CHARGE_BUTTON = "\U0001f202\ufe0f" - JAPANESE_MONTHLY_AMOUNT_BUTTON = "\U0001f237\ufe0f" - JAPANESE_NOT_FREE_OF_CHARGE_BUTTON = "\U0001f236" - JAPANESE_RESERVED_BUTTON = "\U0001f22f" - JAPANESE_BARGAIN_BUTTON = "\U0001f250" - JAPANESE_DISCOUNT_BUTTON = "\U0001f239" - JAPANESE_FREE_OF_CHARGE_BUTTON = "\U0001f21a" - JAPANESE_PROHIBITED_BUTTON = "\U0001f232" - JAPANESE_ACCEPTABLE_BUTTON = "\U0001f251" - JAPANESE_APPLICATION_BUTTON = "\U0001f238" - JAPANESE_PASSING_GRADE_BUTTON = "\U0001f234" - JAPANESE_VACANCY_BUTTON = "\U0001f233" - JAPANESE_CONGRATULATIONS_BUTTON = "\u3297\ufe0f" - JAPANESE_SECRET_BUTTON = "\u3299\ufe0f" - JAPANESE_OPEN_FOR_BUSINESS_BUTTON = "\U0001f23a" - JAPANESE_NO_VACANCY_BUTTON = "\U0001f235" - BLACK_SMALL_SQUARE = "\u25aa\ufe0f" - WHITE_SMALL_SQUARE = "\u25ab\ufe0f" - WHITE_MEDIUM_SQUARE = "\u25fb\ufe0f" - BLACK_MEDIUM_SQUARE = "\u25fc\ufe0f" - WHITE_MEDIUM_SMALL_SQUARE = "\u25fd" - BLACK_MEDIUM_SMALL_SQUARE = "\u25fe" - BLACK_LARGE_SQUARE = "\u2b1b" - WHITE_LARGE_SQUARE = "\u2b1c" - LARGE_ORANGE_DIAMOND = "\U0001f536" - LARGE_BLUE_DIAMOND = "\U0001f537" - SMALL_ORANGE_DIAMOND = "\U0001f538" - SMALL_BLUE_DIAMOND = "\U0001f539" - RED_TRIANGLE_POINTED_UP = "\U0001f53a" - RED_TRIANGLE_POINTED_DOWN = "\U0001f53b" - DIAMOND_WITH_A_DOT = "\U0001f4a0" - RADIO_BUTTON = "\U0001f518" - BLACK_SQUARE_BUTTON = "\U0001f532" - WHITE_SQUARE_BUTTON = "\U0001f533" - WHITE_CIRCLE = "\u26aa" - BLACK_CIRCLE = "\u26ab" - RED_CIRCLE = "\U0001f534" - BLUE_CIRCLE = "\U0001f535" - CHEQUERED_FLAG = "\U0001f3c1" - TRIANGULAR_FLAG = "\U0001f6a9" - CROSSED_FLAGS = "\U0001f38c" - BLACK_FLAG = "\U0001f3f4" - WHITE_FLAG = "\U0001f3f3\ufe0f" - RAINBOW_FLAG = "\U0001f3f3\ufe0f\u200d\U0001f308" - PIRATE_FLAG = "\U0001f3f4\u200d\u2620\ufe0f" - ASCENSION_ISLAND = "\U0001f1e6\U0001f1e8" - ANDORRA = "\U0001f1e6\U0001f1e9" - UNITED_ARAB_EMIRATES = "\U0001f1e6\U0001f1ea" - AFGHANISTAN = "\U0001f1e6\U0001f1eb" - ANTIGUA_AND_BARBUDA = "\U0001f1e6\U0001f1ec" - ANGUILLA = "\U0001f1e6\U0001f1ee" - ALBANIA = "\U0001f1e6\U0001f1f1" - ARMENIA = "\U0001f1e6\U0001f1f2" - ANGOLA = "\U0001f1e6\U0001f1f4" - ANTARCTICA = "\U0001f1e6\U0001f1f6" - ARGENTINA = "\U0001f1e6\U0001f1f7" - AMERICAN_SAMOA = "\U0001f1e6\U0001f1f8" - AUSTRIA = "\U0001f1e6\U0001f1f9" - AUSTRALIA = "\U0001f1e6\U0001f1fa" - ARUBA = "\U0001f1e6\U0001f1fc" - ALAND_ISLANDS = "\U0001f1e6\U0001f1fd" - AZERBAIJAN = "\U0001f1e6\U0001f1ff" - BOSNIA_AND_HERZEGOVINA = "\U0001f1e7\U0001f1e6" - BARBADOS = "\U0001f1e7\U0001f1e7" - BANGLADESH = "\U0001f1e7\U0001f1e9" - BELGIUM = "\U0001f1e7\U0001f1ea" - BURKINA_FASO = "\U0001f1e7\U0001f1eb" - BULGARIA = "\U0001f1e7\U0001f1ec" - BAHRAIN = "\U0001f1e7\U0001f1ed" - BURUNDI = "\U0001f1e7\U0001f1ee" - BENIN = "\U0001f1e7\U0001f1ef" - ST_BARTHELEMY = "\U0001f1e7\U0001f1f1" - BERMUDA = "\U0001f1e7\U0001f1f2" - BRUNEI = "\U0001f1e7\U0001f1f3" - BOLIVIA = "\U0001f1e7\U0001f1f4" - CARIBBEAN_NETHERLANDS = "\U0001f1e7\U0001f1f6" - BRAZIL = "\U0001f1e7\U0001f1f7" - BAHAMAS = "\U0001f1e7\U0001f1f8" - BHUTAN = "\U0001f1e7\U0001f1f9" - BOUVET_ISLAND = "\U0001f1e7\U0001f1fb" - BOTSWANA = "\U0001f1e7\U0001f1fc" - BELARUS = "\U0001f1e7\U0001f1fe" - BELIZE = "\U0001f1e7\U0001f1ff" - CANADA = "\U0001f1e8\U0001f1e6" - COCOS_KEELING_ISLANDS = "\U0001f1e8\U0001f1e8" - CONGO_KINSHASA = "\U0001f1e8\U0001f1e9" - CENTRAL_AFRICAN_REPUBLIC = "\U0001f1e8\U0001f1eb" - CONGO_BRAZZAVILLE = "\U0001f1e8\U0001f1ec" - SWITZERLAND = "\U0001f1e8\U0001f1ed" - COTE_D_IVOIRE = "\U0001f1e8\U0001f1ee" - COOK_ISLANDS = "\U0001f1e8\U0001f1f0" - CHILE = "\U0001f1e8\U0001f1f1" - CAMEROON = "\U0001f1e8\U0001f1f2" - CHINA = "\U0001f1e8\U0001f1f3" - COLOMBIA = "\U0001f1e8\U0001f1f4" - CLIPPERTON_ISLAND = "\U0001f1e8\U0001f1f5" - COSTA_RICA = "\U0001f1e8\U0001f1f7" - CUBA = "\U0001f1e8\U0001f1fa" - CAPE_VERDE = "\U0001f1e8\U0001f1fb" - CURACAO = "\U0001f1e8\U0001f1fc" - CHRISTMAS_ISLAND = "\U0001f1e8\U0001f1fd" - CYPRUS = "\U0001f1e8\U0001f1fe" - CZECHIA = "\U0001f1e8\U0001f1ff" - GERMANY = "\U0001f1e9\U0001f1ea" - DIEGO_GARCIA = "\U0001f1e9\U0001f1ec" - DJIBOUTI = "\U0001f1e9\U0001f1ef" - DENMARK = "\U0001f1e9\U0001f1f0" - DOMINICA = "\U0001f1e9\U0001f1f2" - DOMINICAN_REPUBLIC = "\U0001f1e9\U0001f1f4" - ALGERIA = "\U0001f1e9\U0001f1ff" - CEUTA_AND_MELILLA = "\U0001f1ea\U0001f1e6" - ECUADOR = "\U0001f1ea\U0001f1e8" - ESTONIA = "\U0001f1ea\U0001f1ea" - EGYPT = "\U0001f1ea\U0001f1ec" - WESTERN_SAHARA = "\U0001f1ea\U0001f1ed" - ERITREA = "\U0001f1ea\U0001f1f7" - SPAIN = "\U0001f1ea\U0001f1f8" - ETHIOPIA = "\U0001f1ea\U0001f1f9" - EUROPEAN_UNION = "\U0001f1ea\U0001f1fa" - FINLAND = "\U0001f1eb\U0001f1ee" - FIJI = "\U0001f1eb\U0001f1ef" - FALKLAND_ISLANDS = "\U0001f1eb\U0001f1f0" - MICRONESIA = "\U0001f1eb\U0001f1f2" - FAROE_ISLANDS = "\U0001f1eb\U0001f1f4" - FRANCE = "\U0001f1eb\U0001f1f7" - GABON = "\U0001f1ec\U0001f1e6" - UNITED_KINGDOM = "\U0001f1ec\U0001f1e7" - GRENADA = "\U0001f1ec\U0001f1e9" - GEORGIA = "\U0001f1ec\U0001f1ea" - FRENCH_GUIANA = "\U0001f1ec\U0001f1eb" - GUERNSEY = "\U0001f1ec\U0001f1ec" - GHANA = "\U0001f1ec\U0001f1ed" - GIBRALTAR = "\U0001f1ec\U0001f1ee" - GREENLAND = "\U0001f1ec\U0001f1f1" - GAMBIA = "\U0001f1ec\U0001f1f2" - GUINEA = "\U0001f1ec\U0001f1f3" - GUADELOUPE = "\U0001f1ec\U0001f1f5" - EQUATORIAL_GUINEA = "\U0001f1ec\U0001f1f6" - GREECE = "\U0001f1ec\U0001f1f7" - SOUTH_GEORGIA_AND_SOUTH_SANDWICH_ISLANDS = "\U0001f1ec\U0001f1f8" - GUATEMALA = "\U0001f1ec\U0001f1f9" - GUAM = "\U0001f1ec\U0001f1fa" - GUINEA_BISSAU = "\U0001f1ec\U0001f1fc" - GUYANA = "\U0001f1ec\U0001f1fe" - HONG_KONG_SAR_CHINA = "\U0001f1ed\U0001f1f0" - HEARD_AND_MCDONALD_ISLANDS = "\U0001f1ed\U0001f1f2" - HONDURAS = "\U0001f1ed\U0001f1f3" - CROATIA = "\U0001f1ed\U0001f1f7" - HAITI = "\U0001f1ed\U0001f1f9" - HUNGARY = "\U0001f1ed\U0001f1fa" - CANARY_ISLANDS = "\U0001f1ee\U0001f1e8" - INDONESIA = "\U0001f1ee\U0001f1e9" - IRELAND = "\U0001f1ee\U0001f1ea" - ISRAEL = "\U0001f1ee\U0001f1f1" - ISLE_OF_MAN = "\U0001f1ee\U0001f1f2" - INDIA = "\U0001f1ee\U0001f1f3" - BRITISH_INDIAN_OCEAN_TERRITORY = "\U0001f1ee\U0001f1f4" - IRAQ = "\U0001f1ee\U0001f1f6" - IRAN = "\U0001f1ee\U0001f1f7" - ICELAND = "\U0001f1ee\U0001f1f8" - ITALY = "\U0001f1ee\U0001f1f9" - JERSEY = "\U0001f1ef\U0001f1ea" - JAMAICA = "\U0001f1ef\U0001f1f2" - JORDAN = "\U0001f1ef\U0001f1f4" - JAPAN = "\U0001f1ef\U0001f1f5" - KENYA = "\U0001f1f0\U0001f1ea" - KYRGYZSTAN = "\U0001f1f0\U0001f1ec" - CAMBODIA = "\U0001f1f0\U0001f1ed" - KIRIBATI = "\U0001f1f0\U0001f1ee" - COMOROS = "\U0001f1f0\U0001f1f2" - ST_KITTS_AND_NEVIS = "\U0001f1f0\U0001f1f3" - NORTH_KOREA = "\U0001f1f0\U0001f1f5" - SOUTH_KOREA = "\U0001f1f0\U0001f1f7" - KUWAIT = "\U0001f1f0\U0001f1fc" - CAYMAN_ISLANDS = "\U0001f1f0\U0001f1fe" - KAZAKHSTAN = "\U0001f1f0\U0001f1ff" - LAOS = "\U0001f1f1\U0001f1e6" - LEBANON = "\U0001f1f1\U0001f1e7" - ST_LUCIA = "\U0001f1f1\U0001f1e8" - LIECHTENSTEIN = "\U0001f1f1\U0001f1ee" - SRI_LANKA = "\U0001f1f1\U0001f1f0" - LIBERIA = "\U0001f1f1\U0001f1f7" - LESOTHO = "\U0001f1f1\U0001f1f8" - LITHUANIA = "\U0001f1f1\U0001f1f9" - LUXEMBOURG = "\U0001f1f1\U0001f1fa" - LATVIA = "\U0001f1f1\U0001f1fb" - LIBYA = "\U0001f1f1\U0001f1fe" - MOROCCO = "\U0001f1f2\U0001f1e6" - MONACO = "\U0001f1f2\U0001f1e8" - MOLDOVA = "\U0001f1f2\U0001f1e9" - MONTENEGRO = "\U0001f1f2\U0001f1ea" - ST_MARTIN = "\U0001f1f2\U0001f1eb" - MADAGASCAR = "\U0001f1f2\U0001f1ec" - MARSHALL_ISLANDS = "\U0001f1f2\U0001f1ed" - MACEDONIA = "\U0001f1f2\U0001f1f0" - MALI = "\U0001f1f2\U0001f1f1" - MYANMAR_BURMA = "\U0001f1f2\U0001f1f2" - MONGOLIA = "\U0001f1f2\U0001f1f3" - MACAU_SAR_CHINA = "\U0001f1f2\U0001f1f4" - NORTHERN_MARIANA_ISLANDS = "\U0001f1f2\U0001f1f5" - MARTINIQUE = "\U0001f1f2\U0001f1f6" - MAURITANIA = "\U0001f1f2\U0001f1f7" - MONTSERRAT = "\U0001f1f2\U0001f1f8" - MALTA = "\U0001f1f2\U0001f1f9" - MAURITIUS = "\U0001f1f2\U0001f1fa" - MALDIVES = "\U0001f1f2\U0001f1fb" - MALAWI = "\U0001f1f2\U0001f1fc" - MEXICO = "\U0001f1f2\U0001f1fd" - MALAYSIA = "\U0001f1f2\U0001f1fe" - MOZAMBIQUE = "\U0001f1f2\U0001f1ff" - NAMIBIA = "\U0001f1f3\U0001f1e6" - NEW_CALEDONIA = "\U0001f1f3\U0001f1e8" - NIGER = "\U0001f1f3\U0001f1ea" - NORFOLK_ISLAND = "\U0001f1f3\U0001f1eb" - NIGERIA = "\U0001f1f3\U0001f1ec" - NICARAGUA = "\U0001f1f3\U0001f1ee" - NETHERLANDS = "\U0001f1f3\U0001f1f1" - NORWAY = "\U0001f1f3\U0001f1f4" - NEPAL = "\U0001f1f3\U0001f1f5" - NAURU = "\U0001f1f3\U0001f1f7" - NIUE = "\U0001f1f3\U0001f1fa" - NEW_ZEALAND = "\U0001f1f3\U0001f1ff" - OMAN = "\U0001f1f4\U0001f1f2" - PANAMA = "\U0001f1f5\U0001f1e6" - PERU = "\U0001f1f5\U0001f1ea" - FRENCH_POLYNESIA = "\U0001f1f5\U0001f1eb" - PAPUA_NEW_GUINEA = "\U0001f1f5\U0001f1ec" - PHILIPPINES = "\U0001f1f5\U0001f1ed" - PAKISTAN = "\U0001f1f5\U0001f1f0" - POLAND = "\U0001f1f5\U0001f1f1" - ST_PIERRE_AND_MIQUELON = "\U0001f1f5\U0001f1f2" - PITCAIRN_ISLANDS = "\U0001f1f5\U0001f1f3" - PUERTO_RICO = "\U0001f1f5\U0001f1f7" - PALESTINIAN_TERRITORIES = "\U0001f1f5\U0001f1f8" - PORTUGAL = "\U0001f1f5\U0001f1f9" - PALAU = "\U0001f1f5\U0001f1fc" - PARAGUAY = "\U0001f1f5\U0001f1fe" - QATAR = "\U0001f1f6\U0001f1e6" - REUNION = "\U0001f1f7\U0001f1ea" - ROMANIA = "\U0001f1f7\U0001f1f4" - SERBIA = "\U0001f1f7\U0001f1f8" - RUSSIA = "\U0001f1f7\U0001f1fa" - RWANDA = "\U0001f1f7\U0001f1fc" - SAUDI_ARABIA = "\U0001f1f8\U0001f1e6" - SOLOMON_ISLANDS = "\U0001f1f8\U0001f1e7" - SEYCHELLES = "\U0001f1f8\U0001f1e8" - SUDAN = "\U0001f1f8\U0001f1e9" - SWEDEN = "\U0001f1f8\U0001f1ea" - SINGAPORE = "\U0001f1f8\U0001f1ec" - ST_HELENA = "\U0001f1f8\U0001f1ed" - SLOVENIA = "\U0001f1f8\U0001f1ee" - SVALBARD_AND_JAN_MAYEN = "\U0001f1f8\U0001f1ef" - SLOVAKIA = "\U0001f1f8\U0001f1f0" - SIERRA_LEONE = "\U0001f1f8\U0001f1f1" - SAN_MARINO = "\U0001f1f8\U0001f1f2" - SENEGAL = "\U0001f1f8\U0001f1f3" - SOMALIA = "\U0001f1f8\U0001f1f4" - SURINAME = "\U0001f1f8\U0001f1f7" - SOUTH_SUDAN = "\U0001f1f8\U0001f1f8" - SAO_TOME_AND_PRINCIPE = "\U0001f1f8\U0001f1f9" - EL_SALVADOR = "\U0001f1f8\U0001f1fb" - SINT_MAARTEN = "\U0001f1f8\U0001f1fd" - SYRIA = "\U0001f1f8\U0001f1fe" - SWAZILAND = "\U0001f1f8\U0001f1ff" - TRISTAN_DA_CUNHA = "\U0001f1f9\U0001f1e6" - TURKS_AND_CAICOS_ISLANDS = "\U0001f1f9\U0001f1e8" - CHAD = "\U0001f1f9\U0001f1e9" - FRENCH_SOUTHERN_TERRITORIES = "\U0001f1f9\U0001f1eb" - TOGO = "\U0001f1f9\U0001f1ec" - THAILAND = "\U0001f1f9\U0001f1ed" - TAJIKISTAN = "\U0001f1f9\U0001f1ef" - TOKELAU = "\U0001f1f9\U0001f1f0" - TIMOR_LESTE = "\U0001f1f9\U0001f1f1" - TURKMENISTAN = "\U0001f1f9\U0001f1f2" - TUNISIA = "\U0001f1f9\U0001f1f3" - TONGA = "\U0001f1f9\U0001f1f4" - TURKEY = "\U0001f1f9\U0001f1f7" - TRINIDAD_AND_TOBAGO = "\U0001f1f9\U0001f1f9" - TUVALU = "\U0001f1f9\U0001f1fb" - TAIWAN = "\U0001f1f9\U0001f1fc" - TANZANIA = "\U0001f1f9\U0001f1ff" - UKRAINE = "\U0001f1fa\U0001f1e6" - UGANDA = "\U0001f1fa\U0001f1ec" - U_S_OUTLYING_ISLANDS = "\U0001f1fa\U0001f1f2" - UNITED_NATIONS = "\U0001f1fa\U0001f1f3" - UNITED_STATES = "\U0001f1fa\U0001f1f8" - URUGUAY = "\U0001f1fa\U0001f1fe" - UZBEKISTAN = "\U0001f1fa\U0001f1ff" - VATICAN_CITY = "\U0001f1fb\U0001f1e6" - ST_VINCENT_AND_GRENADINES = "\U0001f1fb\U0001f1e8" - VENEZUELA = "\U0001f1fb\U0001f1ea" - BRITISH_VIRGIN_ISLANDS = "\U0001f1fb\U0001f1ec" - U_S_VIRGIN_ISLANDS = "\U0001f1fb\U0001f1ee" - VIETNAM = "\U0001f1fb\U0001f1f3" - VANUATU = "\U0001f1fb\U0001f1fa" - WALLIS_AND_FUTUNA = "\U0001f1fc\U0001f1eb" - SAMOA = "\U0001f1fc\U0001f1f8" - KOSOVO = "\U0001f1fd\U0001f1f0" - YEMEN = "\U0001f1fe\U0001f1ea" - MAYOTTE = "\U0001f1fe\U0001f1f9" - SOUTH_AFRICA = "\U0001f1ff\U0001f1e6" - ZAMBIA = "\U0001f1ff\U0001f1f2" - ZIMBABWE = "\U0001f1ff\U0001f1fc" - ENGLAND = "\U0001f3f4\U000e0067\U000e0062\U000e0065\U000e006e\U000e0067\U000e007f" - SCOTLAND = "\U0001f3f4\U000e0067\U000e0062\U000e0073\U000e0063\U000e0074\U000e007f" - WALES = "\U0001f3f4\U000e0067\U000e0062\U000e0077\U000e006c\U000e0073\U000e007f" - MODERN_PENTATHLON = "\U0001f93b" - RIFLE = "\U0001f946" - REGIONAL_INDICATOR_SYMBOL_LETTER_A = "\U0001f1e6" - REGIONAL_INDICATOR_SYMBOL_LETTER_B = "\U0001f1e7" - REGIONAL_INDICATOR_SYMBOL_LETTER_C = "\U0001f1e8" - REGIONAL_INDICATOR_SYMBOL_LETTER_D = "\U0001f1e9" - REGIONAL_INDICATOR_SYMBOL_LETTER_E = "\U0001f1ea" - REGIONAL_INDICATOR_SYMBOL_LETTER_F = "\U0001f1eb" - REGIONAL_INDICATOR_SYMBOL_LETTER_G = "\U0001f1ec" - REGIONAL_INDICATOR_SYMBOL_LETTER_H = "\U0001f1ed" - REGIONAL_INDICATOR_SYMBOL_LETTER_I = "\U0001f1ee" - REGIONAL_INDICATOR_SYMBOL_LETTER_J = "\U0001f1ef" - REGIONAL_INDICATOR_SYMBOL_LETTER_K = "\U0001f1f0" - REGIONAL_INDICATOR_SYMBOL_LETTER_L = "\U0001f1f1" - REGIONAL_INDICATOR_SYMBOL_LETTER_M = "\U0001f1f2" - REGIONAL_INDICATOR_SYMBOL_LETTER_N = "\U0001f1f3" - REGIONAL_INDICATOR_SYMBOL_LETTER_O = "\U0001f1f4" - REGIONAL_INDICATOR_SYMBOL_LETTER_P = "\U0001f1f5" - REGIONAL_INDICATOR_SYMBOL_LETTER_Q = "\U0001f1f6" - REGIONAL_INDICATOR_SYMBOL_LETTER_R = "\U0001f1f7" - REGIONAL_INDICATOR_SYMBOL_LETTER_S = "\U0001f1f8" - REGIONAL_INDICATOR_SYMBOL_LETTER_T = "\U0001f1f9" - REGIONAL_INDICATOR_SYMBOL_LETTER_U = "\U0001f1fa" - REGIONAL_INDICATOR_SYMBOL_LETTER_V = "\U0001f1fb" - REGIONAL_INDICATOR_SYMBOL_LETTER_W = "\U0001f1fc" - REGIONAL_INDICATOR_SYMBOL_LETTER_X = "\U0001f1fd" - REGIONAL_INDICATOR_SYMBOL_LETTER_Y = "\U0001f1fe" - REGIONAL_INDICATOR_SYMBOL_LETTER_Z = "\U0001f1ff" - DINO_CAT = "\U0001f431\u200d\U0001f409" - NINJA_CAT = "\U0001f431\u200d\U0001f464" - STUNT_CAT = "\U0001f431\u200d\U0001f3cd" - ASTRO_CAT = "\U0001f431\u200d\U0001f680" - HACKER_CAT = "\U0001f431\u200d\U0001f4bb" - HIPSTER_CAT = "\U0001f431\u200d\U0001f453" - OLYMPIC_RINGS = "\u25ef\u200d\u25ef\u200d\u25ef\u200d\u25ef\u200d\u25ef" - FLAG_FOR_SUKHBAATAR_MN_051 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0035\U000e0031\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - FLAG_FOR_ORKHON_MN_035 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0033\U000e0035\U000e007f" - FLAG_FOR_TIRIS_ZEMMOUR_MR_11 = "\U0001f3f4\U000e006d\U000e0072\U000e0031\U000e0031\U000e007f" - FLAG_FOR_KHOVD_MN_043 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0034\U000e0033\U000e007f" - FLAG_FOR_ASSABA_MR_03 = "\U0001f3f4\U000e006d\U000e0072\U000e0030\U000e0033\U000e007f" - FLAG_FOR_BRAKNA_MR_05 = "\U0001f3f4\U000e006d\U000e0072\U000e0030\U000e0035\U000e007f" - FLAG_FOR_GORGOL_MR_04 = "\U0001f3f4\U000e006d\U000e0072\U000e0030\U000e0034\U000e007f" - FLAG_FOR_ARKHANGAI_MN_073 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0037\U000e0033\U000e007f" - FLAG_FOR_AKMOLA_KZ_AKM = "\U0001f3f4\U000e006b\U000e007a\U000e0061\U000e006b\U000e006d\U000e007f" - FLAG_FOR_BIRKIRKARA_MT_04 = "\U0001f3f4\U000e006d\U000e0074\U000e0030\U000e0034\U000e007f" - FLAG_FOR_IKLIN_MT_19 = "\U0001f3f4\U000e006d\U000e0074\U000e0031\U000e0039\U000e007f" - FLAG_FOR_NAXXAR_MT_38 = "\U0001f3f4\U000e006d\U000e0074\U000e0033\U000e0038\U000e007f" - FLAG_FOR_KALKARA_MT_21 = "\U0001f3f4\U000e006d\U000e0074\U000e0032\U000e0031\U000e007f" - FLAG_FOR_FONTANA_MT_10 = "\U0001f3f4\U000e006d\U000e0074\U000e0031\U000e0030\U000e007f" - FLAG_FOR_LIJA_MT_24 = "\U0001f3f4\U000e006d\U000e0074\U000e0032\U000e0034\U000e007f" - FLAG_FOR_FGURA_MT_08 = "\U0001f3f4\U000e006d\U000e0074\U000e0030\U000e0038\U000e007f" - FLAG_FOR_GUDJA_MT_11 = "\U0001f3f4\U000e006d\U000e0074\U000e0031\U000e0031\U000e007f" - FLAG_FOR_NOUAKCHOTT_SUD_MR_15 = "\U0001f3f4\U000e006d\U000e0072\U000e0031\U000e0035\U000e007f" - FLAG_FOR_MUNXAR_MT_36 = "\U0001f3f4\U000e006d\U000e0074\U000e0033\U000e0036\U000e007f" - FLAG_FOR_G_AJNSIELEM_MT_13 = "\U0001f3f4\U000e006d\U000e0074\U000e0031\U000e0033\U000e007f" - FLAG_FOR_BIRGU_MT_03 = "\U0001f3f4\U000e006d\U000e0074\U000e0030\U000e0033\U000e007f" - FLAG_FOR_ATTARD_MT_01 = "\U0001f3f4\U000e006d\U000e0074\U000e0030\U000e0031\U000e007f" - FLAG_FOR_AMRUN_MT_18 = "\U0001f3f4\U000e006d\U000e0074\U000e0031\U000e0038\U000e007f" - FLAG_FOR_G_ARB_MT_14 = "\U0001f3f4\U000e006d\U000e0074\U000e0031\U000e0034\U000e007f" - FLAG_FOR_MARSAXLOKK_MT_28 = "\U0001f3f4\U000e006d\U000e0074\U000e0032\U000e0038\U000e007f" - FLAG_FOR_G_AXAQ_MT_17 = "\U0001f3f4\U000e006d\U000e0074\U000e0031\U000e0037\U000e007f" - FLAG_FOR_MQABBA_MT_33 = "\U0001f3f4\U000e006d\U000e0074\U000e0033\U000e0033\U000e007f" - FLAG_FOR_GZIRA_MT_12 = "\U0001f3f4\U000e006d\U000e0074\U000e0031\U000e0032\U000e007f" - FLAG_FOR_NADUR_MT_37 = "\U0001f3f4\U000e006d\U000e0074\U000e0033\U000e0037\U000e007f" - FLAG_FOR_MOSTA_MT_32 = "\U0001f3f4\U000e006d\U000e0074\U000e0033\U000e0032\U000e007f" - FLAG_FOR_MELLIE_A_MT_30 = "\U0001f3f4\U000e006d\U000e0074\U000e0033\U000e0030\U000e007f" - FLAG_FOR_PAOLA_MT_39 = "\U0001f3f4\U000e006d\U000e0074\U000e0033\U000e0039\U000e007f" - FLAG_FOR_KERCEM_MT_22 = "\U0001f3f4\U000e006d\U000e0074\U000e0032\U000e0032\U000e007f" - FLAG_FOR_KIRKOP_MT_23 = "\U0001f3f4\U000e006d\U000e0074\U000e0032\U000e0033\U000e007f" - FLAG_FOR_MSIDA_MT_34 = "\U0001f3f4\U000e006d\U000e0074\U000e0033\U000e0034\U000e007f" - FLAG_FOR_DINGLI_MT_07 = "\U0001f3f4\U000e006d\U000e0074\U000e0030\U000e0037\U000e007f" - FLAG_FOR_FLORIANA_MT_09 = "\U0001f3f4\U000e006d\U000e0074\U000e0030\U000e0039\U000e007f" - FLAG_FOR_COSPICUA_MT_06 = "\U0001f3f4\U000e006d\U000e0074\U000e0030\U000e0036\U000e007f" - FLAG_FOR_NOUAKCHOTT_NORD_MR_14 = "\U0001f3f4\U000e006d\U000e0072\U000e0031\U000e0034\U000e007f" - FLAG_FOR_G_ARG_UR_MT_15 = "\U0001f3f4\U000e006d\U000e0074\U000e0031\U000e0035\U000e007f" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_WOMAN = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469" - FLAG_FOR_IMTARFA_MT_35 = "\U0001f3f4\U000e006d\U000e0074\U000e0033\U000e0035\U000e007f" - FLAG_FOR_BIRZEBBUGA_MT_05 = "\U0001f3f4\U000e006d\U000e0074\U000e0030\U000e0035\U000e007f" - FLAG_FOR_BALZAN_MT_02 = "\U0001f3f4\U000e006d\U000e0074\U000e0030\U000e0032\U000e007f" - FLAG_FOR_REDANGE_LU_RD = "\U0001f3f4\U000e006c\U000e0075\U000e0072\U000e0064\U000e007f" - FLAG_FOR_VALLETTA_MT_60 = "\U0001f3f4\U000e006d\U000e0074\U000e0036\U000e0030\U000e007f" - FLAG_FOR_QRENDI_MT_44 = "\U0001f3f4\U000e006d\U000e0074\U000e0034\U000e0034\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_FLACQ_MU_FL = "\U0001f3f4\U000e006d\U000e0075\U000e0066\U000e006c\U000e007f" - FLAG_FOR_SANTA_LUCIJA_MT_53 = "\U0001f3f4\U000e006d\U000e0074\U000e0035\U000e0033\U000e007f" - FLAG_FOR_ZEJTUN_MT_67 = "\U0001f3f4\U000e006d\U000e0074\U000e0036\U000e0037\U000e007f" - FLAG_FOR_FUNAFUTI_TV_FUN = "\U0001f3f4\U000e0074\U000e0076\U000e0066\U000e0075\U000e006e\U000e007f" - FLAG_FOR_PEMBROKE_MT_40 = "\U0001f3f4\U000e006d\U000e0074\U000e0034\U000e0030\U000e007f" - FLAG_FOR_CUREPIPE_MU_CU = "\U0001f3f4\U000e006d\U000e0075\U000e0063\U000e0075\U000e007f" - FLAG_FOR_ZURRIEQ_MT_68 = "\U0001f3f4\U000e006d\U000e0074\U000e0036\U000e0038\U000e007f" - FLAG_FOR_QORMI_MT_43 = "\U0001f3f4\U000e006d\U000e0074\U000e0034\U000e0033\U000e007f" - FLAG_FOR_SAINT_LAWRENCE_MT_50 = "\U0001f3f4\U000e006d\U000e0074\U000e0035\U000e0030\U000e007f" - FLAG_FOR_ZABBAR_MT_64 = "\U0001f3f4\U000e006d\U000e0074\U000e0036\U000e0034\U000e007f" - FLAG_FOR_PAMPLEMOUSSES_MU_PA = "\U0001f3f4\U000e006d\U000e0075\U000e0070\U000e0061\U000e007f" - FLAG_FOR_QALA_MT_42 = "\U0001f3f4\U000e006d\U000e0074\U000e0034\U000e0032\U000e007f" - FLAG_FOR_SLIEMA_MT_56 = "\U0001f3f4\U000e006d\U000e0074\U000e0035\U000e0036\U000e007f" - FLAG_FOR_TARXIEN_MT_59 = "\U0001f3f4\U000e006d\U000e0074\U000e0035\U000e0039\U000e007f" - FLAG_FOR_TA_XBIEX_MT_58 = "\U0001f3f4\U000e006d\U000e0074\U000e0035\U000e0038\U000e007f" - KISS_WOMAN_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - FLAG_FOR_XAG_RA_MT_61 = "\U0001f3f4\U000e006d\U000e0074\U000e0036\U000e0031\U000e007f" - FLAG_FOR_SWIEQI_MT_57 = "\U0001f3f4\U000e006d\U000e0074\U000e0035\U000e0037\U000e007f" - FLAG_FOR_SAN_GWANN_MT_49 = "\U0001f3f4\U000e006d\U000e0074\U000e0034\U000e0039\U000e007f" - FLAG_FOR_ZEBBUG_MT_66 = "\U0001f3f4\U000e006d\U000e0074\U000e0036\U000e0036\U000e007f" - FLAG_FOR_SIGGIEWI_MT_55 = "\U0001f3f4\U000e006d\U000e0074\U000e0035\U000e0035\U000e007f" - FLAG_FOR_PORT_LOUIS_MU_PU = "\U0001f3f4\U000e006d\U000e0075\U000e0070\U000e0075\U000e007f" - FLAG_FOR_SANTA_VENERA_MT_54 = "\U0001f3f4\U000e006d\U000e0074\U000e0035\U000e0034\U000e007f" - FLAG_FOR_XG_AJRA_MT_63 = "\U0001f3f4\U000e006d\U000e0074\U000e0036\U000e0033\U000e007f" - FLAG_FOR_CENTRAL_MW_C = "\U0001f3f4\U000e006d\U000e0077\U000e0063\U000e007f" - FLAG_FOR_SOUTH_PROVINCE_MV_SU = "\U0001f3f4\U000e006d\U000e0076\U000e0073\U000e0075\U000e007f" - FLAG_FOR_TRIESENBERG_LI_10 = "\U0001f3f4\U000e006c\U000e0069\U000e0031\U000e0030\U000e007f" - FLAG_FOR_VACOAS_PHOENIX_MU_VP = "\U0001f3f4\U000e006d\U000e0075\U000e0076\U000e0070\U000e007f" - FLAG_FOR_ANENII_NOI_MD_AN = "\U0001f3f4\U000e006d\U000e0064\U000e0061\U000e006e\U000e007f" - FLAG_FOR_GUANAJUATO_MX_GUA = "\U0001f3f4\U000e006d\U000e0078\U000e0067\U000e0075\U000e0061\U000e007f" - FLAG_FOR_MALE_MV_MLE = "\U0001f3f4\U000e006d\U000e0076\U000e006d\U000e006c\U000e0065\U000e007f" - FLAG_FOR_OAXACA_MX_OAX = "\U0001f3f4\U000e006d\U000e0078\U000e006f\U000e0061\U000e0078\U000e007f" - FLAG_FOR_CENTRAL_PROVINCE_MV_CE = "\U0001f3f4\U000e006d\U000e0076\U000e0063\U000e0065\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_MUNSTER_IE_M = "\U0001f3f4\U000e0069\U000e0065\U000e006d\U000e007f" - FLAG_FOR_MANGYSTAU_KZ_MAN = "\U0001f3f4\U000e006b\U000e007a\U000e006d\U000e0061\U000e006e\U000e007f" - FLAG_FOR_BAJA_CALIFORNIA_SUR_MX_BCS = "\U0001f3f4\U000e006d\U000e0078\U000e0062\U000e0063\U000e0073\U000e007f" - FLAG_FOR_CAMPECHE_MX_CAM = "\U0001f3f4\U000e006d\U000e0078\U000e0063\U000e0061\U000e006d\U000e007f" - FLAG_FOR_KYOTO_JP_26 = "\U0001f3f4\U000e006a\U000e0070\U000e0032\U000e0036\U000e007f" - FLAG_FOR_KOHGILUYEH_AND_BOYER_AHMAD_IR_18 = "\U0001f3f4\U000e0069\U000e0072\U000e0031\U000e0038\U000e007f" - FLAG_FOR_HIDALGO_MX_HID = "\U0001f3f4\U000e006d\U000e0078\U000e0068\U000e0069\U000e0064\U000e007f" - FLAG_FOR_CHLEF_DZ_02 = "\U0001f3f4\U000e0064\U000e007a\U000e0030\U000e0032\U000e007f" - FLAG_FOR_QUATRE_BORNES_MU_QB = "\U0001f3f4\U000e006d\U000e0075\U000e0071\U000e0062\U000e007f" - FLAG_FOR_PLAINES_WILHEMS_MU_PW = "\U0001f3f4\U000e006d\U000e0075\U000e0070\U000e0077\U000e007f" - FLAG_FOR_SAVANNE_MU_SA = "\U0001f3f4\U000e006d\U000e0075\U000e0073\U000e0061\U000e007f" - FLAG_FOR_SOUTHERN_MW_S = "\U0001f3f4\U000e006d\U000e0077\U000e0073\U000e007f" - FLAG_FOR_COAHUILA_MX_COA = "\U0001f3f4\U000e006d\U000e0078\U000e0063\U000e006f\U000e0061\U000e007f" - FLAG_FOR_NEGERI_SEMBILAN_MY_05 = "\U0001f3f4\U000e006d\U000e0079\U000e0030\U000e0035\U000e007f" - FLAG_FOR_SOFALA_MZ_S = "\U0001f3f4\U000e006d\U000e007a\U000e0073\U000e007f" - FLAG_FOR_LABUAN_MY_15 = "\U0001f3f4\U000e006d\U000e0079\U000e0031\U000e0035\U000e007f" - FLAG_FOR_NUEVO_LEON_MX_NLE = "\U0001f3f4\U000e006d\U000e0078\U000e006e\U000e006c\U000e0065\U000e007f" - FLAG_FOR_LA_SOURCE_MC_SO = "\U0001f3f4\U000e006d\U000e0063\U000e0073\U000e006f\U000e007f" - FLAG_FOR_SOUTH_GYEONGSANG_KR_48 = "\U0001f3f4\U000e006b\U000e0072\U000e0034\U000e0038\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f466\U0001f3fb" - FLAG_FOR_GAZA_MZ_G = "\U0001f3f4\U000e006d\U000e007a\U000e0067\U000e007f" - TAG_GRAVE_ACCENT = "\U000e0060" - FLAG_FOR_MALACCA_MY_04 = "\U0001f3f4\U000e006d\U000e0079\U000e0030\U000e0034\U000e007f" - FLAG_FOR_CABO_DELGADO_MZ_P = "\U0001f3f4\U000e006d\U000e007a\U000e0070\U000e007f" - FLAG_FOR_TLAXCALA_MX_TLA = "\U0001f3f4\U000e006d\U000e0078\U000e0074\U000e006c\U000e0061\U000e007f" - FLAG_FOR_APULIA_IT_75 = "\U0001f3f4\U000e0069\U000e0074\U000e0037\U000e0035\U000e007f" - FLAG_FOR_NAMPULA_MZ_N = "\U0001f3f4\U000e006d\U000e007a\U000e006e\U000e007f" - FLAG_FOR_OGOOUE_LOLO_GA_7 = "\U0001f3f4\U000e0067\U000e0061\U000e0037\U000e007f" - FLAG_FOR_ERONGO_NA_ER = "\U0001f3f4\U000e006e\U000e0061\U000e0065\U000e0072\U000e007f" - FLAG_FOR_TETE_MZ_T = "\U0001f3f4\U000e006d\U000e007a\U000e0074\U000e007f" - FLAG_FOR_UPPER_NORTH_PROVINCE_MV_UN = "\U0001f3f4\U000e006d\U000e0076\U000e0075\U000e006e\U000e007f" - FLAG_FOR_MANICA_MZ_B = "\U0001f3f4\U000e006d\U000e007a\U000e0062\U000e007f" - FLAG_FOR_PUTRAJAYA_MY_16 = "\U0001f3f4\U000e006d\U000e0079\U000e0031\U000e0036\U000e007f" - FLAG_FOR_MAPUTO_MZ_MPM = "\U0001f3f4\U000e006d\U000e007a\U000e006d\U000e0070\U000e006d\U000e007f" - FLAG_FOR_HARDAP_NA_HA = "\U0001f3f4\U000e006e\U000e0061\U000e0068\U000e0061\U000e007f" - FLAG_FOR_NIASSA_MZ_A = "\U0001f3f4\U000e006d\U000e007a\U000e0061\U000e007f" - FLAG_FOR_BAGO_MM_02 = "\U0001f3f4\U000e006d\U000e006d\U000e0030\U000e0032\U000e007f" - FLAG_FOR_INHAMBANE_MZ_I = "\U0001f3f4\U000e006d\U000e007a\U000e0069\U000e007f" - FLAG_FOR_ZAMBEZI_NA_CA = "\U0001f3f4\U000e006e\U000e0061\U000e0063\U000e0061\U000e007f" - FLAG_FOR_PERLIS_MY_09 = "\U0001f3f4\U000e006d\U000e0079\U000e0030\U000e0039\U000e007f" - FLAG_FOR_KAVANGO_WEST_NA_KW = "\U0001f3f4\U000e006e\U000e0061\U000e006b\U000e0077\U000e007f" - FLAG_FOR_RIVIERE_DU_REMPART_MU_RR = "\U0001f3f4\U000e006d\U000e0075\U000e0072\U000e0072\U000e007f" - FLAG_FOR_ZACATECAS_MX_ZAC = "\U0001f3f4\U000e006d\U000e0078\U000e007a\U000e0061\U000e0063\U000e007f" - FLAG_FOR_OSHANA_NA_ON = "\U0001f3f4\U000e006e\U000e0061\U000e006f\U000e006e\U000e007f" - FLAG_FOR_DOSSO_NE_3 = "\U0001f3f4\U000e006e\U000e0065\U000e0033\U000e007f" - FLAG_FOR_KHOMAS_NA_KH = "\U0001f3f4\U000e006e\U000e0061\U000e006b\U000e0068\U000e007f" - FLAG_FOR_TILLABERI_NE_6 = "\U0001f3f4\U000e006e\U000e0065\U000e0036\U000e007f" - FLAG_FOR_KANO_NG_KN = "\U0001f3f4\U000e006e\U000e0067\U000e006b\U000e006e\U000e007f" - FLAG_FOR_ANAMBRA_NG_AN = "\U0001f3f4\U000e006e\U000e0067\U000e0061\U000e006e\U000e007f" - FLAG_FOR_NIAMEY_NE_8 = "\U0001f3f4\U000e006e\U000e0065\U000e0038\U000e007f" - FLAG_FOR_KADUNA_NG_KD = "\U0001f3f4\U000e006e\U000e0067\U000e006b\U000e0064\U000e007f" - FLAG_FOR_JIGAWA_NG_JI = "\U0001f3f4\U000e006e\U000e0067\U000e006a\U000e0069\U000e007f" - FLAG_FOR_MARADI_NE_4 = "\U0001f3f4\U000e006e\U000e0065\U000e0034\U000e007f" - FLAG_FOR_OMUSATI_NA_OS = "\U0001f3f4\U000e006e\U000e0061\U000e006f\U000e0073\U000e007f" - FLAG_FOR_AGADEZ_NE_1 = "\U0001f3f4\U000e006e\U000e0065\U000e0031\U000e007f" - FLAG_FOR_KARAS_NA_KA = "\U0001f3f4\U000e006e\U000e0061\U000e006b\U000e0061\U000e007f" - FLAG_FOR_BENUE_NG_BE = "\U0001f3f4\U000e006e\U000e0067\U000e0062\U000e0065\U000e007f" - FLAG_FOR_KUNENE_NA_KU = "\U0001f3f4\U000e006e\U000e0061\U000e006b\U000e0075\U000e007f" - FLAG_FOR_OHANGWENA_NA_OW = "\U0001f3f4\U000e006e\U000e0061\U000e006f\U000e0077\U000e007f" - FLAG_FOR_EKITI_NG_EK = "\U0001f3f4\U000e006e\U000e0067\U000e0065\U000e006b\U000e007f" - FLAG_FOR_SIDI_BEL_ABBES_DZ_22 = "\U0001f3f4\U000e0064\U000e007a\U000e0032\U000e0032\U000e007f" - FLAG_FOR_EBONYI_NG_EB = "\U0001f3f4\U000e006e\U000e0067\U000e0065\U000e0062\U000e007f" - FLAG_FOR_TAHOUA_NE_5 = "\U0001f3f4\U000e006e\U000e0065\U000e0035\U000e007f" - FLAG_FOR_KATSINA_NG_KT = "\U0001f3f4\U000e006e\U000e0067\U000e006b\U000e0074\U000e007f" - FLAG_FOR_BAYELSA_NG_BY = "\U0001f3f4\U000e006e\U000e0067\U000e0062\U000e0079\U000e007f" - FLAG_FOR_ABIA_NG_AB = "\U0001f3f4\U000e006e\U000e0067\U000e0061\U000e0062\U000e007f" - FLAG_FOR_OTJOZONDJUPA_NA_OD = "\U0001f3f4\U000e006e\U000e0061\U000e006f\U000e0064\U000e007f" - FLAG_FOR_ZINDER_NE_7 = "\U0001f3f4\U000e006e\U000e0065\U000e0037\U000e007f" - MAN_WITH_HEADSCARF_LIGHT_SKIN_TONE = "\U0001f9d5\U0001f3fb\u200d\u2642\ufe0f" - FLAG_FOR_DIFFA_NE_2 = "\U0001f3f4\U000e006e\U000e0065\U000e0032\U000e007f" - FLAG_FOR_AKWA_IBOM_NG_AK = "\U0001f3f4\U000e006e\U000e0067\U000e0061\U000e006b\U000e007f" - FLAG_FOR_BOACO_NI_BO = "\U0001f3f4\U000e006e\U000e0069\U000e0062\U000e006f\U000e007f" - FLAG_FOR_OYO_NG_OY = "\U0001f3f4\U000e006e\U000e0067\U000e006f\U000e0079\U000e007f" - FLAG_FOR_CHONTALES_NI_CO = "\U0001f3f4\U000e006e\U000e0069\U000e0063\U000e006f\U000e007f" - FLAG_FOR_NUEVA_SEGOVIA_NI_NS = "\U0001f3f4\U000e006e\U000e0069\U000e006e\U000e0073\U000e007f" - FLAG_FOR_ROTUMA_FJ_R = "\U0001f3f4\U000e0066\U000e006a\U000e0072\U000e007f" - FLAG_FOR_ESTELI_NI_ES = "\U0001f3f4\U000e006e\U000e0069\U000e0065\U000e0073\U000e007f" - FLAG_FOR_MAYOTTE_FR_MAY = "\U0001f3f4\U000e0066\U000e0072\U000e006d\U000e0061\U000e0079\U000e007f" - FLAG_FOR_TARABA_NG_TA = "\U0001f3f4\U000e006e\U000e0067\U000e0074\U000e0061\U000e007f" - FLAG_FOR_CARAZO_NI_CA = "\U0001f3f4\U000e006e\U000e0069\U000e0063\U000e0061\U000e007f" - FLAG_FOR_JINOTEGA_NI_JI = "\U0001f3f4\U000e006e\U000e0069\U000e006a\U000e0069\U000e007f" - FLAG_FOR_GELDERLAND_NL_GE = "\U0001f3f4\U000e006e\U000e006c\U000e0067\U000e0065\U000e007f" - FLAG_FOR_NORTHERN_DISTRICT_IL_Z = "\U0001f3f4\U000e0069\U000e006c\U000e007a\U000e007f" - FLAG_FOR_NASARAWA_NG_NA = "\U0001f3f4\U000e006e\U000e0067\U000e006e\U000e0061\U000e007f" - FLAG_FOR_MANAGUA_NI_MN = "\U0001f3f4\U000e006e\U000e0069\U000e006d\U000e006e\U000e007f" - FLAG_FOR_SANCTI_SPIRITUS_CU_07 = "\U0001f3f4\U000e0063\U000e0075\U000e0030\U000e0037\U000e007f" - FLAG_FOR_ZAMFARA_NG_ZA = "\U0001f3f4\U000e006e\U000e0067\U000e007a\U000e0061\U000e007f" - FLAG_FOR_CHINANDEGA_NI_CI = "\U0001f3f4\U000e006e\U000e0069\U000e0063\U000e0069\U000e007f" - FLAG_FOR_MATAGALPA_NI_MT = "\U0001f3f4\U000e006e\U000e0069\U000e006d\U000e0074\U000e007f" - FLAG_FOR_MADRIZ_NI_MD = "\U0001f3f4\U000e006e\U000e0069\U000e006d\U000e0064\U000e007f" - FLAG_FOR_RIVAS_NI_RI = "\U0001f3f4\U000e006e\U000e0069\U000e0072\U000e0069\U000e007f" - FLAG_FOR_SAINT_JAMES_JM_08 = "\U0001f3f4\U000e006a\U000e006d\U000e0030\U000e0038\U000e007f" - FLAG_FOR_EL_PROGRESO_GT_PR = "\U0001f3f4\U000e0067\U000e0074\U000e0070\U000e0072\U000e007f" - FLAG_FOR_ATLANTICO_NORTE_NI_AN = "\U0001f3f4\U000e006e\U000e0069\U000e0061\U000e006e\U000e007f" - FLAG_FOR_PLATEAU_NG_PL = "\U0001f3f4\U000e006e\U000e0067\U000e0070\U000e006c\U000e007f" - FLAG_FOR_KABARDINO_BALKAR_RU_KB = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0062\U000e007f" - FLAG_FOR_FLEVOLAND_NL_FL = "\U0001f3f4\U000e006e\U000e006c\U000e0066\U000e006c\U000e007f" - FLAG_FOR_KWARA_NG_KW = "\U0001f3f4\U000e006e\U000e0067\U000e006b\U000e0077\U000e007f" - FLAG_FOR_GRANADA_NI_GR = "\U0001f3f4\U000e006e\U000e0069\U000e0067\U000e0072\U000e007f" - FLAG_FOR_SANTIAGO_DE_CUBA_CU_13 = "\U0001f3f4\U000e0063\U000e0075\U000e0031\U000e0033\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_VESTFOLD_NO_07 = "\U0001f3f4\U000e006e\U000e006f\U000e0030\U000e0037\U000e007f" - FLAG_FOR_PURWANCHAL_NP_4 = "\U0001f3f4\U000e006e\U000e0070\U000e0034\U000e007f" - FLAG_FOR_STFOLD_NO_01 = "\U0001f3f4\U000e006e\U000e006f\U000e0030\U000e0031\U000e007f" - FLAG_FOR_S_R_TR_NDELAG_NO_16 = "\U0001f3f4\U000e006e\U000e006f\U000e0031\U000e0036\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_JAN_MAYEN_NO_22 = "\U0001f3f4\U000e006e\U000e006f\U000e0032\U000e0032\U000e007f" - FLAG_FOR_LARVOTTO_MC_LA = "\U0001f3f4\U000e006d\U000e0063\U000e006c\U000e0061\U000e007f" - FLAG_FOR_CENTRAL_NP_1 = "\U0001f3f4\U000e006e\U000e0070\U000e0031\U000e007f" - FLAG_FOR_TELEMARK_NO_08 = "\U0001f3f4\U000e006e\U000e006f\U000e0030\U000e0038\U000e007f" - FLAG_FOR_MADHYA_PASHCHIMANCHAL_NP_2 = "\U0001f3f4\U000e006e\U000e0070\U000e0032\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - FLAG_FOR_AUST_AGDER_NO_09 = "\U0001f3f4\U000e006e\U000e006f\U000e0030\U000e0039\U000e007f" - FLAG_FOR_BALZERS_LI_01 = "\U0001f3f4\U000e006c\U000e0069\U000e0030\U000e0031\U000e007f" - FLAG_FOR_M_RE_OG_ROMSDAL_NO_15 = "\U0001f3f4\U000e006e\U000e006f\U000e0031\U000e0035\U000e007f" - FLAG_FOR_NORD_TR_NDELAG_NO_17 = "\U0001f3f4\U000e006e\U000e006f\U000e0031\U000e0037\U000e007f" - FLAG_FOR_AKERSHUS_NO_02 = "\U0001f3f4\U000e006e\U000e006f\U000e0030\U000e0032\U000e007f" - FLAG_FOR_BUSKERUD_NO_06 = "\U0001f3f4\U000e006e\U000e006f\U000e0030\U000e0036\U000e007f" - FLAG_FOR_BOE_NR_06 = "\U0001f3f4\U000e006e\U000e0072\U000e0030\U000e0036\U000e007f" - FLAG_FOR_NORDLAND_NO_18 = "\U0001f3f4\U000e006e\U000e006f\U000e0031\U000e0038\U000e007f" - FLAG_FOR_PRILEP_MK_62 = "\U0001f3f4\U000e006d\U000e006b\U000e0036\U000e0032\U000e007f" - FLAG_FOR_BAITI_NR_05 = "\U0001f3f4\U000e006e\U000e0072\U000e0030\U000e0035\U000e007f" - FLAG_FOR_ANETAN_NR_03 = "\U0001f3f4\U000e006e\U000e0072\U000e0030\U000e0033\U000e007f" - FLAG_FOR_BUADA_NR_07 = "\U0001f3f4\U000e006e\U000e0072\U000e0030\U000e0037\U000e007f" - FLAG_FOR_NZEREKORE_REGION_GN_N = "\U0001f3f4\U000e0067\U000e006e\U000e006e\U000e007f" - FLAG_FOR_ONDO_NG_ON = "\U0001f3f4\U000e006e\U000e0067\U000e006f\U000e006e\U000e007f" - FLAG_FOR_OPPLAND_NO_05 = "\U0001f3f4\U000e006e\U000e006f\U000e0030\U000e0035\U000e007f" - FLAG_FOR_ANIBARE_NR_04 = "\U0001f3f4\U000e006e\U000e0072\U000e0030\U000e0034\U000e007f" - FLAG_FOR_MUSCAT_OM_MA = "\U0001f3f4\U000e006f\U000e006d\U000e006d\U000e0061\U000e007f" - FLAG_FOR_CHATHAM_ISLANDS_NZ_CIT = "\U0001f3f4\U000e006e\U000e007a\U000e0063\U000e0069\U000e0074\U000e007f" - FLAG_FOR_UNGHENI_MD_UN = "\U0001f3f4\U000e006d\U000e0064\U000e0075\U000e006e\U000e007f" - FLAG_FOR_KANKAN_REGION_GN_K = "\U0001f3f4\U000e0067\U000e006e\U000e006b\U000e007f" - KISS_WOMAN_DARK_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - FLAG_FOR_DAYKUNDI_AF_DAY = "\U0001f3f4\U000e0061\U000e0066\U000e0064\U000e0061\U000e0079\U000e007f" - FLAG_FOR_MUSANDAM_OM_MU = "\U0001f3f4\U000e006f\U000e006d\U000e006d\U000e0075\U000e007f" - FLAG_FOR_KARAK_JO_KA = "\U0001f3f4\U000e006a\U000e006f\U000e006b\U000e0061\U000e007f" - FLAG_FOR_JANUB_ASH_SHARQIYAH_OM_SJ = "\U0001f3f4\U000e006f\U000e006d\U000e0073\U000e006a\U000e007f" - FLAG_FOR_WAIKATO_NZ_WKO = "\U0001f3f4\U000e006e\U000e007a\U000e0077\U000e006b\U000e006f\U000e007f" - FLAG_FOR_TELSIAI_COUNTY_LT_TE = "\U0001f3f4\U000e006c\U000e0074\U000e0074\U000e0065\U000e007f" - FLAG_FOR_SHAMAL_ASH_SHARQIYAH_OM_SS = "\U0001f3f4\U000e006f\U000e006d\U000e0073\U000e0073\U000e007f" - TAG_LATIN_CAPITAL_LETTER_U = "\U000e0055" - FLAG_FOR_IJUW_NR_10 = "\U0001f3f4\U000e006e\U000e0072\U000e0031\U000e0030\U000e007f" - FLAG_FOR_COLON_PA_3 = "\U0001f3f4\U000e0070\U000e0061\U000e0033\U000e007f" - FLAG_FOR_SHAMAL_AL_BATINAH_OM_BS = "\U0001f3f4\U000e006f\U000e006d\U000e0062\U000e0073\U000e007f" - FLAG_FOR_DHOFAR_OM_ZU = "\U0001f3f4\U000e006f\U000e006d\U000e007a\U000e0075\U000e007f" - FLAG_FOR_AD_DHAHIRAH_OM_ZA = "\U0001f3f4\U000e006f\U000e006d\U000e007a\U000e0061\U000e007f" - FLAG_FOR_GISBORNE_NZ_GIS = "\U0001f3f4\U000e006e\U000e007a\U000e0067\U000e0069\U000e0073\U000e007f" - FLAG_FOR_ALOJA_LV_005 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0030\U000e0035\U000e007f" - FLAG_FOR_TROMS_NO_19 = "\U0001f3f4\U000e006e\U000e006f\U000e0031\U000e0039\U000e007f" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - FLAG_FOR_NIBOK_NR_12 = "\U0001f3f4\U000e006e\U000e0072\U000e0031\U000e0032\U000e007f" - FLAG_FOR_JANUB_AL_BATINAH_OM_BJ = "\U0001f3f4\U000e006f\U000e006d\U000e0062\U000e006a\U000e007f" - FLAG_FOR_TUMBES_PE_TUM = "\U0001f3f4\U000e0070\U000e0065\U000e0074\U000e0075\U000e006d\U000e007f" - FLAG_FOR_EL_CALLAO_PE_CAL = "\U0001f3f4\U000e0070\U000e0065\U000e0063\U000e0061\U000e006c\U000e007f" - FLAG_FOR_PUNO_PE_PUN = "\U0001f3f4\U000e0070\U000e0065\U000e0070\U000e0075\U000e006e\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_PASCO_PE_PAS = "\U0001f3f4\U000e0070\U000e0065\U000e0070\U000e0061\U000e0073\U000e007f" - FLAG_FOR_LIMA_PE_LMA = "\U0001f3f4\U000e0070\U000e0065\U000e006c\U000e006d\U000e0061\U000e007f" - FLAG_FOR_MECKLENBURG_VORPOMMERN_DE_MV = "\U0001f3f4\U000e0064\U000e0065\U000e006d\U000e0076\U000e007f" - FLAG_FOR_PIURA_PE_PIU = "\U0001f3f4\U000e0070\U000e0065\U000e0070\U000e0069\U000e0075\U000e007f" - FLAG_FOR_ICA_PE_ICA = "\U0001f3f4\U000e0070\U000e0065\U000e0069\U000e0063\U000e0061\U000e007f" - FLAG_FOR_GITEGA_BI_GI = "\U0001f3f4\U000e0062\U000e0069\U000e0067\U000e0069\U000e007f" - FLAG_FOR_UCAYALI_PE_UCA = "\U0001f3f4\U000e0070\U000e0065\U000e0075\U000e0063\U000e0061\U000e007f" - FLAG_FOR_DENIGOMODU_NR_08 = "\U0001f3f4\U000e006e\U000e0072\U000e0030\U000e0038\U000e007f" - FLAG_FOR_HUANUCO_PE_HUC = "\U0001f3f4\U000e0070\U000e0065\U000e0068\U000e0075\U000e0063\U000e007f" - FLAG_FOR_JUNIN_PE_JUN = "\U0001f3f4\U000e0070\U000e0065\U000e006a\U000e0075\U000e006e\U000e007f" - FLAG_FOR_LA_LIBERTAD_PE_LAL = "\U0001f3f4\U000e0070\U000e0065\U000e006c\U000e0061\U000e006c\U000e007f" - FLAG_FOR_CHIMBU_PG_CPK = "\U0001f3f4\U000e0070\U000e0067\U000e0063\U000e0070\U000e006b\U000e007f" - FLAG_FOR_CAJAMARCA_PE_CAJ = "\U0001f3f4\U000e0070\U000e0065\U000e0063\U000e0061\U000e006a\U000e007f" - FLAG_FOR_BALKAN_TM_B = "\U0001f3f4\U000e0074\U000e006d\U000e0062\U000e007f" - FLAG_FOR_VERAGUAS_PA_9 = "\U0001f3f4\U000e0070\U000e0061\U000e0039\U000e007f" - FLAG_FOR_LAMBAYEQUE_PE_LAM = "\U0001f3f4\U000e0070\U000e0065\U000e006c\U000e0061\U000e006d\U000e007f" - FLAG_FOR_AMAZONAS_PE_AMA = "\U0001f3f4\U000e0070\U000e0065\U000e0061\U000e006d\U000e0061\U000e007f" - FLAG_FOR_NORTH_JEOLLA_KR_45 = "\U0001f3f4\U000e006b\U000e0072\U000e0034\U000e0035\U000e007f" - FLAG_FOR_HUANCAVELICA_PE_HUV = "\U0001f3f4\U000e0070\U000e0065\U000e0068\U000e0075\U000e0076\U000e007f" - FLAG_FOR_DARIEN_PA_5 = "\U0001f3f4\U000e0070\U000e0061\U000e0035\U000e007f" - FLAG_FOR_ROGALAND_NO_11 = "\U0001f3f4\U000e006e\U000e006f\U000e0031\U000e0031\U000e007f" - FLAG_FOR_LORETO_PE_LOR = "\U0001f3f4\U000e0070\U000e0065\U000e006c\U000e006f\U000e0072\U000e007f" - FLAG_FOR_SAN_MARTIN_PE_SAM = "\U0001f3f4\U000e0070\U000e0065\U000e0073\U000e0061\U000e006d\U000e007f" - FLAG_FOR_CHONGQING_CN_50 = "\U0001f3f4\U000e0063\U000e006e\U000e0035\U000e0030\U000e007f" - FLAG_FOR_SANDAUN_PG_SAN = "\U0001f3f4\U000e0070\U000e0067\U000e0073\U000e0061\U000e006e\U000e007f" - FLAG_FOR_CIUDAD_DE_MEXICO_MX_CMX = "\U0001f3f4\U000e006d\U000e0078\U000e0063\U000e006d\U000e0078\U000e007f" - FLAG_FOR_OSUN_NG_OS = "\U0001f3f4\U000e006e\U000e0067\U000e006f\U000e0073\U000e007f" - MAHJONG_TILE_TWO_OF_CIRCLES = "\U0001f01a" - FLAG_FOR_HEDMARK_NO_04 = "\U0001f3f4\U000e006e\U000e006f\U000e0030\U000e0034\U000e007f" - COUPLE_WITH_HEART_MAN_MAN_MEDIUM_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - FLAG_FOR_NORTHERN_MINDANAO_PH_10 = "\U0001f3f4\U000e0070\U000e0068\U000e0031\U000e0030\U000e007f" - FLAG_FOR_MADANG_PG_MPM = "\U0001f3f4\U000e0070\U000e0067\U000e006d\U000e0070\U000e006d\U000e007f" - FLAG_FOR_WESTERN_PG_WPD = "\U0001f3f4\U000e0070\U000e0067\U000e0077\U000e0070\U000e0064\U000e007f" - FLAG_FOR_SOUTH_PYONGAN_KP_02 = "\U0001f3f4\U000e006b\U000e0070\U000e0030\U000e0032\U000e007f" - FLAG_FOR_EASTERN_VISAYAS_PH_08 = "\U0001f3f4\U000e0070\U000e0068\U000e0030\U000e0038\U000e007f" - FLAG_FOR_WESTERN_FJ_W = "\U0001f3f4\U000e0066\U000e006a\U000e0077\U000e007f" - FLAG_FOR_SOCCSKSARGEN_PH_12 = "\U0001f3f4\U000e0070\U000e0068\U000e0031\U000e0032\U000e007f" - FLAG_FOR_MOROBE_PG_MPL = "\U0001f3f4\U000e0070\U000e0067\U000e006d\U000e0070\U000e006c\U000e007f" - FLAG_FOR_MIMAROPA_PH_41 = "\U0001f3f4\U000e0070\U000e0068\U000e0034\U000e0031\U000e007f" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - FLAG_FOR_HELA_PG_HLA = "\U0001f3f4\U000e0070\U000e0067\U000e0068\U000e006c\U000e0061\U000e007f" - FLAG_FOR_CALABARZON_PH_40 = "\U0001f3f4\U000e0070\U000e0068\U000e0034\U000e0030\U000e007f" - FLAG_FOR_ZAMBOANGA_PENINSULA_PH_09 = "\U0001f3f4\U000e0070\U000e0068\U000e0030\U000e0039\U000e007f" - FLAG_FOR_HERRERA_PA_6 = "\U0001f3f4\U000e0070\U000e0061\U000e0036\U000e007f" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - FLAG_FOR_EDO_NG_ED = "\U0001f3f4\U000e006e\U000e0067\U000e0065\U000e0064\U000e007f" - FLAG_FOR_MILNE_BAY_PG_MBA = "\U0001f3f4\U000e0070\U000e0067\U000e006d\U000e0062\U000e0061\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_WESTERN_VISAYAS_PH_06 = "\U0001f3f4\U000e0070\U000e0068\U000e0030\U000e0036\U000e007f" - FLAG_FOR_ANABAR_NR_02 = "\U0001f3f4\U000e006e\U000e0072\U000e0030\U000e0032\U000e007f" - FLAG_FOR_CARAGA_PH_13 = "\U0001f3f4\U000e0070\U000e0068\U000e0031\U000e0033\U000e007f" - FLAG_FOR_KOGI_NG_KO = "\U0001f3f4\U000e006e\U000e0067\U000e006b\U000e006f\U000e007f" - FLAG_FOR_GUANACASTE_CR_G = "\U0001f3f4\U000e0063\U000e0072\U000e0067\U000e007f" - FLAG_FOR_COROZAL_BZ_CZL = "\U0001f3f4\U000e0062\U000e007a\U000e0063\U000e007a\U000e006c\U000e007f" - FLAG_FOR_ALSUNGA_LV_006 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0030\U000e0036\U000e007f" - FLAG_FOR_TULKARM_PS_TKM = "\U0001f3f4\U000e0070\U000e0073\U000e0074\U000e006b\U000e006d\U000e007f" - FLAG_FOR_OPOLE_PL_OP = "\U0001f3f4\U000e0070\U000e006c\U000e006f\U000e0070\U000e007f" - FLAG_FOR_KHYBER_PAKHTUNKHWA_PK_KP = "\U0001f3f4\U000e0070\U000e006b\U000e006b\U000e0070\U000e007f" - FLAG_FOR_WEST_POMERANIA_PL_ZP = "\U0001f3f4\U000e0070\U000e006c\U000e007a\U000e0070\U000e007f" - FLAG_FOR_KURDAMIR_AZ_KUR = "\U0001f3f4\U000e0061\U000e007a\U000e006b\U000e0075\U000e0072\U000e007f" - FLAG_FOR_LUBUSZ_PL_LB = "\U0001f3f4\U000e0070\U000e006c\U000e006c\U000e0062\U000e007f" - FLAG_FOR_HEBRON_PS_HBN = "\U0001f3f4\U000e0070\U000e0073\U000e0068\U000e0062\U000e006e\U000e007f" - FLAG_FOR_RAFAH_PS_RFH = "\U0001f3f4\U000e0070\U000e0073\U000e0072\U000e0066\U000e0068\U000e007f" - FLAG_FOR_WARMIAN_MASURIA_PL_WN = "\U0001f3f4\U000e0070\U000e006c\U000e0077\U000e006e\U000e007f" - FLAG_FOR_PUNJAB_PK_PB = "\U0001f3f4\U000e0070\U000e006b\U000e0070\U000e0062\U000e007f" - FLAG_FOR_AVEIRO_PT_01 = "\U0001f3f4\U000e0070\U000e0074\U000e0030\U000e0031\U000e007f" - FLAG_FOR_MAZOVIA_PL_MZ = "\U0001f3f4\U000e0070\U000e006c\U000e006d\U000e007a\U000e007f" - FLAG_FOR_LUBLIN_PL_LU = "\U0001f3f4\U000e0070\U000e006c\U000e006c\U000e0075\U000e007f" - FLAG_FOR_NABLUS_PS_NBS = "\U0001f3f4\U000e0070\U000e0073\U000e006e\U000e0062\U000e0073\U000e007f" - FLAG_FOR_QALQILYA_PS_QQA = "\U0001f3f4\U000e0070\U000e0073\U000e0071\U000e0071\U000e0061\U000e007f" - FLAG_FOR_KUYAVIAN_POMERANIA_PL_KP = "\U0001f3f4\U000e0070\U000e006c\U000e006b\U000e0070\U000e007f" - FLAG_FOR_SINDH_PK_SD = "\U0001f3f4\U000e0070\U000e006b\U000e0073\U000e0064\U000e007f" - FLAG_FOR_PODLASKIE_PL_PD = "\U0001f3f4\U000e0070\U000e006c\U000e0070\U000e0064\U000e007f" - FLAG_FOR_DAVAO_PH_11 = "\U0001f3f4\U000e0070\U000e0068\U000e0031\U000e0031\U000e007f" - FLAG_FOR_SUBCARPATHIA_PL_PK = "\U0001f3f4\U000e0070\U000e006c\U000e0070\U000e006b\U000e007f" - FLAG_FOR_ODZ_PL_LD = "\U0001f3f4\U000e0070\U000e006c\U000e006c\U000e0064\U000e007f" - FLAG_FOR_SALFIT_PS_SLT = "\U0001f3f4\U000e0070\U000e0073\U000e0073\U000e006c\U000e0074\U000e007f" - FLAG_FOR_JENIN_PS_JEN = "\U0001f3f4\U000e0070\U000e0073\U000e006a\U000e0065\U000e006e\U000e007f" - FLAG_FOR_SILESIA_PL_SL = "\U0001f3f4\U000e0070\U000e006c\U000e0073\U000e006c\U000e007f" - FLAG_FOR_KHAN_YUNIS_PS_KYS = "\U0001f3f4\U000e0070\U000e0073\U000e006b\U000e0079\U000e0073\U000e007f" - TAG_RIGHT_SQUARE_BRACKET = "\U000e005d" - FLAG_FOR_MOSCOW_PROVINCE_RU_MOS = "\U0001f3f4\U000e0072\U000e0075\U000e006d\U000e006f\U000e0073\U000e007f" - FLAG_FOR_TUSCANY_IT_52 = "\U0001f3f4\U000e0069\U000e0074\U000e0035\U000e0032\U000e007f" - FLAG_FOR_BICOL_PH_05 = "\U0001f3f4\U000e0070\U000e0068\U000e0030\U000e0035\U000e007f" - TAG_LATIN_CAPITAL_LETTER_K = "\U000e004b" - FLAG_FOR_LOWER_SILESIAN_PL_DS = "\U0001f3f4\U000e0070\U000e006c\U000e0064\U000e0073\U000e007f" - FLAG_FOR_CAGAYAN_VALLEY_PH_02 = "\U0001f3f4\U000e0070\U000e0068\U000e0030\U000e0032\U000e007f" - FLAG_FOR_RIO_DE_JANEIRO_BR_RJ = "\U0001f3f4\U000e0062\U000e0072\U000e0072\U000e006a\U000e007f" - FLAG_FOR_EVORA_PT_07 = "\U0001f3f4\U000e0070\U000e0074\U000e0030\U000e0037\U000e007f" - FLAG_FOR_NGARAARD_PW_214 = "\U0001f3f4\U000e0070\U000e0077\U000e0032\U000e0031\U000e0034\U000e007f" - FLAG_FOR_BRAGANCA_PT_04 = "\U0001f3f4\U000e0070\U000e0074\U000e0030\U000e0034\U000e007f" - FLAG_FOR_SHIDA_KARTLI_GE_SK = "\U0001f3f4\U000e0067\U000e0065\U000e0073\U000e006b\U000e007f" - FLAG_FOR_MENENG_NR_11 = "\U0001f3f4\U000e006e\U000e0072\U000e0031\U000e0031\U000e007f" - FLAG_FOR_AIMELIIK_PW_002 = "\U0001f3f4\U000e0070\U000e0077\U000e0030\U000e0030\U000e0032\U000e007f" - FLAG_FOR_AMAMBAY_PY_13 = "\U0001f3f4\U000e0070\U000e0079\U000e0031\U000e0033\U000e007f" - FLAG_FOR_HATOHOBEI_PW_050 = "\U0001f3f4\U000e0070\U000e0077\U000e0030\U000e0035\U000e0030\U000e007f" - FLAG_FOR_CENTRAL_PY_11 = "\U0001f3f4\U000e0070\U000e0079\U000e0031\U000e0031\U000e007f" - FLAG_FOR_COIMBRA_PT_06 = "\U0001f3f4\U000e0070\U000e0074\U000e0030\U000e0036\U000e007f" - FLAG_FOR_CENTRAL_PG_CPM = "\U0001f3f4\U000e0070\U000e0067\U000e0063\U000e0070\U000e006d\U000e007f" - FLAG_FOR_KOROR_PW_150 = "\U0001f3f4\U000e0070\U000e0077\U000e0031\U000e0035\U000e0030\U000e007f" - FLAG_FOR_COCLE_PA_2 = "\U0001f3f4\U000e0070\U000e0061\U000e0032\U000e007f" - FLAG_FOR_NEEMBUCU_PY_12 = "\U0001f3f4\U000e0070\U000e0079\U000e0031\U000e0032\U000e007f" - FLAG_FOR_AIRAI_PW_004 = "\U0001f3f4\U000e0070\U000e0077\U000e0030\U000e0030\U000e0034\U000e007f" - FLAG_FOR_SANTAREM_PT_14 = "\U0001f3f4\U000e0070\U000e0074\U000e0031\U000e0034\U000e007f" - FLAG_FOR_NGATPANG_PW_224 = "\U0001f3f4\U000e0070\U000e0077\U000e0032\U000e0032\U000e0034\U000e007f" - FLAG_FOR_PORTALEGRE_PT_12 = "\U0001f3f4\U000e0070\U000e0074\U000e0031\U000e0032\U000e007f" - FLAG_FOR_LEIRIA_PT_10 = "\U0001f3f4\U000e0070\U000e0074\U000e0031\U000e0030\U000e007f" - FLAG_FOR_NGARDMAU_PW_222 = "\U0001f3f4\U000e0070\U000e0077\U000e0032\U000e0032\U000e0032\U000e007f" - FLAG_FOR_NGCHESAR_PW_226 = "\U0001f3f4\U000e0070\U000e0077\U000e0032\U000e0032\U000e0036\U000e007f" - FLAG_FOR_NORTH_HWANGHAE_KP_06 = "\U0001f3f4\U000e006b\U000e0070\U000e0030\U000e0036\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - FLAG_FOR_WESTERN_NP_3 = "\U0001f3f4\U000e006e\U000e0070\U000e0033\U000e007f" - FLAG_FOR_VIANA_DO_CASTELO_PT_16 = "\U0001f3f4\U000e0070\U000e0074\U000e0031\U000e0036\U000e007f" - FLAG_FOR_CANINDEYU_PY_14 = "\U0001f3f4\U000e0070\U000e0079\U000e0031\U000e0034\U000e007f" - FLAG_FOR_CORDILLERA_PY_3 = "\U0001f3f4\U000e0070\U000e0079\U000e0033\U000e007f" - FLAG_FOR_CAAZAPA_PY_6 = "\U0001f3f4\U000e0070\U000e0079\U000e0036\U000e007f" - FLAG_FOR_COVASNA_RO_CV = "\U0001f3f4\U000e0072\U000e006f\U000e0063\U000e0076\U000e007f" - FLAG_FOR_GIURGIU_RO_GR = "\U0001f3f4\U000e0072\U000e006f\U000e0067\U000e0072\U000e007f" - FLAG_FOR_DAMBOVITA_RO_DB = "\U0001f3f4\U000e0072\U000e006f\U000e0064\U000e0062\U000e007f" - FLAG_FOR_ITAPUA_PY_7 = "\U0001f3f4\U000e0070\U000e0079\U000e0037\U000e007f" - FLAG_FOR_CAAGUAZU_PY_5 = "\U0001f3f4\U000e0070\U000e0079\U000e0035\U000e007f" - FLAG_FOR_SAN_PEDRO_PY_2 = "\U0001f3f4\U000e0070\U000e0079\U000e0032\U000e007f" - FLAG_FOR_NGEREMLENGUI_PW_227 = "\U0001f3f4\U000e0070\U000e0077\U000e0032\U000e0032\U000e0037\U000e007f" - FLAG_FOR_BIHOR_RO_BH = "\U0001f3f4\U000e0072\U000e006f\U000e0062\U000e0068\U000e007f" - FLAG_FOR_DOLJ_RO_DJ = "\U0001f3f4\U000e0072\U000e006f\U000e0064\U000e006a\U000e007f" - FLAG_FOR_ARGES_RO_AG = "\U0001f3f4\U000e0072\U000e006f\U000e0061\U000e0067\U000e007f" - FLAG_FOR_AL_KHOR_QA_KH = "\U0001f3f4\U000e0071\U000e0061\U000e006b\U000e0068\U000e007f" - FLAG_FOR_GILGIT_BALTISTAN_PK_GB = "\U0001f3f4\U000e0070\U000e006b\U000e0067\U000e0062\U000e007f" - FLAG_FOR_GUAIRA_PY_4 = "\U0001f3f4\U000e0070\U000e0079\U000e0034\U000e007f" - FLAG_FOR_PARAGUARI_PY_9 = "\U0001f3f4\U000e0070\U000e0079\U000e0039\U000e007f" - FLAG_FOR_CAPITAL_IS_1 = "\U0001f3f4\U000e0069\U000e0073\U000e0031\U000e007f" - FLAG_FOR_GALATI_RO_GL = "\U0001f3f4\U000e0072\U000e006f\U000e0067\U000e006c\U000e007f" - FLAG_FOR_ARAD_RO_AR = "\U0001f3f4\U000e0072\U000e006f\U000e0061\U000e0072\U000e007f" - FLAG_FOR_BRAILA_RO_BR = "\U0001f3f4\U000e0072\U000e006f\U000e0062\U000e0072\U000e007f" - FLAG_FOR_TIVAT_ME_19 = "\U0001f3f4\U000e006d\U000e0065\U000e0031\U000e0039\U000e007f" - FLAG_FOR_HARGHITA_RO_HR = "\U0001f3f4\U000e0072\U000e006f\U000e0068\U000e0072\U000e007f" - FLAG_FOR_MISIONES_PY_8 = "\U0001f3f4\U000e0070\U000e0079\U000e0038\U000e007f" - FLAG_FOR_AL_DAAYEN_QA_ZA = "\U0001f3f4\U000e0071\U000e0061\U000e007a\U000e0061\U000e007f" - FLAG_FOR_DIKHIL_DJ_DI = "\U0001f3f4\U000e0064\U000e006a\U000e0064\U000e0069\U000e007f" - FLAG_FOR_OLT_RO_OT = "\U0001f3f4\U000e0072\U000e006f\U000e006f\U000e0074\U000e007f" - FLAG_FOR_BRANICEVO_RS_11 = "\U0001f3f4\U000e0072\U000e0073\U000e0031\U000e0031\U000e007f" - FLAG_FOR_RASINA_RS_19 = "\U0001f3f4\U000e0072\U000e0073\U000e0031\U000e0039\U000e007f" - FLAG_FOR_SUCEAVA_RO_SV = "\U0001f3f4\U000e0072\U000e006f\U000e0073\U000e0076\U000e007f" - FLAG_FOR_ZAJECAR_RS_15 = "\U0001f3f4\U000e0072\U000e0073\U000e0031\U000e0035\U000e007f" - WHITE_HEART_SUIT = "\u2661" - FLAG_FOR_JABLANICA_RS_23 = "\U0001f3f4\U000e0072\U000e0073\U000e0032\U000e0033\U000e007f" - FLAG_FOR_SUMADIJA_RS_12 = "\U0001f3f4\U000e0072\U000e0073\U000e0031\U000e0032\U000e007f" - FLAG_FOR_PIROT_RS_22 = "\U0001f3f4\U000e0072\U000e0073\U000e0032\U000e0032\U000e007f" - FLAG_FOR_MURES_RO_MS = "\U0001f3f4\U000e0072\U000e006f\U000e006d\U000e0073\U000e007f" - FLAG_FOR_TELEORMAN_RO_TR = "\U0001f3f4\U000e0072\U000e006f\U000e0074\U000e0072\U000e007f" - FLAG_FOR_MACVA_RS_08 = "\U0001f3f4\U000e0072\U000e0073\U000e0030\U000e0038\U000e007f" - FLAG_FOR_MORAVICA_RS_17 = "\U0001f3f4\U000e0072\U000e0073\U000e0031\U000e0037\U000e007f" - FLAG_FOR_ILFOV_RO_IF = "\U0001f3f4\U000e0072\U000e006f\U000e0069\U000e0066\U000e007f" - FLAG_FOR_PRAHOVA_RO_PH = "\U0001f3f4\U000e0072\U000e006f\U000e0070\U000e0068\U000e007f" - FLAG_FOR_LOS_LAGOS_CL_LL = "\U0001f3f4\U000e0063\U000e006c\U000e006c\U000e006c\U000e007f" - FLAG_FOR_TULCEA_RO_TL = "\U0001f3f4\U000e0072\U000e006f\U000e0074\U000e006c\U000e007f" - FLAG_FOR_IALOMITA_RO_IL = "\U0001f3f4\U000e0072\U000e006f\U000e0069\U000e006c\U000e007f" - FLAG_FOR_MOULINS_MC_MU = "\U0001f3f4\U000e006d\U000e0063\U000e006d\U000e0075\U000e007f" - FLAG_FOR_KOLUBARA_RS_09 = "\U0001f3f4\U000e0072\U000e0073\U000e0030\U000e0039\U000e007f" - FLAG_FOR_ZLATIBOR_RS_16 = "\U0001f3f4\U000e0072\U000e0073\U000e0031\U000e0036\U000e007f" - FLAG_FOR_SALAJ_RO_SJ = "\U0001f3f4\U000e0072\U000e006f\U000e0073\U000e006a\U000e007f" - FLAG_FOR_VASLUI_RO_VS = "\U0001f3f4\U000e0072\U000e006f\U000e0076\U000e0073\U000e007f" - FLAG_FOR_POMORAVLJE_RS_13 = "\U0001f3f4\U000e0072\U000e0073\U000e0031\U000e0033\U000e007f" - FLAG_FOR_NISAVA_RS_20 = "\U0001f3f4\U000e0072\U000e0073\U000e0032\U000e0030\U000e007f" - FLAG_FOR_MEHEDINTI_RO_MH = "\U0001f3f4\U000e0072\U000e006f\U000e006d\U000e0068\U000e007f" - FLAG_FOR_RASKA_RS_18 = "\U0001f3f4\U000e0072\U000e0073\U000e0031\U000e0038\U000e007f" - FLAG_FOR_PCINJA_RS_24 = "\U0001f3f4\U000e0072\U000e0073\U000e0032\U000e0034\U000e007f" - FLAG_FOR_BEOGRAD_RS_00 = "\U0001f3f4\U000e0072\U000e0073\U000e0030\U000e0030\U000e007f" - FLAG_FOR_TACNA_PE_TAC = "\U0001f3f4\U000e0070\U000e0065\U000e0074\U000e0061\U000e0063\U000e007f" - FLAG_FOR_BELGOROD_RU_BEL = "\U0001f3f4\U000e0072\U000e0075\U000e0062\U000e0065\U000e006c\U000e007f" - FLAG_FOR_KURGAN_RU_KGN = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0067\U000e006e\U000e007f" - FLAG_FOR_CHELYABINSK_RU_CHE = "\U0001f3f4\U000e0072\U000e0075\U000e0063\U000e0068\U000e0065\U000e007f" - FLAG_FOR_KIROV_RU_KIR = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0069\U000e0072\U000e007f" - KISS_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - FLAG_FOR_UTTAR_PRADESH_IN_UP = "\U0001f3f4\U000e0069\U000e006e\U000e0075\U000e0070\U000e007f" - FLAG_FOR_KOMI_RU_KO = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e006f\U000e007f" - FLAG_FOR_IVANOVO_RU_IVA = "\U0001f3f4\U000e0072\U000e0075\U000e0069\U000e0076\U000e0061\U000e007f" - FLAG_FOR_ALBA_RO_AB = "\U0001f3f4\U000e0072\U000e006f\U000e0061\U000e0062\U000e007f" - FLAG_FOR_KHANTY_MANSI_RU_KHM = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0068\U000e006d\U000e007f" - FLAG_FOR_KALUGA_RU_KLU = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e006c\U000e0075\U000e007f" - FLAG_FOR_PECS_HU_PS = "\U0001f3f4\U000e0068\U000e0075\U000e0070\U000e0073\U000e007f" - FLAG_FOR_MARI_EL_RU_ME = "\U0001f3f4\U000e0072\U000e0075\U000e006d\U000e0065\U000e007f" - FLAG_FOR_IRKUTSK_RU_IRK = "\U0001f3f4\U000e0072\U000e0075\U000e0069\U000e0072\U000e006b\U000e007f" - FLAG_FOR_PLAV_ME_13 = "\U0001f3f4\U000e006d\U000e0065\U000e0031\U000e0033\U000e007f" - FLAG_FOR_GRAND_KRU_LR_GK = "\U0001f3f4\U000e006c\U000e0072\U000e0067\U000e006b\U000e007f" - FLAG_FOR_SIEM_REAP_KH_17 = "\U0001f3f4\U000e006b\U000e0068\U000e0031\U000e0037\U000e007f" - FLAG_FOR_KAMCHATKA_KRAI_RU_KAM = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0061\U000e006d\U000e007f" - FLAG_FOR_ALTAI_RU_AL = "\U0001f3f4\U000e0072\U000e0075\U000e0061\U000e006c\U000e007f" - FLAG_FOR_MORDOVIA_RU_MO = "\U0001f3f4\U000e0072\U000e0075\U000e006d\U000e006f\U000e007f" - FLAG_FOR_ASTRAKHAN_RU_AST = "\U0001f3f4\U000e0072\U000e0075\U000e0061\U000e0073\U000e0074\U000e007f" - FLAG_FOR_KARACHAY_CHERKESS_RU_KC = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0063\U000e007f" - FLAG_FOR_KEMEROVO_RU_KEM = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0065\U000e006d\U000e007f" - FLAG_FOR_ENGA_PG_EPW = "\U0001f3f4\U000e0070\U000e0067\U000e0065\U000e0070\U000e0077\U000e007f" - FLAG_FOR_VOLOGDA_RU_VLG = "\U0001f3f4\U000e0072\U000e0075\U000e0076\U000e006c\U000e0067\U000e007f" - FLAG_FOR_TOMSK_RU_TOM = "\U0001f3f4\U000e0072\U000e0075\U000e0074\U000e006f\U000e006d\U000e007f" - FLAG_FOR_VLADIMIR_RU_VLA = "\U0001f3f4\U000e0072\U000e0075\U000e0076\U000e006c\U000e0061\U000e007f" - FLAG_FOR_CONCEPCION_PY_1 = "\U0001f3f4\U000e0070\U000e0079\U000e0031\U000e007f" - FLAG_FOR_BAUCHI_NG_BA = "\U0001f3f4\U000e006e\U000e0067\U000e0062\U000e0061\U000e007f" - FLAG_FOR_NIZHNY_NOVGOROD_RU_NIZ = "\U0001f3f4\U000e0072\U000e0075\U000e006e\U000e0069\U000e007a\U000e007f" - FLAG_FOR_ORENBURG_RU_ORE = "\U0001f3f4\U000e0072\U000e0075\U000e006f\U000e0072\U000e0065\U000e007f" - FLAG_FOR_NOVOSIBIRSK_RU_NVS = "\U0001f3f4\U000e0072\U000e0075\U000e006e\U000e0076\U000e0073\U000e007f" - FLAG_FOR_SAINT_JOHN_GD_04 = "\U0001f3f4\U000e0067\U000e0064\U000e0030\U000e0034\U000e007f" - FLAG_FOR_TVER_RU_TVE = "\U0001f3f4\U000e0072\U000e0075\U000e0074\U000e0076\U000e0065\U000e007f" - FLAG_FOR_NOVGOROD_RU_NGR = "\U0001f3f4\U000e0072\U000e0075\U000e006e\U000e0067\U000e0072\U000e007f" - FLAG_FOR_TULA_RU_TUL = "\U0001f3f4\U000e0072\U000e0075\U000e0074\U000e0075\U000e006c\U000e007f" - FLAG_FOR_CASTELO_BRANCO_PT_05 = "\U0001f3f4\U000e0070\U000e0074\U000e0030\U000e0035\U000e007f" - FLAG_FOR_PRESIDENTE_HAYES_PY_15 = "\U0001f3f4\U000e0070\U000e0079\U000e0031\U000e0035\U000e007f" - FLAG_FOR_SMOLENSK_RU_SMO = "\U0001f3f4\U000e0072\U000e0075\U000e0073\U000e006d\U000e006f\U000e007f" - FLAG_FOR_TYUMEN_RU_TYU = "\U0001f3f4\U000e0072\U000e0075\U000e0074\U000e0079\U000e0075\U000e007f" - FLAG_FOR_SVERDLOVSK_RU_SVE = "\U0001f3f4\U000e0072\U000e0075\U000e0073\U000e0076\U000e0065\U000e007f" - FLAG_FOR_DAMAN_AND_DIU_IN_DD = "\U0001f3f4\U000e0069\U000e006e\U000e0064\U000e0064\U000e007f" - FLAG_FOR_SARATOV_RU_SAR = "\U0001f3f4\U000e0072\U000e0075\U000e0073\U000e0061\U000e0072\U000e007f" - FLAG_FOR_NENETS_RU_NEN = "\U0001f3f4\U000e0072\U000e0075\U000e006e\U000e0065\U000e006e\U000e007f" - FLAG_FOR_XIANGKHOUANG_LA_XI = "\U0001f3f4\U000e006c\U000e0061\U000e0078\U000e0069\U000e007f" - FLAG_FOR_PSKOV_RU_PSK = "\U0001f3f4\U000e0072\U000e0075\U000e0070\U000e0073\U000e006b\U000e007f" - FLAG_FOR_OTAGO_NZ_OTA = "\U0001f3f4\U000e006e\U000e007a\U000e006f\U000e0074\U000e0061\U000e007f" - FLAG_FOR_CANTERBURY_NZ_CAN = "\U0001f3f4\U000e006e\U000e007a\U000e0063\U000e0061\U000e006e\U000e007f" - FLAG_FOR_HA_IL_SA_06 = "\U0001f3f4\U000e0073\U000e0061\U000e0030\U000e0036\U000e007f" - FLAG_FOR_EASTERN_RW_02 = "\U0001f3f4\U000e0072\U000e0077\U000e0030\U000e0032\U000e007f" - FLAG_FOR_TUVA_RU_TY = "\U0001f3f4\U000e0072\U000e0075\U000e0074\U000e0079\U000e007f" - FLAG_FOR_ANSE_BOILEAU_SC_02 = "\U0001f3f4\U000e0073\U000e0063\U000e0030\U000e0032\U000e007f" - FLAG_FOR_ZABAYKALSKY_KRAI_RU_ZAB = "\U0001f3f4\U000e0072\U000e0075\U000e007a\U000e0061\U000e0062\U000e007f" - FLAG_FOR_BAIE_SAINTE_ANNE_SC_07 = "\U0001f3f4\U000e0073\U000e0063\U000e0030\U000e0037\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_CHOISEUL_SB_CH = "\U0001f3f4\U000e0073\U000e0062\U000e0063\U000e0068\U000e007f" - FLAG_FOR_SOUTHERN_RW_05 = "\U0001f3f4\U000e0072\U000e0077\U000e0030\U000e0035\U000e007f" - FLAG_FOR_VAS_HU_VA = "\U0001f3f4\U000e0068\U000e0075\U000e0076\U000e0061\U000e007f" - FLAG_FOR_ASIR_SA_14 = "\U0001f3f4\U000e0073\U000e0061\U000e0031\U000e0034\U000e007f" - FLAG_FOR_NAJRAN_SA_10 = "\U0001f3f4\U000e0073\U000e0061\U000e0031\U000e0030\U000e007f" - FLAG_FOR_AL_JAWF_SA_12 = "\U0001f3f4\U000e0073\U000e0061\U000e0031\U000e0032\U000e007f" - FLAG_FOR_WESTERN_RW_04 = "\U0001f3f4\U000e0072\U000e0077\U000e0030\U000e0034\U000e007f" - FLAG_FOR_RENNELL_AND_BELLONA_SB_RB = "\U0001f3f4\U000e0073\U000e0062\U000e0072\U000e0062\U000e007f" - FLAG_FOR_EASTERN_SA_04 = "\U0001f3f4\U000e0073\U000e0061\U000e0030\U000e0034\U000e007f" - FLAG_FOR_MALAITA_SB_ML = "\U0001f3f4\U000e0073\U000e0062\U000e006d\U000e006c\U000e007f" - FLAG_FOR_KRASNOYARSK_KRAI_RU_KYA = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0079\U000e0061\U000e007f" - FLAG_FOR_BEAU_VALLON_SC_08 = "\U0001f3f4\U000e0073\U000e0063\U000e0030\U000e0038\U000e007f" - FLAG_FOR_KIGALI_RW_01 = "\U0001f3f4\U000e0072\U000e0077\U000e0030\U000e0031\U000e007f" - FLAG_FOR_ISABEL_SB_IS = "\U0001f3f4\U000e0073\U000e0062\U000e0069\U000e0073\U000e007f" - FLAG_FOR_NORTHERN_BORDERS_SA_08 = "\U0001f3f4\U000e0073\U000e0061\U000e0030\U000e0038\U000e007f" - FLAG_FOR_YAROSLAVL_RU_YAR = "\U0001f3f4\U000e0072\U000e0075\U000e0079\U000e0061\U000e0072\U000e007f" - FLAG_FOR_WILTZ_LU_WI = "\U0001f3f4\U000e006c\U000e0075\U000e0077\U000e0069\U000e007f" - FLAG_FOR_HONIARA_SB_CT = "\U0001f3f4\U000e0073\U000e0062\U000e0063\U000e0074\U000e007f" - FLAG_FOR_NORTHERN_RW_03 = "\U0001f3f4\U000e0072\U000e0077\U000e0030\U000e0033\U000e007f" - FLAG_FOR_SONSOROL_PW_370 = "\U0001f3f4\U000e0070\U000e0077\U000e0033\U000e0037\U000e0030\U000e007f" - FLAG_FOR_TABUK_SA_07 = "\U0001f3f4\U000e0073\U000e0061\U000e0030\U000e0037\U000e007f" - FLAG_FOR_LA_RIVIERE_ANGLAISE_SC_16 = "\U0001f3f4\U000e0073\U000e0063\U000e0031\U000e0036\U000e007f" - FLAG_FOR_GRAND_ANSE_MAHE_SC_13 = "\U0001f3f4\U000e0073\U000e0063\U000e0031\U000e0033\U000e007f" - FLAG_FOR_POINTE_LA_RUE_SC_20 = "\U0001f3f4\U000e0073\U000e0063\U000e0032\U000e0030\U000e007f" - FLAG_FOR_CASCADE_SC_11 = "\U0001f3f4\U000e0073\U000e0063\U000e0031\U000e0031\U000e007f" - FLAG_FOR_NORTH_DARFUR_SD_DN = "\U0001f3f4\U000e0073\U000e0064\U000e0064\U000e006e\U000e007f" - FLAG_FOR_WEST_KURDUFAN_SD_GK = "\U0001f3f4\U000e0073\U000e0064\U000e0067\U000e006b\U000e007f" - FLAG_FOR_RIVER_NILE_SD_NR = "\U0001f3f4\U000e0073\U000e0064\U000e006e\U000e0072\U000e007f" - FLAG_FOR_EAST_DARFUR_SD_DE = "\U0001f3f4\U000e0073\U000e0064\U000e0064\U000e0065\U000e007f" - FLAG_FOR_NORRBOTTEN_SE_BD = "\U0001f3f4\U000e0073\U000e0065\U000e0062\U000e0064\U000e007f" - FLAG_FOR_SODERMANLAND_SE_D = "\U0001f3f4\U000e0073\U000e0065\U000e0064\U000e007f" - FLAG_FOR_TAKAMAKA_SC_23 = "\U0001f3f4\U000e0073\U000e0063\U000e0032\U000e0033\U000e007f" - FLAG_FOR_FRENCH_POLYNESIA_FR_PF = "\U0001f3f4\U000e0066\U000e0072\U000e0070\U000e0066\U000e007f" - FLAG_FOR_AL_QADARIF_SD_GD = "\U0001f3f4\U000e0073\U000e0064\U000e0067\U000e0064\U000e007f" - FLAG_FOR_VASTERBOTTEN_SE_AC = "\U0001f3f4\U000e0073\U000e0065\U000e0061\U000e0063\U000e007f" - FLAG_FOR_NORTHERN_SD_NO = "\U0001f3f4\U000e0073\U000e0064\U000e006e\U000e006f\U000e007f" - FLAG_FOR_MONT_FLEURI_SC_18 = "\U0001f3f4\U000e0073\U000e0063\U000e0031\U000e0038\U000e007f" - FLAG_FOR_CENTRAL_SB_CE = "\U0001f3f4\U000e0073\U000e0062\U000e0063\U000e0065\U000e007f" - FLAG_FOR_CENTRAL_DARFUR_SD_DC = "\U0001f3f4\U000e0073\U000e0064\U000e0064\U000e0063\U000e007f" - FLAG_FOR_VOLGOGRAD_RU_VGG = "\U0001f3f4\U000e0072\U000e0075\U000e0076\U000e0067\U000e0067\U000e007f" - FLAG_FOR_PLAISANCE_SC_19 = "\U0001f3f4\U000e0073\U000e0063\U000e0031\U000e0039\U000e007f" - FLAG_FOR_MONT_BUXTON_SC_17 = "\U0001f3f4\U000e0073\U000e0063\U000e0031\U000e0037\U000e007f" - FLAG_FOR_KASSALA_SD_KA = "\U0001f3f4\U000e0073\U000e0064\U000e006b\U000e0061\U000e007f" - FLAG_FOR_LES_MAMELLES_SC_24 = "\U0001f3f4\U000e0073\U000e0063\U000e0032\U000e0034\U000e007f" - FLAG_FOR_GLACIS_SC_12 = "\U0001f3f4\U000e0073\U000e0063\U000e0031\U000e0032\U000e007f" - FLAG_FOR_ROSTOV_RU_ROS = "\U0001f3f4\U000e0072\U000e0075\U000e0072\U000e006f\U000e0073\U000e007f" - FLAG_FOR_SENNAR_SD_SI = "\U0001f3f4\U000e0073\U000e0064\U000e0073\U000e0069\U000e007f" - FLAG_FOR_LA_DIGUE_SC_15 = "\U0001f3f4\U000e0073\U000e0063\U000e0031\U000e0035\U000e007f" - FLAG_FOR_SOUTH_DARFUR_SD_DS = "\U0001f3f4\U000e0073\U000e0064\U000e0064\U000e0073\U000e007f" - FLAG_FOR_WHITE_NILE_SD_NW = "\U0001f3f4\U000e0073\U000e0064\U000e006e\U000e0077\U000e007f" - FLAG_FOR_AL_JAZIRAH_SD_GZ = "\U0001f3f4\U000e0073\U000e0064\U000e0067\U000e007a\U000e007f" - FLAG_FOR_SOUTH_KURDUFAN_SD_KS = "\U0001f3f4\U000e0073\U000e0064\U000e006b\U000e0073\U000e007f" - FLAG_FOR_NORTH_KURDUFAN_SD_KN = "\U0001f3f4\U000e0073\U000e0064\U000e006b\U000e006e\U000e007f" - FLAG_FOR_PORT_GLAUD_SC_21 = "\U0001f3f4\U000e0073\U000e0063\U000e0032\U000e0031\U000e007f" - FLAG_FOR_OSTERGOTLAND_SE_E = "\U0001f3f4\U000e0073\U000e0065\U000e0065\U000e007f" - FLAG_FOR_GRAND_ANSE_PRASLIN_SC_14 = "\U0001f3f4\U000e0073\U000e0063\U000e0031\U000e0034\U000e007f" - FLAG_FOR_JONKOPING_SE_F = "\U0001f3f4\U000e0073\U000e0065\U000e0066\U000e007f" - FLAG_FOR_VARMLAND_SE_S = "\U0001f3f4\U000e0073\U000e0065\U000e0073\U000e007f" - FLAG_FOR_CERKLJE_NA_GORENJSKEM_SI_012 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0031\U000e0032\U000e007f" - FLAG_FOR_CERKNO_SI_014 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0031\U000e0034\U000e007f" - FLAG_FOR_SVETI_NIKOLE_MK_69 = "\U0001f3f4\U000e006d\U000e006b\U000e0036\U000e0039\U000e007f" - FLAG_FOR_NORTH_EAST_SG_02 = "\U0001f3f4\U000e0073\U000e0067\U000e0030\U000e0032\U000e007f" - FLAG_FOR_SOUTH_EAST_SG_04 = "\U0001f3f4\U000e0073\U000e0067\U000e0030\U000e0034\U000e007f" - FLAG_FOR_NORTH_WEST_SG_03 = "\U0001f3f4\U000e0073\U000e0067\U000e0030\U000e0033\U000e007f" - FLAG_FOR_DESTRNIK_SI_018 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0031\U000e0038\U000e007f" - FLAG_FOR_SOUTH_WEST_SG_05 = "\U0001f3f4\U000e0073\U000e0067\U000e0030\U000e0035\U000e007f" - FLAG_FOR_BRDA_SI_007 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0030\U000e0037\U000e007f" - FLAG_FOR_OREBRO_SE_T = "\U0001f3f4\U000e0073\U000e0065\U000e0074\U000e007f" - FLAG_FOR_KRONOBERG_SE_G = "\U0001f3f4\U000e0073\U000e0065\U000e0067\U000e007f" - FLAG_FOR_ASCENSION_ISLAND_SH_AC = "\U0001f3f4\U000e0073\U000e0068\U000e0061\U000e0063\U000e007f" - FLAG_FOR_VASTMANLAND_SE_U = "\U0001f3f4\U000e0073\U000e0065\U000e0075\U000e007f" - FLAG_FOR_CERKNICA_SI_013 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0031\U000e0033\U000e007f" - FLAG_FOR_CRENSOVCI_SI_015 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0031\U000e0035\U000e007f" - FLAG_FOR_REZINA_MD_RE = "\U0001f3f4\U000e006d\U000e0064\U000e0072\U000e0065\U000e007f" - KISS_WOMAN_LIGHT_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - FLAG_FOR_BLED_SI_003 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0030\U000e0033\U000e007f" - FLAG_FOR_GOIAS_BR_GO = "\U0001f3f4\U000e0062\U000e0072\U000e0067\U000e006f\U000e007f" - FLAG_FOR_BELTINCI_SI_002 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0030\U000e0032\U000e007f" - FLAG_FOR_CRNOMELJ_SI_017 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0031\U000e0037\U000e007f" - FLAG_FOR_BREZOVICA_SI_008 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0030\U000e0038\U000e007f" - FLAG_FOR_MINYA_EG_MN = "\U0001f3f4\U000e0065\U000e0067\U000e006d\U000e006e\U000e007f" - FLAG_FOR_RIVIERE_NOIRE_MU_BL = "\U0001f3f4\U000e006d\U000e0075\U000e0062\U000e006c\U000e007f" - FLAG_FOR_GOVI_ALTAI_MN_065 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0036\U000e0035\U000e007f" - FLAG_FOR_AJDOVSCINA_SI_001 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0030\U000e0031\U000e007f" - FLAG_FOR_BOROVNICA_SI_005 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0030\U000e0035\U000e007f" - FLAG_FOR_JURSINCI_SI_042 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0034\U000e0032\U000e007f" - FLAG_FOR_IDRIJA_SI_036 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0033\U000e0036\U000e007f" - FLAG_FOR_KUZMA_SI_056 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0035\U000e0036\U000e007f" - FLAG_FOR_ULYANOVSK_RU_ULY = "\U0001f3f4\U000e0072\U000e0075\U000e0075\U000e006c\U000e0079\U000e007f" - FLAG_FOR_IZOLA_SI_040 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0034\U000e0030\U000e007f" - FLAG_FOR_KOZJE_SI_051 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0035\U000e0031\U000e007f" - FLAG_FOR_KUNGOTA_SI_055 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0035\U000e0035\U000e007f" - FLAG_FOR_JESENICE_SI_041 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0034\U000e0031\U000e007f" - FLAG_FOR_GORNJI_GRAD_SI_030 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0033\U000e0030\U000e007f" - FLAG_FOR_DIVACA_SI_019 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0031\U000e0039\U000e007f" - FLAG_FOR_IVANCNA_GORICA_SI_039 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0033\U000e0039\U000e007f" - FLAG_FOR_KRSKO_SI_054 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0035\U000e0034\U000e007f" - FLAG_FOR_KAMNIK_SI_043 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0034\U000e0033\U000e007f" - FLAG_FOR_DOBREPOLJE_SI_020 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0032\U000e0030\U000e007f" - FLAG_FOR_SALOVCI_SI_033 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0033\U000e0033\U000e007f" - FLAG_FOR_KOBILJE_SI_047 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0034\U000e0037\U000e007f" - FLAG_FOR_HRASTNIK_SI_034 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0033\U000e0034\U000e007f" - FLAG_FOR_DOBROVA_POLHOV_GRADEC_SI_021 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0032\U000e0031\U000e007f" - FLAG_FOR_DRAVOGRAD_SI_025 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0032\U000e0035\U000e007f" - FLAG_FOR_STOCKHOLM_SE_AB = "\U0001f3f4\U000e0073\U000e0065\U000e0061\U000e0062\U000e007f" - FLAG_FOR_DUPLEK_SI_026 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0032\U000e0036\U000e007f" - FLAG_FOR_SALACGRIVA_LV_086 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0038\U000e0036\U000e007f" - FLAG_FOR_KOCEVJE_SI_048 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0034\U000e0038\U000e007f" - FLAG_FOR_KRANJSKA_GORA_SI_053 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0035\U000e0033\U000e007f" - FLAG_FOR_KANAL_SI_044 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0034\U000e0034\U000e007f" - FLAG_FOR_GORNJI_PETROVCI_SI_031 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0033\U000e0031\U000e007f" - FLAG_FOR_GROSUPLJE_SI_032 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0033\U000e0032\U000e007f" - FLAG_FOR_GORISNICA_SI_028 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0032\U000e0038\U000e007f" - FLAG_FOR_TEMOTU_SB_TE = "\U0001f3f4\U000e0073\U000e0062\U000e0074\U000e0065\U000e007f" - FLAG_FOR_DORNAVA_SI_024 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0032\U000e0034\U000e007f" - FLAG_FOR_DOMZALE_SI_023 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0032\U000e0033\U000e007f" - FLAG_FOR_KOBARID_SI_046 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0034\U000e0036\U000e007f" - FLAG_FOR_GORNJA_RADGONA_SI_029 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0032\U000e0039\U000e007f" - FLAG_FOR_ILIRSKA_BISTRICA_SI_038 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0033\U000e0038\U000e007f" - FLAG_FOR_KOMEN_SI_049 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0034\U000e0039\U000e007f" - FLAG_FOR_MARIBOR_SI_070 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0037\U000e0030\U000e007f" - FLAG_FOR_MEZICA_SI_074 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0037\U000e0034\U000e007f" - FLAG_FOR_LUCE_SI_067 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0036\U000e0037\U000e007f" - FLAG_FOR_PODVELKA_SI_093 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0039\U000e0033\U000e007f" - FLAG_FOR_LOSKI_POTOK_SI_066 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0036\U000e0036\U000e007f" - FLAG_FOR_NAZARJE_SI_083 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0038\U000e0033\U000e007f" - FLAG_FOR_LITIJA_SI_060 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0036\U000e0030\U000e007f" - FLAG_FOR_LUKOVICA_SI_068 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0036\U000e0038\U000e007f" - FLAG_FOR_PESNICA_SI_089 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0038\U000e0039\U000e007f" - FLAG_FOR_OSILNICA_SI_088 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0038\U000e0038\U000e007f" - FLAG_FOR_LENDAVA_SI_059 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0035\U000e0039\U000e007f" - FLAG_FOR_MIREN_KOSTANJEVICA_SI_075 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0037\U000e0035\U000e007f" - FLAG_FOR_MORAVSKE_TOPLICE_SI_078 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0037\U000e0038\U000e007f" - FLAG_FOR_PODCETRTEK_SI_092 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0039\U000e0032\U000e007f" - FLAG_FOR_LJUTOMER_SI_063 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0036\U000e0033\U000e007f" - FLAG_FOR_LASKO_SI_057 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0035\U000e0037\U000e007f" - FLAG_FOR_PIVKA_SI_091 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0039\U000e0031\U000e007f" - FLAG_FOR_METLIKA_SI_073 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0037\U000e0033\U000e007f" - FLAG_FOR_HERCEG_NOVI_ME_08 = "\U0001f3f4\U000e006d\U000e0065\U000e0030\U000e0038\U000e007f" - FLAG_FOR_LOSKA_DOLINA_SI_065 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0036\U000e0035\U000e007f" - FLAG_FOR_ANSE_ETOILE_SC_03 = "\U0001f3f4\U000e0073\U000e0063\U000e0030\U000e0033\U000e007f" - FLAG_FOR_ORMOZ_SI_087 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0038\U000e0037\U000e007f" - FLAG_FOR_LOGATEC_SI_064 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0036\U000e0034\U000e007f" - FLAG_FOR_NAKLO_SI_082 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0038\U000e0032\U000e007f" - FLAG_FOR_NOVA_GORICA_SI_084 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0038\U000e0034\U000e007f" - FLAG_FOR_LJUBNO_SI_062 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0036\U000e0032\U000e007f" - FLAG_FOR_MISLINJA_SI_076 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0037\U000e0036\U000e007f" - FLAG_FOR_MEDVODE_SI_071 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0037\U000e0031\U000e007f" - FLAG_FOR_POSTOJNA_SI_094 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0039\U000e0034\U000e007f" - FLAG_FOR_MORAVCE_SI_077 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0037\U000e0037\U000e007f" - FLAG_FOR_LJUBLJANA_SI_061 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0036\U000e0031\U000e007f" - FLAG_FOR_MAJSPERK_SI_069 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0036\U000e0039\U000e007f" - FLAG_FOR_MENGES_SI_072 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0037\U000e0032\U000e007f" - FLAG_FOR_MUTA_SI_081 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0038\U000e0031\U000e007f" - FLAG_FOR_MOZIRJE_SI_079 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0037\U000e0039\U000e007f" - FLAG_FOR_MURSKA_SOBOTA_SI_080 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0038\U000e0030\U000e007f" - FLAG_FOR_RIBNICA_SI_104 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0030\U000e0034\U000e007f" - FLAG_FOR_SKOFLJICA_SI_123 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0032\U000e0033\U000e007f" - FLAG_FOR_SEZANA_SI_111 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0031\U000e0031\U000e007f" - FLAG_FOR_TRBOVLJE_SI_129 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0032\U000e0039\U000e007f" - FLAG_FOR_SLOVENSKE_KONJICE_SI_114 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0031\U000e0034\U000e007f" - FLAG_FOR_STORE_SI_127 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0032\U000e0037\U000e007f" - FLAG_FOR_PUCONCI_SI_097 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0039\U000e0037\U000e007f" - FLAG_FOR_TREBNJE_SI_130 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0033\U000e0030\U000e007f" - FLAG_FOR_ROGATEC_SI_107 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0030\U000e0037\U000e007f" - FLAG_FOR_TOLMIN_SI_128 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0032\U000e0038\U000e007f" - FLAG_FOR_RADOVLJICA_SI_102 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0030\U000e0032\U000e007f" - FLAG_FOR_SEVNICA_SI_110 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0031\U000e0030\U000e007f" - FLAG_FOR_STARSE_SI_115 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0031\U000e0035\U000e007f" - FLAG_FOR_RADLJE_OB_DRAVI_SI_101 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0030\U000e0031\U000e007f" - FLAG_FOR_PTUJ_SI_096 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0039\U000e0036\U000e007f" - FLAG_FOR_SLOVENSKA_BISTRICA_SI_113 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0031\U000e0033\U000e007f" - FLAG_FOR_SEMIC_SI_109 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0030\U000e0039\U000e007f" - FLAG_FOR_PREDDVOR_SI_095 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0039\U000e0035\U000e007f" - FLAG_FOR_RADECE_SI_099 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0039\U000e0039\U000e007f" - FLAG_FOR_SOSTANJ_SI_126 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0032\U000e0036\U000e007f" - FLAG_FOR_ROGASKA_SLATINA_SI_106 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0030\U000e0036\U000e007f" - FLAG_FOR_TRZIC_SI_131 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0033\U000e0031\U000e007f" - FLAG_FOR_RUSE_SI_108 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0030\U000e0038\U000e007f" - FLAG_FOR_SMARJE_PRI_JELSAH_SI_124 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0032\U000e0034\U000e007f" - FLAG_FOR_TURNISCE_SI_132 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0033\U000e0032\U000e007f" - FLAG_FOR_SKOCJAN_SI_121 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0032\U000e0031\U000e007f" - FLAG_FOR_SVETI_JURIJ_SI_116 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0031\U000e0036\U000e007f" - FLAG_FOR_RACE_FRAM_SI_098 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0039\U000e0038\U000e007f" - FLAG_FOR_SLOVENJ_GRADEC_SI_112 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0031\U000e0032\U000e007f" - FLAG_FOR_SENTILJ_SI_118 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0031\U000e0038\U000e007f" - FLAG_FOR_ROGASOVCI_SI_105 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0030\U000e0035\U000e007f" - FLAG_FOR_SENTJERNEJ_SI_119 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0031\U000e0039\U000e007f" - FLAG_FOR_SENCUR_SI_117 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0031\U000e0037\U000e007f" - FLAG_FOR_SENTJUR_SI_120 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0032\U000e0030\U000e007f" - FLAG_FOR_RAVNE_NA_KOROSKEM_SI_103 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0030\U000e0033\U000e007f" - FLAG_FOR_DOLENJSKE_TOPLICE_SI_157 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0035\U000e0037\U000e007f" - FLAG_FOR_MIKLAVZ_NA_DRAVSKEM_POLJU_SI_169 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0036\U000e0039\U000e007f" - FLAG_FOR_VIDEM_SI_135 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0033\U000e0035\U000e007f" - FLAG_FOR_ZRECE_SI_144 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0034\U000e0034\U000e007f" - FLAG_FOR_WEST_DARFUR_SD_DW = "\U0001f3f4\U000e0073\U000e0064\U000e0064\U000e0077\U000e007f" - FLAG_FOR_KOSTEL_SI_165 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0036\U000e0035\U000e007f" - FLAG_FOR_VOJNIK_SI_139 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0033\U000e0039\U000e007f" - FLAG_FOR_BENEDIKT_SI_148 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0034\U000e0038\U000e007f" - FLAG_FOR_HORJUL_SI_162 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0036\U000e0032\U000e007f" - FLAG_FOR_OPLOTNICA_SI_171 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0037\U000e0031\U000e007f" - FLAG_FOR_JEZERSKO_SI_163 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0036\U000e0033\U000e007f" - FLAG_FOR_VITANJE_SI_137 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0033\U000e0037\U000e007f" - FLAG_FOR_ZAGORJE_OB_SAVI_SI_142 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0034\U000e0032\U000e007f" - FLAG_FOR_VUZENICA_SI_141 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0034\U000e0031\U000e007f" - FLAG_FOR_VIPAVA_SI_136 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0033\U000e0036\U000e007f" - FLAG_FOR_HAJDINA_SI_159 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0035\U000e0039\U000e007f" - FLAG_FOR_ZELEZNIKI_SI_146 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0034\U000e0036\U000e007f" - FLAG_FOR_ZIRI_SI_147 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0034\U000e0037\U000e007f" - FLAG_FOR_KRIZEVCI_SI_166 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0036\U000e0036\U000e007f" - FLAG_FOR_CERKVENJAK_SI_153 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0035\U000e0033\U000e007f" - FLAG_FOR_VRHNIKA_SI_140 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0034\U000e0030\U000e007f" - FLAG_FOR_HOCE_SLIVNICA_SI_160 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0036\U000e0030\U000e007f" - FLAG_FOR_VODICE_SI_138 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0033\U000e0038\U000e007f" - FLAG_FOR_MIRNA_PEC_SI_170 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0037\U000e0030\U000e007f" - FLAG_FOR_MARKOVCI_SI_168 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0036\U000e0038\U000e007f" - FLAG_FOR_HODOS_SI_161 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0036\U000e0031\U000e007f" - FLAG_FOR_DOBRNA_SI_155 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0035\U000e0035\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_KOMENDA_SI_164 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0036\U000e0034\U000e007f" - FLAG_FOR_ZALEC_SI_190 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0039\U000e0030\U000e007f" - FLAG_FOR_TRNOVSKA_VAS_SI_185 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0038\U000e0035\U000e007f" - FLAG_FOR_SMARTNO_PRI_LITIJI_SI_194 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0039\U000e0034\U000e007f" - FLAG_FOR_GORJE_SI_207 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0030\U000e0037\U000e007f" - FLAG_FOR_PREBOLD_SI_174 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0037\U000e0034\U000e007f" - FLAG_FOR_SELNICA_OB_DRAVI_SI_178 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0037\U000e0038\U000e007f" - FLAG_FOR_APACE_SI_195 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0039\U000e0035\U000e007f" - FLAG_FOR_CIRKULANE_SI_196 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0039\U000e0036\U000e007f" - FLAG_FOR_SOLCAVA_SI_180 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0038\U000e0030\U000e007f" - FLAG_FOR_SEMPETER_VRTOJBA_SI_183 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0038\U000e0033\U000e007f" - FLAG_FOR_VALLON_DE_LA_ROUSSE_MC_VR = "\U0001f3f4\U000e006d\U000e0063\U000e0076\U000e0072\U000e007f" - FLAG_FOR_SODRAZICA_SI_179 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0037\U000e0039\U000e007f" - FLAG_FOR_RENCE_VOGRSKO_SI_201 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0030\U000e0031\U000e007f" - FLAG_FOR_PREVALJE_SI_175 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0037\U000e0035\U000e007f" - FLAG_FOR_POLJCANE_SI_200 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0030\U000e0030\U000e007f" - FLAG_FOR_RIBNICA_NA_POHORJU_SI_177 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0037\U000e0037\U000e007f" - FLAG_FOR_VERZEJ_SI_188 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0038\U000e0038\U000e007f" - FLAG_FOR_MAKOLE_SI_198 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0039\U000e0038\U000e007f" - FLAG_FOR_PODLEHNIK_SI_172 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0037\U000e0032\U000e007f" - FLAG_FOR_POLZELA_SI_173 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0037\U000e0033\U000e007f" - FLAG_FOR_RAZKRIZJE_SI_176 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0037\U000e0036\U000e007f" - FLAG_FOR_TABOR_SI_184 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0038\U000e0034\U000e007f" - FLAG_FOR_KOSTANJEVICA_NA_KRKI_SI_197 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0039\U000e0037\U000e007f" - FLAG_FOR_ZETALE_SI_191 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0039\U000e0031\U000e007f" - FLAG_FOR_ZUZEMBERK_SI_193 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0039\U000e0033\U000e007f" - FLAG_FOR_STRAZA_SI_203 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0030\U000e0033\U000e007f" - FLAG_FOR_VRANSKO_SI_189 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0038\U000e0039\U000e007f" - FLAG_FOR_TUBAS_PS_TBS = "\U0001f3f4\U000e0070\U000e0073\U000e0074\U000e0062\U000e0073\U000e007f" - FLAG_FOR_TRZIN_SI_186 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0038\U000e0036\U000e007f" - FLAG_FOR_SVETI_TOMAZ_SI_205 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0030\U000e0035\U000e007f" - FLAG_FOR_MOKRONOG_TREBELNO_SI_199 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0039\U000e0039\U000e007f" - FLAG_FOR_WESTERN_AREA_SL_W = "\U0001f3f4\U000e0073\U000e006c\U000e0077\U000e007f" - FLAG_FOR_CALABRIA_IT_78 = "\U0001f3f4\U000e0069\U000e0074\U000e0037\U000e0038\U000e007f" - FLAG_FOR_SERRAVALLE_SM_09 = "\U0001f3f4\U000e0073\U000e006d\U000e0030\U000e0039\U000e007f" - FLAG_FOR_FAETANO_SM_04 = "\U0001f3f4\U000e0073\U000e006d\U000e0030\U000e0034\U000e007f" - FLAG_FOR_SENTRUPERT_SI_211 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0031\U000e0031\U000e007f" - FLAG_FOR_TRNAVA_SK_TA = "\U0001f3f4\U000e0073\U000e006b\U000e0074\U000e0061\U000e007f" - FLAG_FOR_ACQUAVIVA_SM_01 = "\U0001f3f4\U000e0073\U000e006d\U000e0030\U000e0031\U000e007f" - FLAG_FOR_SOUTHERN_SL_S = "\U0001f3f4\U000e0073\U000e006c\U000e0073\U000e007f" - FLAG_FOR_PRESOV_SK_PV = "\U0001f3f4\U000e0073\U000e006b\U000e0070\U000e0076\U000e007f" - FLAG_FOR_KOSICE_SK_KI = "\U0001f3f4\U000e0073\U000e006b\U000e006b\U000e0069\U000e007f" - FLAG_FOR_NORTHERN_SL_N = "\U0001f3f4\U000e0073\U000e006c\U000e006e\U000e007f" - FLAG_FOR_KAOLACK_SN_KL = "\U0001f3f4\U000e0073\U000e006e\U000e006b\U000e006c\U000e007f" - FLAG_FOR_SAN_MARINO_SM_07 = "\U0001f3f4\U000e0073\U000e006d\U000e0030\U000e0037\U000e007f" - FLAG_FOR_FIORENTINO_SM_05 = "\U0001f3f4\U000e0073\U000e006d\U000e0030\U000e0035\U000e007f" - FLAG_FOR_TAMBACOUNDA_SN_TC = "\U0001f3f4\U000e0073\U000e006e\U000e0074\U000e0063\U000e007f" - FLAG_FOR_SEOUL_KR_11 = "\U0001f3f4\U000e006b\U000e0072\U000e0031\U000e0031\U000e007f" - FLAG_FOR_CHIESANUOVA_SM_02 = "\U0001f3f4\U000e0073\U000e006d\U000e0030\U000e0032\U000e007f" - FLAG_FOR_KOLDA_SN_KD = "\U0001f3f4\U000e0073\U000e006e\U000e006b\U000e0064\U000e007f" - FLAG_FOR_KAFFRINE_SN_KA = "\U0001f3f4\U000e0073\U000e006e\U000e006b\U000e0061\U000e007f" - FLAG_FOR_SEDHIOU_SN_SE = "\U0001f3f4\U000e0073\U000e006e\U000e0073\U000e0065\U000e007f" - FLAG_FOR_FATICK_SN_FK = "\U0001f3f4\U000e0073\U000e006e\U000e0066\U000e006b\U000e007f" - FLAG_FOR_TRENCIN_SK_TC = "\U0001f3f4\U000e0073\U000e006b\U000e0074\U000e0063\U000e007f" - FLAG_FOR_BANSKA_BYSTRICA_SK_BC = "\U0001f3f4\U000e0073\U000e006b\U000e0062\U000e0063\U000e007f" - FLAG_FOR_LOUGA_SN_LG = "\U0001f3f4\U000e0073\U000e006e\U000e006c\U000e0067\U000e007f" - FLAG_FOR_NITRA_SK_NI = "\U0001f3f4\U000e0073\U000e006b\U000e006e\U000e0069\U000e007f" - FLAG_FOR_RECICA_OB_SAVINJI_SI_209 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0030\U000e0039\U000e007f" - FLAG_FOR_RAJASTHAN_IN_RJ = "\U0001f3f4\U000e0069\U000e006e\U000e0072\U000e006a\U000e007f" - FLAG_FOR_LENINGRAD_RU_LEN = "\U0001f3f4\U000e0072\U000e0075\U000e006c\U000e0065\U000e006e\U000e007f" - FLAG_FOR_ZILINA_SK_ZI = "\U0001f3f4\U000e0073\U000e006b\U000e007a\U000e0069\U000e007f" - FLAG_FOR_BORGO_MAGGIORE_SM_06 = "\U0001f3f4\U000e0073\U000e006d\U000e0030\U000e0036\U000e007f" - FLAG_FOR_MATAM_SN_MT = "\U0001f3f4\U000e0073\U000e006e\U000e006d\U000e0074\U000e007f" - FLAG_FOR_DOMAGNANO_SM_03 = "\U0001f3f4\U000e0073\U000e006d\U000e0030\U000e0033\U000e007f" - FLAG_FOR_KEDOUGOU_SN_KE = "\U0001f3f4\U000e0073\U000e006e\U000e006b\U000e0065\U000e007f" - FLAG_FOR_MIRNA_SI_212 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0031\U000e0032\U000e007f" - FLAG_FOR_THIES_SN_TH = "\U0001f3f4\U000e0073\U000e006e\U000e0074\U000e0068\U000e007f" - FLAG_FOR_MONTEGIARDINO_SM_08 = "\U0001f3f4\U000e0073\U000e006d\U000e0030\U000e0038\U000e007f" - FLAG_FOR_VALCEA_RO_VL = "\U0001f3f4\U000e0072\U000e006f\U000e0076\U000e006c\U000e007f" - FLAG_FOR_CLUJ_RO_CJ = "\U0001f3f4\U000e0072\U000e006f\U000e0063\U000e006a\U000e007f" - FLAG_FOR_TOGDHEER_SO_TO = "\U0001f3f4\U000e0073\U000e006f\U000e0074\U000e006f\U000e007f" - FLAG_FOR_UPPER_NILE_SS_NU = "\U0001f3f4\U000e0073\U000e0073\U000e006e\U000e0075\U000e007f" - FLAG_FOR_SARAMACCA_SR_SA = "\U0001f3f4\U000e0073\U000e0072\U000e0073\U000e0061\U000e007f" - FLAG_FOR_WESTERN_BAHR_EL_GHAZAL_SS_BW = "\U0001f3f4\U000e0073\U000e0073\U000e0062\U000e0077\U000e007f" - FLAG_FOR_WARRAP_SS_WR = "\U0001f3f4\U000e0073\U000e0073\U000e0077\U000e0072\U000e007f" - DIE_FACE_6 = "\u2685" - FLAG_FOR_NICKERIE_SR_NI = "\U0001f3f4\U000e0073\U000e0072\U000e006e\U000e0069\U000e007f" - FLAG_FOR_EASTERN_EQUATORIA_SS_EE = "\U0001f3f4\U000e0073\U000e0073\U000e0065\U000e0065\U000e007f" - FLAG_FOR_BAKOOL_SO_BK = "\U0001f3f4\U000e0073\U000e006f\U000e0062\U000e006b\U000e007f" - FLAG_FOR_PARAMARIBO_SR_PM = "\U0001f3f4\U000e0073\U000e0072\U000e0070\U000e006d\U000e007f" - FLAG_FOR_WANICA_SR_WA = "\U0001f3f4\U000e0073\U000e0072\U000e0077\U000e0061\U000e007f" - FLAG_FOR_ANGAUR_PW_010 = "\U0001f3f4\U000e0070\U000e0077\U000e0030\U000e0031\U000e0030\U000e007f" - FLAG_FOR_MUDUG_SO_MU = "\U0001f3f4\U000e0073\U000e006f\U000e006d\U000e0075\U000e007f" - FLAG_FOR_MIDDLE_JUBA_SO_JD = "\U0001f3f4\U000e0073\U000e006f\U000e006a\U000e0064\U000e007f" - FLAG_FOR_WESTERN_EQUATORIA_SS_EW = "\U0001f3f4\U000e0073\U000e0073\U000e0065\U000e0077\U000e007f" - FLAG_FOR_PRINCIPE_ST_P = "\U0001f3f4\U000e0073\U000e0074\U000e0070\U000e007f" - FLAG_FOR_CORONIE_SR_CR = "\U0001f3f4\U000e0073\U000e0072\U000e0063\U000e0072\U000e007f" - FLAG_FOR_CONSTANTA_RO_CT = "\U0001f3f4\U000e0072\U000e006f\U000e0063\U000e0074\U000e007f" - FLAG_FOR_HIRAN_SO_HI = "\U0001f3f4\U000e0073\U000e006f\U000e0068\U000e0069\U000e007f" - FLAG_FOR_KARELIA_RU_KR = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0072\U000e007f" - FLAG_FOR_LOWER_SHEBELLE_SO_SH = "\U0001f3f4\U000e0073\U000e006f\U000e0073\U000e0068\U000e007f" - FLAG_FOR_GEDO_SO_GE = "\U0001f3f4\U000e0073\U000e006f\U000e0067\U000e0065\U000e007f" - FLAG_FOR_ZIGUINCHOR_SN_ZG = "\U0001f3f4\U000e0073\U000e006e\U000e007a\U000e0067\U000e007f" - FLAG_FOR_BOQUERON_PY_19 = "\U0001f3f4\U000e0070\U000e0079\U000e0031\U000e0039\U000e007f" - FLAG_FOR_MIDDLE_SHEBELLE_SO_SD = "\U0001f3f4\U000e0073\U000e006f\U000e0073\U000e0064\U000e007f" - FLAG_FOR_SANAAG_SO_SA = "\U0001f3f4\U000e0073\U000e006f\U000e0073\U000e0061\U000e007f" - FLAG_FOR_BROKOPONDO_SR_BR = "\U0001f3f4\U000e0073\U000e0072\U000e0062\U000e0072\U000e007f" - FLAG_FOR_BREZICE_SI_009 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0030\U000e0039\U000e007f" - FLAG_FOR_HRPELJE_KOZINA_SI_035 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0033\U000e0035\U000e007f" - FLAG_FOR_AWDAL_SO_AW = "\U0001f3f4\U000e0073\U000e006f\U000e0061\U000e0077\U000e007f" - FLAG_FOR_LATAKIA_SY_LA = "\U0001f3f4\U000e0073\U000e0079\U000e006c\U000e0061\U000e007f" - FLAG_FOR_AS_SUWAYDA_SY_SU = "\U0001f3f4\U000e0073\U000e0079\U000e0073\U000e0075\U000e007f" - FLAG_FOR_AR_RAQQAH_SY_RA = "\U0001f3f4\U000e0073\U000e0079\U000e0072\U000e0061\U000e007f" - FLAG_FOR_CUSCATLAN_SV_CU = "\U0001f3f4\U000e0073\U000e0076\U000e0063\U000e0075\U000e007f" - FLAG_FOR_CHALATENANGO_SV_CH = "\U0001f3f4\U000e0073\U000e0076\U000e0063\U000e0068\U000e007f" - FLAG_FOR_GALGUDUUD_SO_GA = "\U0001f3f4\U000e0073\U000e006f\U000e0067\U000e0061\U000e007f" - FLAG_FOR_DOBROVNIK_SI_156 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0035\U000e0036\U000e007f" - FLAG_FOR_BORKOU_TD_BO = "\U0001f3f4\U000e0074\U000e0064\U000e0062\U000e006f\U000e007f" - FLAG_FOR_LUBOMBO_SZ_LU = "\U0001f3f4\U000e0073\U000e007a\U000e006c\U000e0075\U000e007f" - FLAG_FOR_MANZINI_SZ_MA = "\U0001f3f4\U000e0073\U000e007a\U000e006d\U000e0061\U000e007f" - FLAG_FOR_MORAZAN_SV_MO = "\U0001f3f4\U000e0073\U000e0076\U000e006d\U000e006f\U000e007f" - FLAG_FOR_DARAA_SY_DR = "\U0001f3f4\U000e0073\U000e0079\U000e0064\U000e0072\U000e007f" - FLAG_FOR_SANTA_ANA_SV_SA = "\U0001f3f4\U000e0073\U000e0076\U000e0073\U000e0061\U000e007f" - FLAG_FOR_TARTUS_SY_TA = "\U0001f3f4\U000e0073\U000e0079\U000e0074\U000e0061\U000e007f" - FLAG_FOR_SHISELWENI_SZ_SH = "\U0001f3f4\U000e0073\U000e007a\U000e0073\U000e0068\U000e007f" - FLAG_FOR_LA_UNION_SV_UN = "\U0001f3f4\U000e0073\U000e0076\U000e0075\U000e006e\U000e007f" - FLAG_FOR_BATHA_TD_BA = "\U0001f3f4\U000e0074\U000e0064\U000e0062\U000e0061\U000e007f" - FLAG_FOR_KANEM_TD_KA = "\U0001f3f4\U000e0074\U000e0064\U000e006b\U000e0061\U000e007f" - FLAG_FOR_GUADELOUPE_FR_GUA = "\U0001f3f4\U000e0066\U000e0072\U000e0067\U000e0075\U000e0061\U000e007f" - FLAG_FOR_QUNEITRA_SY_QU = "\U0001f3f4\U000e0073\U000e0079\U000e0071\U000e0075\U000e007f" - FLAG_FOR_HOMS_SY_HI = "\U0001f3f4\U000e0073\U000e0079\U000e0068\U000e0069\U000e007f" - FLAG_FOR_AL_HASAKAH_SY_HA = "\U0001f3f4\U000e0073\U000e0079\U000e0068\U000e0061\U000e007f" - FLAG_FOR_HAMA_SY_HM = "\U0001f3f4\U000e0073\U000e0079\U000e0068\U000e006d\U000e007f" - FLAG_FOR_AHUACHAPAN_SV_AH = "\U0001f3f4\U000e0073\U000e0076\U000e0061\U000e0068\U000e007f" - FLAG_FOR_SONSONATE_SV_SO = "\U0001f3f4\U000e0073\U000e0076\U000e0073\U000e006f\U000e007f" - FLAG_FOR_CABANAS_SV_CA = "\U0001f3f4\U000e0073\U000e0076\U000e0063\U000e0061\U000e007f" - FLAG_FOR_ENNEDI_EST_TD_EE = "\U0001f3f4\U000e0074\U000e0064\U000e0065\U000e0065\U000e007f" - FLAG_FOR_ALEPPO_SY_HL = "\U0001f3f4\U000e0073\U000e0079\U000e0068\U000e006c\U000e007f" - FLAG_FOR_GOVISUMBER_MN_064 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0036\U000e0034\U000e007f" - FLAG_FOR_LA_LIBERTAD_SV_LI = "\U0001f3f4\U000e0073\U000e0076\U000e006c\U000e0069\U000e007f" - FLAG_FOR_BAHR_EL_GAZEL_TD_BG = "\U0001f3f4\U000e0074\U000e0064\U000e0062\U000e0067\U000e007f" - FLAG_FOR_SIPALIWINI_SR_SI = "\U0001f3f4\U000e0073\U000e0072\U000e0073\U000e0069\U000e007f" - FLAG_FOR_FINNMARK_NO_20 = "\U0001f3f4\U000e006e\U000e006f\U000e0032\U000e0030\U000e007f" - FLAG_FOR_NONTHABURI_TH_12 = "\U0001f3f4\U000e0074\U000e0068\U000e0031\U000e0032\U000e007f" - FLAG_FOR_PATHUM_THANI_TH_13 = "\U0001f3f4\U000e0074\U000e0068\U000e0031\U000e0033\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_WADI_FIRA_TD_WF = "\U0001f3f4\U000e0074\U000e0064\U000e0077\U000e0066\U000e007f" - FLAG_FOR_PRACHIN_BURI_TH_25 = "\U0001f3f4\U000e0074\U000e0068\U000e0032\U000e0035\U000e007f" - FLAG_FOR_BURI_RAM_TH_31 = "\U0001f3f4\U000e0074\U000e0068\U000e0033\U000e0031\U000e007f" - FLAG_FOR_NAKHON_RATCHASIMA_TH_30 = "\U0001f3f4\U000e0074\U000e0068\U000e0033\U000e0030\U000e007f" - FLAG_FOR_N_DJAMENA_TD_ND = "\U0001f3f4\U000e0074\U000e0064\U000e006e\U000e0064\U000e007f" - FLAG_FOR_PHRA_NAKHON_SI_AYUTTHAYA_TH_14 = "\U0001f3f4\U000e0074\U000e0068\U000e0031\U000e0034\U000e007f" - FLAG_FOR_MARSASKALA_MT_27 = "\U0001f3f4\U000e006d\U000e0074\U000e0032\U000e0037\U000e007f" - FLAG_FOR_LOGONE_OCCIDENTAL_TD_LO = "\U0001f3f4\U000e0074\U000e0064\U000e006c\U000e006f\U000e007f" - FLAG_FOR_CHACHOENGSAO_TH_24 = "\U0001f3f4\U000e0074\U000e0068\U000e0032\U000e0034\U000e007f" - FLAG_FOR_TIBESTI_TD_TI = "\U0001f3f4\U000e0074\U000e0064\U000e0074\U000e0069\U000e007f" - FLAG_FOR_CHAI_NAT_TH_18 = "\U0001f3f4\U000e0074\U000e0068\U000e0031\U000e0038\U000e007f" - FLAG_FOR_MOYEN_CHARI_TD_MC = "\U0001f3f4\U000e0074\U000e0064\U000e006d\U000e0063\U000e007f" - FLAG_FOR_TANDJILE_TD_TA = "\U0001f3f4\U000e0074\U000e0064\U000e0074\U000e0061\U000e007f" - FLAG_FOR_SAINT_HELENA_SH_HL = "\U0001f3f4\U000e0073\U000e0068\U000e0068\U000e006c\U000e007f" - FLAG_FOR_PLATEAUX_TG_P = "\U0001f3f4\U000e0074\U000e0067\U000e0070\U000e007f" - FLAG_FOR_SALAMAT_TD_SA = "\U0001f3f4\U000e0074\U000e0064\U000e0073\U000e0061\U000e007f" - FLAG_FOR_CHON_BURI_TH_20 = "\U0001f3f4\U000e0074\U000e0068\U000e0032\U000e0030\U000e007f" - FLAG_FOR_MANDOUL_TD_MA = "\U0001f3f4\U000e0074\U000e0064\U000e006d\U000e0061\U000e007f" - FLAG_FOR_MAYO_KEBBI_EST_TD_ME = "\U0001f3f4\U000e0074\U000e0064\U000e006d\U000e0065\U000e007f" - FLAG_FOR_SURIN_TH_32 = "\U0001f3f4\U000e0074\U000e0068\U000e0033\U000e0032\U000e007f" - FLAG_FOR_ARDAHAN_TR_75 = "\U0001f3f4\U000e0074\U000e0072\U000e0037\U000e0035\U000e007f" - FLAG_FOR_NAKHON_NAYOK_TH_26 = "\U0001f3f4\U000e0074\U000e0068\U000e0032\U000e0036\U000e007f" - FLAG_FOR_SARABURI_TH_19 = "\U0001f3f4\U000e0074\U000e0068\U000e0031\U000e0039\U000e007f" - FLAG_FOR_RIF_DIMASHQ_SY_RD = "\U0001f3f4\U000e0073\U000e0079\U000e0072\U000e0064\U000e007f" - FLAG_FOR_SAMUT_PRAKAN_TH_11 = "\U0001f3f4\U000e0074\U000e0068\U000e0031\U000e0031\U000e007f" - FLAG_FOR_SA_KAEO_TH_27 = "\U0001f3f4\U000e0074\U000e0068\U000e0032\U000e0037\U000e007f" - FLAG_FOR_GUERA_TD_GR = "\U0001f3f4\U000e0074\U000e0064\U000e0067\U000e0072\U000e007f" - FLAG_FOR_OUADDAI_TD_OD = "\U0001f3f4\U000e0074\U000e0064\U000e006f\U000e0064\U000e007f" - FLAG_FOR_SAVANES_TG_S = "\U0001f3f4\U000e0074\U000e0067\U000e0073\U000e007f" - FLAG_FOR_PHRAE_TH_54 = "\U0001f3f4\U000e0074\U000e0068\U000e0035\U000e0034\U000e007f" - FLAG_FOR_KHON_KAEN_TH_40 = "\U0001f3f4\U000e0074\U000e0068\U000e0034\U000e0030\U000e007f" - FLAG_FOR_UTHAI_THANI_TH_61 = "\U0001f3f4\U000e0074\U000e0068\U000e0036\U000e0031\U000e007f" - FLAG_FOR_MUKDAHAN_TH_49 = "\U0001f3f4\U000e0074\U000e0068\U000e0034\U000e0039\U000e007f" - FLAG_FOR_PHITSANULOK_TH_65 = "\U0001f3f4\U000e0074\U000e0068\U000e0036\U000e0035\U000e007f" - FLAG_FOR_LAMPANG_TH_52 = "\U0001f3f4\U000e0074\U000e0068\U000e0035\U000e0032\U000e007f" - FLAG_FOR_SUPHANBURI_TH_72 = "\U0001f3f4\U000e0074\U000e0068\U000e0037\U000e0032\U000e007f" - FLAG_FOR_RATCHABURI_TH_70 = "\U0001f3f4\U000e0074\U000e0068\U000e0037\U000e0030\U000e007f" - FLAG_FOR_UDON_THANI_TH_41 = "\U0001f3f4\U000e0074\U000e0068\U000e0034\U000e0031\U000e007f" - FLAG_FOR_LOEI_TH_42 = "\U0001f3f4\U000e0074\U000e0068\U000e0034\U000e0032\U000e007f" - FLAG_FOR_NONG_KHAI_TH_43 = "\U0001f3f4\U000e0074\U000e0068\U000e0034\U000e0033\U000e007f" - FLAG_FOR_NAKHON_SAWAN_TH_60 = "\U0001f3f4\U000e0074\U000e0068\U000e0036\U000e0030\U000e007f" - FLAG_FOR_PHETCHABUN_TH_67 = "\U0001f3f4\U000e0074\U000e0068\U000e0036\U000e0037\U000e007f" - FLAG_FOR_SAKON_NAKHON_TH_47 = "\U0001f3f4\U000e0074\U000e0068\U000e0034\U000e0037\U000e007f" - FLAG_FOR_KALASIN_TH_46 = "\U0001f3f4\U000e0074\U000e0068\U000e0034\U000e0036\U000e007f" - FLAG_FOR_KANCHANABURI_TH_71 = "\U0001f3f4\U000e0074\U000e0068\U000e0037\U000e0031\U000e007f" - FLAG_FOR_TOTONICAPAN_GT_TO = "\U0001f3f4\U000e0067\U000e0074\U000e0074\U000e006f\U000e007f" - FLAG_FOR_SAMUT_SAKHON_TH_74 = "\U0001f3f4\U000e0074\U000e0068\U000e0037\U000e0034\U000e007f" - FLAG_FOR_TIGRAY_ET_TI = "\U0001f3f4\U000e0065\U000e0074\U000e0074\U000e0069\U000e007f" - FLAG_FOR_NAKHON_PHANOM_TH_48 = "\U0001f3f4\U000e0074\U000e0068\U000e0034\U000e0038\U000e007f" - FLAG_FOR_NAKHON_PATHOM_TH_73 = "\U0001f3f4\U000e0074\U000e0068\U000e0037\U000e0033\U000e007f" - FLAG_FOR_UBON_RATCHATHANI_TH_34 = "\U0001f3f4\U000e0074\U000e0068\U000e0033\U000e0034\U000e007f" - FLAG_FOR_KAMPHAENG_PHET_TH_62 = "\U0001f3f4\U000e0074\U000e0068\U000e0036\U000e0032\U000e007f" - FLAG_FOR_YASOTHON_TH_35 = "\U0001f3f4\U000e0074\U000e0068\U000e0033\U000e0035\U000e007f" - FLAG_FOR_CHIANG_RAI_TH_57 = "\U0001f3f4\U000e0074\U000e0068\U000e0035\U000e0037\U000e007f" - FLAG_FOR_CHIANG_MAI_TH_50 = "\U0001f3f4\U000e0074\U000e0068\U000e0035\U000e0030\U000e007f" - FLAG_FOR_NONG_BUA_LAM_PHU_TH_39 = "\U0001f3f4\U000e0074\U000e0068\U000e0033\U000e0039\U000e007f" - FLAG_FOR_TAK_TH_63 = "\U0001f3f4\U000e0074\U000e0068\U000e0036\U000e0033\U000e007f" - FLAG_FOR_BUENG_KAN_TH_38 = "\U0001f3f4\U000e0074\U000e0068\U000e0033\U000e0038\U000e007f" - FLAG_FOR_LAMPHUN_TH_51 = "\U0001f3f4\U000e0074\U000e0068\U000e0035\U000e0031\U000e007f" - FLAG_FOR_PHAYAO_TH_56 = "\U0001f3f4\U000e0074\U000e0068\U000e0035\U000e0036\U000e007f" - FLAG_FOR_ROI_ET_TH_45 = "\U0001f3f4\U000e0074\U000e0068\U000e0034\U000e0035\U000e007f" - FLAG_FOR_PHICHIT_TH_66 = "\U0001f3f4\U000e0074\U000e0068\U000e0036\U000e0036\U000e007f" - FLAG_FOR_MAHA_SARAKHAM_TH_44 = "\U0001f3f4\U000e0074\U000e0068\U000e0034\U000e0034\U000e007f" - FLAG_FOR_SI_SA_KET_TH_33 = "\U0001f3f4\U000e0074\U000e0068\U000e0033\U000e0033\U000e007f" - FLAG_FOR_NAN_TH_55 = "\U0001f3f4\U000e0074\U000e0068\U000e0035\U000e0035\U000e007f" - FLAG_FOR_SUKHOTHAI_TH_64 = "\U0001f3f4\U000e0074\U000e0068\U000e0036\U000e0034\U000e007f" - FLAG_FOR_AILEU_TL_AL = "\U0001f3f4\U000e0074\U000e006c\U000e0061\U000e006c\U000e007f" - FLAG_FOR_MOQUEGUA_PE_MOQ = "\U0001f3f4\U000e0070\U000e0065\U000e006d\U000e006f\U000e0071\U000e007f" - FLAG_FOR_BAUCAU_TL_BA = "\U0001f3f4\U000e0074\U000e006c\U000e0062\U000e0061\U000e007f" - FLAG_FOR_AINARO_TL_AN = "\U0001f3f4\U000e0074\U000e006c\U000e0061\U000e006e\U000e007f" - FLAG_FOR_YAP_FM_YAP = "\U0001f3f4\U000e0066\U000e006d\U000e0079\U000e0061\U000e0070\U000e007f" - FLAG_FOR_SATUN_TH_91 = "\U0001f3f4\U000e0074\U000e0068\U000e0039\U000e0031\U000e007f" - FLAG_FOR_PHANG_NGA_TH_82 = "\U0001f3f4\U000e0074\U000e0068\U000e0038\U000e0032\U000e007f" - FLAG_FOR_TRANG_TH_92 = "\U0001f3f4\U000e0074\U000e0068\U000e0039\U000e0032\U000e007f" - FLAG_FOR_SONGKHLA_TH_90 = "\U0001f3f4\U000e0074\U000e0068\U000e0039\U000e0030\U000e007f" - FLAG_FOR_DASOGUZ_TM_D = "\U0001f3f4\U000e0074\U000e006d\U000e0064\U000e007f" - KISS_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - FLAG_FOR_PATTAYA_TH_S = "\U0001f3f4\U000e0074\U000e0068\U000e0073\U000e007f" - FLAG_FOR_BLEKINGE_SE_K = "\U0001f3f4\U000e0073\U000e0065\U000e006b\U000e007f" - FLAG_FOR_MANATUTO_TL_MT = "\U0001f3f4\U000e0074\U000e006c\U000e006d\U000e0074\U000e007f" - FLAG_FOR_PATTANI_TH_94 = "\U0001f3f4\U000e0074\U000e0068\U000e0039\U000e0034\U000e007f" - FLAG_FOR_HIROSHIMA_JP_34 = "\U0001f3f4\U000e006a\U000e0070\U000e0033\U000e0034\U000e007f" - FLAG_FOR_JIWAKA_PG_JWK = "\U0001f3f4\U000e0070\U000e0067\U000e006a\U000e0077\U000e006b\U000e007f" - FLAG_FOR_LIQUICA_TL_LI = "\U0001f3f4\U000e0074\U000e006c\U000e006c\U000e0069\U000e007f" - FLAG_FOR_KHATLON_TJ_KT = "\U0001f3f4\U000e0074\U000e006a\U000e006b\U000e0074\U000e007f" - FLAG_FOR_SUGHD_TJ_SU = "\U0001f3f4\U000e0074\U000e006a\U000e0073\U000e0075\U000e007f" - FLAG_FOR_VIQUEQUE_TL_VI = "\U0001f3f4\U000e0074\U000e006c\U000e0076\U000e0069\U000e007f" - FLAG_FOR_BOBONARO_TL_BO = "\U0001f3f4\U000e0074\U000e006c\U000e0062\U000e006f\U000e007f" - FLAG_FOR_SURAT_THANI_TH_84 = "\U0001f3f4\U000e0074\U000e0068\U000e0038\U000e0034\U000e007f" - FLAG_FOR_RANONG_TH_85 = "\U0001f3f4\U000e0074\U000e0068\U000e0038\U000e0035\U000e007f" - FLAG_FOR_NORD_EST_HT_NE = "\U0001f3f4\U000e0068\U000e0074\U000e006e\U000e0065\U000e007f" - FLAG_FOR_PRACHUAP_KHIRI_KHAN_TH_77 = "\U0001f3f4\U000e0074\U000e0068\U000e0037\U000e0037\U000e007f" - FLAG_FOR_PHETCHABURI_TH_76 = "\U0001f3f4\U000e0074\U000e0068\U000e0037\U000e0036\U000e007f" - FLAG_FOR_NARATHIWAT_TH_96 = "\U0001f3f4\U000e0074\U000e0068\U000e0039\U000e0036\U000e007f" - FLAG_FOR_MAHDIA_TN_53 = "\U0001f3f4\U000e0074\U000e006e\U000e0035\U000e0033\U000e007f" - FLAG_FOR_TONGATAPU_TO_04 = "\U0001f3f4\U000e0074\U000e006f\U000e0030\U000e0034\U000e007f" - FLAG_FOR_VAVA_U_TO_05 = "\U0001f3f4\U000e0074\U000e006f\U000e0030\U000e0035\U000e007f" - FLAG_FOR_KAIROUAN_TN_41 = "\U0001f3f4\U000e0074\U000e006e\U000e0034\U000e0031\U000e007f" - FLAG_FOR_BOLU_TR_14 = "\U0001f3f4\U000e0074\U000e0072\U000e0031\U000e0034\U000e007f" - FLAG_FOR_BINGOL_TR_12 = "\U0001f3f4\U000e0074\U000e0072\U000e0031\U000e0032\U000e007f" - FLAG_FOR_AMASYA_TR_05 = "\U0001f3f4\U000e0074\U000e0072\U000e0030\U000e0035\U000e007f" - FLAG_FOR_BEJA_TN_31 = "\U0001f3f4\U000e0074\U000e006e\U000e0033\U000e0031\U000e007f" - FLAG_FOR_ZAGHOUAN_TN_22 = "\U0001f3f4\U000e0074\U000e006e\U000e0032\U000e0032\U000e007f" - FLAG_FOR_BILECIK_TR_11 = "\U0001f3f4\U000e0074\U000e0072\U000e0031\U000e0031\U000e007f" - FLAG_FOR_AGRI_TR_04 = "\U0001f3f4\U000e0074\U000e0072\U000e0030\U000e0034\U000e007f" - FLAG_FOR_KEF_TN_33 = "\U0001f3f4\U000e0074\U000e006e\U000e0033\U000e0033\U000e007f" - FLAG_FOR_MANOUBA_TN_14 = "\U0001f3f4\U000e0074\U000e006e\U000e0031\U000e0034\U000e007f" - FLAG_FOR_MEDENINE_TN_82 = "\U0001f3f4\U000e0074\U000e006e\U000e0038\U000e0032\U000e007f" - FLAG_FOR_BALIKESIR_TR_10 = "\U0001f3f4\U000e0074\U000e0072\U000e0031\U000e0030\U000e007f" - FLAG_FOR_EWA_NR_09 = "\U0001f3f4\U000e006e\U000e0072\U000e0030\U000e0039\U000e007f" - FLAG_FOR_TOZEUR_TN_72 = "\U0001f3f4\U000e0074\U000e006e\U000e0037\U000e0032\U000e007f" - FLAG_FOR_EUA_TO_01 = "\U0001f3f4\U000e0074\U000e006f\U000e0030\U000e0031\U000e007f" - FLAG_FOR_KASSERINE_TN_42 = "\U0001f3f4\U000e0074\U000e006e\U000e0034\U000e0032\U000e007f" - FLAG_FOR_GABES_TN_81 = "\U0001f3f4\U000e0074\U000e006e\U000e0038\U000e0031\U000e007f" - FLAG_FOR_KAUNAS_LT_16 = "\U0001f3f4\U000e006c\U000e0074\U000e0031\U000e0036\U000e007f" - FLAG_FOR_SILIANA_TN_34 = "\U0001f3f4\U000e0074\U000e006e\U000e0033\U000e0034\U000e007f" - FLAG_FOR_JENDOUBA_TN_32 = "\U0001f3f4\U000e0074\U000e006e\U000e0033\U000e0032\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_BIZERTE_TN_23 = "\U0001f3f4\U000e0074\U000e006e\U000e0032\U000e0033\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_WOMAN = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469" - FLAG_FOR_NIUAS_TO_03 = "\U0001f3f4\U000e0074\U000e006f\U000e0030\U000e0033\U000e007f" - FLAG_FOR_AYDIN_TR_09 = "\U0001f3f4\U000e0074\U000e0072\U000e0030\U000e0039\U000e007f" - FLAG_FOR_SIDI_BOUZID_TN_43 = "\U0001f3f4\U000e0074\U000e006e\U000e0034\U000e0033\U000e007f" - FLAG_FOR_JOHOR_MY_01 = "\U0001f3f4\U000e006d\U000e0079\U000e0030\U000e0031\U000e007f" - FLAG_FOR_KEBILI_TN_73 = "\U0001f3f4\U000e0074\U000e006e\U000e0037\U000e0033\U000e007f" - FLAG_FOR_TATAOUINE_TN_83 = "\U0001f3f4\U000e0074\U000e006e\U000e0038\U000e0033\U000e007f" - FLAG_FOR_MONASTIR_TN_52 = "\U0001f3f4\U000e0074\U000e006e\U000e0035\U000e0032\U000e007f" - FLAG_FOR_ARTVIN_TR_08 = "\U0001f3f4\U000e0074\U000e0072\U000e0030\U000e0038\U000e007f" - FLAG_FOR_GRAUBUNDEN_CH_GR = "\U0001f3f4\U000e0063\U000e0068\U000e0067\U000e0072\U000e007f" - FLAG_FOR_MALATYA_TR_44 = "\U0001f3f4\U000e0074\U000e0072\U000e0034\U000e0034\U000e007f" - FLAG_FOR_DENIZLI_TR_20 = "\U0001f3f4\U000e0074\U000e0072\U000e0032\U000e0030\U000e007f" - FLAG_FOR_RIZE_TR_53 = "\U0001f3f4\U000e0074\U000e0072\U000e0035\U000e0033\U000e007f" - FLAG_FOR_DIYARBAKIR_TR_21 = "\U0001f3f4\U000e0074\U000e0072\U000e0032\U000e0031\U000e007f" - FLAG_FOR_EDIRNE_TR_22 = "\U0001f3f4\U000e0074\U000e0072\U000e0032\U000e0032\U000e007f" - FLAG_FOR_BURSA_TR_16 = "\U0001f3f4\U000e0074\U000e0072\U000e0031\U000e0036\U000e007f" - FLAG_FOR_SIIRT_TR_56 = "\U0001f3f4\U000e0074\U000e0072\U000e0035\U000e0036\U000e007f" - FLAG_FOR_BOKE_REGION_GN_B = "\U0001f3f4\U000e0067\U000e006e\U000e0062\U000e007f" - FLAG_FOR_KAHRAMANMARAS_TR_46 = "\U0001f3f4\U000e0074\U000e0072\U000e0034\U000e0036\U000e007f" - FLAG_FOR_MARDIN_TR_47 = "\U0001f3f4\U000e0074\U000e0072\U000e0034\U000e0037\U000e007f" - FLAG_FOR_ERZURUM_TR_25 = "\U0001f3f4\U000e0074\U000e0072\U000e0032\U000e0035\U000e007f" - FLAG_FOR_ORO_PG_NPP = "\U0001f3f4\U000e0070\U000e0067\U000e006e\U000e0070\U000e0070\U000e007f" - FLAG_FOR_NIGDE_TR_51 = "\U0001f3f4\U000e0074\U000e0072\U000e0035\U000e0031\U000e007f" - FLAG_FOR_ORDU_TR_52 = "\U0001f3f4\U000e0074\U000e0072\U000e0035\U000e0032\U000e007f" - FLAG_FOR_NGOBE_BUGLE_PA_NB = "\U0001f3f4\U000e0070\U000e0061\U000e006e\U000e0062\U000e007f" - FLAG_FOR_HAKKARI_TR_30 = "\U0001f3f4\U000e0074\U000e0072\U000e0033\U000e0030\U000e007f" - FLAG_FOR_SAMSUN_TR_55 = "\U0001f3f4\U000e0074\U000e0072\U000e0035\U000e0035\U000e007f" - FLAG_FOR_HATAY_TR_31 = "\U0001f3f4\U000e0074\U000e0072\U000e0033\U000e0031\U000e007f" - FLAG_FOR_SAKARYA_TR_54 = "\U0001f3f4\U000e0074\U000e0072\U000e0035\U000e0034\U000e007f" - FLAG_FOR_KIRKLARELI_TR_39 = "\U0001f3f4\U000e0074\U000e0072\U000e0033\U000e0039\U000e007f" - FLAG_FOR_VICTORIA_MT_45 = "\U0001f3f4\U000e006d\U000e0074\U000e0034\U000e0035\U000e007f" - FLAG_FOR_KIRSEHIR_TR_40 = "\U0001f3f4\U000e0074\U000e0072\U000e0034\U000e0030\U000e007f" - FLAG_FOR_ISPARTA_TR_32 = "\U0001f3f4\U000e0074\U000e0072\U000e0033\U000e0032\U000e007f" - FLAG_FOR_ESKISEHIR_TR_26 = "\U0001f3f4\U000e0074\U000e0072\U000e0032\U000e0036\U000e007f" - FLAG_FOR_BURDUR_TR_15 = "\U0001f3f4\U000e0074\U000e0072\U000e0031\U000e0035\U000e007f" - FLAG_FOR_MANISA_TR_45 = "\U0001f3f4\U000e0074\U000e0072\U000e0034\U000e0035\U000e007f" - FLAG_FOR_PRAHA_HLAVNI_MESTO_CZ_10 = "\U0001f3f4\U000e0063\U000e007a\U000e0031\U000e0030\U000e007f" - FLAG_FOR_ELAZIG_TR_23 = "\U0001f3f4\U000e0074\U000e0072\U000e0032\U000e0033\U000e007f" - FLAG_FOR_CANAKKALE_TR_17 = "\U0001f3f4\U000e0074\U000e0072\U000e0031\U000e0037\U000e007f" - FLAG_FOR_MAYARO_RIO_CLARO_TT_MRC = "\U0001f3f4\U000e0074\U000e0074\U000e006d\U000e0072\U000e0063\U000e007f" - FLAG_FOR_TOKAT_TR_60 = "\U0001f3f4\U000e0074\U000e0072\U000e0036\U000e0030\U000e007f" - FLAG_FOR_TOBAGO_TT_TOB = "\U0001f3f4\U000e0074\U000e0074\U000e0074\U000e006f\U000e0062\U000e007f" - FLAG_FOR_DIEGO_MARTIN_TT_DMN = "\U0001f3f4\U000e0074\U000e0074\U000e0064\U000e006d\U000e006e\U000e007f" - FLAG_FOR_SAN_FERNANDO_TT_SFO = "\U0001f3f4\U000e0074\U000e0074\U000e0073\U000e0066\U000e006f\U000e007f" - FLAG_FOR_KILIS_TR_79 = "\U0001f3f4\U000e0074\U000e0072\U000e0037\U000e0039\U000e007f" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - FLAG_FOR_PENZA_RU_PNZ = "\U0001f3f4\U000e0072\U000e0075\U000e0070\U000e006e\U000e007a\U000e007f" - FLAG_FOR_SANLIURFA_TR_63 = "\U0001f3f4\U000e0074\U000e0072\U000e0036\U000e0033\U000e007f" - FLAG_FOR_ERZINCAN_TR_24 = "\U0001f3f4\U000e0074\U000e0072\U000e0032\U000e0034\U000e007f" - FLAG_FOR_TEKIRDAG_TR_59 = "\U0001f3f4\U000e0074\U000e0072\U000e0035\U000e0039\U000e007f" - FLAG_FOR_KIRIKKALE_TR_71 = "\U0001f3f4\U000e0074\U000e0072\U000e0037\U000e0031\U000e007f" - FLAG_FOR_IGDIR_TR_76 = "\U0001f3f4\U000e0074\U000e0072\U000e0037\U000e0036\U000e007f" - FLAG_FOR_COUVA_TABAQUITE_TALPARO_TT_CTT = "\U0001f3f4\U000e0074\U000e0074\U000e0063\U000e0074\U000e0074\U000e007f" - FLAG_FOR_KARAMAN_TR_70 = "\U0001f3f4\U000e0074\U000e0072\U000e0037\U000e0030\U000e007f" - FLAG_FOR_ZONGULDAK_TR_67 = "\U0001f3f4\U000e0074\U000e0072\U000e0036\U000e0037\U000e007f" - FLAG_FOR_TUNCELI_TR_62 = "\U0001f3f4\U000e0074\U000e0072\U000e0036\U000e0032\U000e007f" - FLAG_FOR_POINT_FORTIN_TT_PTF = "\U0001f3f4\U000e0074\U000e0074\U000e0070\U000e0074\U000e0066\U000e007f" - FLAG_FOR_PENAL_DEBE_TT_PED = "\U0001f3f4\U000e0074\U000e0074\U000e0070\U000e0065\U000e0064\U000e007f" - FLAG_FOR_SAN_JUAN_LAVENTILLE_TT_SJL = "\U0001f3f4\U000e0074\U000e0074\U000e0073\U000e006a\U000e006c\U000e007f" - FLAG_FOR_PRINCES_TOWN_TT_PRT = "\U0001f3f4\U000e0074\U000e0074\U000e0070\U000e0072\U000e0074\U000e007f" - FLAG_FOR_YALOVA_TR_77 = "\U0001f3f4\U000e0074\U000e0072\U000e0037\U000e0037\U000e007f" - FLAG_FOR_BAYBURT_TR_69 = "\U0001f3f4\U000e0074\U000e0072\U000e0036\U000e0039\U000e007f" - FLAG_FOR_BAIE_LAZARE_SC_06 = "\U0001f3f4\U000e0073\U000e0063\U000e0030\U000e0036\U000e007f" - FLAG_FOR_CHAGUANAS_TT_CHA = "\U0001f3f4\U000e0074\U000e0074\U000e0063\U000e0068\U000e0061\U000e007f" - FLAG_FOR_BARTIN_TR_74 = "\U0001f3f4\U000e0074\U000e0072\U000e0037\U000e0034\U000e007f" - FLAG_FOR_SIPARIA_TT_SIP = "\U0001f3f4\U000e0074\U000e0074\U000e0073\U000e0069\U000e0070\U000e007f" - FLAG_FOR_SINOP_TR_57 = "\U0001f3f4\U000e0074\U000e0072\U000e0035\U000e0037\U000e007f" - FLAG_FOR_GAZIANTEP_TR_27 = "\U0001f3f4\U000e0074\U000e0072\U000e0032\U000e0037\U000e007f" - FLAG_FOR_KARABUK_TR_78 = "\U0001f3f4\U000e0074\U000e0072\U000e0037\U000e0038\U000e007f" - FLAG_FOR_SANTA_BARBARA_HN_SB = "\U0001f3f4\U000e0068\U000e006e\U000e0073\U000e0062\U000e007f" - FLAG_FOR_CHIAYI_COUNTY_TW_CYI = "\U0001f3f4\U000e0074\U000e0077\U000e0063\U000e0079\U000e0069\U000e007f" - FLAG_FOR_KAGERA_TZ_05 = "\U0001f3f4\U000e0074\U000e007a\U000e0030\U000e0035\U000e007f" - FLAG_FOR_NANUMEA_TV_NMA = "\U0001f3f4\U000e0074\U000e0076\U000e006e\U000e006d\U000e0061\U000e007f" - FLAG_FOR_TAINAN_TW_TNN = "\U0001f3f4\U000e0074\U000e0077\U000e0074\U000e006e\U000e006e\U000e007f" - FLAG_FOR_DODOMA_TZ_03 = "\U0001f3f4\U000e0074\U000e007a\U000e0030\U000e0033\U000e007f" - FLAG_FOR_CHIAYI_TW_CYQ = "\U0001f3f4\U000e0074\U000e0077\U000e0063\U000e0079\U000e0071\U000e007f" - FLAG_FOR_YUNLIN_TW_YUN = "\U0001f3f4\U000e0074\U000e0077\U000e0079\U000e0075\U000e006e\U000e007f" - FLAG_FOR_NEW_TAIPEI_TW_NWT = "\U0001f3f4\U000e0074\U000e0077\U000e006e\U000e0077\U000e0074\U000e007f" - FLAG_FOR_KINMEN_TW_KIN = "\U0001f3f4\U000e0074\U000e0077\U000e006b\U000e0069\U000e006e\U000e007f" - FLAG_FOR_HUALIEN_TW_HUA = "\U0001f3f4\U000e0074\U000e0077\U000e0068\U000e0075\U000e0061\U000e007f" - FLAG_FOR_TAICHUNG_TW_TXG = "\U0001f3f4\U000e0074\U000e0077\U000e0074\U000e0078\U000e0067\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_PINGTUNG_TW_PIF = "\U0001f3f4\U000e0074\U000e0077\U000e0070\U000e0069\U000e0066\U000e007f" - FLAG_FOR_IRINGA_TZ_04 = "\U0001f3f4\U000e0074\U000e007a\U000e0030\U000e0034\U000e007f" - FLAG_FOR_KEELUNG_TW_KEE = "\U0001f3f4\U000e0074\U000e0077\U000e006b\U000e0065\U000e0065\U000e007f" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_MAN = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - FLAG_FOR_AGLONA_LV_001 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0030\U000e0031\U000e007f" - FLAG_FOR_CANKOVA_SI_152 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0035\U000e0032\U000e007f" - FLAG_FOR_ARUSHA_TZ_01 = "\U0001f3f4\U000e0074\U000e007a\U000e0030\U000e0031\U000e007f" - FLAG_FOR_NUI_TV_NUI = "\U0001f3f4\U000e0074\U000e0076\U000e006e\U000e0075\U000e0069\U000e007f" - FLAG_FOR_YILAN_TW_ILA = "\U0001f3f4\U000e0074\U000e0077\U000e0069\U000e006c\U000e0061\U000e007f" - FLAG_FOR_VERACRUZ_MX_VER = "\U0001f3f4\U000e006d\U000e0078\U000e0076\U000e0065\U000e0072\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_LIENCHIANG_TW_LIE = "\U0001f3f4\U000e0074\U000e0077\U000e006c\U000e0069\U000e0065\U000e007f" - FLAG_FOR_NUKUFETAU_TV_NKF = "\U0001f3f4\U000e0074\U000e0076\U000e006e\U000e006b\U000e0066\U000e007f" - FLAG_FOR_VAITUPU_TV_VAI = "\U0001f3f4\U000e0074\U000e0076\U000e0076\U000e0061\U000e0069\U000e007f" - FLAG_FOR_VOLYN_UA_07 = "\U0001f3f4\U000e0075\U000e0061\U000e0030\U000e0037\U000e007f" - FLAG_FOR_MTWARA_TZ_17 = "\U0001f3f4\U000e0074\U000e007a\U000e0031\U000e0037\U000e007f" - FLAG_FOR_TAMBOV_RU_TAM = "\U0001f3f4\U000e0072\U000e0075\U000e0074\U000e0061\U000e006d\U000e007f" - FLAG_FOR_KATAVI_TZ_28 = "\U0001f3f4\U000e0074\U000e007a\U000e0032\U000e0038\U000e007f" - FLAG_FOR_SOUTH_PEMBA_TZ_10 = "\U0001f3f4\U000e0074\U000e007a\U000e0031\U000e0030\U000e007f" - FLAG_FOR_RUKWA_TZ_20 = "\U0001f3f4\U000e0074\U000e007a\U000e0032\U000e0030\U000e007f" - FLAG_FOR_PORT_LOUIS_DISTRICT_MU_PL = "\U0001f3f4\U000e006d\U000e0075\U000e0070\U000e006c\U000e007f" - FLAG_FOR_MANYARA_TZ_26 = "\U0001f3f4\U000e0074\U000e007a\U000e0032\U000e0036\U000e007f" - FLAG_FOR_SEVASTOPOL_UA_40 = "\U0001f3f4\U000e0075\U000e0061\U000e0034\U000e0030\U000e007f" - FLAG_FOR_NJOMBE_TZ_29 = "\U0001f3f4\U000e0074\U000e007a\U000e0032\U000e0039\U000e007f" - FLAG_FOR_ZAPORIZHZHYA_UA_23 = "\U0001f3f4\U000e0075\U000e0061\U000e0032\U000e0033\U000e007f" - FLAG_FOR_MBEYA_TZ_14 = "\U0001f3f4\U000e0074\U000e007a\U000e0031\U000e0034\U000e007f" - FLAG_FOR_KYIVSHCHYNA_UA_32 = "\U0001f3f4\U000e0075\U000e0061\U000e0033\U000e0032\U000e007f" - FLAG_FOR_RUVUMA_TZ_21 = "\U0001f3f4\U000e0074\U000e007a\U000e0032\U000e0031\U000e007f" - FLAG_FOR_SHINYANGA_TZ_22 = "\U0001f3f4\U000e0074\U000e007a\U000e0032\U000e0032\U000e007f" - FLAG_FOR_ZAKARPATTIA_UA_21 = "\U0001f3f4\U000e0075\U000e0061\U000e0032\U000e0031\U000e007f" - FLAG_FOR_NORTE_GW_N = "\U0001f3f4\U000e0067\U000e0077\U000e006e\U000e007f" - FLAG_FOR_RIVNENSHCHYNA_UA_56 = "\U0001f3f4\U000e0075\U000e0061\U000e0035\U000e0036\U000e007f" - FLAG_FOR_SAINT_GEORGE_DM_04 = "\U0001f3f4\U000e0064\U000e006d\U000e0030\U000e0034\U000e007f" - FLAG_FOR_ODESHCHYNA_UA_51 = "\U0001f3f4\U000e0075\U000e0061\U000e0035\U000e0031\U000e007f" - FLAG_FOR_SIMIYU_TZ_30 = "\U0001f3f4\U000e0074\U000e007a\U000e0033\U000e0030\U000e007f" - FLAG_FOR_GEITA_TZ_27 = "\U0001f3f4\U000e0074\U000e007a\U000e0032\U000e0037\U000e007f" - FLAG_FOR_POLTAVSHCHYNA_UA_53 = "\U0001f3f4\U000e0075\U000e0061\U000e0035\U000e0033\U000e007f" - FLAG_FOR_TABORA_TZ_24 = "\U0001f3f4\U000e0074\U000e007a\U000e0032\U000e0034\U000e007f" - FLAG_FOR_SINGIDA_TZ_23 = "\U0001f3f4\U000e0074\U000e007a\U000e0032\U000e0033\U000e007f" - FLAG_FOR_MWANZA_TZ_18 = "\U0001f3f4\U000e0074\U000e007a\U000e0031\U000e0038\U000e007f" - FLAG_FOR_SELENGE_MN_049 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0034\U000e0039\U000e007f" - FLAG_FOR_VINNYCHCHYNA_UA_05 = "\U0001f3f4\U000e0075\U000e0061\U000e0030\U000e0035\U000e007f" - FLAG_FOR_FLORIDA_US_FL = "\U0001f3f4\U000e0075\U000e0073\U000e0066\U000e006c\U000e007f" - FLAG_FOR_LOFA_LR_LO = "\U0001f3f4\U000e006c\U000e0072\U000e006c\U000e006f\U000e007f" - RECYCLING_SYMBOL_FOR_TYPE_7_PLASTICS = "\u2679" - FLAG_FOR_BAKER_ISLAND_UM_81 = "\U0001f3f4\U000e0075\U000e006d\U000e0038\U000e0031\U000e007f" - FLAG_FOR_NORTHERN_UG_N = "\U0001f3f4\U000e0075\U000e0067\U000e006e\U000e007f" - FLAG_FOR_INGUSHETIA_RU_IN = "\U0001f3f4\U000e0072\U000e0075\U000e0069\U000e006e\U000e007f" - FLAG_FOR_KHERSONSHCHYNA_UA_65 = "\U0001f3f4\U000e0075\U000e0061\U000e0036\U000e0035\U000e007f" - FLAG_FOR_WAKE_ISLAND_UM_79 = "\U0001f3f4\U000e0075\U000e006d\U000e0037\U000e0039\U000e007f" - FLAG_FOR_PALMYRA_ATOLL_UM_95 = "\U0001f3f4\U000e0075\U000e006d\U000e0039\U000e0035\U000e007f" - FLAG_FOR_KHARKIVSHCHYNA_UA_63 = "\U0001f3f4\U000e0075\U000e0061\U000e0036\U000e0033\U000e007f" - FLAG_FOR_KHMELNYCHCHYNA_UA_68 = "\U0001f3f4\U000e0075\U000e0061\U000e0036\U000e0038\U000e007f" - FLAG_FOR_WESTERN_UG_W = "\U0001f3f4\U000e0075\U000e0067\U000e0077\U000e007f" - FLAG_FOR_EASTERN_UG_E = "\U0001f3f4\U000e0075\U000e0067\U000e0065\U000e007f" - FLAG_FOR_IDLIB_SY_ID = "\U0001f3f4\U000e0073\U000e0079\U000e0069\U000e0064\U000e007f" - FLAG_FOR_TERNOPILSHCHYNA_UA_61 = "\U0001f3f4\U000e0075\U000e0061\U000e0036\U000e0031\U000e007f" - FLAG_FOR_CHERNIVTSI_OBLAST_UA_77 = "\U0001f3f4\U000e0075\U000e0061\U000e0037\U000e0037\U000e007f" - FLAG_FOR_PARA_SR_PR = "\U0001f3f4\U000e0073\U000e0072\U000e0070\U000e0072\U000e007f" - FLAG_FOR_SUMSHCHYNA_UA_59 = "\U0001f3f4\U000e0075\U000e0061\U000e0035\U000e0039\U000e007f" - FAMILY_WOMAN_WOMAN_BABY_BOY = "\U0001f469\u200d\U0001f469\u200d\U0001f476\u200d\U0001f466" - FLAG_FOR_JERICHO_PS_JRH = "\U0001f3f4\U000e0070\U000e0073\U000e006a\U000e0072\U000e0068\U000e007f" - FLAG_FOR_MIDWAY_ATOLL_UM_71 = "\U0001f3f4\U000e0075\U000e006d\U000e0037\U000e0031\U000e007f" - FLAG_FOR_JOHNSTON_ATOLL_UM_67 = "\U0001f3f4\U000e0075\U000e006d\U000e0036\U000e0037\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_CANELONES_UY_CA = "\U0001f3f4\U000e0075\U000e0079\U000e0063\U000e0061\U000e007f" - FLAG_FOR_KOSTROMA_RU_KOS = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e006f\U000e0073\U000e007f" - FLAG_FOR_JARVIS_ISLAND_UM_86 = "\U0001f3f4\U000e0075\U000e006d\U000e0038\U000e0036\U000e007f" - FLAG_FOR_PENNSYLVANIA_US_PA = "\U0001f3f4\U000e0075\U000e0073\U000e0070\U000e0061\U000e007f" - FLAG_FOR_PUEBLA_MX_PUE = "\U0001f3f4\U000e006d\U000e0078\U000e0070\U000e0075\U000e0065\U000e007f" - FLAG_FOR_SVETA_TROJICA_V_SLOVENSKIH_GORICAH_SI_204 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0030\U000e0034\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_CHERKASHCHYNA_UA_71 = "\U0001f3f4\U000e0075\U000e0061\U000e0037\U000e0031\U000e007f" - FLAG_FOR_ALEXANDRIA_EG_ALX = "\U0001f3f4\U000e0065\U000e0067\U000e0061\U000e006c\U000e0078\U000e007f" - FLAG_FOR_CENTRAL_MACEDONIA_GR_B = "\U0001f3f4\U000e0067\U000e0072\U000e0062\U000e007f" - FLAG_FOR_ARTIGAS_UY_AR = "\U0001f3f4\U000e0075\U000e0079\U000e0061\U000e0072\U000e007f" - FLAG_FOR_OSLO_NO_03 = "\U0001f3f4\U000e006e\U000e006f\U000e0030\U000e0033\U000e007f" - FLAG_FOR_LOGONE_ORIENTAL_TD_LR = "\U0001f3f4\U000e0074\U000e0064\U000e006c\U000e0072\U000e007f" - FLAG_FOR_SINT_EUSTATIUS_NL_BQ3 = "\U0001f3f4\U000e006e\U000e006c\U000e0062\U000e0071\U000e0033\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_KINGMAN_REEF_UM_89 = "\U0001f3f4\U000e0075\U000e006d\U000e0038\U000e0039\U000e007f" - FLAG_FOR_DNIPROPETROVSHCHYNA_UA_12 = "\U0001f3f4\U000e0075\U000e0061\U000e0031\U000e0032\U000e007f" - FLAG_FOR_VRANCEA_RO_VN = "\U0001f3f4\U000e0072\U000e006f\U000e0076\U000e006e\U000e007f" - FLAG_FOR_NORTH_PEMBA_TZ_06 = "\U0001f3f4\U000e0074\U000e007a\U000e0030\U000e0036\U000e007f" - FLAG_FOR_MONTEVIDEO_UY_MO = "\U0001f3f4\U000e0075\U000e0079\U000e006d\U000e006f\U000e007f" - FLAG_FOR_COLONIA_UY_CO = "\U0001f3f4\U000e0075\U000e0079\U000e0063\U000e006f\U000e007f" - FLAG_FOR_JIZZAKH_UZ_JI = "\U0001f3f4\U000e0075\U000e007a\U000e006a\U000e0069\U000e007f" - FLAG_FOR_OKLAHOMA_US_OK = "\U0001f3f4\U000e0075\U000e0073\U000e006f\U000e006b\U000e007f" - FLAG_FOR_TREINTA_Y_TRES_UY_TT = "\U0001f3f4\U000e0075\U000e0079\U000e0074\U000e0074\U000e007f" - FLAG_FOR_SOUTH_CAROLINA_US_SC = "\U0001f3f4\U000e0075\U000e0073\U000e0073\U000e0063\U000e007f" - FLAG_FOR_PAYSANDU_UY_PA = "\U0001f3f4\U000e0075\U000e0079\U000e0070\U000e0061\U000e007f" - FLAG_FOR_TASHKENT_PROVINCE_UZ_TO = "\U0001f3f4\U000e0075\U000e007a\U000e0074\U000e006f\U000e007f" - FLAG_FOR_NAMANGAN_UZ_NG = "\U0001f3f4\U000e0075\U000e007a\U000e006e\U000e0067\U000e007f" - FLAG_FOR_DURAZNO_UY_DU = "\U0001f3f4\U000e0075\U000e0079\U000e0064\U000e0075\U000e007f" - FLAG_FOR_ARAGUA_VE_D = "\U0001f3f4\U000e0076\U000e0065\U000e0064\U000e007f" - FLAG_FOR_KARAKALPAKSTAN_UZ_QR = "\U0001f3f4\U000e0075\U000e007a\U000e0071\U000e0072\U000e007f" - FLAG_FOR_CERRO_LARGO_UY_CL = "\U0001f3f4\U000e0075\U000e0079\U000e0063\U000e006c\U000e007f" - FLAG_FOR_KELANTAN_MY_03 = "\U0001f3f4\U000e006d\U000e0079\U000e0030\U000e0033\U000e007f" - FLAG_FOR_FLORES_UY_FS = "\U0001f3f4\U000e0075\U000e0079\U000e0066\U000e0073\U000e007f" - FLAG_FOR_FERGANA_UZ_FA = "\U0001f3f4\U000e0075\U000e007a\U000e0066\U000e0061\U000e007f" - FLAG_FOR_MARYLAND_US_MD = "\U0001f3f4\U000e0075\U000e0073\U000e006d\U000e0064\U000e007f" - FLAG_FOR_ANZOATEGUI_VE_B = "\U0001f3f4\U000e0076\U000e0065\U000e0062\U000e007f" - FLAG_FOR_SAINT_ANDREW_VC_02 = "\U0001f3f4\U000e0076\U000e0063\U000e0030\U000e0032\U000e007f" - FLAG_FOR_BUKHARA_UZ_BU = "\U0001f3f4\U000e0075\U000e007a\U000e0062\U000e0075\U000e007f" - FLAG_FOR_MELEKEOK_PW_212 = "\U0001f3f4\U000e0070\U000e0077\U000e0032\U000e0031\U000e0032\U000e007f" - FLAG_FOR_TELENESTI_MD_TE = "\U0001f3f4\U000e006d\U000e0064\U000e0074\U000e0065\U000e007f" - FLAG_FOR_CHARLOTTE_VC_01 = "\U0001f3f4\U000e0076\U000e0063\U000e0030\U000e0031\U000e007f" - FLAG_FOR_ANDIJAN_UZ_AN = "\U0001f3f4\U000e0075\U000e007a\U000e0061\U000e006e\U000e007f" - FLAG_FOR_SALTO_UY_SA = "\U0001f3f4\U000e0075\U000e0079\U000e0073\U000e0061\U000e007f" - FLAG_FOR_SORIANO_UY_SO = "\U0001f3f4\U000e0075\U000e0079\U000e0073\U000e006f\U000e007f" - FLAG_FOR_SIRDARYO_UZ_SI = "\U0001f3f4\U000e0075\U000e007a\U000e0073\U000e0069\U000e007f" - FLAG_FOR_TASHKENT_UZ_TK = "\U0001f3f4\U000e0075\U000e007a\U000e0074\U000e006b\U000e007f" - FLAG_FOR_CAPITAL_VE_A = "\U0001f3f4\U000e0076\U000e0065\U000e0061\U000e007f" - FLAG_FOR_SAINT_DAVID_VC_03 = "\U0001f3f4\U000e0076\U000e0063\U000e0030\U000e0033\U000e007f" - FLAG_FOR_MALDONADO_UY_MA = "\U0001f3f4\U000e0075\U000e0079\U000e006d\U000e0061\U000e007f" - FLAG_FOR_RIO_NEGRO_UY_RN = "\U0001f3f4\U000e0075\U000e0079\U000e0072\U000e006e\U000e007f" - FLAG_FOR_LAVALLEJA_UY_LA = "\U0001f3f4\U000e0075\U000e0079\U000e006c\U000e0061\U000e007f" - FLAG_FOR_NAVOIY_UZ_NW = "\U0001f3f4\U000e0075\U000e007a\U000e006e\U000e0077\U000e007f" - FLAG_FOR_SAMARQAND_UZ_SA = "\U0001f3f4\U000e0075\U000e007a\U000e0073\U000e0061\U000e007f" - FLAG_FOR_SURXONDARYO_UZ_SU = "\U0001f3f4\U000e0075\U000e007a\U000e0073\U000e0075\U000e007f" - FLAG_FOR_QASHQADARYO_UZ_QA = "\U0001f3f4\U000e0075\U000e007a\U000e0071\U000e0061\U000e007f" - FLAG_FOR_TACUAREMBO_UY_TA = "\U0001f3f4\U000e0075\U000e0079\U000e0074\U000e0061\U000e007f" - FLAG_FOR_SON_LA_VN_05 = "\U0001f3f4\U000e0076\U000e006e\U000e0030\U000e0035\U000e007f" - FLAG_FOR_LANG_SON_VN_09 = "\U0001f3f4\U000e0076\U000e006e\U000e0030\U000e0039\U000e007f" - FLAG_FOR_HA_GIANG_VN_03 = "\U0001f3f4\U000e0076\U000e006e\U000e0030\U000e0033\U000e007f" - FLAG_FOR_MIRANDA_VE_M = "\U0001f3f4\U000e0076\U000e0065\U000e006d\U000e007f" - FLAG_FOR_TUYEN_QUANG_VN_07 = "\U0001f3f4\U000e0076\U000e006e\U000e0030\U000e0037\U000e007f" - FLAG_FOR_THANH_HOA_VN_21 = "\U0001f3f4\U000e0076\U000e006e\U000e0032\U000e0031\U000e007f" - FLAG_FOR_NGHE_AN_VN_22 = "\U0001f3f4\U000e0076\U000e006e\U000e0032\U000e0032\U000e007f" - FLAG_FOR_COJEDES_VE_H = "\U0001f3f4\U000e0076\U000e0065\U000e0068\U000e007f" - FLAG_FOR_CAO_BANG_VN_04 = "\U0001f3f4\U000e0076\U000e006e\U000e0030\U000e0034\U000e007f" - FLAG_FOR_QUANG_NGAI_VN_29 = "\U0001f3f4\U000e0076\U000e006e\U000e0032\U000e0039\U000e007f" - FLAG_FOR_SANTANDER_CO_SAN = "\U0001f3f4\U000e0063\U000e006f\U000e0073\U000e0061\U000e006e\U000e007f" - FLAG_FOR_NINH_BINH_VN_18 = "\U0001f3f4\U000e0076\U000e006e\U000e0031\U000e0038\U000e007f" - FLAG_FOR_YEN_BAI_VN_06 = "\U0001f3f4\U000e0076\U000e006e\U000e0030\U000e0036\U000e007f" - FLAG_FOR_THAI_BINH_VN_20 = "\U0001f3f4\U000e0076\U000e006e\U000e0032\U000e0030\U000e007f" - FLAG_FOR_BARINAS_VE_E = "\U0001f3f4\U000e0076\U000e0065\U000e0065\U000e007f" - FLAG_FOR_HA_TINH_VN_23 = "\U0001f3f4\U000e0076\U000e006e\U000e0032\U000e0033\U000e007f" - FLAG_FOR_LOWER_RIVER_DIVISION_GM_L = "\U0001f3f4\U000e0067\U000e006d\U000e006c\U000e007f" - FLAG_FOR_IG_SI_037 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0033\U000e0037\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_LARA_VE_K = "\U0001f3f4\U000e0076\U000e0065\U000e006b\U000e007f" - FLAG_FOR_QUANG_NINH_VN_13 = "\U0001f3f4\U000e0076\U000e006e\U000e0031\U000e0033\U000e007f" - FLAG_FOR_AU_CAP_SC_04 = "\U0001f3f4\U000e0073\U000e0063\U000e0030\U000e0034\U000e007f" - FLAG_FOR_HOA_BINH_VN_14 = "\U0001f3f4\U000e0076\U000e006e\U000e0031\U000e0034\U000e007f" - FLAG_FOR_KON_TUM_VN_28 = "\U0001f3f4\U000e0076\U000e006e\U000e0032\U000e0038\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_ZANZIBAR_URBAN_WEST_TZ_15 = "\U0001f3f4\U000e0074\U000e007a\U000e0031\U000e0035\U000e007f" - FLAG_FOR_OECUSSE_TL_OE = "\U0001f3f4\U000e0074\U000e006c\U000e006f\U000e0065\U000e007f" - FLAG_FOR_YARACUY_VE_U = "\U0001f3f4\U000e0076\U000e0065\U000e0075\U000e007f" - FLAG_FOR_BINH_PHUOC_VN_58 = "\U0001f3f4\U000e0076\U000e006e\U000e0035\U000e0038\U000e007f" - FLAG_FOR_NINH_THUAN_VN_36 = "\U0001f3f4\U000e0076\U000e006e\U000e0033\U000e0036\U000e007f" - FLAG_FOR_OSHIKOTO_NA_OT = "\U0001f3f4\U000e006e\U000e0061\U000e006f\U000e0074\U000e007f" - FLAG_FOR_CARGADOS_CARAJOS_MU_CC = "\U0001f3f4\U000e006d\U000e0075\U000e0063\U000e0063\U000e007f" - FLAG_FOR_PHU_YEN_VN_32 = "\U0001f3f4\U000e0076\U000e006e\U000e0033\U000e0032\U000e007f" - FLAG_FOR_NAM_INH_VN_67 = "\U0001f3f4\U000e0076\U000e006e\U000e0036\U000e0037\U000e007f" - FLAG_FOR_BAC_GIANG_VN_54 = "\U0001f3f4\U000e0076\U000e006e\U000e0035\U000e0034\U000e007f" - FLAG_FOR_TIEN_GIANG_VN_46 = "\U0001f3f4\U000e0076\U000e006e\U000e0034\U000e0036\U000e007f" - FLAG_FOR_NORTHERN_MW_N = "\U0001f3f4\U000e006d\U000e0077\U000e006e\U000e007f" - FLAG_FOR_CAN_THO_VN_CT = "\U0001f3f4\U000e0076\U000e006e\U000e0063\U000e0074\U000e007f" - FLAG_FOR_BINH_THUAN_VN_40 = "\U0001f3f4\U000e0076\U000e006e\U000e0034\U000e0030\U000e007f" - FLAG_FOR_AK_LAK_VN_33 = "\U0001f3f4\U000e0076\U000e006e\U000e0033\U000e0033\U000e007f" - FLAG_FOR_LAM_ONG_VN_35 = "\U0001f3f4\U000e0076\U000e006e\U000e0033\U000e0035\U000e007f" - FLAG_FOR_BEN_TRE_VN_50 = "\U0001f3f4\U000e0076\U000e006e\U000e0035\U000e0030\U000e007f" - FLAG_FOR_TAY_NINH_VN_37 = "\U0001f3f4\U000e0076\U000e006e\U000e0033\U000e0037\U000e007f" - FLAG_FOR_BINH_INH_VN_31 = "\U0001f3f4\U000e0076\U000e006e\U000e0033\U000e0031\U000e007f" - FLAG_FOR_BAC_LIEU_VN_55 = "\U0001f3f4\U000e0076\U000e006e\U000e0035\U000e0035\U000e007f" - FLAG_FOR_ONG_THAP_VN_45 = "\U0001f3f4\U000e0076\U000e006e\U000e0034\U000e0035\U000e007f" - FLAG_FOR_KIEN_GIANG_VN_47 = "\U0001f3f4\U000e0076\U000e006e\U000e0034\U000e0037\U000e007f" - FLAG_FOR_ONG_NAI_VN_39 = "\U0001f3f4\U000e0076\U000e006e\U000e0033\U000e0039\U000e007f" - FLAG_FOR_BA_RIA_VUNG_TAU_VN_43 = "\U0001f3f4\U000e0076\U000e006e\U000e0034\U000e0033\U000e007f" - FLAG_FOR_UTAH_US_UT = "\U0001f3f4\U000e0075\U000e0073\U000e0075\U000e0074\U000e007f" - FLAG_FOR_VINH_PHUC_VN_70 = "\U0001f3f4\U000e0076\U000e006e\U000e0037\U000e0030\U000e007f" - FLAG_FOR_IEN_BIEN_VN_71 = "\U0001f3f4\U000e0076\U000e006e\U000e0037\U000e0031\U000e007f" - FLAG_FOR_BAC_KAN_VN_53 = "\U0001f3f4\U000e0076\U000e006e\U000e0035\U000e0033\U000e007f" - FLAG_FOR_DA_NANG_VN_DN = "\U0001f3f4\U000e0076\U000e006e\U000e0064\U000e006e\U000e007f" - FLAG_FOR_HA_NAM_VN_63 = "\U0001f3f4\U000e0076\U000e006e\U000e0036\U000e0033\U000e007f" - FLAG_FOR_AK_NONG_VN_72 = "\U0001f3f4\U000e0076\U000e006e\U000e0037\U000e0032\U000e007f" - FLAG_FOR_SOC_TRANG_VN_52 = "\U0001f3f4\U000e0076\U000e006e\U000e0035\U000e0032\U000e007f" - FLAG_FOR_GIA_LAI_VN_30 = "\U0001f3f4\U000e0076\U000e006e\U000e0033\U000e0030\U000e007f" - FLAG_FOR_CA_MAU_VN_59 = "\U0001f3f4\U000e0076\U000e006e\U000e0035\U000e0039\U000e007f" - FLAG_FOR_BOLIVAR_VE_F = "\U0001f3f4\U000e0076\U000e0065\U000e0066\U000e007f" - FLAG_FOR_KHANH_HOA_VN_34 = "\U0001f3f4\U000e0076\U000e006e\U000e0033\U000e0034\U000e007f" - FLAG_FOR_LONG_AN_VN_41 = "\U0001f3f4\U000e0076\U000e006e\U000e0034\U000e0031\U000e007f" - FLAG_FOR_SHEFA_VU_SEE = "\U0001f3f4\U000e0076\U000e0075\U000e0073\U000e0065\U000e0065\U000e007f" - FLAG_FOR_AMRAN_YE_AM = "\U0001f3f4\U000e0079\U000e0065\U000e0061\U000e006d\U000e007f" - FLAG_FOR_RAYMAH_YE_RA = "\U0001f3f4\U000e0079\U000e0065\U000e0072\U000e0061\U000e007f" - FLAG_FOR_MAE_HONG_SON_TH_58 = "\U0001f3f4\U000e0074\U000e0068\U000e0035\U000e0038\U000e007f" - FLAG_FOR_AL_MAHRAH_YE_MR = "\U0001f3f4\U000e0079\U000e0065\U000e006d\U000e0072\U000e007f" - FLAG_FOR_AL_MAHWIT_YE_MW = "\U0001f3f4\U000e0079\U000e0065\U000e006d\U000e0077\U000e007f" - FLAG_FOR_SATUPA_ITEA_WS_SA = "\U0001f3f4\U000e0077\U000e0073\U000e0073\U000e0061\U000e007f" - FLAG_FOR_GAGA_EMAUGA_WS_GE = "\U0001f3f4\U000e0077\U000e0073\U000e0067\U000e0065\U000e007f" - FLAG_FOR_HAIPHONG_VN_HP = "\U0001f3f4\U000e0076\U000e006e\U000e0068\U000e0070\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_DHALE_YE_DA = "\U0001f3f4\U000e0079\U000e0065\U000e0064\U000e0061\U000e007f" - FLAG_FOR_DHAMAR_YE_DH = "\U0001f3f4\U000e0079\U000e0065\U000e0064\U000e0068\U000e007f" - FLAG_FOR_TUAMASAGA_WS_TU = "\U0001f3f4\U000e0077\U000e0073\U000e0074\U000e0075\U000e007f" - FLAG_FOR_AL_BAYDA_YE_BA = "\U0001f3f4\U000e0079\U000e0065\U000e0062\U000e0061\U000e007f" - FLAG_FOR_HAJJAH_YE_HJ = "\U0001f3f4\U000e0079\U000e0065\U000e0068\U000e006a\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_SHABWAH_YE_SH = "\U0001f3f4\U000e0079\U000e0065\U000e0073\U000e0068\U000e007f" - FAMILY_WOMAN_MAN_GIRL_BOY = "\U0001f469\u200d\U0001f468\u200d\U0001f467\u200d\U0001f466" - FLAG_FOR_ATUA_WS_AT = "\U0001f3f4\U000e0077\U000e0073\U000e0061\U000e0074\U000e007f" - FLAG_FOR_UVEA_WF_UV = "\U0001f3f4\U000e0077\U000e0066\U000e0075\U000e0076\U000e007f" - FLAG_FOR_PENAMA_VU_PAM = "\U0001f3f4\U000e0076\U000e0075\U000e0070\U000e0061\U000e006d\U000e007f" - FLAG_FOR_CRNA_NA_KOROSKEM_SI_016 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0031\U000e0036\U000e007f" - FLAG_FOR_ADAN_YE_AD = "\U0001f3f4\U000e0079\U000e0065\U000e0061\U000e0064\U000e007f" - FLAG_FOR_ABYAN_YE_AB = "\U0001f3f4\U000e0079\U000e0065\U000e0061\U000e0062\U000e007f" - FLAG_FOR_PALAULI_WS_PA = "\U0001f3f4\U000e0077\U000e0073\U000e0070\U000e0061\U000e007f" - FLAG_FOR_CENTAR_ZUPA_MK_78 = "\U0001f3f4\U000e006d\U000e006b\U000e0037\U000e0038\U000e007f" - FLAG_FOR_VA_A_O_FONOTI_WS_VF = "\U0001f3f4\U000e0077\U000e0073\U000e0076\U000e0066\U000e007f" - FLAG_FOR_BULAWAYO_ZW_BU = "\U0001f3f4\U000e007a\U000e0077\U000e0062\U000e0075\U000e007f" - FLAG_FOR_HARARE_ZW_HA = "\U0001f3f4\U000e007a\U000e0077\U000e0068\U000e0061\U000e007f" - FLAG_FOR_GAUTENG_ZA_GT = "\U0001f3f4\U000e007a\U000e0061\U000e0067\U000e0074\U000e007f" - FLAG_FOR_TAIZ_YE_TA = "\U0001f3f4\U000e0079\U000e0065\U000e0074\U000e0061\U000e007f" - FLAG_FOR_NEAMT_RO_NT = "\U0001f3f4\U000e0072\U000e006f\U000e006e\U000e0074\U000e007f" - FLAG_FOR_NORTHERN_ZM_05 = "\U0001f3f4\U000e007a\U000e006d\U000e0030\U000e0035\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - FLAG_FOR_MUCHINGA_ZM_10 = "\U0001f3f4\U000e007a\U000e006d\U000e0031\U000e0030\U000e007f" - FLAG_FOR_COPPERBELT_ZM_08 = "\U0001f3f4\U000e007a\U000e006d\U000e0030\U000e0038\U000e007f" - FLAG_FOR_NORTH_WESTERN_ZM_06 = "\U0001f3f4\U000e007a\U000e006d\U000e0030\U000e0036\U000e007f" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - FLAG_FOR_LUAPULA_ZM_04 = "\U0001f3f4\U000e007a\U000e006d\U000e0030\U000e0034\U000e007f" - FLAG_FOR_LIMPOPO_ZA_LP = "\U0001f3f4\U000e007a\U000e0061\U000e006c\U000e0070\U000e007f" - FLAG_FOR_KOCAELI_TR_41 = "\U0001f3f4\U000e0074\U000e0072\U000e0034\U000e0031\U000e007f" - FLAG_FOR_LUSAKA_ZM_09 = "\U0001f3f4\U000e007a\U000e006d\U000e0030\U000e0039\U000e007f" - FLAG_FOR_WESTERN_ZM_01 = "\U0001f3f4\U000e007a\U000e006d\U000e0030\U000e0031\U000e007f" - FLAG_FOR_REPUBLIKA_SRPSKA_BA_SRP = "\U0001f3f4\U000e0062\U000e0061\U000e0073\U000e0072\U000e0070\U000e007f" - FLAG_FOR_NORTHERN_CAPE_ZA_NC = "\U0001f3f4\U000e007a\U000e0061\U000e006e\U000e0063\U000e007f" - FLAG_FOR_SOUTHLAND_NZ_STL = "\U0001f3f4\U000e006e\U000e007a\U000e0073\U000e0074\U000e006c\U000e007f" - FLAG_FOR_MPUMALANGA_ZA_MP = "\U0001f3f4\U000e007a\U000e0061\U000e006d\U000e0070\U000e007f" - FLAG_FOR_EASTERN_ZM_03 = "\U0001f3f4\U000e007a\U000e006d\U000e0030\U000e0033\U000e007f" - FLAG_FOR_MATABELELAND_NORTH_ZW_MN = "\U0001f3f4\U000e007a\U000e0077\U000e006d\U000e006e\U000e007f" - FLAG_FOR_MASHONALAND_EAST_ZW_ME = "\U0001f3f4\U000e007a\U000e0077\U000e006d\U000e0065\U000e007f" - FLAG_FOR_CENTRAL_ZM_02 = "\U0001f3f4\U000e007a\U000e006d\U000e0030\U000e0032\U000e007f" - FLAG_FOR_MASHONALAND_WEST_ZW_MW = "\U0001f3f4\U000e007a\U000e0077\U000e006d\U000e0077\U000e007f" - FLAG_FOR_SOUTHERN_ZM_07 = "\U0001f3f4\U000e007a\U000e006d\U000e0030\U000e0037\U000e007f" - FLAG_FOR_MASVINGO_ZW_MV = "\U0001f3f4\U000e007a\U000e0077\U000e006d\U000e0076\U000e007f" - FLAG_FOR_MATABELELAND_SOUTH_ZW_MS = "\U0001f3f4\U000e007a\U000e0077\U000e006d\U000e0073\U000e007f" - FLAG_FOR_EASTERN_CAPE_ZA_EC = "\U0001f3f4\U000e007a\U000e0061\U000e0065\U000e0063\U000e007f" - FLAG_FOR_NEW_VALLEY_EG_WAD = "\U0001f3f4\U000e0065\U000e0067\U000e0077\U000e0061\U000e0064\U000e007f" - FLAG_FOR_BOLIVAR_EC_B = "\U0001f3f4\U000e0065\U000e0063\U000e0062\U000e007f" - FLAG_FOR_CHANTHABURI_TH_22 = "\U0001f3f4\U000e0074\U000e0068\U000e0032\U000e0032\U000e007f" - FLAG_FOR_ARTA_DJ_AR = "\U0001f3f4\U000e0064\U000e006a\U000e0061\U000e0072\U000e007f" - TAG_COLON = "\U000e003a" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f466\U0001f3fd" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_NIUTAO_TV_NIT = "\U0001f3f4\U000e0074\U000e0076\U000e006e\U000e0069\U000e0074\U000e007f" - TAG_HYPHEN_MINUS = "\U000e002d" - FLAG_FOR_PRIMORSKY_KRAI_RU_PRI = "\U0001f3f4\U000e0072\U000e0075\U000e0070\U000e0072\U000e0069\U000e007f" - FLAG_FOR_MANICALAND_ZW_MA = "\U0001f3f4\U000e007a\U000e0077\U000e006d\U000e0061\U000e007f" - FLAG_FOR_CHUY_KG_C = "\U0001f3f4\U000e006b\U000e0067\U000e0063\U000e007f" - FLAG_FOR_MAINE_US_ME = "\U0001f3f4\U000e0075\U000e0073\U000e006d\U000e0065\U000e007f" - FLAG_FOR_LOWER_JUBA_SO_JH = "\U0001f3f4\U000e0073\U000e006f\U000e006a\U000e0068\U000e007f" - FLAG_FOR_FUKUSHIMA_JP_07 = "\U0001f3f4\U000e006a\U000e0070\U000e0030\U000e0037\U000e007f" - FLAG_FOR_PUDUCHERRY_IN_PY = "\U0001f3f4\U000e0069\U000e006e\U000e0070\U000e0079\U000e007f" - FLAG_FOR_KRABI_TH_81 = "\U0001f3f4\U000e0074\U000e0068\U000e0038\U000e0031\U000e007f" - FLAG_FOR_UTRECHT_NL_UT = "\U0001f3f4\U000e006e\U000e006c\U000e0075\U000e0074\U000e007f" - FLAG_FOR_MANITOBA_CA_MB = "\U0001f3f4\U000e0063\U000e0061\U000e006d\U000e0062\U000e007f" - FLAG_FOR_GAGA_IFOMAUGA_WS_GI = "\U0001f3f4\U000e0077\U000e0073\U000e0067\U000e0069\U000e007f" - FLAG_FOR_NORTH_KHORASAN_IR_31 = "\U0001f3f4\U000e0069\U000e0072\U000e0033\U000e0031\U000e007f" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - FLAG_FOR_IOWA_US_IA = "\U0001f3f4\U000e0075\U000e0073\U000e0069\U000e0061\U000e007f" - FLAG_FOR_LARNACA_CY_03 = "\U0001f3f4\U000e0063\U000e0079\U000e0030\U000e0033\U000e007f" - RESTRICTED_LEFT_ENTRY_2 = "\u26e1" - FLAG_FOR_NORMANDIE_FR_NOR = "\U0001f3f4\U000e0066\U000e0072\U000e006e\U000e006f\U000e0072\U000e007f" - FLAG_FOR_HAWAII_US_HI = "\U0001f3f4\U000e0075\U000e0073\U000e0068\U000e0069\U000e007f" - FLAG_FOR_ZAMBEZIA_MZ_Q = "\U0001f3f4\U000e006d\U000e007a\U000e0071\U000e007f" - FLAG_FOR_MURMANSK_RU_MUR = "\U0001f3f4\U000e0072\U000e0075\U000e006d\U000e0075\U000e0072\U000e007f" - FLAG_FOR_CANARIES_LC_12 = "\U0001f3f4\U000e006c\U000e0063\U000e0031\U000e0032\U000e007f" - FLAG_FOR_NEW_HAMPSHIRE_US_NH = "\U0001f3f4\U000e0075\U000e0073\U000e006e\U000e0068\U000e007f" - FLAG_FOR_DJIBOUTI_DJ_DJ = "\U0001f3f4\U000e0064\U000e006a\U000e0064\U000e006a\U000e007f" - FLAG_FOR_JIZAN_SA_09 = "\U0001f3f4\U000e0073\U000e0061\U000e0030\U000e0039\U000e007f" - FLAG_FOR_MARSA_MT_26 = "\U0001f3f4\U000e006d\U000e0074\U000e0032\U000e0036\U000e007f" - FLAG_FOR_MUGLA_TR_48 = "\U0001f3f4\U000e0074\U000e0072\U000e0034\U000e0038\U000e007f" - TAG_LATIN_CAPITAL_LETTER_G = "\U000e0047" - FLAG_FOR_LAANE_VIRU_EE_59 = "\U0001f3f4\U000e0065\U000e0065\U000e0035\U000e0039\U000e007f" - FLAG_FOR_SAN_JOSE_UY_SJ = "\U0001f3f4\U000e0075\U000e0079\U000e0073\U000e006a\U000e007f" - FLAG_FOR_NORTH_GAZA_PS_NGZ = "\U0001f3f4\U000e0070\U000e0073\U000e006e\U000e0067\U000e007a\U000e007f" - FLAG_FOR_MANUS_PG_MRL = "\U0001f3f4\U000e0070\U000e0067\U000e006d\U000e0072\U000e006c\U000e007f" - FLAG_FOR_SIVAS_TR_58 = "\U0001f3f4\U000e0074\U000e0072\U000e0035\U000e0038\U000e007f" - WOMAN_IN_TUXEDO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f935\U0001f3fc\u200d\u2640\ufe0f" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - FLAG_FOR_LESSER_POLAND_PL_MA = "\U0001f3f4\U000e0070\U000e006c\U000e006d\U000e0061\U000e007f" - FLAG_FOR_WEST_MACEDONIA_GR_C = "\U0001f3f4\U000e0067\U000e0072\U000e0063\U000e007f" - FLAG_FOR_DEMIR_HISAR_MK_25 = "\U0001f3f4\U000e006d\U000e006b\U000e0032\U000e0035\U000e007f" - FLAG_FOR_ARKHABIL_SUQUTRA_YE_SU = "\U0001f3f4\U000e0079\U000e0065\U000e0073\U000e0075\U000e007f" - FLAG_FOR_COMMEWIJNE_SR_CM = "\U0001f3f4\U000e0073\U000e0072\U000e0063\U000e006d\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f467\U0001f3ff" - COUPLE_WITH_HEART_WOMAN_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - FLAG_FOR_PRYKARPATTIA_UA_26 = "\U0001f3f4\U000e0075\U000e0061\U000e0032\U000e0036\U000e007f" - FLAG_FOR_NUEVA_ESPARTA_VE_O = "\U0001f3f4\U000e0076\U000e0065\U000e006f\U000e007f" - FLAG_FOR_HARJU_EE_37 = "\U0001f3f4\U000e0065\U000e0065\U000e0033\U000e0037\U000e007f" - FLAG_FOR_GUJARAT_IN_GJ = "\U0001f3f4\U000e0069\U000e006e\U000e0067\U000e006a\U000e007f" - FLAG_FOR_JEKABPILS_MUNICIPALITY_LV_042 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0034\U000e0032\U000e007f" - FLAG_FOR_NAVASSA_ISLAND_UM_76 = "\U0001f3f4\U000e0075\U000e006d\U000e0037\U000e0036\U000e007f" - KISS_MAN_DARK_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - FLAG_FOR_OGRE_LV_067 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0036\U000e0037\U000e007f" - FLAG_FOR_YAREN_NR_14 = "\U0001f3f4\U000e006e\U000e0072\U000e0031\U000e0034\U000e007f" - FLAG_FOR_SCHELLENBERG_LI_08 = "\U0001f3f4\U000e006c\U000e0069\U000e0030\U000e0038\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_TELANGANA_IN_TG = "\U0001f3f4\U000e0069\U000e006e\U000e0074\U000e0067\U000e007f" - FLAG_FOR_OROMIA_ET_OR = "\U0001f3f4\U000e0065\U000e0074\U000e006f\U000e0072\U000e007f" - FLAG_FOR_UUSIMAA_FI_18 = "\U0001f3f4\U000e0066\U000e0069\U000e0031\U000e0038\U000e007f" - FLAG_FOR_SASSANDRA_MARAHOUE_CI_SM = "\U0001f3f4\U000e0063\U000e0069\U000e0073\U000e006d\U000e007f" - FLAG_FOR_HA_APAI_TO_02 = "\U0001f3f4\U000e0074\U000e006f\U000e0030\U000e0032\U000e007f" - FLAG_FOR_GUAYAS_EC_G = "\U0001f3f4\U000e0065\U000e0063\U000e0067\U000e007f" - FLAG_FOR_DUZCE_TR_81 = "\U0001f3f4\U000e0074\U000e0072\U000e0038\U000e0031\U000e007f" - FLAG_FOR_APURIMAC_PE_APU = "\U0001f3f4\U000e0070\U000e0065\U000e0061\U000e0070\U000e0075\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f466\U0001f3fb" - FAMILY_WOMAN_MAN_BABY_BOY = "\U0001f469\u200d\U0001f468\u200d\U0001f476\u200d\U0001f466" - FLAG_FOR_SOUTHERN_NATIONS_NATIONALITIES_AND_PEOPLES_ET_SN = "\U0001f3f4\U000e0065\U000e0074\U000e0073\U000e006e\U000e007f" - FLAG_FOR_CHOCO_CO_CHO = "\U0001f3f4\U000e0063\U000e006f\U000e0063\U000e0068\U000e006f\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f466\U0001f3fb" - FLAG_FOR_SAINT_PATRICK_VC_05 = "\U0001f3f4\U000e0076\U000e0063\U000e0030\U000e0035\U000e007f" - FLAG_FOR_HAWALLI_KW_HA = "\U0001f3f4\U000e006b\U000e0077\U000e0068\U000e0061\U000e007f" - FLAG_FOR_ADRAR_MR_07 = "\U0001f3f4\U000e006d\U000e0072\U000e0030\U000e0037\U000e007f" - FLAG_FOR_BOUENZA_CG_11 = "\U0001f3f4\U000e0063\U000e0067\U000e0031\U000e0031\U000e007f" - FLAG_FOR_WYOMING_US_WY = "\U0001f3f4\U000e0075\U000e0073\U000e0077\U000e0079\U000e007f" - FLAG_FOR_BAY_ISLANDS_HN_IB = "\U0001f3f4\U000e0068\U000e006e\U000e0069\U000e0062\U000e007f" - FLAG_FOR_HSINCHU_TW_HSZ = "\U0001f3f4\U000e0074\U000e0077\U000e0068\U000e0073\U000e007a\U000e007f" - TAG_FULL_STOP = "\U000e002e" - FLAG_FOR_VAKAGA_CF_VK = "\U0001f3f4\U000e0063\U000e0066\U000e0076\U000e006b\U000e007f" - FLAG_FOR_ALBERTA_CA_AB = "\U0001f3f4\U000e0063\U000e0061\U000e0061\U000e0062\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_PORTUGUESA_VE_P = "\U0001f3f4\U000e0076\U000e0065\U000e0070\U000e007f" - FLAG_FOR_ILE_DE_FRANCE_FR_IDF = "\U0001f3f4\U000e0066\U000e0072\U000e0069\U000e0064\U000e0066\U000e007f" - FLAG_FOR_MISSISSIPPI_US_MS = "\U0001f3f4\U000e0075\U000e0073\U000e006d\U000e0073\U000e007f" - FLAG_FOR_SKOFJA_LOKA_SI_122 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0032\U000e0032\U000e007f" - FLAG_FOR_VAINODE_LV_100 = "\U0001f3f4\U000e006c\U000e0076\U000e0031\U000e0030\U000e0030\U000e007f" - FLAG_FOR_AUSTRALIAN_CAPITAL_TERRITORY_AU_ACT = "\U0001f3f4\U000e0061\U000e0075\U000e0061\U000e0063\U000e0074\U000e007f" - FLAG_FOR_GUARICO_VE_J = "\U0001f3f4\U000e0076\U000e0065\U000e006a\U000e007f" - FLAG_FOR_SAINT_CATHERINE_JM_14 = "\U0001f3f4\U000e006a\U000e006d\U000e0031\U000e0034\U000e007f" - FLAG_FOR_SOKOTO_NG_SO = "\U0001f3f4\U000e006e\U000e0067\U000e0073\U000e006f\U000e007f" - FLAG_FOR_AREQUIPA_PE_ARE = "\U0001f3f4\U000e0070\U000e0065\U000e0061\U000e0072\U000e0065\U000e007f" - FLAG_FOR_SONORA_MX_SON = "\U0001f3f4\U000e006d\U000e0078\U000e0073\U000e006f\U000e006e\U000e007f" - FLAG_FOR_CHANGHUA_TW_CHA = "\U0001f3f4\U000e0074\U000e0077\U000e0063\U000e0068\U000e0061\U000e007f" - FLAG_FOR_LERIBE_LS_C = "\U0001f3f4\U000e006c\U000e0073\U000e0063\U000e007f" - FLAG_FOR_SAINTE_DEVOTE_CHAPEL_MC_SD = "\U0001f3f4\U000e006d\U000e0063\U000e0073\U000e0064\U000e007f" - FLAG_FOR_ISSYK_KUL_KG_Y = "\U0001f3f4\U000e006b\U000e0067\U000e0079\U000e007f" - FLAG_FOR_CHANDIGARH_IN_CH = "\U0001f3f4\U000e0069\U000e006e\U000e0063\U000e0068\U000e007f" - FAMILY_MAN_MAN_BOY_BABY = "\U0001f468\u200d\U0001f468\u200d\U0001f466\u200d\U0001f476" - FLAG_FOR_ARAGON_ES_AR = "\U0001f3f4\U000e0065\U000e0073\U000e0061\U000e0072\U000e007f" - KISS_MAN_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - FLAG_FOR_PLASNICA_MK_61 = "\U0001f3f4\U000e006d\U000e006b\U000e0036\U000e0031\U000e007f" - FLAG_FOR_ANTALYA_TR_07 = "\U0001f3f4\U000e0074\U000e0072\U000e0030\U000e0037\U000e007f" - FLAG_FOR_VARAZDIN_HR_05 = "\U0001f3f4\U000e0068\U000e0072\U000e0030\U000e0035\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_TAFEA_VU_TAE = "\U0001f3f4\U000e0076\U000e0075\U000e0074\U000e0061\U000e0065\U000e007f" - FLAG_FOR_VELIKE_LASCE_SI_134 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0033\U000e0034\U000e007f" - FLAG_FOR_QUERETARO_MX_QUE = "\U0001f3f4\U000e006d\U000e0078\U000e0071\U000e0075\U000e0065\U000e007f" - FLAG_FOR_DEIR_AL_BALAH_PS_DEB = "\U0001f3f4\U000e0070\U000e0073\U000e0064\U000e0065\U000e0062\U000e007f" - FLAG_FOR_MEXICO_STATE_MX_MEX = "\U0001f3f4\U000e006d\U000e0078\U000e006d\U000e0065\U000e0078\U000e007f" - FLAG_FOR_LEON_NI_LE = "\U0001f3f4\U000e006e\U000e0069\U000e006c\U000e0065\U000e007f" - FLAG_FOR_NORTH_PROVINCE_MV_NO = "\U0001f3f4\U000e006d\U000e0076\U000e006e\U000e006f\U000e007f" - FLAG_FOR_ST_BARTHELEMY_FR_BL = "\U0001f3f4\U000e0066\U000e0072\U000e0062\U000e006c\U000e007f" - FLAG_FOR_HORDALAND_NO_12 = "\U0001f3f4\U000e006e\U000e006f\U000e0031\U000e0032\U000e007f" - FLAG_FOR_PLZENSKY_KRAJ_CZ_32 = "\U0001f3f4\U000e0063\U000e007a\U000e0033\U000e0032\U000e007f" - FLAG_FOR_EGER_HU_EG = "\U0001f3f4\U000e0068\U000e0075\U000e0065\U000e0067\U000e007f" - FLAG_FOR_TABASCO_MX_TAB = "\U0001f3f4\U000e006d\U000e0078\U000e0074\U000e0061\U000e0062\U000e007f" - FLAG_FOR_FLANDERS_BE_VLG = "\U0001f3f4\U000e0062\U000e0065\U000e0076\U000e006c\U000e0067\U000e007f" - FLAG_FOR_KERMANSHAH_IR_17 = "\U0001f3f4\U000e0069\U000e0072\U000e0031\U000e0037\U000e007f" - FLAG_FOR_APURE_VE_C = "\U0001f3f4\U000e0076\U000e0065\U000e0063\U000e007f" - FLAG_FOR_SILA_TD_SI = "\U0001f3f4\U000e0074\U000e0064\U000e0073\U000e0069\U000e007f" - FLAG_FOR_DURANGO_MX_DUR = "\U0001f3f4\U000e006d\U000e0078\U000e0064\U000e0075\U000e0072\U000e007f" - FLAG_FOR_MARAMURES_RO_MM = "\U0001f3f4\U000e0072\U000e006f\U000e006d\U000e006d\U000e007f" - FLAG_FOR_VELENJE_SI_133 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0033\U000e0033\U000e007f" - FLAG_FOR_SAINT_JOHN_DM_05 = "\U0001f3f4\U000e0064\U000e006d\U000e0030\U000e0035\U000e007f" - FLAG_FOR_NORTH_GYEONGSANG_KR_47 = "\U0001f3f4\U000e006b\U000e0072\U000e0034\U000e0037\U000e007f" - FLAG_FOR_MOROGORO_TZ_16 = "\U0001f3f4\U000e0074\U000e007a\U000e0031\U000e0036\U000e007f" - FLAG_FOR_NORTH_HOLLAND_NL_NH = "\U0001f3f4\U000e006e\U000e006c\U000e006e\U000e0068\U000e007f" - FLAG_FOR_MERIDA_VE_L = "\U0001f3f4\U000e0076\U000e0065\U000e006c\U000e007f" - FLAG_FOR_AUCKLAND_NZ_AUK = "\U0001f3f4\U000e006e\U000e007a\U000e0061\U000e0075\U000e006b\U000e007f" - FLAG_FOR_RIO_GRANDE_DO_SUL_BR_RS = "\U0001f3f4\U000e0062\U000e0072\U000e0072\U000e0073\U000e007f" - FLAG_FOR_RYAZAN_RU_RYA = "\U0001f3f4\U000e0072\U000e0075\U000e0072\U000e0079\U000e0061\U000e007f" - FLAG_FOR_DAR_ES_SALAAM_TZ_02 = "\U0001f3f4\U000e0074\U000e007a\U000e0030\U000e0032\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_GAFSA_TN_71 = "\U0001f3f4\U000e0074\U000e006e\U000e0037\U000e0031\U000e007f" - FLAG_FOR_MASHONALAND_CENTRAL_ZW_MC = "\U0001f3f4\U000e007a\U000e0077\U000e006d\U000e0063\U000e007f" - FLAG_FOR_BOVEC_SI_006 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0030\U000e0036\U000e007f" - FLAG_FOR_ANKARAN_SI_213 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0031\U000e0033\U000e007f" - KISS_MAN_MEDIUM_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - TAG_LATIN_CAPITAL_LETTER_O = "\U000e004f" - FLAG_FOR_GUERRERO_MX_GRO = "\U0001f3f4\U000e006d\U000e0078\U000e0067\U000e0072\U000e006f\U000e007f" - FLAG_FOR_DOBJE_SI_154 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0035\U000e0034\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_RETALHULEU_GT_RE = "\U0001f3f4\U000e0067\U000e0074\U000e0072\U000e0065\U000e007f" - FLAG_FOR_NARINO_CO_NAR = "\U0001f3f4\U000e0063\U000e006f\U000e006e\U000e0061\U000e0072\U000e007f" - FLAG_FOR_TUNIS_TN_11 = "\U0001f3f4\U000e0074\U000e006e\U000e0031\U000e0031\U000e007f" - FLAG_FOR_TIBET_CN_54 = "\U0001f3f4\U000e0063\U000e006e\U000e0035\U000e0034\U000e007f" - FLAG_FOR_MALAMPA_VU_MAP = "\U0001f3f4\U000e0076\U000e0075\U000e006d\U000e0061\U000e0070\U000e007f" - FLAG_FOR_PIEDMONT_IT_21 = "\U0001f3f4\U000e0069\U000e0074\U000e0032\U000e0031\U000e007f" - FLAG_FOR_KAYSERI_TR_38 = "\U0001f3f4\U000e0074\U000e0072\U000e0033\U000e0038\U000e007f" - FLAG_FOR_EQUATEUR_CD_EQ = "\U0001f3f4\U000e0063\U000e0064\U000e0065\U000e0071\U000e007f" - FLAG_FOR_SABAH_MY_12 = "\U0001f3f4\U000e006d\U000e0079\U000e0031\U000e0032\U000e007f" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - FLAG_FOR_NYANGA_GA_5 = "\U0001f3f4\U000e0067\U000e0061\U000e0035\U000e007f" - FLAG_FOR_TAVASTIA_PROPER_FI_06 = "\U0001f3f4\U000e0066\U000e0069\U000e0030\U000e0036\U000e007f" - FLAG_FOR_CARAS_SEVERIN_RO_CS = "\U0001f3f4\U000e0072\U000e006f\U000e0063\U000e0073\U000e007f" - FLAG_FOR_CENTRAL_VISAYAS_PH_07 = "\U0001f3f4\U000e0070\U000e0068\U000e0030\U000e0037\U000e007f" - FLAG_FOR_MASERU_LS_A = "\U0001f3f4\U000e006c\U000e0073\U000e0061\U000e007f" - FLAG_FOR_SAINT_ANDREW_GD_01 = "\U0001f3f4\U000e0067\U000e0064\U000e0030\U000e0031\U000e007f" - FLAG_FOR_LAI_CHAU_VN_01 = "\U0001f3f4\U000e0076\U000e006e\U000e0030\U000e0031\U000e007f" - FLAG_FOR_CHAIYAPHUM_TH_36 = "\U0001f3f4\U000e0074\U000e0068\U000e0033\U000e0036\U000e007f" - FLAG_FOR_ESMERALDAS_EC_E = "\U0001f3f4\U000e0065\U000e0063\U000e0065\U000e007f" - FLAG_FOR_DILI_TL_DI = "\U0001f3f4\U000e0074\U000e006c\U000e0064\U000e0069\U000e007f" - FLAG_FOR_USULUTAN_SV_US = "\U0001f3f4\U000e0073\U000e0076\U000e0075\U000e0073\U000e007f" - FLAG_FOR_MARSABIT_KE_25 = "\U0001f3f4\U000e006b\U000e0065\U000e0032\U000e0035\U000e007f" - FLAG_FOR_FALCON_VE_I = "\U0001f3f4\U000e0076\U000e0065\U000e0069\U000e007f" - FLAG_FOR_ZANZAN_CI_ZZ = "\U0001f3f4\U000e0063\U000e0069\U000e007a\U000e007a\U000e007f" - FLAG_FOR_NORD_UBANGI_CD_NU = "\U0001f3f4\U000e0063\U000e0064\U000e006e\U000e0075\U000e007f" - FLAG_FOR_PAILIN_KH_24 = "\U0001f3f4\U000e006b\U000e0068\U000e0032\U000e0034\U000e007f" - FLAG_FOR_CASTILE_AND_LEON_ES_CL = "\U0001f3f4\U000e0065\U000e0073\U000e0063\U000e006c\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_SAMUT_SONGKHRAM_TH_75 = "\U0001f3f4\U000e0074\U000e0068\U000e0037\U000e0035\U000e007f" - FLAG_FOR_ADRAR_DZ_01 = "\U0001f3f4\U000e0064\U000e007a\U000e0030\U000e0031\U000e007f" - FLAG_FOR_EAST_SEPIK_PG_ESW = "\U0001f3f4\U000e0070\U000e0067\U000e0065\U000e0073\U000e0077\U000e007f" - FLAG_FOR_EMILIA_ROMAGNA_IT_45 = "\U0001f3f4\U000e0069\U000e0074\U000e0034\U000e0035\U000e007f" - FLAG_FOR_CHUMPHON_TH_86 = "\U0001f3f4\U000e0074\U000e0068\U000e0038\U000e0036\U000e007f" - FLAG_FOR_MAZSALACA_LV_060 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0036\U000e0030\U000e007f" - FLAG_FOR_BARI_SO_BR = "\U0001f3f4\U000e0073\U000e006f\U000e0062\U000e0072\U000e007f" - FLAG_FOR_ALAND_ISLANDS_FI_01 = "\U0001f3f4\U000e0066\U000e0069\U000e0030\U000e0031\U000e007f" - FLAG_FOR_QUANG_NAM_VN_27 = "\U0001f3f4\U000e0076\U000e006e\U000e0032\U000e0037\U000e007f" - FLAG_FOR_LINE_ISLANDS_KI_L = "\U0001f3f4\U000e006b\U000e0069\U000e006c\U000e007f" - FLAG_FOR_KAGOSHIMA_JP_46 = "\U0001f3f4\U000e006a\U000e0070\U000e0034\U000e0036\U000e007f" - FLAG_FOR_CAIRO_EG_C = "\U0001f3f4\U000e0065\U000e0067\U000e0063\U000e007f" - FLAG_FOR_KUTAHYA_TR_43 = "\U0001f3f4\U000e0074\U000e0072\U000e0034\U000e0033\U000e007f" - FAMILY_MAN_WOMAN_BOY_BABY = "\U0001f468\u200d\U0001f469\u200d\U0001f466\u200d\U0001f476" - FLAG_FOR_AL_BAHAH_SA_11 = "\U0001f3f4\U000e0073\U000e0061\U000e0031\U000e0031\U000e007f" - FLAG_FOR_GREATER_POLAND_PL_WP = "\U0001f3f4\U000e0070\U000e006c\U000e0077\U000e0070\U000e007f" - FLAG_FOR_WEST_AZARBAIJAN_IR_02 = "\U0001f3f4\U000e0069\U000e0072\U000e0030\U000e0032\U000e007f" - FLAG_FOR_YAMALO_NENETS_OKRUG_RU_YAN = "\U0001f3f4\U000e0072\U000e0075\U000e0079\U000e0061\U000e006e\U000e007f" - FLAG_FOR_MONTANA_US_MT = "\U0001f3f4\U000e0075\U000e0073\U000e006d\U000e0074\U000e007f" - KISS_WOMAN_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - FLAG_FOR_POMEROON_SUPENAAM_GY_PM = "\U0001f3f4\U000e0067\U000e0079\U000e0070\U000e006d\U000e007f" - FLAG_FOR_GWANGJU_CITY_KR_29 = "\U0001f3f4\U000e006b\U000e0072\U000e0032\U000e0039\U000e007f" - FLAG_FOR_DONECHCHYNA_UA_14 = "\U0001f3f4\U000e0075\U000e0061\U000e0031\U000e0034\U000e007f" - FLAG_FOR_SAFI_MT_47 = "\U0001f3f4\U000e006d\U000e0074\U000e0034\U000e0037\U000e007f" - COUPLE_WITH_HEART_MAN_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - KISS_MAN_DARK_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - FLAG_FOR_ANTIOQUIA_CO_ANT = "\U0001f3f4\U000e0063\U000e006f\U000e0061\U000e006e\U000e0074\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_KRANJ_SI_052 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0035\U000e0032\U000e007f" - FLAG_FOR_MIYAGI_JP_04 = "\U0001f3f4\U000e006a\U000e0070\U000e0030\U000e0034\U000e007f" - FLAG_FOR_MARGIBI_LR_MG = "\U0001f3f4\U000e006c\U000e0072\U000e006d\U000e0067\U000e007f" - FLAG_FOR_ZULIA_VE_V = "\U0001f3f4\U000e0076\U000e0065\U000e0076\U000e007f" - FLAG_FOR_VAISIGANO_WS_VS = "\U0001f3f4\U000e0077\U000e0073\U000e0076\U000e0073\U000e007f" - FLAG_FOR_GLARUS_CH_GL = "\U0001f3f4\U000e0063\U000e0068\U000e0067\U000e006c\U000e007f" - FLAG_FOR_BECHAR_DZ_08 = "\U0001f3f4\U000e0064\U000e007a\U000e0030\U000e0038\U000e007f" - FLAG_FOR_EMBERA_PA_EM = "\U0001f3f4\U000e0070\U000e0061\U000e0065\U000e006d\U000e007f" - FLAG_FOR_LUQA_MT_25 = "\U0001f3f4\U000e006d\U000e0074\U000e0032\U000e0035\U000e007f" - FLAG_FOR_IBB_YE_IB = "\U0001f3f4\U000e0079\U000e0065\U000e0069\U000e0062\U000e007f" - FLAG_FOR_EAST_BERBICE_CORENTYNE_GY_EB = "\U0001f3f4\U000e0067\U000e0079\U000e0065\U000e0062\U000e007f" - FLAG_FOR_U_S_VIRGIN_ISLANDS_US_VI = "\U0001f3f4\U000e0075\U000e0073\U000e0076\U000e0069\U000e007f" - FLAG_FOR_PHATTHALUNG_TH_93 = "\U0001f3f4\U000e0074\U000e0068\U000e0039\U000e0033\U000e007f" - FLAG_FOR_YUCATAN_MX_YUC = "\U0001f3f4\U000e006d\U000e0078\U000e0079\U000e0075\U000e0063\U000e007f" - FLAG_FOR_KALMYKIA_RU_KL = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e006c\U000e007f" - FLAG_FOR_ANDALUSIA_ES_AN = "\U0001f3f4\U000e0065\U000e0073\U000e0061\U000e006e\U000e007f" - FLAG_FOR_CAPELLEN_LU_CA = "\U0001f3f4\U000e006c\U000e0075\U000e0063\U000e0061\U000e007f" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - FLAG_FOR_POOL_CG_12 = "\U0001f3f4\U000e0063\U000e0067\U000e0031\U000e0032\U000e007f" - FLAG_FOR_CAUSENI_MD_CS = "\U0001f3f4\U000e006d\U000e0064\U000e0063\U000e0073\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_SZABOLCS_SZATMAR_BEREG_HU_SZ = "\U0001f3f4\U000e0068\U000e0075\U000e0073\U000e007a\U000e007f" - FLAG_FOR_ZANZIBAR_NORTH_TZ_07 = "\U0001f3f4\U000e0074\U000e007a\U000e0030\U000e0037\U000e007f" - FLAG_FOR_AL_JAWF_YE_JA = "\U0001f3f4\U000e0079\U000e0065\U000e006a\U000e0061\U000e007f" - FLAG_FOR_KOKNESE_LV_046 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0034\U000e0036\U000e007f" - FLAG_FOR_DELTA_NG_DE = "\U0001f3f4\U000e006e\U000e0067\U000e0064\U000e0065\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff" - SALTIRE = "\u2613" - FLAG_FOR_NORTH_SINAI_EG_SIN = "\U0001f3f4\U000e0065\U000e0067\U000e0073\U000e0069\U000e006e\U000e007f" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - FAMILY_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_GORENJA_VAS_POLJANE_SI_027 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0032\U000e0037\U000e007f" - WHITE_FLAG_WITH_HORIZONTAL_MIDDLE_BLACK_STRIPE = "\u26ff" - FLAG_FOR_XEWKIJA_MT_62 = "\U0001f3f4\U000e006d\U000e0074\U000e0036\U000e0032\U000e007f" - FLAG_FOR_BAC_NINH_VN_56 = "\U0001f3f4\U000e0076\U000e006e\U000e0035\U000e0036\U000e007f" - FLAG_FOR_HADJER_LAMIS_TD_HL = "\U0001f3f4\U000e0074\U000e0064\U000e0068\U000e006c\U000e007f" - FLAG_FOR_SAINT_MICHAEL_BB_08 = "\U0001f3f4\U000e0062\U000e0062\U000e0030\U000e0038\U000e007f" - FLAG_FOR_MAPUTO_PROVINCE_MZ_L = "\U0001f3f4\U000e006d\U000e007a\U000e006c\U000e007f" - FLAG_FOR_GUIDIMAKA_MR_10 = "\U0001f3f4\U000e006d\U000e0072\U000e0031\U000e0030\U000e007f" - FLAG_FOR_ARACINOVO_MK_02 = "\U0001f3f4\U000e006d\U000e006b\U000e0030\U000e0032\U000e007f" - FLAG_FOR_PAHANG_MY_06 = "\U0001f3f4\U000e006d\U000e0079\U000e0030\U000e0036\U000e007f" - FLAG_FOR_SVAY_RIENG_KH_20 = "\U0001f3f4\U000e006b\U000e0068\U000e0032\U000e0030\U000e007f" - FLAG_FOR_JELGAVA_MUNICIPALITY_LV_041 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0034\U000e0031\U000e007f" - FLAG_FOR_NORTHERN_OSTROBOTHNIA_FI_14 = "\U0001f3f4\U000e0066\U000e0069\U000e0031\U000e0034\U000e007f" - FLAG_FOR_SOUSSE_TN_51 = "\U0001f3f4\U000e0074\U000e006e\U000e0035\U000e0031\U000e007f" - FLAG_FOR_ODRANCI_SI_086 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0038\U000e0036\U000e007f" - FLAG_FOR_ALTO_PARANA_PY_10 = "\U0001f3f4\U000e0070\U000e0079\U000e0031\U000e0030\U000e007f" - FLAG_FOR_WASHINGTON_US_WA = "\U0001f3f4\U000e0075\U000e0073\U000e0077\U000e0061\U000e007f" - FLAG_FOR_TAOYUAN_TW_TAO = "\U0001f3f4\U000e0074\U000e0077\U000e0074\U000e0061\U000e006f\U000e007f" - FLAG_FOR_OMSK_RU_OMS = "\U0001f3f4\U000e0072\U000e0075\U000e006f\U000e006d\U000e0073\U000e007f" - FLAG_FOR_BRATISLAVA_SK_BL = "\U0001f3f4\U000e0073\U000e006b\U000e0062\U000e006c\U000e007f" - FLAG_FOR_GIFU_JP_21 = "\U0001f3f4\U000e006a\U000e0070\U000e0032\U000e0031\U000e007f" - FLAG_FOR_CHIRIQUI_PA_4 = "\U0001f3f4\U000e0070\U000e0061\U000e0034\U000e007f" - FLAG_FOR_HESSE_DE_HE = "\U0001f3f4\U000e0064\U000e0065\U000e0068\U000e0065\U000e007f" - FLAG_FOR_AIWO_NR_01 = "\U0001f3f4\U000e006e\U000e0072\U000e0030\U000e0031\U000e007f" - FLAG_FOR_MA_RIB_YE_MA = "\U0001f3f4\U000e0079\U000e0065\U000e006d\U000e0061\U000e007f" - FLAG_FOR_SINT_EUSTATIUS_BQ_SE = "\U0001f3f4\U000e0062\U000e0071\U000e0073\U000e0065\U000e007f" - FLAG_FOR_ASSAM_IN_AS = "\U0001f3f4\U000e0069\U000e006e\U000e0061\U000e0073\U000e007f" - FLAG_FOR_HUNEDOARA_RO_HD = "\U0001f3f4\U000e0072\U000e006f\U000e0068\U000e0064\U000e007f" - FLAG_FOR_VENTSPILS_MUNICIPALITY_LV_106 = "\U0001f3f4\U000e006c\U000e0076\U000e0031\U000e0030\U000e0036\U000e007f" - FLAG_FOR_SAITAMA_JP_11 = "\U0001f3f4\U000e006a\U000e0070\U000e0031\U000e0031\U000e007f" - FLAG_FOR_CAPITAL_DISTRICT_CO_DC = "\U0001f3f4\U000e0063\U000e006f\U000e0064\U000e0063\U000e007f" - FLAG_FOR_SOUTH_CENTRAL_PROVINCE_MV_SC = "\U0001f3f4\U000e006d\U000e0076\U000e0073\U000e0063\U000e007f" - FLAG_FOR_CHARI_BAGUIRMI_TD_CB = "\U0001f3f4\U000e0074\U000e0064\U000e0063\U000e0062\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_ALYTUS_MUNICIPALITY_LT_02 = "\U0001f3f4\U000e006c\U000e0074\U000e0030\U000e0032\U000e007f" - FLAG_FOR_HANOI_VN_HN = "\U0001f3f4\U000e0076\U000e006e\U000e0068\U000e006e\U000e007f" - FLAG_FOR_CRIMEA_UA_43 = "\U0001f3f4\U000e0075\U000e0061\U000e0034\U000e0033\U000e007f" - FLAG_FOR_SAINT_ANDREW_JM_02 = "\U0001f3f4\U000e006a\U000e006d\U000e0030\U000e0032\U000e007f" - FLAG_FOR_SANMA_VU_SAM = "\U0001f3f4\U000e0076\U000e0075\U000e0073\U000e0061\U000e006d\U000e007f" - FLAG_FOR_KHOJAVEND_AZ_XVD = "\U0001f3f4\U000e0061\U000e007a\U000e0078\U000e0076\U000e0064\U000e007f" - FLAG_FOR_LOWER_SAXONY_DE_NI = "\U0001f3f4\U000e0064\U000e0065\U000e006e\U000e0069\U000e007f" - FLAG_FOR_SAN_MARCOS_GT_SM = "\U0001f3f4\U000e0067\U000e0074\U000e0073\U000e006d\U000e007f" - FLAG_FOR_HUNG_YEN_VN_66 = "\U0001f3f4\U000e0076\U000e006e\U000e0036\U000e0036\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_SINALOA_MX_SIN = "\U0001f3f4\U000e006d\U000e0078\U000e0073\U000e0069\U000e006e\U000e007f" - FLAG_FOR_MICHIGAN_US_MI = "\U0001f3f4\U000e0075\U000e0073\U000e006d\U000e0069\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_BURYAT_RU_BU = "\U0001f3f4\U000e0072\U000e0075\U000e0062\U000e0075\U000e007f" - FLAG_FOR_PODUNAVLJE_RS_10 = "\U0001f3f4\U000e0072\U000e0073\U000e0031\U000e0030\U000e007f" - FLAG_FOR_CURACAO_NL_CW = "\U0001f3f4\U000e006e\U000e006c\U000e0063\U000e0077\U000e007f" - FLAG_FOR_GUANGDONG_CN_44 = "\U0001f3f4\U000e0063\U000e006e\U000e0034\U000e0034\U000e007f" - FLAG_FOR_VASTRA_GOTALAND_SE_O = "\U0001f3f4\U000e0073\U000e0065\U000e006f\U000e007f" - FLAG_FOR_XORAZM_UZ_XO = "\U0001f3f4\U000e0075\U000e007a\U000e0078\U000e006f\U000e007f" - FLAG_FOR_CENTRALE_TG_C = "\U0001f3f4\U000e0074\U000e0067\U000e0063\U000e007f" - FLAG_FOR_BUCHAREST_RO_B = "\U0001f3f4\U000e0072\U000e006f\U000e0062\U000e007f" - FLAG_FOR_SREDISCE_OB_DRAVI_SI_202 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0030\U000e0032\U000e007f" - FLAG_FOR_HODMEZOVASARHELY_HU_HV = "\U0001f3f4\U000e0068\U000e0075\U000e0068\U000e0076\U000e007f" - FLAG_FOR_BUENOS_AIRES_AR_C = "\U0001f3f4\U000e0061\U000e0072\U000e0063\U000e007f" - FLAG_FOR_KERALA_IN_KL = "\U0001f3f4\U000e0069\U000e006e\U000e006b\U000e006c\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_PHUKET_TH_83 = "\U0001f3f4\U000e0074\U000e0068\U000e0038\U000e0033\U000e007f" - FLAG_FOR_SOUTH_KAZAKHSTAN_KZ_YUZ = "\U0001f3f4\U000e006b\U000e007a\U000e0079\U000e0075\U000e007a\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f476\U0001f3fd" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb" - KISS_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - FLAG_FOR_BETHLEHEM_PS_BTH = "\U0001f3f4\U000e0070\U000e0073\U000e0062\U000e0074\U000e0068\U000e007f" - FLAG_FOR_OZOLNIEKI_LV_069 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0036\U000e0039\U000e007f" - FLAG_FOR_BUZAU_RO_BZ = "\U0001f3f4\U000e0072\U000e006f\U000e0062\U000e007a\U000e007f" - FLAG_FOR_OUAKA_CF_UK = "\U0001f3f4\U000e0063\U000e0066\U000e0075\U000e006b\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_BONG_LR_BG = "\U0001f3f4\U000e006c\U000e0072\U000e0062\U000e0067\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_LEBAP_TM_L = "\U0001f3f4\U000e0074\U000e006d\U000e006c\U000e007f" - FLAG_FOR_VORONEZH_RU_VOR = "\U0001f3f4\U000e0072\U000e0075\U000e0076\U000e006f\U000e0072\U000e007f" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - FLAG_FOR_SAN_JOSE_CR_SJ = "\U0001f3f4\U000e0063\U000e0072\U000e0073\U000e006a\U000e007f" - FLAG_FOR_KISUMU_KE_17 = "\U0001f3f4\U000e006b\U000e0065\U000e0031\U000e0037\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_LAHIJ_YE_LA = "\U0001f3f4\U000e0079\U000e0065\U000e006c\U000e0061\U000e007f" - FLAG_FOR_RACHA_LECHKHUMI_AND_KVEMO_SVANETI_GE_RL = "\U0001f3f4\U000e0067\U000e0065\U000e0072\U000e006c\U000e007f" - FLAG_FOR_ULCINJ_ME_20 = "\U0001f3f4\U000e006d\U000e0065\U000e0032\U000e0030\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_OSH_KG_GO = "\U0001f3f4\U000e006b\U000e0067\U000e0067\U000e006f\U000e007f" - FLAG_FOR_AMAZONAS_VE_Z = "\U0001f3f4\U000e0076\U000e0065\U000e007a\U000e007f" - FLAG_FOR_NORTH_RHINE_WESTPHALIA_DE_NW = "\U0001f3f4\U000e0064\U000e0065\U000e006e\U000e0077\U000e007f" - FLAG_FOR_MONAGAS_VE_N = "\U0001f3f4\U000e0076\U000e0065\U000e006e\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_CANTABRIA_ES_CB = "\U0001f3f4\U000e0065\U000e0073\U000e0063\U000e0062\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_M_SILA_DZ_28 = "\U0001f3f4\U000e0064\U000e007a\U000e0032\U000e0038\U000e007f" - FAMILY_WOMAN_MAN_BOY = "\U0001f469\u200d\U0001f468\u200d\U0001f466" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f466\U0001f3fc" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_EASTERN_HIGHLANDS_PG_EHG = "\U0001f3f4\U000e0070\U000e0067\U000e0065\U000e0068\U000e0067\U000e007f" - FLAG_FOR_OHRID_MK_58 = "\U0001f3f4\U000e006d\U000e006b\U000e0035\U000e0038\U000e007f" - FLAG_FOR_SATU_MARE_RO_SM = "\U0001f3f4\U000e0072\U000e006f\U000e0073\U000e006d\U000e007f" - TAG_LATIN_CAPITAL_LETTER_Y = "\U000e0059" - FLAG_FOR_CHERNIHIVSHCHYNA_UA_74 = "\U0001f3f4\U000e0075\U000e0061\U000e0037\U000e0034\U000e007f" - TAG_DIGIT_TWO = "\U000e0032" - FLAG_FOR_RODRIGUES_MU_RO = "\U0001f3f4\U000e006d\U000e0075\U000e0072\U000e006f\U000e007f" - COUPLE_WITH_HEART_WOMAN_MAN_DARK_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_HAWKE_S_BAY_NZ_HKB = "\U0001f3f4\U000e006e\U000e007a\U000e0068\U000e006b\U000e0062\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_SANT_JULIA_DE_LORIA_AD_06 = "\U0001f3f4\U000e0061\U000e0064\U000e0030\U000e0036\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f467\U0001f3fe" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_AN_GIANG_VN_44 = "\U0001f3f4\U000e0076\U000e006e\U000e0034\U000e0034\U000e007f" - FLAG_FOR_UPPSALA_SE_C = "\U0001f3f4\U000e0073\U000e0065\U000e0063\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_UDMURT_RU_UD = "\U0001f3f4\U000e0072\U000e0075\U000e0075\U000e0064\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f467\U0001f3fe" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_ERMERA_TL_ER = "\U0001f3f4\U000e0074\U000e006c\U000e0065\U000e0072\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f476\U0001f3fe" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_PRIMORJE_GORSKI_KOTAR_HR_08 = "\U0001f3f4\U000e0068\U000e0072\U000e0030\U000e0038\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_MUS_TR_49 = "\U0001f3f4\U000e0074\U000e0072\U000e0034\U000e0039\U000e007f" - FLAG_FOR_AD_DAKHILIYAH_OM_DA = "\U0001f3f4\U000e006f\U000e006d\U000e0064\U000e0061\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_ORIENTAL_MA_04 = "\U0001f3f4\U000e006d\U000e0061\U000e0030\U000e0034\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_MAYO_KEBBI_OUEST_TD_MO = "\U0001f3f4\U000e0074\U000e0064\U000e006d\U000e006f\U000e007f" - FLAG_FOR_TBILISI_GE_TB = "\U0001f3f4\U000e0067\U000e0065\U000e0074\U000e0062\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f466\U0001f3fe" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f476\U0001f3fd" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_PHU_THO_VN_68 = "\U0001f3f4\U000e0076\U000e006e\U000e0036\U000e0038\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_FREE_ZA_FS = "\U0001f3f4\U000e007a\U000e0061\U000e0066\U000e0073\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f476\U0001f3fe" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_SUCRE_VE_R = "\U0001f3f4\U000e0076\U000e0065\U000e0072\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_SALGOTARJAN_HU_ST = "\U0001f3f4\U000e0068\U000e0075\U000e0073\U000e0074\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_RAYONG_TH_21 = "\U0001f3f4\U000e0074\U000e0068\U000e0032\U000e0031\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - FAMILY_MAN_MAN_BABY_GIRL = "\U0001f468\u200d\U0001f468\u200d\U0001f476\u200d\U0001f467" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f467\U0001f3ff" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f476\U0001f3fb" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f466\U0001f3fb" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f476\U0001f3ff" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_SUD_EST_HT_SE = "\U0001f3f4\U000e0068\U000e0074\U000e0073\U000e0065\U000e007f" - FLAG_FOR_CETINJE_ME_06 = "\U0001f3f4\U000e006d\U000e0065\U000e0030\U000e0036\U000e007f" - KISS_WOMAN_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - FLAG_FOR_OVERIJSSEL_NL_OV = "\U0001f3f4\U000e006e\U000e006c\U000e006f\U000e0076\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_SMARTNO_OB_PAKI_SI_125 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0032\U000e0035\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_CENTRAL_ANDROS_BS_CS = "\U0001f3f4\U000e0062\U000e0073\U000e0063\U000e0073\U000e007f" - FLAG_FOR_GAZA_PS_GZA = "\U0001f3f4\U000e0070\U000e0073\U000e0067\U000e007a\U000e0061\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_TASMANIA_AU_TAS = "\U0001f3f4\U000e0061\U000e0075\U000e0074\U000e0061\U000e0073\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_GAMBELA_ET_GA = "\U0001f3f4\U000e0065\U000e0074\U000e0067\U000e0061\U000e007f" - FLAG_FOR_SAINT_PETERSBURG_RU_SPE = "\U0001f3f4\U000e0072\U000e0075\U000e0073\U000e0070\U000e0065\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_NORTH_OSSETIA_ALANIA_RU_SE = "\U0001f3f4\U000e0072\U000e0075\U000e0073\U000e0065\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f476\U0001f3fe" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_GALICIA_ES_GA = "\U0001f3f4\U000e0065\U000e0073\U000e0067\U000e0061\U000e007f" - TAG_REVERSE_SOLIDUS = "\U000e005c" - KISS_MAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - FLAG_FOR_KILIMANJARO_TZ_09 = "\U0001f3f4\U000e0074\U000e007a\U000e0030\U000e0039\U000e007f" - FLAG_FOR_GIRESUN_TR_28 = "\U0001f3f4\U000e0074\U000e0072\U000e0032\U000e0038\U000e007f" - FLAG_FOR_KEBBI_NG_KE = "\U0001f3f4\U000e006e\U000e0067\U000e006b\U000e0065\U000e007f" - FLAG_FOR_MAROWIJNE_SR_MA = "\U0001f3f4\U000e0073\U000e0072\U000e006d\U000e0061\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f466\U0001f3fe" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f476\U0001f3fe" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f476\U0001f3fd" - FAMILY_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_SOUTHWEST_FINLAND_FI_19 = "\U0001f3f4\U000e0066\U000e0069\U000e0031\U000e0039\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f467\U0001f3fe" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f467\U0001f3fc" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f476\U0001f3ff" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_BOKEO_LA_BK = "\U0001f3f4\U000e006c\U000e0061\U000e0062\U000e006b\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f466\U0001f3fc" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f466\U0001f3fb" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f466\U0001f3fd" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f476\U0001f3fd" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_GASH_BARKA_ER_GB = "\U0001f3f4\U000e0065\U000e0072\U000e0067\U000e0062\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f467\U0001f3fb" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_ARUNACHAL_PRADESH_IN_AR = "\U0001f3f4\U000e0069\U000e006e\U000e0061\U000e0072\U000e007f" - COUPLE_WITH_HEART_MAN_MAN_DARK_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f467\U0001f3fb" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_MINNESOTA_US_MN = "\U0001f3f4\U000e0075\U000e0073\U000e006d\U000e006e\U000e007f" - FLAG_FOR_ROZAJE_ME_17 = "\U0001f3f4\U000e006d\U000e0065\U000e0031\U000e0037\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f467\U0001f3ff" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_EL_OUED_DZ_39 = "\U0001f3f4\U000e0064\U000e007a\U000e0033\U000e0039\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_OMNOGOVI_MN_053 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0035\U000e0033\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_WEST_COAST_DIVISION_GM_W = "\U0001f3f4\U000e0067\U000e006d\U000e0077\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_MALUKU_ISLANDS_ID_ML = "\U0001f3f4\U000e0069\U000e0064\U000e006d\U000e006c\U000e007f" - FLAG_FOR_SVETI_JURIJ_V_SLOVENSKIH_GORICAH_SI_210 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0031\U000e0030\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_TANGA_TZ_25 = "\U0001f3f4\U000e0074\U000e007a\U000e0032\U000e0035\U000e007f" - FLAG_FOR_FAR_NORTH_CM_EN = "\U0001f3f4\U000e0063\U000e006d\U000e0065\U000e006e\U000e007f" - FLAG_FOR_SANNAT_MT_52 = "\U0001f3f4\U000e006d\U000e0074\U000e0035\U000e0032\U000e007f" - FLAG_FOR_INNER_MONGOLIA_CN_15 = "\U0001f3f4\U000e0063\U000e006e\U000e0031\U000e0035\U000e007f" - FLAG_FOR_ST_PIERRE_ANDAMP_MIQUELON_FR_PM = "\U0001f3f4\U000e0066\U000e0072\U000e0070\U000e006d\U000e007f" - NKO_SYMBOL_GBAKURUNEN = "\u07f7" - FLAG_FOR_RIVER_GEE_LR_RG = "\U0001f3f4\U000e006c\U000e0072\U000e0072\U000e0067\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_NAIROBI_COUNTY_KE_30 = "\U0001f3f4\U000e006b\U000e0065\U000e0033\U000e0030\U000e007f" - FLAG_FOR_ORYOL_RU_ORL = "\U0001f3f4\U000e0072\U000e0075\U000e006f\U000e0072\U000e006c\U000e007f" - FLAG_FOR_BEJA_PT_02 = "\U0001f3f4\U000e0070\U000e0074\U000e0030\U000e0032\U000e007f" - FLAG_FOR_SKOPJE_MK_85 = "\U0001f3f4\U000e006d\U000e006b\U000e0038\U000e0035\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_MOUNT_LEBANON_LB_JL = "\U0001f3f4\U000e006c\U000e0062\U000e006a\U000e006c\U000e007f" - FLAG_FOR_PERM_KRAI_RU_PER = "\U0001f3f4\U000e0072\U000e0075\U000e0070\U000e0065\U000e0072\U000e007f" - FAMILY_WOMAN_WOMAN_BABY_BABY = "\U0001f469\u200d\U0001f469\u200d\U0001f476\u200d\U0001f476" - KISS_MAN_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_ISLA_DE_LA_JUVENTUD_CU_99 = "\U0001f3f4\U000e0063\U000e0075\U000e0039\U000e0039\U000e007f" - UNMARRIED_PARTNERSHIP_SYMBOL = "\u26af" - FLAG_FOR_LAGUNES_CI_LG = "\U0001f3f4\U000e0063\U000e0069\U000e006c\U000e0067\U000e007f" - FLAG_FOR_WESTERN_AUSTRALIA_AU_WA = "\U0001f3f4\U000e0061\U000e0075\U000e0077\U000e0061\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd" - FAMILY_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_HEREDIA_CR_H = "\U0001f3f4\U000e0063\U000e0072\U000e0068\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_AIGA_I_LE_TAI_WS_AL = "\U0001f3f4\U000e0077\U000e0073\U000e0061\U000e006c\U000e007f" - KISS_WOMAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - FLAG_FOR_BAVARIA_DE_BY = "\U0001f3f4\U000e0064\U000e0065\U000e0062\U000e0079\U000e007f" - FLAG_FOR_VALPARAISO_CL_VS = "\U0001f3f4\U000e0063\U000e006c\U000e0076\U000e0073\U000e007f" - WOMAN_IN_BUSINESS_SUIT_LEVITATING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f574\U0001f3fc\u200d\u2640\ufe0f" - FLAG_FOR_BAGHDAD_IQ_BG = "\U0001f3f4\U000e0069\U000e0071\U000e0062\U000e0067\U000e007f" - FLAG_FOR_TENNESSEE_US_TN = "\U0001f3f4\U000e0075\U000e0073\U000e0074\U000e006e\U000e007f" - FAMILY_MAN_WOMAN_BABY = "\U0001f468\u200d\U0001f469\u200d\U0001f476" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_LA_PAZ_SV_PA = "\U0001f3f4\U000e0073\U000e0076\U000e0070\U000e0061\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_RABAT_MT_46 = "\U0001f3f4\U000e006d\U000e0074\U000e0034\U000e0036\U000e007f" - FLAG_FOR_IMO_NG_IM = "\U0001f3f4\U000e006e\U000e0067\U000e0069\U000e006d\U000e007f" - FLAG_FOR_WELLINGTON_NZ_WGN = "\U0001f3f4\U000e006e\U000e007a\U000e0077\U000e0067\U000e006e\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_ZABLJAK_ME_21 = "\U0001f3f4\U000e006d\U000e0065\U000e0032\U000e0031\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_BORNO_NG_BO = "\U0001f3f4\U000e006e\U000e0067\U000e0062\U000e006f\U000e007f" - FLAG_FOR_NAKURU_KE_31 = "\U0001f3f4\U000e006b\U000e0065\U000e0033\U000e0031\U000e007f" - FLAG_FOR_CARABOBO_VE_G = "\U0001f3f4\U000e0076\U000e0065\U000e0067\U000e007f" - FLAG_FOR_TEHRAN_IR_07 = "\U0001f3f4\U000e0069\U000e0072\U000e0030\U000e0037\U000e007f" - FLAG_FOR_BADEN_WURTTEMBERG_DE_BW = "\U0001f3f4\U000e0064\U000e0065\U000e0062\U000e0077\U000e007f" - FLAG_FOR_YANGON_MM_06 = "\U0001f3f4\U000e006d\U000e006d\U000e0030\U000e0036\U000e007f" - TAG_LEFT_PARENTHESIS = "\U000e0028" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_USTECKY_KRAJ_CZ_42 = "\U0001f3f4\U000e0063\U000e007a\U000e0034\U000e0032\U000e007f" - FLAG_FOR_KUALA_LUMPUR_MY_14 = "\U0001f3f4\U000e006d\U000e0079\U000e0031\U000e0034\U000e007f" - FLAG_FOR_AL_WUSTA_OM_WU = "\U0001f3f4\U000e006f\U000e006d\U000e0077\U000e0075\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f466\U0001f3fb" - FLAG_FOR_SOUTH_JEOLLA_KR_46 = "\U0001f3f4\U000e006b\U000e0072\U000e0034\U000e0036\U000e007f" - FLAG_FOR_KHUZESTAN_IR_10 = "\U0001f3f4\U000e0069\U000e0072\U000e0031\U000e0030\U000e007f" - FLAG_FOR_NANTOU_TW_NAN = "\U0001f3f4\U000e0074\U000e0077\U000e006e\U000e0061\U000e006e\U000e007f" - FLAG_FOR_DUSHANBE_TJ_DU = "\U0001f3f4\U000e0074\U000e006a\U000e0064\U000e0075\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f467\U0001f3ff" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_LIMBURG_NL_LI = "\U0001f3f4\U000e006e\U000e006c\U000e006c\U000e0069\U000e007f" - FLAG_FOR_AYACUCHO_PE_AYA = "\U0001f3f4\U000e0070\U000e0065\U000e0061\U000e0079\U000e0061\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_SAINT_PHILIP_AG_08 = "\U0001f3f4\U000e0061\U000e0067\U000e0030\U000e0038\U000e007f" - FLAG_FOR_VALKA_LV_101 = "\U0001f3f4\U000e006c\U000e0076\U000e0031\U000e0030\U000e0031\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_MDINA_MT_29 = "\U0001f3f4\U000e006d\U000e0074\U000e0032\U000e0039\U000e007f" - FLAG_FOR_NORTHERN_DENMARK_DK_81 = "\U0001f3f4\U000e0064\U000e006b\U000e0038\U000e0031\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_GUAM_US_GU = "\U0001f3f4\U000e0075\U000e0073\U000e0067\U000e0075\U000e007f" - FLAG_FOR_SELANGOR_MY_10 = "\U0001f3f4\U000e006d\U000e0079\U000e0031\U000e0030\U000e007f" - FLAG_FOR_PRINCE_EDWARD_ISLAND_CA_PE = "\U0001f3f4\U000e0063\U000e0061\U000e0070\U000e0065\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_GORNO_BADAKHSHAN_TJ_GB = "\U0001f3f4\U000e0074\U000e006a\U000e0067\U000e0062\U000e007f" - FLAG_FOR_OGUN_NG_OG = "\U0001f3f4\U000e006e\U000e0067\U000e006f\U000e0067\U000e007f" - FLAG_FOR_EASTERN_LK_5 = "\U0001f3f4\U000e006c\U000e006b\U000e0035\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_SANTA_ROSA_GT_SR = "\U0001f3f4\U000e0067\U000e0074\U000e0073\U000e0072\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_JAFARA_LY_JI = "\U0001f3f4\U000e006c\U000e0079\U000e006a\U000e0069\U000e007f" - FLAG_FOR_BASILICATA_IT_77 = "\U0001f3f4\U000e0069\U000e0074\U000e0037\U000e0037\U000e007f" - FLAG_FOR_GRONINGEN_NL_GR = "\U0001f3f4\U000e006e\U000e006c\U000e0067\U000e0072\U000e007f" - FLAG_FOR_MATO_GROSSO_DO_SUL_BR_MS = "\U0001f3f4\U000e0062\U000e0072\U000e006d\U000e0073\U000e007f" - FLAG_FOR_KANDAL_KH_8 = "\U0001f3f4\U000e006b\U000e0068\U000e0038\U000e007f" - FLAG_FOR_NORTH_WEST_ZA_NW = "\U0001f3f4\U000e007a\U000e0061\U000e006e\U000e0077\U000e007f" - FLAG_FOR_CONNECTICUT_US_CT = "\U0001f3f4\U000e0075\U000e0073\U000e0063\U000e0074\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_HEBEI_CN_13 = "\U0001f3f4\U000e0063\U000e006e\U000e0031\U000e0033\U000e007f" - FLAG_FOR_FA_ASALELEAGA_WS_FA = "\U0001f3f4\U000e0077\U000e0073\U000e0066\U000e0061\U000e007f" - FLAG_FOR_ALBORZ_IR_32 = "\U0001f3f4\U000e0069\U000e0072\U000e0033\U000e0032\U000e007f" - FLAG_FOR_BRASLOVCE_SI_151 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0035\U000e0031\U000e007f" - FLAG_FOR_HARYANA_IN_HR = "\U0001f3f4\U000e0069\U000e006e\U000e0068\U000e0072\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - FLAG_FOR_SAN_VICENTE_SV_SV = "\U0001f3f4\U000e0073\U000e0076\U000e0073\U000e0076\U000e007f" - FLAG_FOR_MATO_GROSSO_BR_MT = "\U0001f3f4\U000e0062\U000e0072\U000e006d\U000e0074\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_PELOPONNESE_GR_J = "\U0001f3f4\U000e0067\U000e0072\U000e006a\U000e007f" - FLAG_FOR_ADAMAWA_NG_AD = "\U0001f3f4\U000e006e\U000e0067\U000e0061\U000e0064\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_KWAZULU_NATAL_ZA_NL = "\U0001f3f4\U000e007a\U000e0061\U000e006e\U000e006c\U000e007f" - FLAG_FOR_SINT_MAARTEN_NL_SX = "\U0001f3f4\U000e006e\U000e006c\U000e0073\U000e0078\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f466\U0001f3fe" - TAG_SPACE = "\U000e0020" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_CORDILLERA_ADMINISTRATIVE_PH_15 = "\U0001f3f4\U000e0070\U000e0068\U000e0031\U000e0035\U000e007f" - FLAG_FOR_AUCE_LV_010 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0031\U000e0030\U000e007f" - FLAG_FOR_ROCHA_UY_RO = "\U0001f3f4\U000e0075\U000e0079\U000e0072\U000e006f\U000e007f" - FLAG_FOR_FRIESLAND_NL_FR = "\U0001f3f4\U000e006e\U000e006c\U000e0066\U000e0072\U000e007f" - FLAG_FOR_AUVERGNE_RHONE_ALPES_FR_ARA = "\U0001f3f4\U000e0066\U000e0072\U000e0061\U000e0072\U000e0061\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_NOHIYAHOI_TOBEI_JUMHURI_TJ_RA = "\U0001f3f4\U000e0074\U000e006a\U000e0072\U000e0061\U000e007f" - APPLE_LOGO = "\uf8ff" - FLAG_FOR_SAO_TOME_ST_S = "\U0001f3f4\U000e0073\U000e0074\U000e0073\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f466\U0001f3fb" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_ANDHRA_PRADESH_IN_AP = "\U0001f3f4\U000e0069\U000e006e\U000e0061\U000e0070\U000e007f" - FLAG_FOR_INCUKALNS_LV_037 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0033\U000e0037\U000e007f" - FLAG_FOR_KAKHETI_GE_KA = "\U0001f3f4\U000e0067\U000e0065\U000e006b\U000e0061\U000e007f" - FLAG_FOR_BOURGOGNE_FRANCHE_COMTE_FR_BFC = "\U0001f3f4\U000e0066\U000e0072\U000e0062\U000e0066\U000e0063\U000e007f" - KISS_WOMAN_MEDIUM_SKIN_TONE_MAN = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - FLAG_FOR_ENNEDI_OUEST_TD_EO = "\U0001f3f4\U000e0074\U000e0064\U000e0065\U000e006f\U000e007f" - FLAG_FOR_SOUSS_MASSA_DRAA_MA_13 = "\U0001f3f4\U000e006d\U000e0061\U000e0031\U000e0033\U000e007f" - FLAG_FOR_USAK_TR_64 = "\U0001f3f4\U000e0074\U000e0072\U000e0036\U000e0034\U000e007f" - FLAG_FOR_JEJU_KR_49 = "\U0001f3f4\U000e006b\U000e0072\U000e0034\U000e0039\U000e007f" - FLAG_FOR_CHHATTISGARH_IN_CT = "\U0001f3f4\U000e0069\U000e006e\U000e0063\U000e0074\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f476\U0001f3fe" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f476\U0001f3fb" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f476\U0001f3fe" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f466\U0001f3fd" - FAMILY_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f466\U0001f3fd" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f476\U0001f3fe" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_TLEMCEN_DZ_13 = "\U0001f3f4\U000e0064\U000e007a\U000e0031\U000e0033\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_QUINTANA_ROO_MX_ROO = "\U0001f3f4\U000e006d\U000e0078\U000e0072\U000e006f\U000e006f\U000e007f" - FLAG_FOR_WESTERN_IS_3 = "\U0001f3f4\U000e0069\U000e0073\U000e0033\U000e007f" - FLAG_FOR_BANAADIR_SO_BN = "\U0001f3f4\U000e0073\U000e006f\U000e0062\U000e006e\U000e007f" - FLAG_FOR_RHINELAND_PALATINATE_DE_RP = "\U0001f3f4\U000e0064\U000e0065\U000e0072\U000e0070\U000e007f" - FLAG_FOR_MARITIME_TG_M = "\U0001f3f4\U000e0074\U000e0067\U000e006d\U000e007f" - FLAG_FOR_GYOR_MOSON_SOPRON_HU_GS = "\U0001f3f4\U000e0068\U000e0075\U000e0067\U000e0073\U000e007f" - FLAG_FOR_BEN_AROUS_TN_13 = "\U0001f3f4\U000e0074\U000e006e\U000e0031\U000e0033\U000e007f" - WOMAN_IN_BUSINESS_SUIT_LEVITATING_LIGHT_SKIN_TONE = "\U0001f574\U0001f3fb\u200d\u2640\ufe0f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f476\U0001f3fc" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_FUKUI_JP_18 = "\U0001f3f4\U000e006a\U000e0070\U000e0031\U000e0038\U000e007f" - FLAG_FOR_EAST_NEW_BRITAIN_PG_EBR = "\U0001f3f4\U000e0070\U000e0067\U000e0065\U000e0062\U000e0072\U000e007f" - VARIATION_SELECTOR_16 = "\ufe0f" - FLAG_FOR_CENTRAL_EQUATORIA_SS_EC = "\U0001f3f4\U000e0073\U000e0073\U000e0065\U000e0063\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_KHAMMOUANE_LA_KH = "\U0001f3f4\U000e006c\U000e0061\U000e006b\U000e0068\U000e007f" - FLAG_FOR_DADRA_AND_NAGAR_HAVELI_IN_DN = "\U0001f3f4\U000e0069\U000e006e\U000e0064\U000e006e\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f466\U0001f3fd" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_SOUTHERN_RED_SEA_ER_DK = "\U0001f3f4\U000e0065\U000e0072\U000e0064\U000e006b\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f466\U0001f3fd" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f467\U0001f3fb" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_VOJVODINA_RS_VO = "\U0001f3f4\U000e0072\U000e0073\U000e0076\U000e006f\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_ATLANTICO_SUR_NI_AS = "\U0001f3f4\U000e006e\U000e0069\U000e0061\U000e0073\U000e007f" - COUPLE_WITH_HEART_WOMAN_MAN_MEDIUM_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f466\U0001f3fc" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_KERMAN_IR_15 = "\U0001f3f4\U000e0069\U000e0072\U000e0031\U000e0035\U000e007f" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_KALMAR_SE_H = "\U0001f3f4\U000e0073\U000e0065\U000e0068\U000e007f" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FLAG_FOR_ALMATY_REGION_KZ_ALM = "\U0001f3f4\U000e006b\U000e007a\U000e0061\U000e006c\U000e006d\U000e007f" - FLAG_FOR_ZLINSKY_KRAJ_CZ_72 = "\U0001f3f4\U000e0063\U000e007a\U000e0037\U000e0032\U000e007f" - FLAG_FOR_SANGRE_GRANDE_TT_SGE = "\U0001f3f4\U000e0074\U000e0074\U000e0073\U000e0067\U000e0065\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_PUERTO_RICO_US_PR = "\U0001f3f4\U000e0075\U000e0073\U000e0070\U000e0072\U000e007f" - FLAG_FOR_ALO_WF_AL = "\U0001f3f4\U000e0077\U000e0066\U000e0061\U000e006c\U000e007f" - FLAG_FOR_WASHINGTON_DC_US_DC = "\U0001f3f4\U000e0075\U000e0073\U000e0064\U000e0063\U000e007f" - FLAG_FOR_LA_REUNION_FR_LRE = "\U0001f3f4\U000e0066\U000e0072\U000e006c\U000e0072\U000e0065\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_GRAD_SI_158 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0035\U000e0038\U000e007f" - FLAG_FOR_TEXAS_US_TX = "\U0001f3f4\U000e0075\U000e0073\U000e0074\U000e0078\U000e007f" - MAN_ZOMBIE_MEDIUM_DARK_SKIN_TONE = "\U0001f9df\U0001f3fe\u200d\u2642\ufe0f" - FLAG_FOR_PARAIBA_BR_PB = "\U0001f3f4\U000e0062\U000e0072\U000e0070\U000e0062\U000e007f" - FLAG_FOR_VARGAS_VE_X = "\U0001f3f4\U000e0076\U000e0065\U000e0078\U000e007f" - TAG_LATIN_CAPITAL_LETTER_H = "\U000e0048" - FLAG_FOR_BERN_CH_BE = "\U0001f3f4\U000e0063\U000e0068\U000e0062\U000e0065\U000e007f" - FLAG_FOR_MARA_TZ_13 = "\U0001f3f4\U000e0074\U000e007a\U000e0031\U000e0033\U000e007f" - FLAG_FOR_THURINGIA_DE_TH = "\U0001f3f4\U000e0064\U000e0065\U000e0074\U000e0068\U000e007f" - COUPLE_WITH_HEART_WOMAN_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f467\U0001f3fe" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f466\U0001f3fb" - TAG_LATIN_CAPITAL_LETTER_R = "\U000e0052" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_GOTLAND_SE_I = "\U0001f3f4\U000e0073\U000e0065\U000e0069\U000e007f" - FLAG_FOR_ANDAMAN_AND_NICOBAR_ISLANDS_IN_AN = "\U0001f3f4\U000e0069\U000e006e\U000e0061\U000e006e\U000e007f" - FLAG_FOR_SAN_ANDRES_ANDAMP_PROVIDENCIA_CO_SAP = "\U0001f3f4\U000e0063\U000e006f\U000e0073\U000e0061\U000e0070\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_SOUTHERN_DENMARK_DK_83 = "\U0001f3f4\U000e0064\U000e006b\U000e0038\U000e0033\U000e007f" - FLAG_FOR_AMUR_RU_AMU = "\U0001f3f4\U000e0072\U000e0075\U000e0061\U000e006d\U000e0075\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_NAGASAKI_JP_42 = "\U0001f3f4\U000e006a\U000e0070\U000e0034\U000e0032\U000e007f" - FLAG_FOR_NEWFOUNDLAND_AND_LABRADOR_CA_NL = "\U0001f3f4\U000e0063\U000e0061\U000e006e\U000e006c\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f467\U0001f3ff" - TAG_GREATER_THAN_SIGN = "\U000e003e" - FLAG_FOR_RAMALLAH_AND_AL_BIREH_PS_RBH = "\U0001f3f4\U000e0070\U000e0073\U000e0072\U000e0062\U000e0068\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f467\U0001f3fd" - KISS_MAN_MAN_MEDIUM_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - FLAG_FOR_ANTOFAGASTA_CL_AN = "\U0001f3f4\U000e0063\U000e006c\U000e0061\U000e006e\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f466\U0001f3fb" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f466\U0001f3fb" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - KISS_MAN_MEDIUM_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - FLAG_FOR_CHUVASH_RU_CU = "\U0001f3f4\U000e0072\U000e0075\U000e0063\U000e0075\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f466\U0001f3fc" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f467\U0001f3fd" - FAMILY_WOMAN_WOMAN_BOY_GIRL = "\U0001f469\u200d\U0001f469\u200d\U0001f466\u200d\U0001f467" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f466\U0001f3fe" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_ULSTER_IE_U = "\U0001f3f4\U000e0069\U000e0065\U000e0075\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_NABEUL_TN_21 = "\U0001f3f4\U000e0074\U000e006e\U000e0032\U000e0031\U000e007f" - FAMILY_MAN_BABY_BABY = "\U0001f468\u200d\U0001f476\u200d\U0001f476" - FLAG_FOR_TAIPEI_TW_TPE = "\U0001f3f4\U000e0074\U000e0077\U000e0074\U000e0070\U000e0065\U000e007f" - COUPLE_WITH_HEART_MAN_WOMAN_DARK_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_ZEELAND_NL_ZE = "\U0001f3f4\U000e006e\U000e006c\U000e007a\U000e0065\U000e007f" - FLAG_FOR_JAVA_ID_JW = "\U0001f3f4\U000e0069\U000e0064\U000e006a\U000e0077\U000e007f" - FLAG_FOR_AZAD_KASHMIR_PK_JK = "\U0001f3f4\U000e0070\U000e006b\U000e006a\U000e006b\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_UNITY_SS_UY = "\U0001f3f4\U000e0073\U000e0073\U000e0075\U000e0079\U000e007f" - FLAG_FOR_CENTRAL_LUZON_PH_03 = "\U0001f3f4\U000e0070\U000e0068\U000e0030\U000e0033\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f466\U0001f3ff" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_SOUTHERN_LK_3 = "\U0001f3f4\U000e006c\U000e006b\U000e0033\U000e007f" - FLAG_FOR_SAO_PAULO_BR_SP = "\U0001f3f4\U000e0062\U000e0072\U000e0073\U000e0070\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_JAMMU_AND_KASHMIR_IN_JK = "\U0001f3f4\U000e0069\U000e006e\U000e006a\U000e006b\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_CAT_ISLAND_BS_CI = "\U0001f3f4\U000e0062\U000e0073\U000e0063\U000e0069\U000e007f" - FLAG_FOR_LAGHOUAT_DZ_03 = "\U0001f3f4\U000e0064\U000e007a\U000e0030\U000e0033\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_MARJ_LY_MJ = "\U0001f3f4\U000e006c\U000e0079\U000e006d\U000e006a\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f476\U0001f3fc" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - FLAG_FOR_TRUJILLO_VE_T = "\U0001f3f4\U000e0076\U000e0065\U000e0074\U000e007f" - WOMAN_WITH_HEADSCARF_MEDIUM_DARK_SKIN_TONE = "\U0001f9d5\U0001f3fe\u200d\u2640\ufe0f" - FLAG_FOR_SAARLAND_DE_SL = "\U0001f3f4\U000e0064\U000e0065\U000e0073\U000e006c\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_TRENTINO_SOUTH_TYROL_IT_32 = "\U0001f3f4\U000e0069\U000e0074\U000e0033\U000e0032\U000e007f" - FLAG_FOR_KHARTOUM_SD_KH = "\U0001f3f4\U000e0073\U000e0064\U000e006b\U000e0068\U000e007f" - TAG_EXCLAMATION_MARK = "\U000e0021" - FAMILY_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f466\U0001f3fb" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_TRANSNISTRIA_MD_SN = "\U0001f3f4\U000e006d\U000e0064\U000e0073\U000e006e\U000e007f" - FLAG_FOR_PINAR_DEL_RIO_CU_01 = "\U0001f3f4\U000e0063\U000e0075\U000e0030\U000e0031\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f466\U0001f3fc" - FAMILY_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_KEDAH_MY_02 = "\U0001f3f4\U000e006d\U000e0079\U000e0030\U000e0032\U000e007f" - FLAG_FOR_JILIN_CN_22 = "\U0001f3f4\U000e0063\U000e006e\U000e0032\U000e0032\U000e007f" - ZERO_WIDTH_JOINER = "\u200d" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_MANUFAHI_TL_MF = "\U0001f3f4\U000e0074\U000e006c\U000e006d\U000e0066\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_STUDENICANI_MK_74 = "\U0001f3f4\U000e006d\U000e006b\U000e0037\U000e0034\U000e007f" - FLAG_FOR_ILUKSTE_LV_036 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0033\U000e0036\U000e007f" - FLAG_FOR_MAZANDARAN_IR_21 = "\U0001f3f4\U000e0069\U000e0072\U000e0032\U000e0031\U000e007f" - FLAG_FOR_VISEU_PT_18 = "\U0001f3f4\U000e0070\U000e0074\U000e0031\U000e0038\U000e007f" - FLAG_FOR_ESTUAIRE_GA_1 = "\U0001f3f4\U000e0067\U000e0061\U000e0031\U000e007f" - FLAG_FOR_GANSU_CN_62 = "\U0001f3f4\U000e0063\U000e006e\U000e0036\U000e0032\U000e007f" - FLAG_FOR_SOUTH_KHORASAN_IR_29 = "\U0001f3f4\U000e0069\U000e0072\U000e0032\U000e0039\U000e007f" - FLAG_FOR_DIOURBEL_SN_DB = "\U0001f3f4\U000e0073\U000e006e\U000e0064\U000e0062\U000e007f" - FLAG_FOR_MORELOS_MX_MOR = "\U0001f3f4\U000e006d\U000e0078\U000e006d\U000e006f\U000e0072\U000e007f" - FLAG_FOR_DELAWARE_US_DE = "\U0001f3f4\U000e0075\U000e0073\U000e0064\U000e0065\U000e007f" - FLAG_FOR_SIGAVE_WF_SG = "\U0001f3f4\U000e0077\U000e0066\U000e0073\U000e0067\U000e007f" - FLAG_FOR_RIVERA_UY_RV = "\U0001f3f4\U000e0075\U000e0079\U000e0072\U000e0076\U000e007f" - FLAG_FOR_TUNGURAHUA_EC_T = "\U0001f3f4\U000e0065\U000e0063\U000e0074\U000e007f" - BEAMED_DESCENDING_MUSICAL_NOTES = "\U0001f39d" - FLAG_FOR_KALININGRAD_RU_KGD = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0067\U000e0064\U000e007f" - TAG_LATIN_CAPITAL_LETTER_T = "\U000e0054" - FLAG_FOR_TOMBOUCTOU_ML_6 = "\U0001f3f4\U000e006d\U000e006c\U000e0036\U000e007f" - COUPLE_WITH_HEART_WOMAN_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - FLAG_FOR_ENCAMP_AD_03 = "\U0001f3f4\U000e0061\U000e0064\U000e0030\U000e0033\U000e007f" - FLAG_FOR_MIAOLI_TW_MIA = "\U0001f3f4\U000e0074\U000e0077\U000e006d\U000e0069\U000e0061\U000e007f" - FLAG_FOR_KENTUCKY_US_KY = "\U0001f3f4\U000e0075\U000e0073\U000e006b\U000e0079\U000e007f" - FLAG_FOR_GUSINJE_ME_22 = "\U0001f3f4\U000e006d\U000e0065\U000e0032\U000e0032\U000e007f" - FLAG_FOR_SAATLY_AZ_SAT = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e0061\U000e0074\U000e007f" - FLAG_FOR_NUNAVUT_CA_NU = "\U0001f3f4\U000e0063\U000e0061\U000e006e\U000e0075\U000e007f" - FLAG_FOR_SPANISH_WELLS_BS_SW = "\U0001f3f4\U000e0062\U000e0073\U000e0073\U000e0077\U000e007f" - FLAG_FOR_BITLIS_TR_13 = "\U0001f3f4\U000e0074\U000e0072\U000e0031\U000e0033\U000e007f" - FLAG_FOR_BADGHIS_AF_BDG = "\U0001f3f4\U000e0061\U000e0066\U000e0062\U000e0064\U000e0067\U000e007f" - KISS_MAN_DARK_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - FLAG_FOR_SAGA_JP_41 = "\U0001f3f4\U000e006a\U000e0070\U000e0034\U000e0031\U000e007f" - FLAG_FOR_ST_PAUL_S_BAY_MT_51 = "\U0001f3f4\U000e006d\U000e0074\U000e0035\U000e0031\U000e007f" - FLAG_FOR_TORBA_VU_TOB = "\U0001f3f4\U000e0076\U000e0075\U000e0074\U000e006f\U000e0062\U000e007f" - KISS_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - FLAG_FOR_BERLIN_DE_BE = "\U0001f3f4\U000e0064\U000e0065\U000e0062\U000e0065\U000e007f" - FLAG_FOR_BABITE_LV_012 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0031\U000e0032\U000e007f" - FLAG_FOR_EL_VALLE_DO_37 = "\U0001f3f4\U000e0064\U000e006f\U000e0033\U000e0037\U000e007f" - FLAG_FOR_BENI_SUEF_EG_BNS = "\U0001f3f4\U000e0065\U000e0067\U000e0062\U000e006e\U000e0073\U000e007f" - FLAG_FOR_SFAX_TN_61 = "\U0001f3f4\U000e0074\U000e006e\U000e0036\U000e0031\U000e007f" - FLAG_FOR_MONTE_CARLO_MC_MC = "\U0001f3f4\U000e006d\U000e0063\U000e006d\U000e0063\U000e007f" - FLAG_FOR_YUNNAN_CN_53 = "\U0001f3f4\U000e0063\U000e006e\U000e0035\U000e0033\U000e007f" - FLAG_FOR_KLAIPEDOS_MUNICIPALITY_LT_20 = "\U0001f3f4\U000e006c\U000e0074\U000e0032\U000e0030\U000e007f" - FLAG_FOR_BARINGO_KE_01 = "\U0001f3f4\U000e006b\U000e0065\U000e0030\U000e0031\U000e007f" - FLAG_FOR_CENTRAL_RIVER_DIVISION_GM_M = "\U0001f3f4\U000e0067\U000e006d\U000e006d\U000e007f" - FLAG_FOR_AMANAT_AL_ASIMAH_YE_SA = "\U0001f3f4\U000e0079\U000e0065\U000e0073\U000e0061\U000e007f" - FLAG_FOR_HAUTS_BASSINS_BF_09 = "\U0001f3f4\U000e0062\U000e0066\U000e0030\U000e0039\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f476\U0001f3fe" - TAG_EQUALS_SIGN = "\U000e003d" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_SENGLEA_MT_20 = "\U0001f3f4\U000e006d\U000e0074\U000e0032\U000e0030\U000e007f" - ALTERNATE_ONE_WAY_LEFT_WAY_TRAFFIC = "\u26d5" - FLAG_FOR_G_ASRI_MT_16 = "\U0001f3f4\U000e006d\U000e0074\U000e0031\U000e0036\U000e007f" - WHITE_CHESS_PAWN = "\u2659" - FLAG_FOR_HAU_GIANG_VN_73 = "\U0001f3f4\U000e0076\U000e006e\U000e0037\U000e0033\U000e007f" - MAN_ZOMBIE_MEDIUM_SKIN_TONE = "\U0001f9df\U0001f3fd\u200d\u2642\ufe0f" - FLAG_FOR_TEARCE_MK_75 = "\U0001f3f4\U000e006d\U000e006b\U000e0037\U000e0035\U000e007f" - FLAG_FOR_FAMAGUSTA_CY_04 = "\U0001f3f4\U000e0063\U000e0079\U000e0030\U000e0034\U000e007f" - FLAG_FOR_COTOPAXI_EC_X = "\U0001f3f4\U000e0065\U000e0063\U000e0078\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_ANG_THONG_TH_15 = "\U0001f3f4\U000e0074\U000e0068\U000e0031\U000e0035\U000e007f" - RECYCLING_SYMBOL_FOR_TYPE_2_PLASTICS = "\u2674" - FLAG_FOR_SETUBAL_PT_15 = "\U0001f3f4\U000e0070\U000e0074\U000e0031\U000e0035\U000e007f" - BLACK_CIRCLE_WITH_WHITE_DOT_RIGHT = "\u2688" - WHITE_SPADE_SUIT = "\u2664" - FLAG_FOR_DAGDA_LV_024 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0032\U000e0034\U000e007f" - FLAG_FOR_BAR_ME_02 = "\U0001f3f4\U000e006d\U000e0065\U000e0030\U000e0032\U000e007f" - FLAG_FOR_CATALONIA_ES_CT = "\U0001f3f4\U000e0065\U000e0073\U000e0063\U000e0074\U000e007f" - COUPLE_WITH_HEART_MAN_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FLAG_FOR_WESTERN_SB_WE = "\U0001f3f4\U000e0073\U000e0062\U000e0077\U000e0065\U000e007f" - FLAG_FOR_BAYQONGYR_KZ_BAY = "\U0001f3f4\U000e006b\U000e007a\U000e0062\U000e0061\U000e0079\U000e007f" - NOTE_PAD = "\U0001f5ca" - BLACK_CHESS_KING = "\u265a" - FLAG_FOR_PORTO_PT_13 = "\U0001f3f4\U000e0070\U000e0074\U000e0031\U000e0033\U000e007f" - FLAG_FOR_KAMPONG_CHHNANG_KH_4 = "\U0001f3f4\U000e006b\U000e0068\U000e0034\U000e007f" - FLAG_FOR_DAKAR_SN_DK = "\U0001f3f4\U000e0073\U000e006e\U000e0064\U000e006b\U000e007f" - FLAG_FOR_FEDERAL_CAPITAL_TERRITORY_PL_PM = "\U0001f3f4\U000e0070\U000e006c\U000e0070\U000e006d\U000e007f" - WHITE_TOUCHTONE_TELEPHONE = "\U0001f57e" - FLAG_FOR_TAMIL_NADU_IN_TN = "\U0001f3f4\U000e0069\U000e006e\U000e0074\U000e006e\U000e007f" - FLAG_FOR_BRAGA_PT_03 = "\U0001f3f4\U000e0070\U000e0074\U000e0030\U000e0033\U000e007f" - FLAG_FOR_SPELUGUES_MC_SP = "\U0001f3f4\U000e006d\U000e0063\U000e0073\U000e0070\U000e007f" - FLAG_FOR_JHARKHAND_IN_JH = "\U0001f3f4\U000e0069\U000e006e\U000e006a\U000e0068\U000e007f" - FLAG_FOR_BOCAS_DEL_TORO_PA_1 = "\U0001f3f4\U000e0070\U000e0061\U000e0031\U000e007f" - FLAG_FOR_CANAR_EC_F = "\U0001f3f4\U000e0065\U000e0063\U000e0066\U000e007f" - FLAG_FOR_AICHI_JP_23 = "\U0001f3f4\U000e006a\U000e0070\U000e0032\U000e0033\U000e007f" - FLAG_FOR_OMAHEKE_NA_OH = "\U0001f3f4\U000e006e\U000e0061\U000e006f\U000e0068\U000e007f" - FLAG_FOR_MERSIN_TR_33 = "\U0001f3f4\U000e0074\U000e0072\U000e0033\U000e0033\U000e007f" - FLAG_FOR_OSH_REGION_KG_O = "\U0001f3f4\U000e006b\U000e0067\U000e006f\U000e007f" - FLAG_FOR_MIYAZAKI_JP_45 = "\U0001f3f4\U000e006a\U000e0070\U000e0034\U000e0035\U000e007f" - WHITE_RIGHT_POINTING_INDEX = "\u261e" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - FLAG_FOR_PAIJANNE_TAVASTIA_FI_16 = "\U0001f3f4\U000e0066\U000e0069\U000e0031\U000e0036\U000e007f" - FLAG_FOR_TARANAKI_NZ_TKI = "\U0001f3f4\U000e006e\U000e007a\U000e0074\U000e006b\U000e0069\U000e007f" - FLAG_FOR_ILLINOIS_US_IL = "\U0001f3f4\U000e0075\U000e0073\U000e0069\U000e006c\U000e007f" - FLAG_FOR_BAMYAN_AF_BAM = "\U0001f3f4\U000e0061\U000e0066\U000e0062\U000e0061\U000e006d\U000e007f" - FLAG_FOR_FLORIDA_UY_FD = "\U0001f3f4\U000e0075\U000e0079\U000e0066\U000e0064\U000e007f" - UP_POINTING_AIRPLANE = "\U0001f6e7" - FLAG_FOR_THAI_NGUYEN_VN_69 = "\U0001f3f4\U000e0076\U000e006e\U000e0036\U000e0039\U000e007f" - FLAG_FOR_VIROVITICA_PODRAVINA_HR_10 = "\U0001f3f4\U000e0068\U000e0072\U000e0031\U000e0030\U000e007f" - KISS_MAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - WHITE_LEFT_POINTING_INDEX = "\u261c" - FLAG_FOR_KIGOMA_TZ_08 = "\U0001f3f4\U000e0074\U000e007a\U000e0030\U000e0038\U000e007f" - FLAG_FOR_SUL_GW_S = "\U0001f3f4\U000e0067\U000e0077\U000e0073\U000e007f" - FLAG_FOR_BELIZE_BZ_BZ = "\U0001f3f4\U000e0062\U000e007a\U000e0062\U000e007a\U000e007f" - FLAG_FOR_HHOHHO_SZ_HH = "\U0001f3f4\U000e0073\U000e007a\U000e0068\U000e0068\U000e007f" - FLAG_FOR_AKTOBE_KZ_AKT = "\U0001f3f4\U000e006b\U000e007a\U000e0061\U000e006b\U000e0074\U000e007f" - FLAG_FOR_ZHEJIANG_CN_33 = "\U0001f3f4\U000e0063\U000e006e\U000e0033\U000e0033\U000e007f" - FLAG_FOR_EL_PARAISO_HN_EP = "\U0001f3f4\U000e0068\U000e006e\U000e0065\U000e0070\U000e007f" - MONOGRAM_FOR_YIN = "\u268b" - FLAG_FOR_NUGAL_SO_NU = "\U0001f3f4\U000e0073\U000e006f\U000e006e\U000e0075\U000e007f" - MAHJONG_TILE_NINE_OF_CHARACTERS = "\U0001f00f" - FLAG_FOR_ATTICA_GR_I = "\U0001f3f4\U000e0067\U000e0072\U000e0069\U000e007f" - NOTE_PAGE = "\U0001f5c9" - FLAG_FOR_DURBE_LV_028 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0032\U000e0038\U000e007f" - FLAG_FOR_CAYO_BZ_CY = "\U0001f3f4\U000e0062\U000e007a\U000e0063\U000e0079\U000e007f" - SOFT_SHELL_FLOPPY_DISK = "\U0001f5ac" - FLAG_FOR_SAKHA_RU_SA = "\U0001f3f4\U000e0072\U000e0075\U000e0073\U000e0061\U000e007f" - FLAG_FOR_SEGOU_ML_4 = "\U0001f3f4\U000e006d\U000e006c\U000e0034\U000e007f" - FLAG_FOR_BALKH_AF_BAL = "\U0001f3f4\U000e0061\U000e0066\U000e0062\U000e0061\U000e006c\U000e007f" - FLAG_FOR_WESTFJORDS_IS_4 = "\U0001f3f4\U000e0069\U000e0073\U000e0034\U000e007f" - FLAG_FOR_CALIFORNIA_US_CA = "\U0001f3f4\U000e0075\U000e0073\U000e0063\U000e0061\U000e007f" - FLAG_FOR_SETIF_DZ_19 = "\U0001f3f4\U000e0064\U000e007a\U000e0031\U000e0039\U000e007f" - TAG_COMMA = "\U000e002c" - FLAG_FOR_BAJA_VERAPAZ_GT_BV = "\U0001f3f4\U000e0067\U000e0074\U000e0062\U000e0076\U000e007f" - TAG_LATIN_CAPITAL_LETTER_E = "\U000e0045" - FLAG_FOR_WEST_CM_OU = "\U0001f3f4\U000e0063\U000e006d\U000e006f\U000e0075\U000e007f" - FLAG_FOR_SHAANXI_CN_61 = "\U0001f3f4\U000e0063\U000e006e\U000e0036\U000e0031\U000e007f" - FLAG_FOR_SOUTH_CM_SU = "\U0001f3f4\U000e0063\U000e006d\U000e0073\U000e0075\U000e007f" - FLAG_FOR_RAKHINE_MM_16 = "\U0001f3f4\U000e006d\U000e006d\U000e0031\U000e0036\U000e007f" - FLAG_FOR_BARIMA_WAINI_GY_BA = "\U0001f3f4\U000e0067\U000e0079\U000e0062\U000e0061\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_SANA_A_YE_SN = "\U0001f3f4\U000e0079\U000e0065\U000e0073\U000e006e\U000e007f" - FLAG_FOR_VILNIAUS_MUNICIPALITY_LT_57 = "\U0001f3f4\U000e006c\U000e0074\U000e0035\U000e0037\U000e007f" - FLAG_FOR_RANKOVCE_MK_65 = "\U0001f3f4\U000e006d\U000e006b\U000e0036\U000e0035\U000e007f" - FLAG_FOR_WEST_BENGAL_IN_WB = "\U0001f3f4\U000e0069\U000e006e\U000e0077\U000e0062\U000e007f" - TAG_LEFT_CURLY_BRACKET = "\U000e007b" - FLAG_FOR_KIROVOHRADSCHYNA_UA_35 = "\U0001f3f4\U000e0075\U000e0061\U000e0033\U000e0035\U000e007f" - LEFT_THOUGHT_BUBBLE = "\U0001f5ec" - FLAG_FOR_KAPOSVAR_HU_KV = "\U0001f3f4\U000e0068\U000e0075\U000e006b\U000e0076\U000e007f" - RIGHT_SPEAKER_WITH_THREE_SOUND_WAVES = "\U0001f56a" - FLAG_FOR_ARIMA_TT_ARI = "\U0001f3f4\U000e0074\U000e0074\U000e0061\U000e0072\U000e0069\U000e007f" - WHITE_CLUB_SUIT = "\u2667" - REVERSED_THUMBS_DOWN_SIGN = "\U0001f593" - BEAMED_EIGHTH_NOTES = "\u266b" - FLAG_FOR_JUFRA_LY_JU = "\U0001f3f4\U000e006c\U000e0079\U000e006a\U000e0075\U000e007f" - FLAG_FOR_BAGHLAN_AF_BGL = "\U0001f3f4\U000e0061\U000e0066\U000e0062\U000e0067\U000e006c\U000e007f" - TAG_RIGHT_PARENTHESIS = "\U000e0029" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_OHIO_US_OH = "\U0001f3f4\U000e0075\U000e0073\U000e006f\U000e0068\U000e007f" - CANCEL_TAG = "\U000e007f" - FLAG_FOR_ST_MARTIN_FR_MF = "\U0001f3f4\U000e0066\U000e0072\U000e006d\U000e0066\U000e007f" - RIGHT_HAND_TELEPHONE_RECEIVER = "\U0001f57d" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_MAN = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468" - FLAG_FOR_ASTANA_KZ_AST = "\U0001f3f4\U000e006b\U000e007a\U000e0061\U000e0073\U000e0074\U000e007f" - FLAG_FOR_EASTERN_SL_E = "\U0001f3f4\U000e0073\U000e006c\U000e0065\U000e007f" - FLAG_FOR_YALA_TH_95 = "\U0001f3f4\U000e0074\U000e0068\U000e0039\U000e0035\U000e007f" - FLAG_FOR_AHAL_TM_A = "\U0001f3f4\U000e0074\U000e006d\U000e0061\U000e007f" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - MAHJONG_TILE_SIX_OF_CIRCLES = "\U0001f01e" - TURNED_BLACK_SHOGI_PIECE = "\u26ca" - FLAG_FOR_WOQOOYI_GALBEED_SO_WO = "\U0001f3f4\U000e0073\U000e006f\U000e0077\U000e006f\U000e007f" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - FLAG_FOR_MAGWAY_MM_03 = "\U0001f3f4\U000e006d\U000e006d\U000e0030\U000e0033\U000e007f" - FLAG_FOR_SAVANNAKHET_LA_SV = "\U0001f3f4\U000e006c\U000e0061\U000e0073\U000e0076\U000e007f" - FLAG_FOR_CRETE_GR_M = "\U0001f3f4\U000e0067\U000e0072\U000e006d\U000e007f" - FLAG_FOR_BIRZAI_LT_06 = "\U0001f3f4\U000e006c\U000e0074\U000e0030\U000e0036\U000e007f" - FLAG_FOR_NGIWAL_PW_228 = "\U0001f3f4\U000e0070\U000e0077\U000e0032\U000e0032\U000e0038\U000e007f" - FLAG_FOR_RADOVIS_MK_64 = "\U0001f3f4\U000e006d\U000e006b\U000e0036\U000e0034\U000e007f" - FLOWER = "\u2698" - FLAG_FOR_PLANKEN_LI_05 = "\U0001f3f4\U000e006c\U000e0069\U000e0030\U000e0035\U000e007f" - FLAG_FOR_MANGROVE_CAY_BS_MC = "\U0001f3f4\U000e0062\U000e0073\U000e006d\U000e0063\U000e007f" - FLAG_FOR_EMBU_KE_06 = "\U0001f3f4\U000e006b\U000e0065\U000e0030\U000e0036\U000e007f" - FLAG_FOR_FARAH_AF_FRA = "\U0001f3f4\U000e0061\U000e0066\U000e0066\U000e0072\U000e0061\U000e007f" - THREE_RAYS_BELOW = "\U0001f5e5" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - FLAG_FOR_THURGAU_CH_TG = "\U0001f3f4\U000e0063\U000e0068\U000e0074\U000e0067\U000e007f" - FLAG_FOR_KAMPONG_CHAM_KH_3 = "\U0001f3f4\U000e006b\U000e0068\U000e0033\U000e007f" - FLAG_FOR_LESSER_SUNDA_ISLANDS_ID_NU = "\U0001f3f4\U000e0069\U000e0064\U000e006e\U000e0075\U000e007f" - FLAG_FOR_BERRY_ISLANDS_BS_BY = "\U0001f3f4\U000e0062\U000e0073\U000e0062\U000e0079\U000e007f" - TWO_SPEECH_BUBBLES = "\U0001f5ea" - FLAG_FOR_WEST_GREECE_GR_G = "\U0001f3f4\U000e0067\U000e0072\U000e0067\U000e007f" - WHITE_SUN = "\U0001f323" - TAG_ASTERISK = "\U000e002a" - PAGE_WITH_CIRCLED_TEXT = "\U0001f5df" - FAMILY_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_OGOOUE_MARITIME_GA_8 = "\U0001f3f4\U000e0067\U000e0061\U000e0038\U000e007f" - FLAG_FOR_MADEIRA_PT_30 = "\U0001f3f4\U000e0070\U000e0074\U000e0033\U000e0030\U000e007f" - FLAG_FOR_GURIA_GE_GU = "\U0001f3f4\U000e0067\U000e0065\U000e0067\U000e0075\U000e007f" - FLAG_FOR_PARA_BR_PA = "\U0001f3f4\U000e0062\U000e0072\U000e0070\U000e0061\U000e007f" - FAMILY_WOMAN_BABY_BABY = "\U0001f469\u200d\U0001f476\u200d\U0001f476" - FLAG_FOR_SCHAFFHAUSEN_CH_SH = "\U0001f3f4\U000e0063\U000e0068\U000e0073\U000e0068\U000e007f" - FLAG_FOR_GHOR_AF_GHO = "\U0001f3f4\U000e0061\U000e0066\U000e0067\U000e0068\U000e006f\U000e007f" - FLAG_FOR_ARKANSAS_US_AR = "\U0001f3f4\U000e0075\U000e0073\U000e0061\U000e0072\U000e007f" - FLAG_FOR_DRENTHE_NL_DR = "\U0001f3f4\U000e006e\U000e006c\U000e0064\U000e0072\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_GHAZNI_AF_GHA = "\U0001f3f4\U000e0061\U000e0066\U000e0067\U000e0068\U000e0061\U000e007f" - FLAG_FOR_OZAMA_DO_40 = "\U0001f3f4\U000e0064\U000e006f\U000e0034\U000e0030\U000e007f" - FLAG_FOR_HERAT_AF_HER = "\U0001f3f4\U000e0061\U000e0066\U000e0068\U000e0065\U000e0072\U000e007f" - TAG_DIGIT_FOUR = "\U000e0034" - FLAG_FOR_NEBRASKA_US_NE = "\U0001f3f4\U000e0075\U000e0073\U000e006e\U000e0065\U000e007f" - FLAG_FOR_ARICA_Y_PARINACOTA_CL_AP = "\U0001f3f4\U000e0063\U000e006c\U000e0061\U000e0070\U000e007f" - FLAG_FOR_ZANJAN_IR_11 = "\U0001f3f4\U000e0069\U000e0072\U000e0031\U000e0031\U000e007f" - FLAG_FOR_BRANDENBURG_DE_BB = "\U0001f3f4\U000e0064\U000e0065\U000e0062\U000e0062\U000e007f" - FLAG_FOR_BISTRICA_OB_SOTLI_SI_149 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0034\U000e0039\U000e007f" - MAHJONG_TILE_NORTH_WIND = "\U0001f003" - FLAG_FOR_ALABAMA_US_AL = "\U0001f3f4\U000e0075\U000e0073\U000e0061\U000e006c\U000e007f" - FLAG_FOR_AL_RAYYAN_QA_RA = "\U0001f3f4\U000e0071\U000e0061\U000e0072\U000e0061\U000e007f" - LOWER_RIGHT_PENCIL = "\u270e" - FLAG_FOR_SKRUNDA_LV_093 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0039\U000e0033\U000e007f" - NUMBER_SIGN = "#\ufe0f" - EMPTY_NOTE_PAGE = "\U0001f5c6" - DIGIT_FOUR = "4\ufe0f" - FLAG_FOR_KIDAL_ML_8 = "\U0001f3f4\U000e006d\U000e006c\U000e0038\U000e007f" - FLAG_FOR_BACAU_RO_BC = "\U0001f3f4\U000e0072\U000e006f\U000e0062\U000e0063\U000e007f" - BACK_OF_ENVELOPE = "\U0001f582" - MAN_ZOMBIE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9df\U0001f3fc\u200d\u2642\ufe0f" - FLAG_FOR_BURGENLAND_AT_1 = "\U0001f3f4\U000e0061\U000e0074\U000e0031\U000e007f" - FLAG_FOR_KAYANGEL_PW_100 = "\U0001f3f4\U000e0070\U000e0077\U000e0031\U000e0030\U000e0030\U000e007f" - FLAG_FOR_TOPLICA_RS_21 = "\U0001f3f4\U000e0072\U000e0073\U000e0032\U000e0031\U000e007f" - FLAG_FOR_KRASNODAR_KRAI_RU_KDA = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0064\U000e0061\U000e007f" - FLAG_FOR_LAUTEM_TL_LA = "\U0001f3f4\U000e0074\U000e006c\U000e006c\U000e0061\U000e007f" - UPPER_RIGHT_PENCIL = "\u2710" - FLAG_FOR_BANGKOK_TH_10 = "\U0001f3f4\U000e0074\U000e0068\U000e0031\U000e0030\U000e007f" - FLAG_FOR_BOUGAINVILLE_PG_NSB = "\U0001f3f4\U000e0070\U000e0067\U000e006e\U000e0073\U000e0062\U000e007f" - FLAG_FOR_GRENADINES_VC_06 = "\U0001f3f4\U000e0076\U000e0063\U000e0030\U000e0036\U000e007f" - WIRED_KEYBOARD = "\U0001f5ae" - FLAG_FOR_KABUL_AF_KAB = "\U0001f3f4\U000e0061\U000e0066\U000e006b\U000e0061\U000e0062\U000e007f" - TAG_LATIN_CAPITAL_LETTER_J = "\U000e004a" - FLAG_FOR_AMAZONAS_CO_AMA = "\U0001f3f4\U000e0063\U000e006f\U000e0061\U000e006d\U000e0061\U000e007f" - DIGIT_NINE = "9\ufe0f" - FLAG_FOR_TASMAN_NZ_TAS = "\U0001f3f4\U000e006e\U000e007a\U000e0074\U000e0061\U000e0073\U000e007f" - FLAG_FOR_STYRIA_AT_6 = "\U0001f3f4\U000e0061\U000e0074\U000e0036\U000e007f" - FLAG_FOR_GABORONE_BW_GA = "\U0001f3f4\U000e0062\U000e0077\U000e0067\U000e0061\U000e007f" - FLAG_FOR_SAINT_MARK_GD_05 = "\U0001f3f4\U000e0067\U000e0064\U000e0030\U000e0035\U000e007f" - FLAG_FOR_VALLE_DEL_CAUCA_CO_VAC = "\U0001f3f4\U000e0063\U000e006f\U000e0076\U000e0061\U000e0063\U000e007f" - FLAG_FOR_KHAKASSIA_RU_KK = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e006b\U000e007f" - FLAG_FOR_MISRATA_LY_MI = "\U0001f3f4\U000e006c\U000e0079\U000e006d\U000e0069\U000e007f" - FLAG_FOR_QUEENSLAND_AU_QLD = "\U0001f3f4\U000e0061\U000e0075\U000e0071\U000e006c\U000e0064\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_OSAKA_JP_27 = "\U0001f3f4\U000e006a\U000e0070\U000e0032\U000e0037\U000e007f" - FLAG_FOR_MICHOACAN_MX_MIC = "\U0001f3f4\U000e006d\U000e0078\U000e006d\U000e0069\U000e0063\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f467\U0001f3fe" - FAMILY_MAN_WOMAN_BOY_GIRL = "\U0001f468\u200d\U0001f469\u200d\U0001f466\u200d\U0001f467" - KISS_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - BLACK_UP_POINTING_BACKHAND_INDEX = "\U0001f5a2" - RIGHT_SPEAKER = "\U0001f568" - COMBINING_ENCLOSING_KEYCAP = "\u20e3" - FLAG_FOR_AZUAY_EC_A = "\U0001f3f4\U000e0065\U000e0063\U000e0061\U000e007f" - FLAG_FOR_LUHANSHCHYNA_UA_09 = "\U0001f3f4\U000e0075\U000e0061\U000e0030\U000e0039\U000e007f" - FLAG_FOR_MAHARASHTRA_IN_MH = "\U0001f3f4\U000e0069\U000e006e\U000e006d\U000e0068\U000e007f" - UPPER_RIGHT_SHADOWED_WHITE_CIRCLE = "\U0001f53f" - FLAG_FOR_INSULAR_GQ_I = "\U0001f3f4\U000e0067\U000e0071\U000e0069\U000e007f" - JUPITER = "\u2643" - FLAG_FOR_AKKAR_LB_AK = "\U0001f3f4\U000e006c\U000e0062\U000e0061\U000e006b\U000e007f" - FLAG_FOR_SOHAG_EG_SHG = "\U0001f3f4\U000e0065\U000e0067\U000e0073\U000e0068\U000e0067\U000e007f" - FLAG_FOR_MOHELI_KM_M = "\U0001f3f4\U000e006b\U000e006d\U000e006d\U000e007f" - FLAG_FOR_AL_AHMADI_KW_AH = "\U0001f3f4\U000e006b\U000e0077\U000e0061\U000e0068\U000e007f" - WOMAN_IN_TUXEDO_LIGHT_SKIN_TONE = "\U0001f935\U0001f3fb\u200d\u2640\ufe0f" - FLAG_FOR_GUADALCANAL_SB_GU = "\U0001f3f4\U000e0073\U000e0062\U000e0067\U000e0075\U000e007f" - FLAG_FOR_CIBITOKE_BI_CI = "\U0001f3f4\U000e0062\U000e0069\U000e0063\U000e0069\U000e007f" - WOMAN_ZOMBIE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9df\U0001f3fc\u200d\u2640\ufe0f" - FLAG_FOR_BAS_UELE_CD_BU = "\U0001f3f4\U000e0063\U000e0064\U000e0062\U000e0075\U000e007f" - FLAG_FOR_NEVIS_KN_N = "\U0001f3f4\U000e006b\U000e006e\U000e006e\U000e007f" - FLAG_FOR_BONAIRE_BQ_BO = "\U0001f3f4\U000e0062\U000e0071\U000e0062\U000e006f\U000e007f" - FLAG_FOR_ANCASH_PE_ANC = "\U0001f3f4\U000e0070\U000e0065\U000e0061\U000e006e\U000e0063\U000e007f" - CAR_SLIDING = "\u26d0" - DIGRAM_FOR_LESSER_YANG = "\u268e" - THREE_NETWORKED_COMPUTERS = "\U0001f5a7" - FLAG_FOR_ASUNCION_PY_ASU = "\U0001f3f4\U000e0070\U000e0079\U000e0061\U000e0073\U000e0075\U000e007f" - CROSS_POMMEE_WITH_HALF_CIRCLE_BELOW = "\U0001f541" - FLAG_FOR_TOLIMA_CO_TOL = "\U0001f3f4\U000e0063\U000e006f\U000e0074\U000e006f\U000e006c\U000e007f" - TAG_DIGIT_ONE = "\U000e0031" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_JEWISH_RU_YEV = "\U0001f3f4\U000e0072\U000e0075\U000e0079\U000e0065\U000e0076\U000e007f" - FLAG_FOR_LA_PAZ_HN_LP = "\U0001f3f4\U000e0068\U000e006e\U000e006c\U000e0070\U000e007f" - FLAG_FOR_RIO_SAN_JUAN_NI_SJ = "\U0001f3f4\U000e006e\U000e0069\U000e0073\U000e006a\U000e007f" - FLAG_FOR_PAYS_DE_LA_LOIRE_FR_PDL = "\U0001f3f4\U000e0066\U000e0072\U000e0070\U000e0064\U000e006c\U000e007f" - FLAG_FOR_RIVERS_NG_RI = "\U0001f3f4\U000e006e\U000e0067\U000e0072\U000e0069\U000e007f" - OLD_PERSONAL_COMPUTER = "\U0001f5b3" - FLAG_FOR_DAEGU_KR_27 = "\U0001f3f4\U000e006b\U000e0072\U000e0032\U000e0037\U000e007f" - EMPTY_NOTE_PAD = "\U0001f5c7" - FLAG_FOR_SHAN_MM_17 = "\U0001f3f4\U000e006d\U000e006d\U000e0031\U000e0037\U000e007f" - BLACK_FLAG_2 = "\u2691" - MAHJONG_TILE_SEVEN_OF_CHARACTERS = "\U0001f00d" - FAMILY_MAN_BOY_GIRL = "\U0001f468\u200d\U0001f466\u200d\U0001f467" - FLAG_FOR_ADANA_TR_01 = "\U0001f3f4\U000e0074\U000e0072\U000e0030\U000e0031\U000e007f" - TAG_LATIN_CAPITAL_LETTER_C = "\U000e0043" - TWO_BUTTON_MOUSE = "\U0001f5b0" - ASTERISK = "*\ufe0f" - MAHJONG_TILE_FOUR_OF_CIRCLES = "\U0001f01c" - FLAG_FOR_KAPISA_AF_KAP = "\U0001f3f4\U000e0061\U000e0066\U000e006b\U000e0061\U000e0070\U000e007f" - FLAG_FOR_MON_MM_15 = "\U0001f3f4\U000e006d\U000e006d\U000e0031\U000e0035\U000e007f" - FLAG_FOR_AL_BURAIMI_OM_BU = "\U0001f3f4\U000e006f\U000e006d\U000e0062\U000e0075\U000e007f" - FLAG_FOR_AGALEGA_MU_AG = "\U0001f3f4\U000e006d\U000e0075\U000e0061\U000e0067\U000e007f" - ONE_BUTTON_MOUSE = "\U0001f5af" - FLAG_FOR_LOGAR_AF_LOG = "\U0001f3f4\U000e0061\U000e0066\U000e006c\U000e006f\U000e0067\U000e007f" - FLAG_FOR_BEL_OMBRE_SC_10 = "\U0001f3f4\U000e0073\U000e0063\U000e0031\U000e0030\U000e007f" - FLAG_FOR_ORANGE_WALK_BZ_OW = "\U0001f3f4\U000e0062\U000e007a\U000e006f\U000e0077\U000e007f" - MALE_WITH_STROKE_AND_MALE_AND_FEMALE_SIGN = "\u26a7" - FLAG_FOR_KANDAHAR_AF_KAN = "\U0001f3f4\U000e0061\U000e0066\U000e006b\U000e0061\U000e006e\U000e007f" - TAPE_CARTRIDGE = "\U0001f5ad" - FLAG_FOR_ULAANBAATAR_MN_1 = "\U0001f3f4\U000e006d\U000e006e\U000e0031\U000e007f" - FLAG_FOR_FARYAB_AF_FYB = "\U0001f3f4\U000e0061\U000e0066\U000e0066\U000e0079\U000e0062\U000e007f" - TAG_LATIN_SMALL_LETTER_F = "\U000e0066" - FLAG_FOR_PARWAN_AF_PAR = "\U0001f3f4\U000e0061\U000e0066\U000e0070\U000e0061\U000e0072\U000e007f" - FLAG_FOR_NIMRUZ_AF_NIM = "\U0001f3f4\U000e0061\U000e0066\U000e006e\U000e0069\U000e006d\U000e007f" - FLAG_FOR_HIIU_EE_39 = "\U0001f3f4\U000e0065\U000e0065\U000e0033\U000e0039\U000e007f" - FLAG_FOR_EXTREMADURA_ES_EX = "\U0001f3f4\U000e0065\U000e0073\U000e0065\U000e0078\U000e007f" - FLAG_FOR_SABA_BQ_SA = "\U0001f3f4\U000e0062\U000e0071\U000e0073\U000e0061\U000e007f" - FLAG_FOR_KARLOVAC_HR_04 = "\U0001f3f4\U000e0068\U000e0072\U000e0030\U000e0034\U000e007f" - FLAG_FOR_BROD_POSAVINA_HR_12 = "\U0001f3f4\U000e0068\U000e0072\U000e0031\U000e0032\U000e007f" - FLAG_FOR_NANGARHAR_AF_NAN = "\U0001f3f4\U000e0061\U000e0066\U000e006e\U000e0061\U000e006e\U000e007f" - MAHJONG_TILE_SEVEN_OF_CIRCLES = "\U0001f01f" - TRIGRAM_FOR_HEAVEN = "\u2630" - DIGIT_SEVEN = "7\ufe0f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - RECYCLING_SYMBOL_FOR_TYPE_1_PLASTICS = "\u2673" - FLAG_FOR_CORSE_FR_COR = "\U0001f3f4\U000e0066\U000e0072\U000e0063\U000e006f\U000e0072\U000e007f" - MAN_WITH_HEADSCARF_MEDIUM_SKIN_TONE = "\U0001f9d5\U0001f3fd\u200d\u2642\ufe0f" - FLAG_FOR_HAMADAN_IR_24 = "\U0001f3f4\U000e0069\U000e0072\U000e0032\U000e0034\U000e007f" - FLAG_FOR_FARS_IR_14 = "\U0001f3f4\U000e0069\U000e0072\U000e0031\U000e0034\U000e007f" - FLAG_FOR_FRENCH_GUIANA_FR_GF = "\U0001f3f4\U000e0066\U000e0072\U000e0067\U000e0066\U000e007f" - FLAG_FOR_TICINO_CH_TI = "\U0001f3f4\U000e0063\U000e0068\U000e0074\U000e0069\U000e007f" - FLAG_FOR_BOR_RS_14 = "\U0001f3f4\U000e0072\U000e0073\U000e0031\U000e0034\U000e007f" - FLAG_FOR_UTTARADIT_TH_53 = "\U0001f3f4\U000e0074\U000e0068\U000e0035\U000e0033\U000e007f" - TAG_LATIN_SMALL_LETTER_M = "\U000e006d" - FLAG_FOR_BAMAKO_ML_BKO = "\U0001f3f4\U000e006d\U000e006c\U000e0062\U000e006b\U000e006f\U000e007f" - FLAG_FOR_ESPIRITO_SANTO_BR_ES = "\U0001f3f4\U000e0062\U000e0072\U000e0065\U000e0073\U000e007f" - TAG_LATIN_SMALL_LETTER_R = "\U000e0072" - FLAG_FOR_BOLIKHAMSAI_LA_BL = "\U0001f3f4\U000e006c\U000e0061\U000e0062\U000e006c\U000e007f" - BULLHORN_WITH_SOUND_WAVES = "\U0001f56c" - FLAG_FOR_HALLAND_SE_N = "\U0001f3f4\U000e0073\U000e0065\U000e006e\U000e007f" - FLAG_FOR_UPPER_DEMERARA_BERBICE_GY_UD = "\U0001f3f4\U000e0067\U000e0079\U000e0075\U000e0064\U000e007f" - WOMAN_ZOMBIE_MEDIUM_SKIN_TONE = "\U0001f9df\U0001f3fd\u200d\u2640\ufe0f" - FLAG_FOR_ZIROVNICA_SI_192 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0039\U000e0032\U000e007f" - FLAG_FOR_TAITUNG_TW_TTT = "\U0001f3f4\U000e0074\U000e0077\U000e0074\U000e0074\U000e0074\U000e007f" - FLAG_FOR_NANUMANGA_TV_NMG = "\U0001f3f4\U000e0074\U000e0076\U000e006e\U000e006d\U000e0067\U000e007f" - FLAG_FOR_TUNAPUNA_PIARCO_TT_TUP = "\U0001f3f4\U000e0074\U000e0074\U000e0074\U000e0075\U000e0070\U000e007f" - TAG_DIGIT_SEVEN = "\U000e0037" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - KEYBOARD_AND_MOUSE = "\U0001f5a6" - MAHJONG_TILE_GREEN_DRAGON = "\U0001f005" - FLAG_FOR_CEUTA_ES_CE = "\U0001f3f4\U000e0065\U000e0073\U000e0063\U000e0065\U000e007f" - KISS_MAN_MEDIUM_SKIN_TONE_WOMAN = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - FLAG_FOR_SABARAGAMUWA_LK_9 = "\U0001f3f4\U000e006c\U000e006b\U000e0039\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f466\U0001f3fe" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - FLAG_FOR_BUTNAN_LY_BU = "\U0001f3f4\U000e006c\U000e0079\U000e0062\U000e0075\U000e007f" - FLAG_FOR_COLIMA_MX_COL = "\U0001f3f4\U000e006d\U000e0078\U000e0063\U000e006f\U000e006c\U000e007f" - FLAG_FOR_QUEBEC_CA_QC = "\U0001f3f4\U000e0063\U000e0061\U000e0071\U000e0063\U000e007f" - WHITE_DOWN_POINTING_INDEX = "\u261f" - FLAG_FOR_CUNDINAMARCA_CO_CUN = "\U0001f3f4\U000e0063\U000e006f\U000e0063\U000e0075\U000e006e\U000e007f" - TAG_LATIN_CAPITAL_LETTER_D = "\U000e0044" - FLAG_FOR_DAMASCUS_SY_DI = "\U0001f3f4\U000e0073\U000e0079\U000e0064\U000e0069\U000e007f" - FLAG_FOR_DUBAI_AE_DU = "\U0001f3f4\U000e0061\U000e0065\U000e0064\U000e0075\U000e007f" - SHIBUYA = "\ue50a" - FLAG_FOR_KAYES_ML_1 = "\U0001f3f4\U000e006d\U000e006c\U000e0031\U000e007f" - FLAG_FOR_CEARA_BR_CE = "\U0001f3f4\U000e0062\U000e0072\U000e0063\U000e0065\U000e007f" - FLAG_FOR_SHARJAH_AE_SH = "\U0001f3f4\U000e0061\U000e0065\U000e0073\U000e0068\U000e007f" - FLAG_FOR_EASTERN_IS_7 = "\U0001f3f4\U000e0069\U000e0073\U000e0037\U000e007f" - WHITE_CHESS_BISHOP = "\u2657" - FLAG_FOR_AFAR_ET_AF = "\U0001f3f4\U000e0065\U000e0074\U000e0061\U000e0066\U000e007f" - TAG_QUESTION_MARK = "\U000e003f" - FAMILY_WOMAN_GIRL_BABY = "\U0001f469\u200d\U0001f467\u200d\U0001f476" - FLAG_FOR_RADENCI_SI_100 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0030\U000e0030\U000e007f" - FLAG_FOR_LIMA_REGION_PE_LIM = "\U0001f3f4\U000e0070\U000e0065\U000e006c\U000e0069\U000e006d\U000e007f" - FLAG_FOR_NORTH_CENTRAL_PROVINCE_MV_NC = "\U0001f3f4\U000e006d\U000e0076\U000e006e\U000e0063\U000e007f" - DOCUMENT_WITH_PICTURE = "\U0001f5bb" - FLAG_FOR_VALAIS_CH_VS = "\U0001f3f4\U000e0063\U000e0068\U000e0076\U000e0073\U000e007f" - FLAG_FOR_BAY_OF_PLENTY_NZ_BOP = "\U0001f3f4\U000e006e\U000e007a\U000e0062\U000e006f\U000e0070\U000e007f" - TAG_LATIN_CAPITAL_LETTER_P = "\U000e0050" - FLAG_FOR_BASSE_KOTTO_CF_BK = "\U0001f3f4\U000e0063\U000e0066\U000e0062\U000e006b\U000e007f" - DOCUMENT_WITH_TEXT_AND_PICTURE = "\U0001f5ba" - TAG_DIGIT_NINE = "\U000e0039" - WOMAN_IN_TUXEDO_MEDIUM_DARK_SKIN_TONE = "\U0001f935\U0001f3fe\u200d\u2640\ufe0f" - FLAG_FOR_ZURICH_CH_ZH = "\U0001f3f4\U000e0063\U000e0068\U000e007a\U000e0068\U000e007f" - MAHJONG_TILE_THREE_OF_CIRCLES = "\U0001f01b" - FLAG_FOR_LOG_DRAGOMER_SI_208 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0030\U000e0038\U000e007f" - MAN_ZOMBIE_DARK_SKIN_TONE = "\U0001f9df\U0001f3ff\u200d\u2642\ufe0f" - FLAG_FOR_ARIZONA_US_AZ = "\U0001f3f4\U000e0075\U000e0073\U000e0061\U000e007a\U000e007f" - FLAG_FOR_PAKTIKA_AF_PKA = "\U0001f3f4\U000e0061\U000e0066\U000e0070\U000e006b\U000e0061\U000e007f" - PROHIBITED_SIGN = "\U0001f6c7" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - FLAG_FOR_ALASKA_US_AK = "\U0001f3f4\U000e0075\U000e0073\U000e0061\U000e006b\U000e007f" - FLAG_FOR_SOOL_SO_SO = "\U0001f3f4\U000e0073\U000e006f\U000e0073\U000e006f\U000e007f" - FLAG_FOR_LAGHMAN_AF_LAG = "\U0001f3f4\U000e0061\U000e0066\U000e006c\U000e0061\U000e0067\U000e007f" - BLACK_CIRCLE_WITH_TWO_WHITE_DOTS = "\u2689" - FLAG_FOR_NUKULAELAE_TV_NKL = "\U0001f3f4\U000e0074\U000e0076\U000e006e\U000e006b\U000e006c\U000e007f" - FLAG_FOR_ABKHAZIA_GE_AB = "\U0001f3f4\U000e0067\U000e0065\U000e0061\U000e0062\U000e007f" - FLAG_FOR_ESCH_SUR_ALZETTE_LU_ES = "\U0001f3f4\U000e006c\U000e0075\U000e0065\U000e0073\U000e007f" - FLAG_FOR_MANIPUR_IN_MN = "\U0001f3f4\U000e0069\U000e006e\U000e006d\U000e006e\U000e007f" - FLAG_FOR_HELMAND_AF_HEL = "\U0001f3f4\U000e0061\U000e0066\U000e0068\U000e0065\U000e006c\U000e007f" - FLAG_FOR_VICHADA_CO_VID = "\U0001f3f4\U000e0063\U000e006f\U000e0076\U000e0069\U000e0064\U000e007f" - DOCUMENT = "\U0001f5ce" - FLAG_FOR_ISLAMABAD_PK_IS = "\U0001f3f4\U000e0070\U000e006b\U000e0069\U000e0073\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb" - FLAG_FOR_RAS_AL_KHAIMAH_AE_RK = "\U0001f3f4\U000e0061\U000e0065\U000e0072\U000e006b\U000e007f" - FAMILY_MAN_BABY = "\U0001f468\u200d\U0001f476" - FLAG_FOR_KONYA_TR_42 = "\U0001f3f4\U000e0074\U000e0072\U000e0034\U000e0032\U000e007f" - FLAG_FOR_CANKIRI_TR_18 = "\U0001f3f4\U000e0074\U000e0072\U000e0031\U000e0038\U000e007f" - FLAG_FOR_GANJA_AZ_GA = "\U0001f3f4\U000e0061\U000e007a\U000e0067\U000e0061\U000e007f" - MAHJONG_TILE_SIX_OF_CHARACTERS = "\U0001f00c" - TAG_LATIN_CAPITAL_LETTER_M = "\U000e004d" - FLAG_FOR_OITA_JP_44 = "\U0001f3f4\U000e006a\U000e0070\U000e0034\U000e0034\U000e007f" - FLAG_FOR_GUATEMALA_GT_GU = "\U0001f3f4\U000e0067\U000e0074\U000e0067\U000e0075\U000e007f" - FLAG_FOR_NORTH_BRABANT_NL_NB = "\U0001f3f4\U000e006e\U000e006c\U000e006e\U000e0062\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f476\U0001f3fb" - KISS_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_GILBERT_ISLANDS_KI_G = "\U0001f3f4\U000e006b\U000e0069\U000e0067\U000e007f" - FLAG_FOR_PAKTIA_AF_PIA = "\U0001f3f4\U000e0061\U000e0066\U000e0070\U000e0069\U000e0061\U000e007f" - FLAG_FOR_PARDUBICKY_KRAJ_CZ_53 = "\U0001f3f4\U000e0063\U000e007a\U000e0035\U000e0033\U000e007f" - FLAG_FOR_SALCININKAI_LT_42 = "\U0001f3f4\U000e006c\U000e0074\U000e0034\U000e0032\U000e007f" - BALLOT_BOX_WITH_BOLD_CHECK = "\U0001f5f9" - FLAG_FOR_CORUM_TR_19 = "\U0001f3f4\U000e0074\U000e0072\U000e0031\U000e0039\U000e007f" - FLAG_FOR_SAMANGAN_AF_SAM = "\U0001f3f4\U000e0061\U000e0066\U000e0073\U000e0061\U000e006d\U000e007f" - FLAG_FOR_MASAYA_NI_MS = "\U0001f3f4\U000e006e\U000e0069\U000e006d\U000e0073\U000e007f" - FLAG_FOR_CSONGRAD_HU_CS = "\U0001f3f4\U000e0068\U000e0075\U000e0063\U000e0073\U000e007f" - FLAG_FOR_AKSARAY_TR_68 = "\U0001f3f4\U000e0074\U000e0072\U000e0036\U000e0038\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - FLAG_FOR_SAINT_MARY_AG_05 = "\U0001f3f4\U000e0061\U000e0067\U000e0030\U000e0035\U000e007f" - WOMAN_IN_BUSINESS_SUIT_LEVITATING_DARK_SKIN_TONE = "\U0001f574\U0001f3ff\u200d\u2640\ufe0f" - TAG_COMMERCIAL_AT = "\U000e0040" - FLAG_FOR_BERANE_ME_03 = "\U0001f3f4\U000e006d\U000e0065\U000e0030\U000e0033\U000e007f" - FLAG_FOR_MARYLAND_LR_MY = "\U0001f3f4\U000e006c\U000e0072\U000e006d\U000e0079\U000e007f" - FLAG_FOR_KARA_TG_K = "\U0001f3f4\U000e0074\U000e0067\U000e006b\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f466\U0001f3fe" - OPTICAL_DISC_ICON = "\U0001f5b8" - FLAG_FOR_MASCARA_DZ_29 = "\U0001f3f4\U000e0064\U000e007a\U000e0032\U000e0039\U000e007f" - THREE_RAYS_LEFT = "\U0001f5e6" - RECYCLING_SYMBOL_FOR_TYPE_3_PLASTICS = "\u2675" - FLAG_FOR_REDONDA_AG_11 = "\U0001f3f4\U000e0061\U000e0067\U000e0031\U000e0031\U000e007f" - FAX_ICON = "\U0001f5b7" - FLAG_FOR_GAGAUZIA_MD_GA = "\U0001f3f4\U000e006d\U000e0064\U000e0067\U000e0061\U000e007f" - THREE_SPEECH_BUBBLES = "\U0001f5eb" - TAG_LATIN_SMALL_LETTER_S = "\U000e0073" - FLAG_FOR_WAKAYAMA_JP_30 = "\U0001f3f4\U000e006a\U000e0070\U000e0033\U000e0030\U000e007f" - FLAG_FOR_SZEKSZARD_HU_SS = "\U0001f3f4\U000e0068\U000e0075\U000e0073\U000e0073\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f466\U0001f3fb" - OVERLAP = "\U0001f5d7" - FLAG_FOR_HSINCHU_COUNTY_TW_HSQ = "\U0001f3f4\U000e0074\U000e0077\U000e0068\U000e0073\U000e0071\U000e007f" - MAHJONG_TILE_EAST_WIND = "\U0001f000" - FLAG_FOR_GOMBE_NG_GO = "\U0001f3f4\U000e006e\U000e0067\U000e0067\U000e006f\U000e007f" - FLAG_FOR_VILNIUS_LT_58 = "\U0001f3f4\U000e006c\U000e0074\U000e0035\U000e0038\U000e007f" - TAG_LATIN_SMALL_LETTER_O = "\U000e006f" - PAGE = "\U0001f5cf" - STOCK_CHART = "\U0001f5e0" - FLAG_FOR_SAINT_JOHN_AG_04 = "\U0001f3f4\U000e0061\U000e0067\U000e0030\U000e0034\U000e007f" - FLAG_FOR_VERMONT_US_VT = "\U0001f3f4\U000e0075\U000e0073\U000e0076\U000e0074\U000e007f" - FLAG_FOR_MURCIA_REGION_ES_MC = "\U0001f3f4\U000e0065\U000e0073\U000e006d\U000e0063\U000e007f" - FLAG_FOR_PWANI_TZ_19 = "\U0001f3f4\U000e0074\U000e007a\U000e0031\U000e0039\U000e007f" - FLAG_FOR_SOMALI_ET_SO = "\U0001f3f4\U000e0065\U000e0074\U000e0073\U000e006f\U000e007f" - MAN_WITH_HEADSCARF_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d5\U0001f3fc\u200d\u2642\ufe0f" - DESKTOP_WINDOW = "\U0001f5d4" - FLAG_FOR_MADONA_LV_059 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0035\U000e0039\U000e007f" - FLAG_FOR_SING_BURI_TH_17 = "\U0001f3f4\U000e0074\U000e0068\U000e0031\U000e0037\U000e007f" - FLAG_FOR_MOKA_MU_MO = "\U0001f3f4\U000e006d\U000e0075\U000e006d\U000e006f\U000e007f" - KISS_MAN_LIGHT_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc" - BLACK_LEFT_POINTING_BACKHAND_INDEX = "\U0001f59c" - REVERSED_VICTORY_HAND = "\U0001f594" - FAMILY_WOMAN_WOMAN_BABY = "\U0001f469\u200d\U0001f469\u200d\U0001f476" - FLAG_FOR_MICOUD_LC_08 = "\U0001f3f4\U000e006c\U000e0063\U000e0030\U000e0038\U000e007f" - TRIGRAM_FOR_MOUNTAIN = "\u2636" - WOMAN_WITH_HEADSCARF_2 = "\U0001f9d5\u200d\u2640\ufe0f" - FLAG_FOR_MARCHE_IT_57 = "\U0001f3f4\U000e0069\U000e0074\U000e0035\U000e0037\U000e007f" - MAHJONG_TILE_FIVE_OF_CIRCLES = "\U0001f01d" - FLAG_FOR_COVA_LIMA_TL_CO = "\U0001f3f4\U000e0074\U000e006c\U000e0063\U000e006f\U000e007f" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_BEL_AIR_SC_09 = "\U0001f3f4\U000e0073\U000e0063\U000e0030\U000e0039\U000e007f" - FLAG_FOR_VILA_REAL_PT_17 = "\U0001f3f4\U000e0070\U000e0074\U000e0031\U000e0037\U000e007f" - FLAG_FOR_MACAU_SAR_CHINA_CN_92 = "\U0001f3f4\U000e0063\U000e006e\U000e0039\U000e0032\U000e007f" - FLAG_FOR_SOUTH_DAKOTA_US_SD = "\U0001f3f4\U000e0075\U000e0073\U000e0073\U000e0064\U000e007f" - FLAG_FOR_WEST_PANAMA_PA_10 = "\U0001f3f4\U000e0070\U000e0061\U000e0031\U000e0030\U000e007f" - FLAG_FOR_CHIAPAS_MX_CHP = "\U0001f3f4\U000e006d\U000e0078\U000e0063\U000e0068\U000e0070\U000e007f" - FLAG_FOR_KUKES_COUNTY_AL_07 = "\U0001f3f4\U000e0061\U000e006c\U000e0030\U000e0037\U000e007f" - PAGES = "\U0001f5d0" - TAG_LATIN_CAPITAL_LETTER_L = "\U000e004c" - EMPTY_PAGES = "\U0001f5cd" - FLAG_FOR_SVETA_ANA_SI_181 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0038\U000e0031\U000e007f" - FLAG_FOR_SKRIVERI_LV_092 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0039\U000e0032\U000e007f" - FLAG_FOR_KITUI_KE_18 = "\U0001f3f4\U000e006b\U000e0065\U000e0031\U000e0038\U000e007f" - FIRST_QUARTER_MOON_2 = "\u263d" - FLAG_FOR_PELELIU_PW_350 = "\U0001f3f4\U000e0070\U000e0077\U000e0033\U000e0035\U000e0030\U000e007f" - FLAG_FOR_MARY_TM_M = "\U0001f3f4\U000e0074\U000e006d\U000e006d\U000e007f" - FLAG_FOR_UPPER_SOUTH_PROVINCE_MV_US = "\U0001f3f4\U000e006d\U000e0076\U000e0075\U000e0073\U000e007f" - FLAG_FOR_MAKKAH_SA_02 = "\U0001f3f4\U000e0073\U000e0061\U000e0030\U000e0032\U000e007f" - FLAG_FOR_ZEBBUG_GOZO_MT_65 = "\U0001f3f4\U000e006d\U000e0074\U000e0036\U000e0035\U000e007f" - FLAG_FOR_OSMANIYE_TR_80 = "\U0001f3f4\U000e0074\U000e0072\U000e0038\U000e0030\U000e007f" - BLACK_TWO_WAY_LEFT_WAY_TRAFFIC = "\u26d6" - FLAG_FOR_LAGOS_NG_LA = "\U0001f3f4\U000e006e\U000e0067\U000e006c\U000e0061\U000e007f" - MAHJONG_TILE_JOKER = "\U0001f02a" - FLAG_FOR_KARS_TR_36 = "\U0001f3f4\U000e0074\U000e0072\U000e0033\U000e0036\U000e007f" - FLAG_FOR_NAYARIT_MX_NAY = "\U0001f3f4\U000e006d\U000e0078\U000e006e\U000e0061\U000e0079\U000e007f" - CUP_ON_BLACK_SQUARE = "\u26fe" - FLAG_FOR_RIVERCESS_LR_RI = "\U0001f3f4\U000e006c\U000e0072\U000e0072\U000e0069\U000e007f" - THREE_RAYS_ABOVE = "\U0001f5e4" - FLAG_FOR_UABOE_NR_13 = "\U0001f3f4\U000e006e\U000e0072\U000e0031\U000e0033\U000e007f" - TAG_LATIN_SMALL_LETTER_P = "\U000e0070" - FLAG_FOR_MGARR_MT_31 = "\U0001f3f4\U000e006d\U000e0074\U000e0033\U000e0031\U000e007f" - FLAG_FOR_SALAVAN_LA_SL = "\U0001f3f4\U000e006c\U000e0061\U000e0073\U000e006c\U000e007f" - FLAG_FOR_AJMAN_AE_AJ = "\U0001f3f4\U000e0061\U000e0065\U000e0061\U000e006a\U000e007f" - FLAG_FOR_DEMIR_KAPIJA_MK_24 = "\U0001f3f4\U000e006d\U000e006b\U000e0032\U000e0034\U000e007f" - FLAG_FOR_KHABAROVSK_KRAI_RU_KHA = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0068\U000e0061\U000e007f" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - FLAG_FOR_WEST_KAZAKHSTAN_KZ_ZAP = "\U0001f3f4\U000e006b\U000e007a\U000e007a\U000e0061\U000e0070\U000e007f" - TAG_LATIN_SMALL_LETTER_W = "\U000e0077" - ADI_SHAKTI = "\u262c" - BOYS_SYMBOL = "\U0001f6c9" - FLAG_FOR_NORTHERN_BAHR_EL_GHAZAL_SS_BN = "\U0001f3f4\U000e0073\U000e0073\U000e0062\U000e006e\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_LINDI_TZ_12 = "\U0001f3f4\U000e0074\U000e007a\U000e0031\U000e0032\U000e007f" - FLAG_FOR_KUNAR_AF_KNR = "\U0001f3f4\U000e0061\U000e0066\U000e006b\U000e006e\U000e0072\U000e007f" - FOLDER = "\U0001f5c0" - COUPLE_WITH_HEART_MAN_MAN_LIGHT_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - TAG_NUMBER_SIGN = "\U000e0023" - FLAG_FOR_VALENCIAN_COMMUNITY_ES_VC = "\U0001f3f4\U000e0065\U000e0073\U000e0076\U000e0063\U000e007f" - TAG_RIGHT_CURLY_BRACKET = "\U000e007d" - FLAG_FOR_SAINT_PAUL_AG_06 = "\U0001f3f4\U000e0061\U000e0067\U000e0030\U000e0036\U000e007f" - WOMAN_IN_TUXEDO = "\U0001f935\u200d\u2640\ufe0f" - FLAG_FOR_SICILY_IT_82 = "\U0001f3f4\U000e0069\U000e0074\U000e0038\U000e0032\U000e007f" - FLAG_FOR_LEZHE_COUNTY_AL_08 = "\U0001f3f4\U000e0061\U000e006c\U000e0030\U000e0038\U000e007f" - FLAG_FOR_CHIHUAHUA_MX_CHH = "\U0001f3f4\U000e006d\U000e0078\U000e0063\U000e0068\U000e0068\U000e007f" - BLACK_RIGHT_POINTING_BACKHAND_INDEX = "\U0001f59d" - WHITE_LATIN_CROSS = "\U0001f546" - FLAG_FOR_NORD_OUEST_HT_NO = "\U0001f3f4\U000e0068\U000e0074\U000e006e\U000e006f\U000e007f" - DIGIT_ONE = "1\ufe0f" - PORTABLE_STEREO = "\U0001f4fe" - FLAG_FOR_MADINAT_ASH_SHAMAL_QA_MS = "\U0001f3f4\U000e0071\U000e0061\U000e006d\U000e0073\U000e007f" - BULLHORN = "\U0001f56b" - TAG_DIGIT_SIX = "\U000e0036" - FLAG_FOR_SIKKIM_IN_SK = "\U0001f3f4\U000e0069\U000e006e\U000e0073\U000e006b\U000e007f" - CANCELLATION_X = "\U0001f5d9" - LEFT_WRITING_HAND = "\U0001f58e" - MAHJONG_TILE_FOUR_OF_CHARACTERS = "\U0001f00a" - RINGING_BELL = "\U0001f56d" - FLAG_FOR_TIRANA_COUNTY_AL_11 = "\U0001f3f4\U000e0061\U000e006c\U000e0031\U000e0031\U000e007f" - FLAG_FOR_TRAT_TH_23 = "\U0001f3f4\U000e0074\U000e0068\U000e0032\U000e0033\U000e007f" - TAG_LATIN_SMALL_LETTER_D = "\U000e0064" - FLAG_FOR_SAMARA_RU_SAM = "\U0001f3f4\U000e0072\U000e0075\U000e0073\U000e0061\U000e006d\U000e007f" - FLAG_FOR_NGOUNIE_GA_4 = "\U0001f3f4\U000e0067\U000e0061\U000e0034\U000e007f" - BLACK_ROSETTE = "\U0001f3f6" - TAG_CIRCUMFLEX_ACCENT = "\U000e005e" - FLAG_FOR_IASI_RO_IS = "\U0001f3f4\U000e0072\U000e006f\U000e0069\U000e0073\U000e007f" - FLAG_FOR_GEORGIA_US_GA = "\U0001f3f4\U000e0075\U000e0073\U000e0067\U000e0061\U000e007f" - FLAG_FOR_DURRES_COUNTY_AL_02 = "\U0001f3f4\U000e0061\U000e006c\U000e0030\U000e0032\U000e007f" - KISS_MAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - FLAG_FOR_TAZA_AL_HOCEIMA_TAOUNATE_MA_03 = "\U0001f3f4\U000e006d\U000e0061\U000e0030\U000e0033\U000e007f" - FLAG_FOR_LOMBARDY_IT_25 = "\U0001f3f4\U000e0069\U000e0074\U000e0032\U000e0035\U000e007f" - FLAG_FOR_TRABZON_TR_61 = "\U0001f3f4\U000e0074\U000e0072\U000e0036\U000e0031\U000e007f" - FLAG_FOR_UROZGAN_AF_URU = "\U0001f3f4\U000e0061\U000e0066\U000e0075\U000e0072\U000e0075\U000e007f" - FLAG_FOR_CENTRAL_GH_CP = "\U0001f3f4\U000e0067\U000e0068\U000e0063\U000e0070\U000e007f" - WOMAN_ZOMBIE_LIGHT_SKIN_TONE = "\U0001f9df\U0001f3fb\u200d\u2640\ufe0f" - MAHJONG_TILE_SUMMER = "\U0001f027" - FLAG_FOR_KIDRICEVO_SI_045 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0034\U000e0035\U000e007f" - FLAG_FOR_RAZAVI_KHORASAN_IR_30 = "\U0001f3f4\U000e0069\U000e0072\U000e0033\U000e0030\U000e007f" - FLAG_FOR_KOTAYK_AM_KT = "\U0001f3f4\U000e0061\U000e006d\U000e006b\U000e0074\U000e007f" - TELEPHONE_RECEIVER_WITH_PAGE = "\U0001f57c" - FLAG_FOR_SHKODER_COUNTY_AL_10 = "\U0001f3f4\U000e0061\U000e006c\U000e0031\U000e0030\U000e007f" - FLAG_FOR_AL_WAKRAH_QA_WA = "\U0001f3f4\U000e0071\U000e0061\U000e0077\U000e0061\U000e007f" - TAG_LATIN_SMALL_LETTER_U = "\U000e0075" - FLAG_FOR_CHACO_AR_H = "\U0001f3f4\U000e0061\U000e0072\U000e0068\U000e007f" - BLACK_HARD_SHELL_FLOPPY_DISK = "\U0001f5aa" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f466\U0001f3fb" - FLAG_FOR_HOKKAIDO_JP_01 = "\U0001f3f4\U000e006a\U000e0070\U000e0030\U000e0031\U000e007f" - FLAG_FOR_GEGHARKUNIK_AM_GR = "\U0001f3f4\U000e0061\U000e006d\U000e0067\U000e0072\U000e007f" - FLAG_FOR_BLACK_POINT_BS_BP = "\U0001f3f4\U000e0062\U000e0073\U000e0062\U000e0070\U000e007f" - FLAG_FOR_LUXOR_EG_LX = "\U0001f3f4\U000e0065\U000e0067\U000e006c\U000e0078\U000e007f" - FLAG_FOR_WISCONSIN_US_WI = "\U0001f3f4\U000e0075\U000e0073\U000e0077\U000e0069\U000e007f" - FLAG_FOR_MONACO_VILLE_MC_MO = "\U0001f3f4\U000e006d\U000e0063\U000e006d\U000e006f\U000e007f" - FLAG_FOR_ARMAVIR_AM_AV = "\U0001f3f4\U000e0061\U000e006d\U000e0061\U000e0076\U000e007f" - MAHJONG_TILE_EIGHT_OF_BAMBOOS = "\U0001f017" - TRIGRAM_FOR_EARTH = "\u2637" - FLAG_FOR_THUA_THIEN_HUE_VN_26 = "\U0001f3f4\U000e0076\U000e006e\U000e0032\U000e0036\U000e007f" - FLAG_FOR_POINTE_NOIRE_CG_16 = "\U0001f3f4\U000e0063\U000e0067\U000e0031\U000e0036\U000e007f" - FLAG_FOR_SAKHALIN_RU_SAK = "\U0001f3f4\U000e0072\U000e0075\U000e0073\U000e0061\U000e006b\U000e007f" - TAG_LATIN_SMALL_LETTER_Z = "\U000e007a" - FLAG_FOR_PAKRUOJIS_LT_30 = "\U0001f3f4\U000e006c\U000e0074\U000e0033\U000e0030\U000e007f" - FLAG_FOR_APE_LV_009 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0030\U000e0039\U000e007f" - LOWER_RIGHT_SHADOWED_WHITE_CIRCLE = "\U0001f53e" - FLAG_FOR_ARUBA_NL_AW = "\U0001f3f4\U000e006e\U000e006c\U000e0061\U000e0077\U000e007f" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - FLAG_FOR_KIEV_UA_30 = "\U0001f3f4\U000e0075\U000e0061\U000e0033\U000e0030\U000e007f" - FLAG_FOR_PORT_SAID_EG_PTS = "\U0001f3f4\U000e0065\U000e0067\U000e0070\U000e0074\U000e0073\U000e007f" - MAXIMIZE = "\U0001f5d6" - FLAG_FOR_TRA_VINH_VN_51 = "\U0001f3f4\U000e0076\U000e006e\U000e0035\U000e0031\U000e007f" - FLAG_FOR_RIYADH_SA_01 = "\U0001f3f4\U000e0073\U000e0061\U000e0030\U000e0031\U000e007f" - GIRLS_SYMBOL = "\U0001f6ca" - FLAG_FOR_SKIKDA_DZ_21 = "\U0001f3f4\U000e0064\U000e007a\U000e0032\U000e0031\U000e007f" - FLAG_FOR_ABU_DHABI_AE_AZ = "\U0001f3f4\U000e0061\U000e0065\U000e0061\U000e007a\U000e007f" - MAHJONG_TILE_ONE_OF_CIRCLES = "\U0001f019" - BLACK_DOWN_POINTING_BACKHAND_INDEX = "\U0001f5a3" - MAHJONG_TILE_NINE_OF_CIRCLES = "\U0001f021" - FLAG_FOR_RIGA_LV_RIX = "\U0001f3f4\U000e006c\U000e0076\U000e0072\U000e0069\U000e0078\U000e007f" - FLAG_FOR_MAKIRA_ULAWA_SB_MK = "\U0001f3f4\U000e0073\U000e0062\U000e006d\U000e006b\U000e007f" - FLAG_FOR_JUTIAPA_GT_JU = "\U0001f3f4\U000e0067\U000e0074\U000e006a\U000e0075\U000e007f" - FLAG_FOR_LORESTAN_IR_20 = "\U0001f3f4\U000e0069\U000e0072\U000e0032\U000e0030\U000e007f" - FLAG_FOR_BASHKORTOSTAN_RU_BA = "\U0001f3f4\U000e0072\U000e0075\U000e0062\U000e0061\U000e007f" - FLAG_FOR_BUSAN_KR_26 = "\U0001f3f4\U000e006b\U000e0072\U000e0032\U000e0036\U000e007f" - FLAG_FOR_MWARO_BI_MW = "\U0001f3f4\U000e0062\U000e0069\U000e006d\U000e0077\U000e007f" - FLAG_FOR_ASTURIAS_ES_AS = "\U0001f3f4\U000e0065\U000e0073\U000e0061\U000e0073\U000e007f" - FLAG_FOR_ALTA_VERAPAZ_GT_AV = "\U0001f3f4\U000e0067\U000e0074\U000e0061\U000e0076\U000e007f" - FLAG_FOR_BRUNEI_MUARA_BN_BM = "\U0001f3f4\U000e0062\U000e006e\U000e0062\U000e006d\U000e007f" - FLAG_FOR_LOVRENC_NA_POHORJU_SI_167 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0036\U000e0037\U000e007f" - FLAG_FOR_WALLIS_ANDAMP_FUTUNA_FR_WF = "\U0001f3f4\U000e0066\U000e0072\U000e0077\U000e0066\U000e007f" - KISS_MAN_WOMAN_DARK_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - FLAG_FOR_LORI_AM_LO = "\U0001f3f4\U000e0061\U000e006d\U000e006c\U000e006f\U000e007f" - KISS_MAN_DARK_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - FLAG_FOR_GIZA_EG_GZ = "\U0001f3f4\U000e0065\U000e0067\U000e0067\U000e007a\U000e007f" - FLAG_FOR_SAINT_MARY_JM_05 = "\U0001f3f4\U000e006a\U000e006d\U000e0030\U000e0035\U000e007f" - DIGIT_FIVE = "5\ufe0f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_MAGADAN_RU_MAG = "\U0001f3f4\U000e0072\U000e0075\U000e006d\U000e0061\U000e0067\U000e007f" - LEFT_ANGER_BUBBLE = "\U0001f5ee" - DIGIT_EIGHT = "8\ufe0f" - SIDEWAYS_BLACK_UP_POINTING_INDEX = "\U0001f5a0" - FLAG_FOR_SOUTHERN_HIGHLANDS_PG_SHM = "\U0001f3f4\U000e0070\U000e0067\U000e0073\U000e0068\U000e006d\U000e007f" - FLAG_FOR_NURISTAN_AF_NUR = "\U0001f3f4\U000e0061\U000e0066\U000e006e\U000e0075\U000e0072\U000e007f" - FLAG_FOR_LOUISIANA_US_LA = "\U0001f3f4\U000e0075\U000e0073\U000e006c\U000e0061\U000e007f" - FLAG_FOR_MAULE_CL_ML = "\U0001f3f4\U000e0063\U000e006c\U000e006d\U000e006c\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f466\U0001f3fd" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_PANAMA_PA_8 = "\U0001f3f4\U000e0070\U000e0061\U000e0038\U000e007f" - FLAG_FOR_IZMIR_TR_35 = "\U0001f3f4\U000e0074\U000e0072\U000e0033\U000e0035\U000e007f" - FLAG_FOR_CABINDA_AO_CAB = "\U0001f3f4\U000e0061\U000e006f\U000e0063\U000e0061\U000e0062\U000e007f" - OPEN_FOLDER = "\U0001f5c1" - FLAG_FOR_VAUD_CH_VD = "\U0001f3f4\U000e0063\U000e0068\U000e0076\U000e0064\U000e007f" - LIGHTNING_MOOD = "\U0001f5f2" - KISS_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - FLAG_FOR_SUCRE_CO_SUC = "\U0001f3f4\U000e0063\U000e006f\U000e0073\U000e0075\U000e0063\U000e007f" - MAHJONG_TILE_WHITE_DRAGON = "\U0001f006" - FLAG_FOR_MADRE_DE_DIOS_PE_MDD = "\U0001f3f4\U000e0070\U000e0065\U000e006d\U000e0064\U000e0064\U000e007f" - FLAG_FOR_BENGUELA_AO_BGU = "\U0001f3f4\U000e0061\U000e006f\U000e0062\U000e0067\U000e0075\U000e007f" - FLAG_FOR_ST_JULIAN_S_MT_48 = "\U0001f3f4\U000e006d\U000e0074\U000e0034\U000e0038\U000e007f" - FLAG_FOR_TIMIS_RO_TM = "\U0001f3f4\U000e0072\U000e006f\U000e0074\U000e006d\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_BIE_AO_BIE = "\U0001f3f4\U000e0061\U000e006f\U000e0062\U000e0069\U000e0065\U000e007f" - MAHJONG_TILE_WINTER = "\U0001f029" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_BLUE_NILE_SD_NB = "\U0001f3f4\U000e0073\U000e0064\U000e006e\U000e0062\U000e007f" - EMPTY_DOCUMENT = "\U0001f5cb" - MINIMIZE = "\U0001f5d5" - FLAG_FOR_KWALE_KE_19 = "\U0001f3f4\U000e006b\U000e0065\U000e0031\U000e0039\U000e007f" - FLAG_FOR_GRAND_PORT_MU_GP = "\U0001f3f4\U000e006d\U000e0075\U000e0067\U000e0070\U000e007f" - FLAG_FOR_CHIMBORAZO_EC_H = "\U0001f3f4\U000e0065\U000e0063\U000e0068\U000e007f" - FLAG_FOR_HUAMBO_AO_HUA = "\U0001f3f4\U000e0061\U000e006f\U000e0068\U000e0075\U000e0061\U000e007f" - FLAG_FOR_CUANZA_SUL_AO_CUS = "\U0001f3f4\U000e0061\U000e006f\U000e0063\U000e0075\U000e0073\U000e007f" - FLAG_FOR_BREMEN_DE_HB = "\U0001f3f4\U000e0064\U000e0065\U000e0068\U000e0062\U000e007f" - LIPS = "\U0001f5e2" - FLAG_FOR_ALTO_PARAGUAY_PY_16 = "\U0001f3f4\U000e0070\U000e0079\U000e0031\U000e0036\U000e007f" - FLAG_FOR_NEW_YORK_US_NY = "\U0001f3f4\U000e0075\U000e0073\U000e006e\U000e0079\U000e007f" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - FLAG_FOR_NORTH_CAROLINA_US_NC = "\U0001f3f4\U000e0075\U000e0073\U000e006e\U000e0063\U000e007f" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - WHITE_CIRCLE_WITH_TWO_DOTS = "\u2687" - KISS_MAN_MEDIUM_SKIN_TONE_MAN = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - MAN_ZOMBIE_LIGHT_SKIN_TONE = "\U0001f9df\U0001f3fb\u200d\u2642\ufe0f" - FLAG_FOR_PERAK_MY_08 = "\U0001f3f4\U000e006d\U000e0079\U000e0030\U000e0038\U000e007f" - FLAG_FOR_SISAK_MOSLAVINA_HR_03 = "\U0001f3f4\U000e0068\U000e0072\U000e0030\U000e0033\U000e007f" - FLAG_FOR_ARDABIL_IR_03 = "\U0001f3f4\U000e0069\U000e0072\U000e0030\U000e0033\U000e007f" - FLAG_FOR_KARNATAKA_IN_KA = "\U0001f3f4\U000e0069\U000e006e\U000e006b\U000e0061\U000e007f" - LEFT_HAND_TELEPHONE_RECEIVER = "\U0001f57b" - FLAG_FOR_NEVADA_US_NV = "\U0001f3f4\U000e0075\U000e0073\U000e006e\U000e0076\U000e007f" - FLAG_FOR_DIBER_COUNTY_AL_09 = "\U0001f3f4\U000e0061\U000e006c\U000e0030\U000e0039\U000e007f" - FLAG_FOR_LUNDA_SUL_AO_LSU = "\U0001f3f4\U000e0061\U000e006f\U000e006c\U000e0073\U000e0075\U000e007f" - KISS_WOMAN_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - SIDEWAYS_WHITE_DOWN_POINTING_INDEX = "\U0001f59f" - FLAG_FOR_NAKHON_SI_THAMMARAT_TH_80 = "\U0001f3f4\U000e0074\U000e0068\U000e0038\U000e0030\U000e007f" - FLAG_FOR_KYRENIA_CY_06 = "\U0001f3f4\U000e0063\U000e0079\U000e0030\U000e0036\U000e007f" - FLAG_FOR_GUNA_YALA_PA_KY = "\U0001f3f4\U000e0070\U000e0061\U000e006b\U000e0079\U000e007f" - FLAG_FOR_HUILA_AO_HUI = "\U0001f3f4\U000e0061\U000e006f\U000e0068\U000e0075\U000e0069\U000e007f" - FLAG_FOR_NAAMA_DZ_45 = "\U0001f3f4\U000e0064\U000e007a\U000e0034\U000e0035\U000e007f" - FLAG_FOR_SAR_E_POL_AF_SAR = "\U0001f3f4\U000e0061\U000e0066\U000e0073\U000e0061\U000e0072\U000e007f" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - FLAG_FOR_META_CO_MET = "\U0001f3f4\U000e0063\U000e006f\U000e006d\U000e0065\U000e0074\U000e007f" - FLAG_FOR_NORTHWEST_TERRITORIES_CA_NT = "\U0001f3f4\U000e0063\U000e0061\U000e006e\U000e0074\U000e007f" - FLAG_FOR_PENGHU_TW_PEN = "\U0001f3f4\U000e0074\U000e0077\U000e0070\U000e0065\U000e006e\U000e007f" - FLAG_FOR_TOKYO_JP_13 = "\U0001f3f4\U000e006a\U000e0070\U000e0031\U000e0033\U000e007f" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - TAG_LATIN_SMALL_LETTER_X = "\U000e0078" - FLAG_FOR_SAINT_GEORGE_AG_03 = "\U0001f3f4\U000e0061\U000e0067\U000e0030\U000e0033\U000e007f" - REVERSED_RAISED_HAND_WITH_FINGERS_SPLAYED = "\U0001f591" - JAPANESE_BANK_SYMBOL = "\u26fb" - FLAG_FOR_CUANZA_NORTE_AO_CNO = "\U0001f3f4\U000e0061\U000e006f\U000e0063\U000e006e\U000e006f\U000e007f" - FLAG_FOR_NANA_GREBIZI_CF_KB = "\U0001f3f4\U000e0063\U000e0066\U000e006b\U000e0062\U000e007f" - FLAG_FOR_MALANJE_AO_MAL = "\U0001f3f4\U000e0061\U000e006f\U000e006d\U000e0061\U000e006c\U000e007f" - ROTATED_HEAVY_BLACK_HEART_BULLET = "\u2765" - REVERSED_THUMBS_UP_SIGN = "\U0001f592" - CELTIC_CROSS = "\U0001f548" - KISS_WOMAN_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - SYMBOL_FOR_MARKS_CHAPTER = "\U0001f545" - TAG_LATIN_SMALL_LETTER_E = "\U000e0065" - FLAG_FOR_NIGER_NG_NI = "\U0001f3f4\U000e006e\U000e0067\U000e006e\U000e0069\U000e007f" - TAG_DIGIT_EIGHT = "\U000e0038" - MAHJONG_TILE_ORCHID = "\U0001f023" - TAG_LATIN_CAPITAL_LETTER_B = "\U000e0042" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - FLAG_FOR_BEIRUT_LB_BA = "\U0001f3f4\U000e006c\U000e0062\U000e0062\U000e0061\U000e007f" - BLACK_DROPLET = "\U0001f322" - FLAG_FOR_KALBAJAR_AZ_KAL = "\U0001f3f4\U000e0061\U000e007a\U000e006b\U000e0061\U000e006c\U000e007f" - FLAG_FOR_BINH_DUONG_VN_57 = "\U0001f3f4\U000e0076\U000e006e\U000e0035\U000e0037\U000e007f" - FLAG_FOR_NAMIBE_AO_NAM = "\U0001f3f4\U000e0061\U000e006f\U000e006e\U000e0061\U000e006d\U000e007f" - FLAG_FOR_CALARASI_RO_CL = "\U0001f3f4\U000e0072\U000e006f\U000e0063\U000e006c\U000e007f" - CIRCLED_CROSS_POMMEE = "\U0001f540" - FLAG_FOR_A_ANA_WS_AA = "\U0001f3f4\U000e0077\U000e0073\U000e0061\U000e0061\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f467\U0001f3fb" - BALLOT_SCRIPT_X = "\U0001f5f4" - MAHJONG_TILE_WEST_WIND = "\U0001f002" - MAHJONG_TILE_EIGHT_OF_CIRCLES = "\U0001f020" - FLAG_FOR_MOXICO_AO_MOX = "\U0001f3f4\U000e0061\U000e006f\U000e006d\U000e006f\U000e0078\U000e007f" - EMPTY_NOTE = "\U0001f5c5" - FLAG_FOR_MISSOURI_US_MO = "\U0001f3f4\U000e0075\U000e0073\U000e006d\U000e006f\U000e007f" - FLAG_FOR_PENANG_MY_07 = "\U0001f3f4\U000e006d\U000e0079\U000e0030\U000e0037\U000e007f" - FLAG_FOR_WAJIR_KE_46 = "\U0001f3f4\U000e006b\U000e0065\U000e0034\U000e0036\U000e007f" - FLAG_FOR_CANILLO_AD_02 = "\U0001f3f4\U000e0061\U000e0064\U000e0030\U000e0032\U000e007f" - FLAG_FOR_VIRGINIA_US_VA = "\U0001f3f4\U000e0075\U000e0073\U000e0076\U000e0061\U000e007f" - CROSS_POMMEE = "\U0001f542" - FLAG_FOR_FIER_COUNTY_AL_04 = "\U0001f3f4\U000e0061\U000e006c\U000e0030\U000e0034\U000e007f" - FLAG_FOR_SCHLESWIG_HOLSTEIN_DE_SH = "\U0001f3f4\U000e0064\U000e0065\U000e0073\U000e0068\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - FLAG_FOR_LUALABA_CD_LU = "\U0001f3f4\U000e0063\U000e0064\U000e006c\U000e0075\U000e007f" - NORTHEAST_POINTING_AIRPLANE = "\U0001f6ea" - FAMILY_WOMAN_WOMAN_GIRL_BABY = "\U0001f469\u200d\U0001f469\u200d\U0001f467\u200d\U0001f476" - MAHJONG_TILE_SEVEN_OF_BAMBOOS = "\U0001f016" - FLAG_FOR_AGSTAFA_AZ_AGA = "\U0001f3f4\U000e0061\U000e007a\U000e0061\U000e0067\U000e0061\U000e007f" - FLAG_FOR_AMNAT_CHAROEN_TH_37 = "\U0001f3f4\U000e0074\U000e0068\U000e0033\U000e0037\U000e007f" - FLAG_FOR_QUANG_TRI_VN_25 = "\U0001f3f4\U000e0076\U000e006e\U000e0032\U000e0035\U000e007f" - STAMPED_ENVELOPE = "\U0001f583" - BEATS_1_LOGO = "\uf79c" - FLAG_FOR_AFYONKARAHISAR_TR_03 = "\U0001f3f4\U000e0074\U000e0072\U000e0030\U000e0033\U000e007f" - FLAG_FOR_MASSACHUSETTS_US_MA = "\U0001f3f4\U000e0075\U000e0073\U000e006d\U000e0061\U000e007f" - FLAG_FOR_GULF_PG_GPK = "\U0001f3f4\U000e0070\U000e0067\U000e0067\U000e0070\U000e006b\U000e007f" - FLAG_FOR_UIGE_AO_UIG = "\U0001f3f4\U000e0061\U000e006f\U000e0075\U000e0069\U000e0067\U000e007f" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - FLAG_FOR_SAINT_KITTS_KN_K = "\U0001f3f4\U000e006b\U000e006e\U000e006b\U000e007f" - FLAG_FOR_CUANDO_CUBANGO_AO_CCU = "\U0001f3f4\U000e0061\U000e006f\U000e0063\U000e0063\U000e0075\U000e007f" - KISS_WOMAN_MEDIUM_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - FLAG_FOR_SAN_LUIS_AR_D = "\U0001f3f4\U000e0061\U000e0072\U000e0064\U000e007f" - FLAG_FOR_ZHYTOMYRSHCHYNA_UA_18 = "\U0001f3f4\U000e0075\U000e0061\U000e0031\U000e0038\U000e007f" - MAHJONG_TILE_TWO_OF_BAMBOOS = "\U0001f011" - FLAG_FOR_SAINT_THOMAS_JM_03 = "\U0001f3f4\U000e006a\U000e006d\U000e0030\U000e0033\U000e007f" - TAG_LATIN_SMALL_LETTER_I = "\U000e0069" - VESTA = "\u26b6" - TAG_LATIN_SMALL_LETTER_Y = "\U000e0079" - TAG_LATIN_SMALL_LETTER_Q = "\U000e0071" - SIDEWAYS_WHITE_LEFT_POINTING_INDEX = "\U0001f598" - FLAG_FOR_IDAHO_US_ID = "\U0001f3f4\U000e0075\U000e0073\U000e0069\U000e0064\U000e007f" - TAG_LATIN_CAPITAL_LETTER_Z = "\U000e005a" - FLAG_FOR_SYUNIK_AM_SU = "\U0001f3f4\U000e0061\U000e006d\U000e0073\U000e0075\U000e007f" - FLAG_FOR_EAST_KAZAKHSTAN_KZ_VOS = "\U0001f3f4\U000e006b\U000e007a\U000e0076\U000e006f\U000e0073\U000e007f" - FLAG_FOR_JAMTLAND_SE_Z = "\U0001f3f4\U000e0073\U000e0065\U000e007a\U000e007f" - WOMAN_ZOMBIE_MEDIUM_DARK_SKIN_TONE = "\U0001f9df\U0001f3fe\u200d\u2640\ufe0f" - FLAG_FOR_NEVSEHIR_TR_50 = "\U0001f3f4\U000e0074\U000e0072\U000e0035\U000e0030\U000e007f" - FLAG_FOR_SKANE_SE_M = "\U0001f3f4\U000e0073\U000e0065\U000e006d\U000e007f" - KISS_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - FRAME_WITH_AN_X = "\U0001f5be" - FLAG_FOR_SANTIAGO_DEL_ESTERO_AR_G = "\U0001f3f4\U000e0061\U000e0072\U000e0067\U000e007f" - FLAG_FOR_LA_MASSANA_AD_04 = "\U0001f3f4\U000e0061\U000e0064\U000e0030\U000e0034\U000e007f" - FLAG_FOR_STAVROPOL_KRAI_RU_STA = "\U0001f3f4\U000e0072\U000e0075\U000e0073\U000e0074\U000e0061\U000e007f" - FAMILY_MAN_BABY_GIRL = "\U0001f468\u200d\U0001f476\u200d\U0001f467" - NEUTER = "\u26b2" - FLAG_FOR_TRIPURA_IN_TR = "\U0001f3f4\U000e0069\U000e006e\U000e0074\U000e0072\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_ENUGU_NG_EN = "\U0001f3f4\U000e006e\U000e0067\U000e0065\U000e006e\U000e007f" - FLAG_FOR_EL_ORO_EC_O = "\U0001f3f4\U000e0065\U000e0063\U000e006f\U000e007f" - SQUARED_KEY = "\u26bf" - MAHJONG_TILE_NINE_OF_BAMBOOS = "\U0001f018" - PRINTER_ICON = "\U0001f5b6" - SESQUIQUADRATE = "\u26bc" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f466\U0001f3ff" - MAHJONG_TILE_SIX_OF_BAMBOOS = "\U0001f015" - WOMAN_IN_TUXEDO_DARK_SKIN_TONE = "\U0001f935\U0001f3ff\u200d\u2640\ufe0f" - FLAG_FOR_LA_RIOJA_AR_F = "\U0001f3f4\U000e0061\U000e0072\U000e0066\U000e007f" - FLAG_FOR_BUSHEHR_IR_06 = "\U0001f3f4\U000e0069\U000e0072\U000e0030\U000e0036\U000e007f" - DIGIT_THREE = "3\ufe0f" - FLAG_FOR_LUXEMBOURG_LU_LU = "\U0001f3f4\U000e006c\U000e0075\U000e006c\U000e0075\U000e007f" - FLAG_FOR_DAGESTAN_RU_DA = "\U0001f3f4\U000e0072\U000e0075\U000e0064\U000e0061\U000e007f" - BLACK_DRAUGHTS_KING = "\u26c3" - WHITE_DRAUGHTS_KING = "\u26c1" - FLAG_FOR_CATAMARCA_AR_K = "\U0001f3f4\U000e0061\U000e0072\U000e006b\U000e007f" - TAG_LATIN_SMALL_LETTER_B = "\U000e0062" - FLAG_FOR_BARBUDA_AG_10 = "\U0001f3f4\U000e0061\U000e0067\U000e0031\U000e0030\U000e007f" - FLAG_FOR_MARL_NZ_MBH = "\U0001f3f4\U000e006e\U000e007a\U000e006d\U000e0062\U000e0068\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb" - BLACK_SNOWMAN = "\u26c7" - ASTRONOMICAL_SYMBOL_FOR_URANUS = "\u26e2" - FLAG_FOR_LAO_CAI_VN_02 = "\U0001f3f4\U000e0076\U000e006e\U000e0030\U000e0032\U000e007f" - FLAG_FOR_JURA_CH_JU = "\U0001f3f4\U000e0063\U000e0068\U000e006a\U000e0075\U000e007f" - MAHJONG_TILE_FOUR_OF_BAMBOOS = "\U0001f013" - TAG_LATIN_CAPITAL_LETTER_N = "\U000e004e" - FAMILY_MAN_BABY_BOY = "\U0001f468\u200d\U0001f476\u200d\U0001f466" - FLAG_FOR_MISIONES_AR_N = "\U0001f3f4\U000e0061\U000e0072\U000e006e\U000e007f" - WOMAN_ZOMBIE_DARK_SKIN_TONE = "\U0001f9df\U0001f3ff\u200d\u2640\ufe0f" - FAMILY_WOMAN_BABY = "\U0001f469\u200d\U0001f476" - PALLAS = "\u26b4" - DIGIT_SIX = "6\ufe0f" - DOUBLED_MALE_SIGN = "\u26a3" - FLAG_FOR_JOWZJAN_AF_JOW = "\U0001f3f4\U000e0061\U000e0066\U000e006a\U000e006f\U000e0077\U000e007f" - FLAG_FOR_ESCALDES_ENGORDANY_AD_08 = "\U0001f3f4\U000e0061\U000e0064\U000e0030\U000e0038\U000e007f" - FLAG_FOR_MYKOLAYIVSCHYNA_UA_48 = "\U0001f3f4\U000e0075\U000e0061\U000e0034\U000e0038\U000e007f" - FLAG_FOR_DEIR_EZ_ZOR_SY_DY = "\U0001f3f4\U000e0073\U000e0079\U000e0064\U000e0079\U000e007f" - RIGHT_SPEECH_BUBBLE = "\U0001f5e9" - TAG_DIGIT_ZERO = "\U000e0030" - FLAG_FOR_FUJAIRAH_AE_FU = "\U0001f3f4\U000e0061\U000e0065\U000e0066\U000e0075\U000e007f" - LEFT_CLOSED_ENTRY = "\u26dc" - MAHJONG_TILE_BAMBOO = "\U0001f024" - SQUARED_SALTIRE = "\u26dd" - BLACK_MOON_LILITH = "\u26b8" - FLAG_FOR_LUNDA_NORTE_AO_LNO = "\U0001f3f4\U000e0061\U000e006f\U000e006c\U000e006e\U000e006f\U000e007f" - DRIVE_SLOW_SIGN = "\u26da" - FLAG_FOR_GRAND_CAPE_MOUNT_LR_CM = "\U0001f3f4\U000e006c\U000e0072\U000e0063\U000e006d\U000e007f" - FLAG_FOR_FORMOSA_AR_P = "\U0001f3f4\U000e0061\U000e0072\U000e0070\U000e007f" - FLAG_FOR_WEST_NEW_BRITAIN_PG_WBK = "\U0001f3f4\U000e0070\U000e0067\U000e0077\U000e0062\U000e006b\U000e007f" - BLACK_LEFT_LANE_MERGE = "\u26d8" - FLAG_FOR_ARARAT_AM_AR = "\U0001f3f4\U000e0061\U000e006d\U000e0061\U000e0072\U000e007f" - SEXTILE = "\u26b9" - FLAG_FOR_SAN_JUAN_AR_J = "\U0001f3f4\U000e0061\U000e0072\U000e006a\U000e007f" - FLAG_FOR_BLOKE_SI_150 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0035\U000e0030\U000e007f" - INCREASE_FONT_SIZE_SYMBOL = "\U0001f5da" - FLAG_FOR_ANHUI_CN_34 = "\U0001f3f4\U000e0063\U000e006e\U000e0033\U000e0034\U000e007f" - FLAG_FOR_NORTH_AEGEAN_GR_K = "\U0001f3f4\U000e0067\U000e0072\U000e006b\U000e007f" - FAMILY_MAN_WOMAN_BABY_GIRL = "\U0001f468\u200d\U0001f469\u200d\U0001f476\u200d\U0001f467" - FLAG_FOR_HADRAMAUT_YE_HD = "\U0001f3f4\U000e0079\U000e0065\U000e0068\U000e0064\U000e007f" - TURNED_WHITE_SHOGI_PIECE = "\u26c9" - MALE_WITH_STROKE_SIGN = "\u26a6" - RESTRICTED_LEFT_ENTRY_1 = "\u26e0" - FLAG_FOR_HAVANA_CU_03 = "\U0001f3f4\U000e0063\U000e0075\U000e0030\U000e0033\U000e007f" - LOWER_LEFT_PENCIL = "\U0001f589" - FLAG_FOR_CHUBUT_AR_U = "\U0001f3f4\U000e0061\U000e0072\U000e0075\U000e007f" - CLOCKWISE_RIGHT_AND_LEFT_SEMICIRCLE_ARROWS = "\U0001f5d8" - FLAG_FOR_SANTIAGO_METROPOLITAN_CL_RM = "\U0001f3f4\U000e0063\U000e006c\U000e0072\U000e006d\U000e007f" - CASTLE_2 = "\u26eb" - THREE_RAYS_RIGHT = "\U0001f5e7" - JUNO = "\u26b5" - FLAG_FOR_HAI_DUONG_VN_61 = "\U0001f3f4\U000e0076\U000e006e\U000e0036\U000e0031\U000e007f" - FLAG_FOR_ABSHERON_AZ_ABS = "\U0001f3f4\U000e0061\U000e007a\U000e0061\U000e0062\U000e0073\U000e007f" - FLAG_FOR_CORRIENTES_AR_W = "\U0001f3f4\U000e0061\U000e0072\U000e0077\U000e007f" - MAHJONG_TILE_SOUTH_WIND = "\U0001f001" - FLAG_FOR_GRAND_CASABLANCA_MA_08 = "\U0001f3f4\U000e006d\U000e0061\U000e0030\U000e0038\U000e007f" - FLAG_FOR_NGARCHELONG_PW_218 = "\U0001f3f4\U000e0070\U000e0077\U000e0032\U000e0031\U000e0038\U000e007f" - FLAG_FOR_CORDOBA_AR_X = "\U0001f3f4\U000e0061\U000e0072\U000e0078\U000e007f" - FLAG_FOR_CENTRAL_SINGAPORE_SG_01 = "\U0001f3f4\U000e0073\U000e0067\U000e0030\U000e0031\U000e007f" - FLAG_FOR_CAMPANIA_IT_72 = "\U0001f3f4\U000e0069\U000e0074\U000e0037\U000e0032\U000e007f" - FLAG_FOR_CIBAO_NORTE_DO_35 = "\U0001f3f4\U000e0064\U000e006f\U000e0033\U000e0035\U000e007f" - MAHJONG_TILE_THREE_OF_BAMBOOS = "\U0001f012" - FLAG_FOR_ARAGATSOTN_AM_AG = "\U0001f3f4\U000e0061\U000e006d\U000e0061\U000e0067\U000e007f" - FLAG_FOR_GRAND_GEDEH_LR_GG = "\U0001f3f4\U000e006c\U000e0072\U000e0067\U000e0067\U000e007f" - FLAG_FOR_ABRUZZO_IT_65 = "\U0001f3f4\U000e0069\U000e0074\U000e0036\U000e0035\U000e007f" - CERES = "\u26b3" - FAMILY_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb" - FLAG_FOR_CARINTHIA_AT_2 = "\U0001f3f4\U000e0061\U000e0074\U000e0032\U000e007f" - MARRIAGE_SYMBOL = "\u26ad" - LIGHTNING = "\u2607" - SUN_2 = "\u2609" - FLAG_FOR_CENTRAL_GREECE_GR_H = "\U0001f3f4\U000e0067\U000e0072\U000e0068\U000e007f" - FAMILY_WOMAN_MAN_BOY_GIRL = "\U0001f469\u200d\U0001f468\u200d\U0001f466\u200d\U0001f467" - FLAG_FOR_BASEL_LANDSCHAFT_CH_BL = "\U0001f3f4\U000e0063\U000e0068\U000e0062\U000e006c\U000e007f" - FLAG_FOR_UTTARAKHAND_IN_UT = "\U0001f3f4\U000e0069\U000e006e\U000e0075\U000e0074\U000e007f" - UP_POINTING_SMALL_AIRPLANE = "\U0001f6e8" - FLAG_FOR_MENDOZA_AR_M = "\U0001f3f4\U000e0061\U000e0072\U000e006d\U000e007f" - FLAG_FOR_MAMOU_REGION_GN_M = "\U0001f3f4\U000e0067\U000e006e\U000e006d\U000e007f" - FLAG_FOR_ATTAPEU_LA_AT = "\U0001f3f4\U000e006c\U000e0061\U000e0061\U000e0074\U000e007f" - FLAG_FOR_SABA_NL_BQ2 = "\U0001f3f4\U000e006e\U000e006c\U000e0062\U000e0071\U000e0032\U000e007f" - FLYING_ENVELOPE = "\U0001f585" - FLAG_FOR_KIRKUK_IQ_KI = "\U0001f3f4\U000e0069\U000e0071\U000e006b\U000e0069\U000e007f" - BLACK_PUSHPIN = "\U0001f588" - CROSSING_LANES = "\u26cc" - FAMILY_WOMAN_BABY_BOY = "\U0001f469\u200d\U0001f476\u200d\U0001f466" - TAG_LATIN_SMALL_LETTER_T = "\U000e0074" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469" - MOOD_BUBBLE = "\U0001f5f0" - MAHJONG_TILE_PLUM = "\U0001f022" - FLAG_FOR_NOUAKCHOTT_OUEST_MR_13 = "\U0001f3f4\U000e006d\U000e0072\U000e0031\U000e0033\U000e007f" - RIGHT_THOUGHT_BUBBLE = "\U0001f5ed" - DIGIT_ZERO = "0\ufe0f" - FLAG_FOR_SAXONY_DE_SN = "\U0001f3f4\U000e0064\U000e0065\U000e0073\U000e006e\U000e007f" - FLAG_FOR_SACATEPEQUEZ_GT_SA = "\U0001f3f4\U000e0067\U000e0074\U000e0073\U000e0061\U000e007f" - KISS_MAN_DARK_SKIN_TONE_MAN = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - DESCENDING_NODE = "\u260b" - FLAG_FOR_VIEUX_FORT_LC_11 = "\U0001f3f4\U000e006c\U000e0063\U000e0031\U000e0031\U000e007f" - ONCOMING_FIRE_ENGINE = "\U0001f6f1" - FLAG_FOR_QUANG_BINH_VN_24 = "\U0001f3f4\U000e0076\U000e006e\U000e0032\U000e0034\U000e007f" - FLAG_FOR_TYROL_AT_7 = "\U0001f3f4\U000e0061\U000e0074\U000e0037\U000e007f" - FLAG_FOR_FRANCISTOWN_BW_FR = "\U0001f3f4\U000e0062\U000e0077\U000e0066\U000e0072\U000e007f" - DISABLED_CAR = "\u26cd" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_MBOMOU_CF_MB = "\U0001f3f4\U000e0063\U000e0066\U000e006d\U000e0062\U000e007f" - ASCENDING_NODE = "\u260a" - FLAG_FOR_ILOCOS_PH_01 = "\U0001f3f4\U000e0070\U000e0068\U000e0030\U000e0031\U000e007f" - HEAVY_CIRCLE_WITH_STROKE_AND_TWO_DOTS_ABOVE = "\u26e3" - MAHJONG_TILE_FIVE_OF_BAMBOOS = "\U0001f014" - FLAG_FOR_SAINT_GEORGE_GD_03 = "\U0001f3f4\U000e0067\U000e0064\U000e0030\U000e0033\U000e007f" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FLAG_FOR_TAIWAN_CN_71 = "\U0001f3f4\U000e0063\U000e006e\U000e0037\U000e0031\U000e007f" - FLAG_FOR_VENETO_IT_34 = "\U0001f3f4\U000e0069\U000e0074\U000e0033\U000e0034\U000e007f" - FLAG_FOR_LUANDA_AO_LUA = "\U0001f3f4\U000e0061\U000e006f\U000e006c\U000e0075\U000e0061\U000e007f" - FLAG_FOR_SAINT_LOUIS_SN_SL = "\U0001f3f4\U000e0073\U000e006e\U000e0073\U000e006c\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff" - EMPTY_PAGE = "\U0001f5cc" - BOUQUET_OF_FLOWERS = "\U0001f395" - FLAG_FOR_XAISOMBOUN_LA_XS = "\U0001f3f4\U000e006c\U000e0061\U000e0078\U000e0073\U000e007f" - FLAG_FOR_TUCUMAN_AR_T = "\U0001f3f4\U000e0061\U000e0072\U000e0074\U000e007f" - RAIN = "\u26c6" - FAMILY_MAN_MAN_BOY_GIRL = "\U0001f468\u200d\U0001f468\u200d\U0001f466\u200d\U0001f467" - FLAG_FOR_ANKARA_TR_06 = "\U0001f3f4\U000e0074\U000e0072\U000e0030\U000e0036\U000e007f" - FLAG_FOR_GUIZHOU_CN_52 = "\U0001f3f4\U000e0063\U000e006e\U000e0035\U000e0032\U000e007f" - FLAG_FOR_SVALBARD_NO_21 = "\U0001f3f4\U000e006e\U000e006f\U000e0032\U000e0031\U000e007f" - FARSI_SYMBOL = "\u262b" - PENTAGRAM = "\u26e4" - HARD_DISK = "\U0001f5b4" - FLAG_FOR_VORARLBERG_AT_8 = "\U0001f3f4\U000e0061\U000e0074\U000e0038\U000e007f" - NO_PIRACY = "\U0001f572" - RECYCLING_SYMBOL_FOR_TYPE_6_PLASTICS = "\u2678" - OPPOSITION = "\u260d" - FLAG_FOR_ZAIRE_AO_ZAI = "\U0001f3f4\U000e0061\U000e006f\U000e007a\U000e0061\U000e0069\U000e007f" - FLAG_FOR_AMHARA_ET_AM = "\U0001f3f4\U000e0065\U000e0074\U000e0061\U000e006d\U000e007f" - MAHJONG_TILE_SPRING = "\U0001f026" - FLAG_FOR_RED_SEA_SD_RS = "\U0001f3f4\U000e0073\U000e0064\U000e0072\U000e0073\U000e007f" - FLAG_FOR_PIETA_MT_41 = "\U0001f3f4\U000e006d\U000e0074\U000e0034\U000e0031\U000e007f" - FLAG_FOR_ZABUL_AF_ZAB = "\U0001f3f4\U000e0061\U000e0066\U000e007a\U000e0061\U000e0062\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f467\U0001f3fd" - BLACK_SMILING_FACE = "\u263b" - FLAG_FOR_SANTA_CRUZ_BO_S = "\U0001f3f4\U000e0062\U000e006f\U000e0073\U000e007f" - KISS_MAN_DARK_SKIN_TONE_WOMAN = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - BLACK_FOLDER = "\U0001f5bf" - FLAG_FOR_SANTA_CATARINA_BR_SC = "\U0001f3f4\U000e0062\U000e0072\U000e0073\U000e0063\U000e007f" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - FAMILY_WOMAN_MAN_GIRL_BABY = "\U0001f469\u200d\U0001f468\u200d\U0001f467\u200d\U0001f476" - FLAG_FOR_BASQUE_COUNTRY_ES_PV = "\U0001f3f4\U000e0065\U000e0073\U000e0070\U000e0076\U000e007f" - TAG_LATIN_CAPITAL_LETTER_V = "\U000e0056" - FLAG_FOR_MANABI_EC_M = "\U0001f3f4\U000e0065\U000e0063\U000e006d\U000e007f" - LAST_QUARTER_MOON_2 = "\u263e" - FLAG_FOR_NAVARRA_CHARTERED_COMMUNITY_ES_NC = "\U0001f3f4\U000e0065\U000e0073\U000e006e\U000e0063\U000e007f" - INVERTED_PENTAGRAM = "\u26e7" - FAMILY_WOMAN_MAN_GIRL = "\U0001f469\u200d\U0001f468\u200d\U0001f467" - FLAG_FOR_DALARNA_SE_W = "\U0001f3f4\U000e0073\U000e0065\U000e0077\U000e007f" - MAHJONG_TILE_TWO_OF_CHARACTERS = "\U0001f008" - BITCOIN_SIGN = "\u20bf" - FLAG_FOR_CHUUK_FM_TRK = "\U0001f3f4\U000e0066\U000e006d\U000e0074\U000e0072\U000e006b\U000e007f" - FLAG_FOR_KERICHO_KE_12 = "\U0001f3f4\U000e006b\U000e0065\U000e0031\U000e0032\U000e007f" - BLACK_LEFT_POINTING_INDEX = "\u261a" - BLACK_RIGHT_POINTING_INDEX = "\u261b" - KISS_MAN_LIGHT_SKIN_TONE_WOMAN = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - FLAG_FOR_SARAWAK_MY_13 = "\U0001f3f4\U000e006d\U000e0079\U000e0031\U000e0033\U000e007f" - BLACK_DRAUGHTS_MAN = "\u26c2" - FLAG_FOR_BEAU_BASSIN_ROSE_HILL_MU_BR = "\U0001f3f4\U000e006d\U000e0075\U000e0062\U000e0072\U000e007f" - FLAG_FOR_GOA_IN_GA = "\U0001f3f4\U000e0069\U000e006e\U000e0067\U000e0061\U000e007f" - FLAG_FOR_PERNAMBUCO_BR_PE = "\U0001f3f4\U000e0062\U000e0072\U000e0070\U000e0065\U000e007f" - WOMAN_WITH_HEADSCARF_DARK_SKIN_TONE = "\U0001f9d5\U0001f3ff\u200d\u2640\ufe0f" - FLAG_FOR_YUKON_CA_YT = "\U0001f3f4\U000e0063\U000e0061\U000e0079\U000e0074\U000e007f" - FLAG_FOR_SICHUAN_CN_51 = "\U0001f3f4\U000e0063\U000e006e\U000e0035\U000e0031\U000e007f" - FLAG_FOR_LAKES_SS_LK = "\U0001f3f4\U000e0073\U000e0073\U000e006c\U000e006b\U000e007f" - HAMMER_AND_SICKLE = "\u262d" - FLAG_FOR_BEIJING_CN_11 = "\U0001f3f4\U000e0063\U000e006e\U000e0031\U000e0031\U000e007f" - FLAG_FOR_UPPER_AUSTRIA_AT_4 = "\U0001f3f4\U000e0061\U000e0074\U000e0034\U000e007f" - FLAG_FOR_LAPLAND_FI_10 = "\U0001f3f4\U000e0066\U000e0069\U000e0031\U000e0030\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_HIMACHAL_PRADESH_IN_HP = "\U0001f3f4\U000e0069\U000e006e\U000e0068\U000e0070\U000e007f" - FLAG_FOR_VELIKA_POLANA_SI_187 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0038\U000e0037\U000e007f" - FLAG_FOR_MUSLIM_MINDANAO_PH_14 = "\U0001f3f4\U000e0070\U000e0068\U000e0031\U000e0034\U000e007f" - HEADSTONE_GRAVEYARD_SYMBOL = "\u26fc" - CLAMSHELL_MOBILE_PHONE = "\U0001f581" - FLAG_FOR_KOSOVO_METOHIJA_RS_KM = "\U0001f3f4\U000e0072\U000e0073\U000e006b\U000e006d\U000e007f" - DIGIT_TWO = "2\ufe0f" - FLAG_FOR_PUNJAB_IN_PB = "\U0001f3f4\U000e0069\U000e006e\U000e0070\U000e0062\U000e007f" - SIDEWAYS_BLACK_DOWN_POINTING_INDEX = "\U0001f5a1" - FLAG_FOR_DOHA_QA_DA = "\U0001f3f4\U000e0071\U000e0061\U000e0064\U000e0061\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f476\U0001f3ff" - DOUBLED_FEMALE_SIGN = "\u26a2" - BLACK_SKULL_AND_CROSSBONES = "\U0001f571" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_ZEALAND_DK_85 = "\U0001f3f4\U000e0064\U000e006b\U000e0038\U000e0035\U000e007f" - STAFF_OF_HERMES = "\u269a" - QUINCUNX = "\u26bb" - FLAG_FOR_SANTA_FE_AR_S = "\U0001f3f4\U000e0061\U000e0072\U000e0073\U000e007f" - FLAG_FOR_ADIYAMAN_TR_02 = "\U0001f3f4\U000e0074\U000e0072\U000e0030\U000e0032\U000e007f" - FLAG_FOR_KAFR_EL_SHEIKH_EG_KFS = "\U0001f3f4\U000e0065\U000e0067\U000e006b\U000e0066\U000e0073\U000e007f" - FLAG_FOR_ASTARA_AZ_AST = "\U0001f3f4\U000e0061\U000e007a\U000e0061\U000e0073\U000e0074\U000e007f" - FLAG_FOR_SAINT_PATRICK_DM_09 = "\U0001f3f4\U000e0064\U000e006d\U000e0030\U000e0039\U000e007f" - FLAG_FOR_AGDAM_AZ_AGM = "\U0001f3f4\U000e0061\U000e007a\U000e0061\U000e0067\U000e006d\U000e007f" - FLAG_FOR_TIERRA_DEL_FUEGO_AR_V = "\U0001f3f4\U000e0061\U000e0072\U000e0076\U000e007f" - SIDEWAYS_BLACK_LEFT_POINTING_INDEX = "\U0001f59a" - TAG_DIGIT_FIVE = "\U000e0035" - FLAG_FOR_KANSAS_US_KS = "\U0001f3f4\U000e0075\U000e0073\U000e006b\U000e0073\U000e007f" - MUSIC_FLAT_SIGN = "\u266d" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f476\U0001f3fc" - BALLOT_BOX_WITH_X = "\u2612" - TAG_LOW_LINE = "\U000e005f" - FLAG_FOR_ADYGEA_RU_AD = "\U0001f3f4\U000e0072\U000e0075\U000e0061\U000e0064\U000e007f" - TELEPHONE_ON_TOP_OF_MODEM = "\U0001f580" - FLAG_FOR_NINGXIA_CN_64 = "\U0001f3f4\U000e0063\U000e006e\U000e0036\U000e0034\U000e007f" - FLAG_FOR_GAVLEBORG_SE_X = "\U0001f3f4\U000e0073\U000e0065\U000e0078\U000e007f" - FLAG_FOR_AGSU_AZ_AGU = "\U0001f3f4\U000e0061\U000e007a\U000e0061\U000e0067\U000e0075\U000e007f" - HISTORIC_SITE = "\u26ec" - FLAG_FOR_KAGAWA_JP_37 = "\U0001f3f4\U000e006a\U000e0070\U000e0033\U000e0037\U000e007f" - FLAG_FOR_BOMI_LR_BM = "\U0001f3f4\U000e006c\U000e0072\U000e0062\U000e006d\U000e007f" - FLAG_FOR_MIDLANDS_ZW_MI = "\U0001f3f4\U000e007a\U000e0077\U000e006d\U000e0069\U000e007f" - FLAG_FOR_AGHJABADI_AZ_AGC = "\U0001f3f4\U000e0061\U000e007a\U000e0061\U000e0067\U000e0063\U000e007f" - SIDEWAYS_WHITE_UP_POINTING_INDEX = "\U0001f59e" - KISS_MAN_WOMAN = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - FLAG_FOR_NEUQUEN_AR_Q = "\U0001f3f4\U000e0061\U000e0072\U000e0071\U000e007f" - FLAG_FOR_AZORES_PT_20 = "\U0001f3f4\U000e0070\U000e0074\U000e0032\U000e0030\U000e007f" - FLAG_FOR_BAS_CONGO_CD_BC = "\U0001f3f4\U000e0063\U000e0064\U000e0062\U000e0063\U000e007f" - FLAG_FOR_BILASUVAR_AZ_BIL = "\U0001f3f4\U000e0061\U000e007a\U000e0062\U000e0069\U000e006c\U000e007f" - FLAG_FOR_KURSK_RU_KRS = "\U0001f3f4\U000e0072\U000e0075\U000e006b\U000e0072\U000e0073\U000e007f" - FLAG_FOR_BARDA_AZ_BAR = "\U0001f3f4\U000e0061\U000e007a\U000e0062\U000e0061\U000e0072\U000e007f" - TRIGRAM_FOR_LAKE = "\u2631" - FLAG_FOR_JABRAYIL_AZ_CAB = "\U0001f3f4\U000e0061\U000e007a\U000e0063\U000e0061\U000e0062\U000e007f" - NOTCHED_RIGHT_SEMICIRCLE_WITH_THREE_DOTS = "\U0001f544" - FLAG_FOR_FIZULI_AZ_FUZ = "\U0001f3f4\U000e0061\U000e007a\U000e0066\U000e0075\U000e007a\U000e007f" - FLAG_FOR_BEYLAGAN_AZ_BEY = "\U0001f3f4\U000e0061\U000e007a\U000e0062\U000e0065\U000e0079\U000e007f" - FLAG_FOR_NIARI_CG_9 = "\U0001f3f4\U000e0063\U000e0067\U000e0039\U000e007f" - FAMILY_WOMAN_MAN_BABY = "\U0001f469\u200d\U0001f468\u200d\U0001f476" - FAMILY_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f466\U0001f3ff" - WHITE_DRAUGHTS_MAN = "\u26c0" - FLAG_FOR_SAINT_JOSEPH_DM_06 = "\U0001f3f4\U000e0064\U000e006d\U000e0030\U000e0036\U000e007f" - DIGRAM_FOR_LESSER_YIN = "\u268d" - TAG_DIGIT_THREE = "\U000e0033" - FLAG_FOR_PAPUA_ISLANDS_ID_PP = "\U0001f3f4\U000e0069\U000e0064\U000e0070\U000e0070\U000e007f" - FLAG_FOR_HARBOUR_ISLAND_BS_HI = "\U0001f3f4\U000e0062\U000e0073\U000e0068\U000e0069\U000e007f" - FLAG_FOR_YEREVAN_AM_ER = "\U0001f3f4\U000e0061\U000e006d\U000e0065\U000e0072\U000e007f" - KISS_WOMAN_LIGHT_SKIN_TONE_WOMAN = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - ANKH = "\u2625" - LIGHT_CHECK_MARK = "\U0001f5f8" - KISS_WOMAN_WOMAN_DARK_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - FLAG_FOR_GOYCHAY_AZ_GOY = "\U0001f3f4\U000e0061\U000e007a\U000e0067\U000e006f\U000e0079\U000e007f" - TAG_LATIN_CAPITAL_LETTER_A = "\U000e0041" - FLAG_FOR_PORT_HERCULES_MC_PH = "\U0001f3f4\U000e006d\U000e0063\U000e0070\U000e0068\U000e007f" - CIRCLED_CROSSING_LANES = "\u26d2" - MONOGRAM_FOR_YANG = "\u268a" - FLAG_FOR_CESAR_CO_CES = "\U0001f3f4\U000e0063\U000e006f\U000e0063\U000e0065\U000e0073\U000e007f" - DECREASE_FONT_SIZE_SYMBOL = "\U0001f5db" - BALLOT_BOLD_SCRIPT_X = "\U0001f5f6" - FLAG_FOR_JERUSALEM_PS_JEM = "\U0001f3f4\U000e0070\U000e0073\U000e006a\U000e0065\U000e006d\U000e007f" - FLAG_FOR_UMM_SALAL_QA_US = "\U0001f3f4\U000e0071\U000e0061\U000e0075\U000e0073\U000e007f" - BLACK_CHESS_BISHOP = "\u265d" - FLAG_FOR_KALIMANTAN_ID_KA = "\U0001f3f4\U000e0069\U000e0064\U000e006b\U000e0061\U000e007f" - BALLOT_BOX = "\u2610" - FLAG_FOR_BRYANSK_RU_BRY = "\U0001f3f4\U000e0072\U000e0075\U000e0062\U000e0072\U000e0079\U000e007f" - KISS_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - FLAG_FOR_AGDASH_AZ_AGS = "\U0001f3f4\U000e0061\U000e007a\U000e0061\U000e0067\U000e0073\U000e007f" - FLAG_FOR_GOYGOL_AZ_GYG = "\U0001f3f4\U000e0061\U000e007a\U000e0067\U000e0079\U000e0067\U000e007f" - FLAG_FOR_HAJIGABUL_AZ_HAC = "\U0001f3f4\U000e0061\U000e007a\U000e0068\U000e0061\U000e0063\U000e007f" - FLAG_FOR_KASTAMONU_TR_37 = "\U0001f3f4\U000e0074\U000e0072\U000e0033\U000e0037\U000e007f" - FLAG_FOR_REZEKNE_MUNICIPALITY_LV_077 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0037\U000e0037\U000e007f" - FLAG_FOR_BONAIRE_NL_BQ1 = "\U0001f3f4\U000e006e\U000e006c\U000e0062\U000e0071\U000e0031\U000e007f" - FLAG_FOR_TAVUSH_AM_TV = "\U0001f3f4\U000e0061\U000e006d\U000e0074\U000e0076\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f476\U0001f3fc" - WHITE_TELEPHONE = "\u260f" - FLAG_FOR_VEST_AGDER_NO_10 = "\U0001f3f4\U000e006e\U000e006f\U000e0031\U000e0030\U000e007f" - FLAG_FOR_GORANBOY_AZ_GOR = "\U0001f3f4\U000e0061\U000e007a\U000e0067\U000e006f\U000e0072\U000e007f" - FLAG_FOR_CROSS_RIVER_NG_CR = "\U0001f3f4\U000e006e\U000e0067\U000e0063\U000e0072\U000e007f" - FLAG_FOR_IMISHLI_AZ_IMI = "\U0001f3f4\U000e0061\U000e007a\U000e0069\U000e006d\U000e0069\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_TANGANYIKA_CD_TA = "\U0001f3f4\U000e0063\U000e0064\U000e0074\U000e0061\U000e007f" - BLACK_STAR = "\u2605" - CAUTION_SIGN = "\u2621" - FLAG_FOR_SHANGHAI_CN_31 = "\U0001f3f4\U000e0063\U000e006e\U000e0033\U000e0031\U000e007f" - CHI_RHO = "\u2627" - BALLOT_BOX_WITH_BOLD_SCRIPT_X = "\U0001f5f7" - TRIGRAM_FOR_FIRE = "\u2632" - FLAG_FOR_WEST_VIRGINIA_US_WV = "\U0001f3f4\U000e0075\U000e0073\U000e0077\U000e0076\U000e007f" - FLAG_FOR_CLIPPERTON_ISLAND_FR_CP = "\U0001f3f4\U000e0066\U000e0072\U000e0063\U000e0070\U000e007f" - EIGHTH_NOTE = "\u266a" - CROSS_OF_LORRAINE = "\u2628" - CADUCEUS = "\u2624" - FLAG_FOR_GORJ_RO_GJ = "\U0001f3f4\U000e0072\U000e006f\U000e0067\U000e006a\U000e007f" - OUTLINED_WHITE_STAR = "\u269d" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_ALTAI_KRAI_RU_ALT = "\U0001f3f4\U000e0072\U000e0075\U000e0061\U000e006c\U000e0074\U000e007f" - KISS_WOMAN_MEDIUM_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - FLAG_FOR_LACHIN_AZ_LAC = "\U0001f3f4\U000e0061\U000e007a\U000e006c\U000e0061\U000e0063\U000e007f" - FLAG_FOR_TAKHAR_AF_TAK = "\U0001f3f4\U000e0061\U000e0066\U000e0074\U000e0061\U000e006b\U000e007f" - FLAG_FOR_LANKARAN_AZ_LA = "\U0001f3f4\U000e0061\U000e007a\U000e006c\U000e0061\U000e007f" - TAG_LATIN_CAPITAL_LETTER_S = "\U000e0053" - FLAG_FOR_CENTRAL_UG_C = "\U0001f3f4\U000e0075\U000e0067\U000e0063\U000e007f" - FLAG_FOR_ZUG_CH_ZG = "\U0001f3f4\U000e0063\U000e0068\U000e007a\U000e0067\U000e007f" - TAG_LATIN_CAPITAL_LETTER_I = "\U000e0049" - BEAMED_ASCENDING_MUSICAL_NOTES = "\U0001f39c" - FLAG_FOR_LERIK_AZ_LER = "\U0001f3f4\U000e0061\U000e007a\U000e006c\U000e0065\U000e0072\U000e007f" - PLUTO = "\u2647" - FLAG_FOR_AMERICAN_SAMOA_US_AS = "\U0001f3f4\U000e0075\U000e0073\U000e0061\U000e0073\U000e007f" - PARTIALLY_RECYCLED_PAPER_SYMBOL = "\u267d" - FLAG_FOR_OKINAWA_JP_47 = "\U0001f3f4\U000e006a\U000e0070\U000e0034\U000e0037\U000e007f" - FLAG_FOR_GADABAY_AZ_GAD = "\U0001f3f4\U000e0061\U000e007a\U000e0067\U000e0061\U000e0064\U000e007f" - FLAG_FOR_VASTERNORRLAND_SE_Y = "\U0001f3f4\U000e0073\U000e0065\U000e0079\U000e007f" - FLAG_FOR_ORDINO_AD_05 = "\U0001f3f4\U000e0061\U000e0064\U000e0030\U000e0035\U000e007f" - EARTH = "\u2641" - VERTICAL_MALE_WITH_STROKE_SIGN = "\u26a8" - TAG_VERTICAL_LINE = "\U000e007c" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_MAN = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468" - FLAG_FOR_NAFTALAN_AZ_NA = "\U0001f3f4\U000e0061\U000e007a\U000e006e\U000e0061\U000e007f" - FLAG_FOR_MASALLY_AZ_MAS = "\U0001f3f4\U000e0061\U000e007a\U000e006d\U000e0061\U000e0073\U000e007f" - FLAG_FOR_MINGACHEVIR_AZ_MI = "\U0001f3f4\U000e0061\U000e007a\U000e006d\U000e0069\U000e007f" - FLAG_FOR_KVEMO_KARTLI_GE_KK = "\U0001f3f4\U000e0067\U000e0065\U000e006b\U000e006b\U000e007f" - TAG_LATIN_CAPITAL_LETTER_X = "\U000e0058" - HEART_WITH_TIP_ON_THE_LEFT = "\U0001f394" - TAG_PERCENT_SIGN = "\U000e0025" - SATURN = "\u2644" - NEPTUNE = "\u2646" - FLAG_FOR_LAS_TUNAS_CU_10 = "\U0001f3f4\U000e0063\U000e0075\U000e0031\U000e0030\U000e007f" - THREE_LINES_CONVERGING_RIGHT = "\u269e" - FAMILY_WOMAN_WOMAN_BOY_BABY = "\U0001f469\u200d\U0001f469\u200d\U0001f466\u200d\U0001f476" - REVERSED_ROTATED_FLORAL_HEART_BULLET = "\u2619" - FLAG_FOR_FAIYUM_EG_FYM = "\U0001f3f4\U000e0065\U000e0067\U000e0066\U000e0079\U000e006d\U000e007f" - FLAG_FOR_CELJE_SI_011 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0031\U000e0031\U000e007f" - FLAG_FOR_GILAN_IR_19 = "\U0001f3f4\U000e0069\U000e0072\U000e0031\U000e0039\U000e007f" - FLAG_FOR_PANEVEZIO_MUNICIPALITY_LT_32 = "\U0001f3f4\U000e006c\U000e0074\U000e0033\U000e0032\U000e007f" - FLAG_FOR_AYSEN_CL_AI = "\U0001f3f4\U000e0063\U000e006c\U000e0061\U000e0069\U000e007f" - SCREEN = "\U0001f5b5" - WHITE_CHESS_ROOK = "\u2656" - FLAG_FOR_WEST_COAST_NZ_WTC = "\U0001f3f4\U000e006e\U000e007a\U000e0077\U000e0074\U000e0063\U000e007f" - FLAG_FOR_TANGIER_TETOUAN_MA_01 = "\U0001f3f4\U000e006d\U000e0061\U000e0030\U000e0031\U000e007f" - FLAG_FOR_NEFTCHALA_AZ_NEF = "\U0001f3f4\U000e0061\U000e007a\U000e006e\U000e0065\U000e0066\U000e007f" - FLAG_FOR_MOSCOW_RU_MOW = "\U0001f3f4\U000e0072\U000e0075\U000e006d\U000e006f\U000e0077\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - WHITE_CHESS_QUEEN = "\u2655" - FLAG_FOR_ISMAILLI_AZ_ISM = "\U0001f3f4\U000e0061\U000e007a\U000e0069\U000e0073\U000e006d\U000e007f" - BLACK_CROSS_ON_SHIELD = "\u26e8" - FLAG_FOR_TARACLIA_MD_TA = "\U0001f3f4\U000e006d\U000e0064\U000e0074\U000e0061\U000e007f" - FLAG_FOR_DROCHIA_MD_DR = "\U0001f3f4\U000e006d\U000e0064\U000e0064\U000e0072\U000e007f" - FLAG_FOR_ONTARIO_CA_ON = "\U0001f3f4\U000e0063\U000e0061\U000e006f\U000e006e\U000e007f" - EAST_SYRIAC_CROSS = "\u2671" - TAG_PLUS_SIGN = "\U000e002b" - DIGRAM_FOR_GREATER_YIN = "\u268f" - WHITE_PENNANT = "\U0001f3f1" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - FLAG_FOR_GOBUSTAN_AZ_QOB = "\U0001f3f4\U000e0061\U000e007a\U000e0071\U000e006f\U000e0062\U000e007f" - FLAG_FOR_NORTHERN_IRELAND_GB_NIR = "\U0001f3f4\U000e0067\U000e0062\U000e006e\U000e0069\U000e0072\U000e007f" - KISS_MAN_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - FLAG_FOR_NAPO_EC_N = "\U0001f3f4\U000e0065\U000e0063\U000e006e\U000e007f" - FLAG_FOR_KORCE_COUNTY_AL_06 = "\U0001f3f4\U000e0061\U000e006c\U000e0030\U000e0036\U000e007f" - FLAG_FOR_QABALA_AZ_QAB = "\U0001f3f4\U000e0061\U000e007a\U000e0071\U000e0061\U000e0062\U000e007f" - TRIGRAM_FOR_WIND = "\u2634" - FLAG_FOR_NANA_MAMBERE_CF_NM = "\U0001f3f4\U000e0063\U000e0066\U000e006e\U000e006d\U000e007f" - FLAG_FOR_OGHUZ_AZ_OGU = "\U0001f3f4\U000e0061\U000e007a\U000e006f\U000e0067\U000e0075\U000e007f" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - FLAG_FOR_SMARJESKE_TOPLICE_SI_206 = "\U0001f3f4\U000e0073\U000e0069\U000e0032\U000e0030\U000e0036\U000e007f" - FLAG_FOR_HO_CHI_MINH_CITY_VN_SG = "\U0001f3f4\U000e0076\U000e006e\U000e0073\U000e0067\U000e007f" - FLAG_FOR_QUBADLI_AZ_QBI = "\U0001f3f4\U000e0061\U000e007a\U000e0071\U000e0062\U000e0069\U000e007f" - FLAG_FOR_SUD_UBANGI_CD_SU = "\U0001f3f4\U000e0063\U000e0064\U000e0073\U000e0075\U000e007f" - KISS_WOMAN_LIGHT_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - RECYCLING_SYMBOL_FOR_TYPE_5_PLASTICS = "\u2677" - MAHJONG_TILE_CHRYSANTHEMUM = "\U0001f025" - FLAG_FOR_BRASOV_RO_BV = "\U0001f3f4\U000e0072\U000e006f\U000e0062\U000e0076\U000e007f" - FLAG_FOR_MOGILA_MK_53 = "\U0001f3f4\U000e006d\U000e006b\U000e0035\U000e0033\U000e007f" - THUNDERSTORM = "\u2608" - FLAG_FOR_JALILABAD_AZ_CAL = "\U0001f3f4\U000e0061\U000e007a\U000e0063\U000e0061\U000e006c\U000e007f" - FLAG_FOR_QUSAR_AZ_QUS = "\U0001f3f4\U000e0061\U000e007a\U000e0071\U000e0075\U000e0073\U000e007f" - TAG_QUOTATION_MARK = "\U000e0022" - DIE_FACE_3 = "\u2682" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_QAZAKH_AZ_QAZ = "\U0001f3f4\U000e0061\U000e007a\U000e0071\U000e0061\U000e007a\U000e007f" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - FLAG_FOR_KAVANGO_EAST_NA_KE = "\U0001f3f4\U000e006e\U000e0061\U000e006b\U000e0065\U000e007f" - FLAG_FOR_QAKH_AZ_QAX = "\U0001f3f4\U000e0061\U000e007a\U000e0071\U000e0061\U000e0078\U000e007f" - FLAG_FOR_SAINT_PETER_AG_07 = "\U0001f3f4\U000e0061\U000e0067\U000e0030\U000e0037\U000e007f" - FLAG_FOR_BAJA_CALIFORNIA_MX_BCN = "\U0001f3f4\U000e006d\U000e0078\U000e0062\U000e0063\U000e006e\U000e007f" - KISS_WOMAN_DARK_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - FLAG_FOR_ASGABAT_TM_S = "\U0001f3f4\U000e0074\U000e006d\U000e0073\U000e007f" - FLAG_FOR_SABIRABAD_AZ_SAB = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e0061\U000e0062\U000e007f" - BLACK_SHOGI_PIECE = "\u2617" - THREE_LINES_CONVERGING_LEFT = "\u269f" - FAMILY_WOMAN_BOY_BABY = "\U0001f469\u200d\U0001f466\u200d\U0001f476" - MUSIC_NATURAL_SIGN = "\u266e" - FLAG_FOR_QUTHING_LS_G = "\U0001f3f4\U000e006c\U000e0073\U000e0067\U000e007f" - FLAG_FOR_JONGLEI_SS_JG = "\U0001f3f4\U000e0073\U000e0073\U000e006a\U000e0067\U000e007f" - FLAG_FOR_NELSON_NZ_NSN = "\U0001f3f4\U000e006e\U000e007a\U000e006e\U000e0073\U000e006e\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - FLAG_FOR_VIENNA_AT_9 = "\U0001f3f4\U000e0061\U000e0074\U000e0039\U000e007f" - FLAG_FOR_SHABRAN_AZ_SBN = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e0062\U000e006e\U000e007f" - DIE_FACE_4 = "\u2683" - WHITE_SHOGI_PIECE = "\u2616" - RECYCLING_SYMBOL_FOR_TYPE_4_PLASTICS = "\u2676" - FLAG_FOR_MAKEDONSKI_BROD_MK_52 = "\U0001f3f4\U000e006d\U000e006b\U000e0035\U000e0032\U000e007f" - KISS_WOMAN_MAN_MEDIUM_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - FLAG_FOR_SHAKI_DISTRICT_AZ_SAK = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e0061\U000e006b\U000e007f" - URANUS = "\u2645" - FLAG_FOR_QUBA_AZ_QBA = "\U0001f3f4\U000e0061\U000e007a\U000e0071\U000e0062\U000e0061\U000e007f" - FLAG_FOR_SAMUKH_AZ_SMX = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e006d\U000e0078\U000e007f" - FLAG_FOR_FEDERAL_CAPITAL_TERRITORY_NG_FC = "\U0001f3f4\U000e006e\U000e0067\U000e0066\U000e0063\U000e007f" - FLAG_FOR_FRIULI_VENEZIA_GIULIA_IT_36 = "\U0001f3f4\U000e0069\U000e0074\U000e0033\U000e0036\U000e007f" - WHITE_FLAG_2 = "\u2690" - DIE_FACE_2 = "\u2681" - FLAG_FOR_SHAKI_AZ_SA = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e0061\U000e007f" - FLAG_FOR_LA_PAMPA_AR_L = "\U0001f3f4\U000e0061\U000e0072\U000e006c\U000e007f" - FLAG_FOR_SIAZAN_AZ_SIY = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e0069\U000e0079\U000e007f" - FLAG_FOR_NEW_IRELAND_PG_NIK = "\U0001f3f4\U000e0070\U000e0067\U000e006e\U000e0069\U000e006b\U000e007f" - FLAG_FOR_AKMENE_LT_01 = "\U0001f3f4\U000e006c\U000e0074\U000e0030\U000e0031\U000e007f" - FLAG_FOR_SAINT_LOUIS_SC_22 = "\U0001f3f4\U000e0073\U000e0063\U000e0032\U000e0032\U000e007f" - FLAG_FOR_UPPER_TAKUTU_UPPER_ESSEQUIBO_GY_UT = "\U0001f3f4\U000e0067\U000e0079\U000e0075\U000e0074\U000e007f" - FLAG_FOR_SHIRVAN_AZ_SR = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e0072\U000e007f" - FLAG_FOR_HAUT_MBOMOU_CF_HM = "\U0001f3f4\U000e0063\U000e0066\U000e0068\U000e006d\U000e007f" - TRIANGLE_WITH_ROUNDED_CORNERS = "\U0001f6c6" - FLAG_FOR_SHAMAKHI_AZ_SMI = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e006d\U000e0069\U000e007f" - KISS_WOMAN_DARK_SKIN_TONE_MAN = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f467\U0001f3ff" - KISS_WOMAN_DARK_SKIN_TONE_WOMAN = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - DOCUMENT_WITH_TEXT = "\U0001f5b9" - FLAG_FOR_TOVUZ_AZ_TOV = "\U0001f3f4\U000e0061\U000e007a\U000e0074\U000e006f\U000e0076\U000e007f" - FLAG_FOR_PORT_MORESBY_PG_NCD = "\U0001f3f4\U000e0070\U000e0067\U000e006e\U000e0063\U000e0064\U000e007f" - WHITE_SUN_WITH_RAYS = "\u263c" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f467\U0001f3fd" - MAHJONG_TILE_AUTUMN = "\U0001f028" - FLAG_FOR_UJAR_AZ_UCA = "\U0001f3f4\U000e0061\U000e007a\U000e0075\U000e0063\U000e0061\U000e007f" - FLAG_FOR_STRUMICA_MK_73 = "\U0001f3f4\U000e006d\U000e006b\U000e0037\U000e0033\U000e007f" - FLAG_FOR_LVIVSHCHYNA_UA_46 = "\U0001f3f4\U000e0075\U000e0061\U000e0034\U000e0036\U000e007f" - TAG_LATIN_SMALL_LETTER_H = "\U000e0068" - KISS_MAN_DARK_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - FAMILY_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f466\U0001f3ff" - SEMISEXTILE = "\u26ba" - BLACK_TOUCHTONE_TELEPHONE = "\U0001f57f" - WHITE_CIRCLE_WITH_DOT_RIGHT = "\u2686" - FAMILY_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_LIPETSK_RU_LIP = "\U0001f3f4\U000e0072\U000e0075\U000e006c\U000e0069\U000e0070\U000e007f" - FLAG_FOR_DOL_PRI_LJUBLJANI_SI_022 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0032\U000e0032\U000e007f" - KISS_MAN_MAN_DARK_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - WHITE_DIAMOND_IN_SQUARE = "\u26cb" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - FLAG_FOR_KHIZI_AZ_XIZ = "\U0001f3f4\U000e0061\U000e007a\U000e0078\U000e0069\U000e007a\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f467\U0001f3fd" - KISS_WOMAN_DARK_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - UP_POINTING_MILITARY_AIRPLANE = "\U0001f6e6" - FLAG_FOR_KHOJALI_AZ_XCI = "\U0001f3f4\U000e0061\U000e007a\U000e0078\U000e0063\U000e0069\U000e007f" - FLAG_FOR_YEVLAKH_DISTRICT_AZ_YEV = "\U0001f3f4\U000e0061\U000e007a\U000e0079\U000e0065\U000e0076\U000e007f" - FLAG_FOR_ZANZIBAR_CENTRAL_SOUTH_TZ_11 = "\U0001f3f4\U000e0074\U000e007a\U000e0031\U000e0031\U000e007f" - TAG_LEFT_SQUARE_BRACKET = "\U000e005b" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_NORTHLAND_NZ_NTL = "\U0001f3f4\U000e006e\U000e007a\U000e006e\U000e0074\U000e006c\U000e007f" - DIVORCE_SYMBOL = "\u26ae" - FLAG_FOR_BALAKAN_AZ_BAL = "\U0001f3f4\U000e0061\U000e007a\U000e0062\U000e0061\U000e006c\U000e007f" - FLAG_FOR_PROVENCE_ALPES_COTE_D_AZUR_FR_PAC = "\U0001f3f4\U000e0066\U000e0072\U000e0070\U000e0061\U000e0063\U000e007f" - FLAG_FOR_SHUSHA_AZ_SUS = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e0075\U000e0073\U000e007f" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FLAG_FOR_MONTSERRADO_LR_MO = "\U0001f3f4\U000e006c\U000e0072\U000e006d\U000e006f\U000e007f" - FAMILY_MAN_MAN_GIRL_BABY = "\U0001f468\u200d\U0001f468\u200d\U0001f467\u200d\U0001f476" - FLAG_FOR_YARDYMLI_AZ_YAR = "\U0001f3f4\U000e0061\U000e007a\U000e0079\U000e0061\U000e0072\U000e007f" - FLAG_FOR_SALYAN_AZ_SAL = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e0061\U000e006c\U000e007f" - MALE_AND_FEMALE_SIGN = "\u26a5" - FLAG_FOR_NEW_CALEDONIA_FR_NC = "\U0001f3f4\U000e0066\U000e0072\U000e006e\U000e0063\U000e007f" - FRAME_WITH_TILES = "\U0001f5bd" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f466\U0001f3fe" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_SAINT_THOMAS_BB_11 = "\U0001f3f4\U000e0062\U000e0062\U000e0031\U000e0031\U000e007f" - FLAG_FOR_CONSTANTINE_DZ_25 = "\U0001f3f4\U000e0064\U000e007a\U000e0032\U000e0035\U000e007f" - FLAG_FOR_YEVLAKH_AZ_YE = "\U0001f3f4\U000e0061\U000e007a\U000e0079\U000e0065\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f476\U0001f3ff" - COUPLE_WITH_HEART_MAN_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - FLAG_FOR_BOTOSANI_RO_BT = "\U0001f3f4\U000e0072\U000e006f\U000e0062\U000e0074\U000e007f" - FLAG_FOR_ZAQATALA_AZ_ZAQ = "\U0001f3f4\U000e0061\U000e007a\U000e007a\U000e0061\U000e0071\U000e007f" - FLAG_FOR_CHIN_MM_14 = "\U0001f3f4\U000e006d\U000e006d\U000e0031\U000e0034\U000e007f" - FLAG_FOR_KHOST_AF_KHO = "\U0001f3f4\U000e0061\U000e0066\U000e006b\U000e0068\U000e006f\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f476\U0001f3fb" - QUARTER_NOTE = "\u2669" - HEAVY_LATIN_CROSS = "\U0001f547" - FLAG_FOR_QUINDIO_CO_QUI = "\U0001f3f4\U000e0063\U000e006f\U000e0071\U000e0075\U000e0069\U000e007f" - FLAG_FOR_CUSCO_PE_CUS = "\U0001f3f4\U000e0070\U000e0065\U000e0063\U000e0075\U000e0073\U000e007f" - COUPLE_WITH_HEART_WOMAN_WOMAN_DARK_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - MAHJONG_TILE_BACK = "\U0001f02b" - FLAG_FOR_SAINT_ANDREW_BB_02 = "\U0001f3f4\U000e0062\U000e0062\U000e0030\U000e0032\U000e007f" - FLAG_FOR_SOUTH_HOLLAND_NL_ZH = "\U0001f3f4\U000e006e\U000e006c\U000e007a\U000e0068\U000e007f" - FLAG_FOR_LAC_TD_LC = "\U0001f3f4\U000e0074\U000e0064\U000e006c\U000e0063\U000e007f" - FLAG_FOR_VELIKO_TARNOVO_BG_04 = "\U0001f3f4\U000e0062\U000e0067\U000e0030\U000e0034\U000e007f" - FLAG_FOR_EASTERN_FJ_E = "\U0001f3f4\U000e0066\U000e006a\U000e0065\U000e007f" - COUPLE_WITH_HEART_MAN_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - FLAG_FOR_SHAMKIR_AZ_SKR = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e006b\U000e0072\U000e007f" - PEN_OVER_STAMPED_ENVELOPE = "\U0001f586" - FLAG_FOR_BALEARIC_ISLANDS_ES_IB = "\U0001f3f4\U000e0065\U000e0073\U000e0069\U000e0062\U000e007f" - FLAG_FOR_BATKEN_KG_B = "\U0001f3f4\U000e006b\U000e0067\U000e0062\U000e007f" - FLAG_FOR_NAKHCHIVAN_AR_AZ_NX = "\U0001f3f4\U000e0061\U000e007a\U000e006e\U000e0078\U000e007f" - FLAG_FOR_SAINT_LUCY_BB_07 = "\U0001f3f4\U000e0062\U000e0062\U000e0030\U000e0037\U000e007f" - TAG_LATIN_SMALL_LETTER_N = "\U000e006e" - FLAG_FOR_INDIANA_US_IN = "\U0001f3f4\U000e0075\U000e0073\U000e0069\U000e006e\U000e007f" - FLAG_FOR_SAINT_JOSEPH_BB_06 = "\U0001f3f4\U000e0062\U000e0062\U000e0030\U000e0036\U000e007f" - FAMILY_MAN_WOMAN_BABY_BOY = "\U0001f468\u200d\U0001f469\u200d\U0001f476\u200d\U0001f466" - FLAG_FOR_TARTAR_AZ_TAR = "\U0001f3f4\U000e0061\U000e007a\U000e0074\U000e0061\U000e0072\U000e007f" - CONJUNCTION = "\u260c" - FLAG_FOR_SAINT_ROMAN_MC_SR = "\U0001f3f4\U000e006d\U000e0063\U000e0073\U000e0072\U000e007f" - FLAG_FOR_BREST_BY_BR = "\U0001f3f4\U000e0062\U000e0079\U000e0062\U000e0072\U000e007f" - WOMAN_IN_TUXEDO_MEDIUM_SKIN_TONE = "\U0001f935\U0001f3fd\u200d\u2640\ufe0f" - FLAG_FOR_SASKATCHEWAN_CA_SK = "\U0001f3f4\U000e0063\U000e0061\U000e0073\U000e006b\U000e007f" - FLAG_FOR_SAINT_GEORGE_VC_04 = "\U0001f3f4\U000e0076\U000e0063\U000e0030\U000e0034\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f466\U0001f3fb" - MAHJONG_TILE_THREE_OF_CHARACTERS = "\U0001f009" - FLAG_FOR_SAINT_PHILIP_BB_10 = "\U0001f3f4\U000e0062\U000e0062\U000e0031\U000e0030\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_ZARDAB_AZ_ZAR = "\U0001f3f4\U000e0061\U000e007a\U000e007a\U000e0061\U000e0072\U000e007f" - FAMILY_MAN_MAN_BABY_BOY = "\U0001f468\u200d\U0001f468\u200d\U0001f476\u200d\U0001f466" - FLAG_FOR_BARISAL_BD_A = "\U0001f3f4\U000e0062\U000e0064\U000e0061\U000e007f" - FLAG_FOR_SANTO_DOMINGO_DE_LOS_TSACHILAS_EC_SD = "\U0001f3f4\U000e0065\U000e0063\U000e0073\U000e0064\U000e007f" - FLAG_FOR_ZANGILAN_AZ_ZAN = "\U0001f3f4\U000e0061\U000e007a\U000e007a\U000e0061\U000e006e\U000e007f" - INTERLOCKED_FEMALE_AND_MALE_SIGN = "\u26a4" - FLAG_FOR_WESTERN_LK_1 = "\U0001f3f4\U000e006c\U000e006b\U000e0031\U000e007f" - FLAG_FOR_KINGSTON_JM_01 = "\U0001f3f4\U000e006a\U000e006d\U000e0030\U000e0031\U000e007f" - DIESEL_LOCOMOTIVE = "\U0001f6f2" - NOTE = "\U0001f5c8" - MAHJONG_TILE_EIGHT_OF_CHARACTERS = "\U0001f00e" - SIDEWAYS_WHITE_RIGHT_POINTING_INDEX = "\U0001f599" - TAG_LESS_THAN_SIGN = "\U000e003c" - FLAG_FOR_RAJSHAHI_DIVISION_BD_E = "\U0001f3f4\U000e0062\U000e0064\U000e0065\U000e007f" - KISS_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - FAMILY_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_SARDINIA_IT_88 = "\U0001f3f4\U000e0069\U000e0074\U000e0038\U000e0038\U000e007f" - HEAVY_WHITE_DOWN_POINTING_TRIANGLE = "\u26db" - FLAG_FOR_KHULNA_DIVISION_BD_D = "\U0001f3f4\U000e0062\U000e0064\U000e0064\U000e007f" - FLAG_FOR_SAINT_PETER_BB_09 = "\U0001f3f4\U000e0062\U000e0062\U000e0030\U000e0039\U000e007f" - MUSIC_SHARP_SIGN = "\u266f" - RIGHT_HANDED_INTERLACED_PENTAGRAM = "\u26e5" - TAG_LATIN_SMALL_LETTER_C = "\U000e0063" - FLAG_FOR_ADDIS_ABABA_ET_AA = "\U0001f3f4\U000e0065\U000e0074\U000e0061\U000e0061\U000e007f" - FLAG_FOR_PORTLAND_JM_04 = "\U0001f3f4\U000e006a\U000e006d\U000e0030\U000e0034\U000e007f" - FLAG_FOR_MYMENSINGH_DIVISION_BD_H = "\U0001f3f4\U000e0062\U000e0064\U000e0068\U000e007f" - FLAG_FOR_PORT_OF_SPAIN_TT_POS = "\U0001f3f4\U000e0074\U000e0074\U000e0070\U000e006f\U000e0073\U000e007f" - FLAG_FOR_CASANARE_CO_CAS = "\U0001f3f4\U000e0063\U000e006f\U000e0063\U000e0061\U000e0073\U000e007f" - TAG_LATIN_CAPITAL_LETTER_Q = "\U000e0051" - TRIGRAM_FOR_THUNDER = "\u2633" - POCKET_CALCULATOR = "\U0001f5a9" - RIGHT_SPEAKER_WITH_ONE_SOUND_WAVE = "\U0001f569" - FLAG_FOR_LOS_SANTOS_PA_7 = "\U0001f3f4\U000e0070\U000e0061\U000e0037\U000e007f" - FLAG_FOR_LOWER_AUSTRIA_AT_3 = "\U0001f3f4\U000e0061\U000e0074\U000e0033\U000e007f" - FLAG_FOR_SUMQAYIT_AZ_SM = "\U0001f3f4\U000e0061\U000e007a\U000e0073\U000e006d\U000e007f" - FLAG_FOR_CASCADES_BF_02 = "\U0001f3f4\U000e0062\U000e0066\U000e0030\U000e0032\U000e007f" - FLAG_FOR_BOUCLE_DU_MOUHOUN_BF_01 = "\U0001f3f4\U000e0062\U000e0066\U000e0030\U000e0031\U000e007f" - FLAG_FOR_AL_HUDAYDAH_YE_HU = "\U0001f3f4\U000e0079\U000e0065\U000e0068\U000e0075\U000e007f" - FLAG_FOR_SAINT_PATRICK_GD_06 = "\U0001f3f4\U000e0067\U000e0064\U000e0030\U000e0036\U000e007f" - FLAG_FOR_NOVA_SCOTIA_CA_NS = "\U0001f3f4\U000e0063\U000e0061\U000e006e\U000e0073\U000e007f" - FLAG_FOR_MINAS_GERAIS_BR_MG = "\U0001f3f4\U000e0062\U000e0072\U000e006d\U000e0067\U000e007f" - FLAG_FOR_CENTRE_SUD_BF_07 = "\U0001f3f4\U000e0062\U000e0066\U000e0030\U000e0037\U000e007f" - MUSICAL_KEYBOARD_WITH_JACKS = "\U0001f398" - FLAG_FOR_BENGO_AO_BGO = "\U0001f3f4\U000e0061\U000e006f\U000e0062\U000e0067\U000e006f\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - FLAG_FOR_CENTRE_OUEST_BF_06 = "\U0001f3f4\U000e0062\U000e0066\U000e0030\U000e0036\U000e007f" - GEAR_WITHOUT_HUB = "\u26ed" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_CENTRE_BF_03 = "\U0001f3f4\U000e0062\U000e0066\U000e0030\U000e0033\U000e007f" - FAMILY_WOMAN_MAN_GIRL_GIRL = "\U0001f469\u200d\U0001f468\u200d\U0001f467\u200d\U0001f467" - WHITE_TWO_WAY_LEFT_WAY_TRAFFIC = "\u26d7" - FLAG_FOR_HOWLAND_ISLAND_UM_84 = "\U0001f3f4\U000e0075\U000e006d\U000e0038\U000e0034\U000e007f" - FLAG_FOR_EST_BF_08 = "\U0001f3f4\U000e0062\U000e0066\U000e0030\U000e0038\U000e007f" - FLAG_FOR_ELBASAN_COUNTY_AL_03 = "\U0001f3f4\U000e0061\U000e006c\U000e0030\U000e0033\U000e007f" - FLAG_FOR_RATAK_CHAIN_MH_T = "\U0001f3f4\U000e006d\U000e0068\U000e0074\U000e007f" - FLAG_FOR_CANARY_ISLANDS_ES_CN = "\U0001f3f4\U000e0065\U000e0073\U000e0063\U000e006e\U000e007f" - FLAG_FOR_PLATEAU_CENTRAL_BF_11 = "\U0001f3f4\U000e0062\U000e0066\U000e0031\U000e0031\U000e007f" - FLAG_FOR_DOUKKALA_ABDA_MA_10 = "\U0001f3f4\U000e006d\U000e0061\U000e0031\U000e0030\U000e007f" - FLAG_FOR_TERENGGANU_MY_11 = "\U0001f3f4\U000e006d\U000e0079\U000e0031\U000e0031\U000e007f" - MAN_WITH_HEADSCARF_MEDIUM_DARK_SKIN_TONE = "\U0001f9d5\U0001f3fe\u200d\u2642\ufe0f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - FLAG_FOR_SANTA_CRUZ_AR_Z = "\U0001f3f4\U000e0061\U000e0072\U000e007a\U000e007f" - FLAG_FOR_DHAKA_DIVISION_BD_C = "\U0001f3f4\U000e0062\U000e0064\U000e0063\U000e007f" - FLAG_FOR_JUJUY_AR_Y = "\U0001f3f4\U000e0061\U000e0072\U000e0079\U000e007f" - CIRCLED_INFORMATION_SOURCE = "\U0001f6c8" - FLAG_FOR_SYLHET_DIVISION_BD_G = "\U0001f3f4\U000e0062\U000e0064\U000e0067\U000e007f" - FLAG_FOR_VIDIN_BG_05 = "\U0001f3f4\U000e0062\U000e0067\U000e0030\U000e0035\U000e007f" - FLAG_FOR_ARKHANGELSK_RU_ARK = "\U0001f3f4\U000e0072\U000e0075\U000e0061\U000e0072\U000e006b\U000e007f" - MAHJONG_TILE_ONE_OF_CHARACTERS = "\U0001f007" - FLAG_FOR_BADAKHSHAN_AF_BDS = "\U0001f3f4\U000e0061\U000e0066\U000e0062\U000e0064\U000e0073\U000e007f" - FLAG_FOR_ALGIERS_DZ_16 = "\U0001f3f4\U000e0064\U000e007a\U000e0031\U000e0036\U000e007f" - FLAG_FOR_STEPANAKERT_AZ_XA = "\U0001f3f4\U000e0061\U000e007a\U000e0078\U000e0061\U000e007f" - FLAG_FOR_GABROVO_BG_07 = "\U0001f3f4\U000e0062\U000e0067\U000e0030\U000e0037\U000e007f" - FLAG_FOR_BUENOS_AIRES_PROVINCE_AR_B = "\U0001f3f4\U000e0061\U000e0072\U000e0062\U000e007f" - FLAG_FOR_DOBRICH_BG_08 = "\U0001f3f4\U000e0062\U000e0067\U000e0030\U000e0038\U000e007f" - BLACK_PENNANT = "\U0001f3f2" - FLAG_FOR_CENTRE_EST_BF_04 = "\U0001f3f4\U000e0062\U000e0066\U000e0030\U000e0034\U000e007f" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - KISS_MAN_LIGHT_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - FLAG_FOR_BAHIA_BR_BA = "\U0001f3f4\U000e0062\U000e0072\U000e0062\U000e0061\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - MAHJONG_TILE_FIVE_OF_CHARACTERS = "\U0001f00b" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_AKITA_JP_05 = "\U0001f3f4\U000e006a\U000e0070\U000e0030\U000e0035\U000e007f" - FLAG_FOR_KYUSTENDIL_BG_10 = "\U0001f3f4\U000e0062\U000e0067\U000e0031\U000e0030\U000e007f" - CHIRON = "\u26b7" - FLAG_FOR_RALIK_CHAIN_MH_L = "\U0001f3f4\U000e006d\U000e0068\U000e006c\U000e007f" - FLAG_FOR_LOVECH_BG_11 = "\U0001f3f4\U000e0062\U000e0067\U000e0031\U000e0031\U000e007f" - FLAG_FOR_VAYOTS_DZOR_AM_VD = "\U0001f3f4\U000e0061\U000e006d\U000e0076\U000e0064\U000e007f" - FLAG_FOR_BANTEAY_MEANCHEY_KH_1 = "\U0001f3f4\U000e006b\U000e0068\U000e0031\U000e007f" - FLAG_FOR_PAZARDZHIK_BG_13 = "\U0001f3f4\U000e0062\U000e0067\U000e0031\U000e0033\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f467\U0001f3fe" - DIE_FACE_5 = "\u2684" - FAMILY_WOMAN_WOMAN_BABY_GIRL = "\U0001f469\u200d\U0001f469\u200d\U0001f476\u200d\U0001f467" - FLAG_FOR_BLAGOEVGRAD_BG_01 = "\U0001f3f4\U000e0062\U000e0067\U000e0030\U000e0031\U000e007f" - FLAG_FOR_CARRIACOU_AND_PETITE_MARTINIQUE_GD_10 = "\U0001f3f4\U000e0067\U000e0064\U000e0031\U000e0030\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_PLOVDIV_BG_16 = "\U0001f3f4\U000e0062\U000e0067\U000e0031\U000e0036\U000e007f" - FLAG_FOR_PLEVEN_BG_15 = "\U0001f3f4\U000e0062\U000e0067\U000e0031\U000e0035\U000e007f" - FLAG_FOR_NORD_BF_10 = "\U0001f3f4\U000e0062\U000e0066\U000e0031\U000e0030\U000e007f" - FLAG_FOR_KURDISTAN_IR_16 = "\U0001f3f4\U000e0069\U000e0072\U000e0031\U000e0036\U000e007f" - FLAG_FOR_DASHKASAN_AZ_DAS = "\U0001f3f4\U000e0061\U000e007a\U000e0064\U000e0061\U000e0073\U000e007f" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_MAN = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468" - FLAG_FOR_BORDJ_BOU_ARRERIDJ_DZ_34 = "\U0001f3f4\U000e0064\U000e007a\U000e0033\U000e0034\U000e007f" - TAG_AMPERSAND = "\U000e0026" - FLAG_FOR_VALLEE_DU_BANDAMA_CI_VB = "\U0001f3f4\U000e0063\U000e0069\U000e0076\U000e0062\U000e007f" - FLAG_FOR_RAZGRAD_BG_17 = "\U0001f3f4\U000e0062\U000e0067\U000e0031\U000e0037\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_SOFIA_BG_22 = "\U0001f3f4\U000e0062\U000e0067\U000e0032\U000e0032\U000e007f" - FLAG_FOR_SOFIA_DISTRICT_BG_23 = "\U0001f3f4\U000e0062\U000e0067\U000e0032\U000e0033\U000e007f" - FLAG_FOR_TARGOVISHTE_BG_25 = "\U0001f3f4\U000e0062\U000e0067\U000e0032\U000e0035\U000e007f" - FLAG_FOR_LOPBURI_TH_16 = "\U0001f3f4\U000e0074\U000e0068\U000e0031\U000e0036\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_CUNENE_AO_CNN = "\U0001f3f4\U000e0061\U000e006f\U000e0063\U000e006e\U000e006e\U000e007f" - FLAG_FOR_ADJARA_GE_AJ = "\U0001f3f4\U000e0067\U000e0065\U000e0061\U000e006a\U000e007f" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - FLAG_FOR_VARNA_BG_03 = "\U0001f3f4\U000e0062\U000e0067\U000e0030\U000e0033\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_YOBE_NG_YO = "\U0001f3f4\U000e006e\U000e0067\U000e0079\U000e006f\U000e007f" - FLAG_FOR_PERNIK_BG_14 = "\U0001f3f4\U000e0062\U000e0067\U000e0031\U000e0034\U000e007f" - FLAG_FOR_BAY_SOMALIA_SO_BY = "\U0001f3f4\U000e0073\U000e006f\U000e0062\U000e0079\U000e007f" - FLAG_FOR_SAINT_GEORGE_BB_03 = "\U0001f3f4\U000e0062\U000e0062\U000e0030\U000e0033\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f476\U0001f3fb" - WOMAN_WITH_HEADSCARF_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d5\U0001f3fc\u200d\u2640\ufe0f" - FLAG_FOR_WESTERN_CAPE_ZA_WC = "\U0001f3f4\U000e007a\U000e0061\U000e0077\U000e0063\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f466\U0001f3fb" - FLAG_FOR_HASKOVO_BG_26 = "\U0001f3f4\U000e0062\U000e0067\U000e0032\U000e0036\U000e007f" - FLAG_FOR_YAMBOL_BG_28 = "\U0001f3f4\U000e0062\U000e0067\U000e0032\U000e0038\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - FLAG_FOR_SCHAAN_LI_07 = "\U0001f3f4\U000e006c\U000e0069\U000e0030\U000e0037\U000e007f" - FLAG_FOR_STREDOCESKY_KRAJ_CZ_20 = "\U0001f3f4\U000e0063\U000e007a\U000e0032\U000e0030\U000e007f" - FLAG_FOR_ZAVRC_SI_143 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0034\U000e0033\U000e007f" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - FLAG_FOR_TACHIRA_VE_S = "\U0001f3f4\U000e0076\U000e0065\U000e0073\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_SOUTHERN_BH_14 = "\U0001f3f4\U000e0062\U000e0068\U000e0031\U000e0034\U000e007f" - FLAG_FOR_SIBIU_RO_SB = "\U0001f3f4\U000e0072\U000e006f\U000e0073\U000e0062\U000e007f" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_WOMAN = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469" - DIE_FACE_1 = "\u2680" - FAMILY_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_SOUTHERN_IS_8 = "\U0001f3f4\U000e0069\U000e0073\U000e0038\U000e007f" - FLAG_FOR_MUHARRAQ_BH_15 = "\U0001f3f4\U000e0062\U000e0068\U000e0031\U000e0035\U000e007f" - FLAG_FOR_BRUSSELS_BE_BRU = "\U0001f3f4\U000e0062\U000e0065\U000e0062\U000e0072\U000e0075\U000e007f" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - WOMAN_WITH_HEADSCARF_MEDIUM_SKIN_TONE = "\U0001f9d5\U0001f3fd\u200d\u2640\ufe0f" - FLAG_FOR_CENTRE_NORD_BF_05 = "\U0001f3f4\U000e0062\U000e0066\U000e0030\U000e0035\U000e007f" - ENVELOPE_WITH_LIGHTNING = "\U0001f584" - FLAG_FOR_COLORADO_US_CO = "\U0001f3f4\U000e0075\U000e0073\U000e0063\U000e006f\U000e007f" - FLAG_FOR_CAPITAL_BH_13 = "\U0001f3f4\U000e0062\U000e0068\U000e0031\U000e0033\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_TATARSTAN_RU_TA = "\U0001f3f4\U000e0072\U000e0075\U000e0074\U000e0061\U000e007f" - FLAG_FOR_NORTHERN_BH_17 = "\U0001f3f4\U000e0062\U000e0068\U000e0031\U000e0037\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_BUJUMBURA_BI_BM = "\U0001f3f4\U000e0062\U000e0069\U000e0062\U000e006d\U000e007f" - WEST_SYRIAC_CROSS = "\u2670" - FLAG_FOR_SA_DAH_YE_SD = "\U0001f3f4\U000e0079\U000e0065\U000e0073\U000e0064\U000e007f" - FLAG_FOR_AL_QASSIM_SA_05 = "\U0001f3f4\U000e0073\U000e0061\U000e0030\U000e0035\U000e007f" - FLAG_FOR_CANKUZO_BI_CA = "\U0001f3f4\U000e0062\U000e0069\U000e0063\U000e0061\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_NORTHERN_TERRITORY_AU_NT = "\U0001f3f4\U000e0061\U000e0075\U000e006e\U000e0074\U000e007f" - CROSS_OF_JERUSALEM = "\u2629" - FLAG_FOR_CHUKOTKA_OKRUG_RU_CHU = "\U0001f3f4\U000e0072\U000e0075\U000e0063\U000e0068\U000e0075\U000e007f" - FLAG_FOR_KARDZHALI_BG_09 = "\U0001f3f4\U000e0062\U000e0067\U000e0030\U000e0039\U000e007f" - FLAG_FOR_SALA_LV_085 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0038\U000e0035\U000e007f" - FLAG_FOR_CENTRAL_DENMARK_DK_82 = "\U0001f3f4\U000e0064\U000e006b\U000e0038\U000e0032\U000e007f" - FLAG_FOR_BURURI_BI_BR = "\U0001f3f4\U000e0062\U000e0069\U000e0062\U000e0072\U000e007f" - FLAG_FOR_WALLONIA_BE_WAL = "\U0001f3f4\U000e0062\U000e0065\U000e0077\U000e0061\U000e006c\U000e007f" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - TAG_LATIN_SMALL_LETTER_G = "\U000e0067" - FLAG_FOR_MARTINIQUE_FR_MQ = "\U0001f3f4\U000e0066\U000e0072\U000e006d\U000e0071\U000e007f" - FLAG_FOR_KARUZI_BI_KR = "\U0001f3f4\U000e0062\U000e0069\U000e006b\U000e0072\U000e007f" - FLAG_FOR_BABYLON_IQ_BB = "\U0001f3f4\U000e0069\U000e0071\U000e0062\U000e0062\U000e007f" - FLAG_FOR_KIRUNDO_BI_KI = "\U0001f3f4\U000e0062\U000e0069\U000e006b\U000e0069\U000e007f" - FLAG_FOR_LANKARAN_DISTRICT_AZ_LAN = "\U0001f3f4\U000e0061\U000e007a\U000e006c\U000e0061\U000e006e\U000e007f" - FLAG_FOR_MURAMVYA_BI_MU = "\U0001f3f4\U000e0062\U000e0069\U000e006d\U000e0075\U000e007f" - FLAG_FOR_MUYINGA_BI_MY = "\U0001f3f4\U000e0062\U000e0069\U000e006d\U000e0079\U000e007f" - FLAG_FOR_TIANJIN_CN_12 = "\U0001f3f4\U000e0063\U000e006e\U000e0031\U000e0032\U000e007f" - FLAG_FOR_LAAYOUNE_BOUJDOUR_SAKIA_EL_HAMRA_MA_15 = "\U0001f3f4\U000e006d\U000e0061\U000e0031\U000e0035\U000e007f" - DIGRAM_FOR_GREATER_YANG = "\u268c" - FLAG_FOR_SHUMEN_BG_27 = "\U0001f3f4\U000e0062\U000e0067\U000e0032\U000e0037\U000e007f" - RECYCLED_PAPER_SYMBOL = "\u267c" - FLAG_FOR_NGOZI_BI_NG = "\U0001f3f4\U000e0062\U000e0069\U000e006e\U000e0067\U000e007f" - FAMILY_WOMAN_MAN_BOY_BOY = "\U0001f469\u200d\U0001f468\u200d\U0001f466\u200d\U0001f466" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - FLAG_FOR_SISTAN_AND_BALUCHESTAN_IR_13 = "\U0001f3f4\U000e0069\U000e0072\U000e0031\U000e0033\U000e007f" - FLAG_FOR_RUMONGE_BI_RM = "\U0001f3f4\U000e0062\U000e0069\U000e0072\U000e006d\U000e007f" - FLAG_FOR_AOSTA_VALLEY_IT_23 = "\U0001f3f4\U000e0069\U000e0074\U000e0032\U000e0033\U000e007f" - FLAG_FOR_NOVO_MESTO_SI_085 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0038\U000e0035\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc" - BEAMED_SIXTEENTH_NOTES = "\u266c" - FAMILY_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_HAUTS_DE_FRANCE_FR_HDF = "\U0001f3f4\U000e0066\U000e0072\U000e0068\U000e0064\U000e0066\U000e007f" - FLAG_FOR_RIO_NEGRO_AR_R = "\U0001f3f4\U000e0061\U000e0072\U000e0072\U000e007f" - WHITE_CHESS_KNIGHT = "\u2658" - FLAG_FOR_ALIBORI_BJ_AL = "\U0001f3f4\U000e0062\U000e006a\U000e0061\U000e006c\U000e007f" - FLAG_FOR_DONGA_BJ_DO = "\U0001f3f4\U000e0062\U000e006a\U000e0064\U000e006f\U000e007f" - FLAG_FOR_HAMBURG_DE_HH = "\U0001f3f4\U000e0064\U000e0065\U000e0068\U000e0068\U000e007f" - FLAG_FOR_SAHEL_BF_12 = "\U0001f3f4\U000e0062\U000e0066\U000e0031\U000e0032\U000e007f" - FLAG_FOR_ATAKORA_BJ_AK = "\U0001f3f4\U000e0062\U000e006a\U000e0061\U000e006b\U000e007f" - FLAG_FOR_RUYIGI_BI_RY = "\U0001f3f4\U000e0062\U000e0069\U000e0072\U000e0079\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469" - FLAG_FOR_MA_AN_JO_MN = "\U0001f3f4\U000e006a\U000e006f\U000e006d\U000e006e\U000e007f" - FLAG_FOR_SMOLYAN_BG_21 = "\U0001f3f4\U000e0062\U000e0067\U000e0032\U000e0031\U000e007f" - FLAG_FOR_LITTORAL_BJ_LI = "\U0001f3f4\U000e0062\U000e006a\U000e006c\U000e0069\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_ZOU_BJ_ZO = "\U0001f3f4\U000e0062\U000e006a\U000e007a\U000e006f\U000e007f" - FLAG_FOR_RED_SEA_EG_BA = "\U0001f3f4\U000e0065\U000e0067\U000e0062\U000e0061\U000e007f" - FLAG_FOR_VLORE_COUNTY_AL_12 = "\U0001f3f4\U000e0061\U000e006c\U000e0031\U000e0032\U000e007f" - FLAG_FOR_KOPER_SI_050 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0035\U000e0030\U000e007f" - KISS_WOMAN_DARK_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_MANAWATU_WANGANUI_NZ_MWT = "\U0001f3f4\U000e006e\U000e007a\U000e006d\U000e0077\U000e0074\U000e007f" - FLAG_FOR_ENTRE_RIOS_AR_E = "\U0001f3f4\U000e0061\U000e0072\U000e0065\U000e007f" - FLAG_FOR_NORTH_DAKOTA_US_ND = "\U0001f3f4\U000e0075\U000e0073\U000e006e\U000e0064\U000e007f" - MEDIUM_SMALL_WHITE_CIRCLE = "\u26ac" - FLAG_FOR_BEQAA_LB_BI = "\U0001f3f4\U000e006c\U000e0062\U000e0062\U000e0069\U000e007f" - FLAG_FOR_SEKONG_LA_XE = "\U0001f3f4\U000e006c\U000e0061\U000e0078\U000e0065\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_OUEME_BJ_OU = "\U0001f3f4\U000e0062\U000e006a\U000e006f\U000e0075\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - BALLOT_BOX_WITH_SCRIPT_X = "\U0001f5f5" - FLAG_FOR_TUTONG_BN_TU = "\U0001f3f4\U000e0062\U000e006e\U000e0074\U000e0075\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - FLAG_FOR_VRATSA_BG_06 = "\U0001f3f4\U000e0062\U000e0067\U000e0030\U000e0036\U000e007f" - MAN_WITH_HEADSCARF = "\U0001f9d5\u200d\u2642\ufe0f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_KHENTII_MN_039 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0033\U000e0039\U000e007f" - FLAG_FOR_DELTA_AMACURO_VE_Y = "\U0001f3f4\U000e0076\U000e0065\U000e0079\U000e007f" - RECYCLING_SYMBOL_FOR_GENERIC_MATERIALS = "\u267a" - FLAG_FOR_ASHANTI_GH_AH = "\U0001f3f4\U000e0067\U000e0068\U000e0061\U000e0068\U000e007f" - FLAG_FOR_DOLNENI_MK_27 = "\U0001f3f4\U000e006d\U000e006b\U000e0032\U000e0037\U000e007f" - BLACK_TRUCK = "\u26df" - KISS_WOMAN_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - FLAG_FOR_BORGOU_BJ_BO = "\U0001f3f4\U000e0062\U000e006a\U000e0062\U000e006f\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_SAINT_JAMES_BB_04 = "\U0001f3f4\U000e0062\U000e0062\U000e0030\U000e0034\U000e007f" - FLAG_FOR_PANDO_BO_N = "\U0001f3f4\U000e0062\U000e006f\U000e006e\U000e007f" - FLAG_FOR_LA_PAZ_BO_L = "\U0001f3f4\U000e0062\U000e006f\U000e006c\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_STARA_ZAGORA_BG_24 = "\U0001f3f4\U000e0062\U000e0067\U000e0032\U000e0034\U000e007f" - FLAG_FOR_CHUQUISACA_BO_H = "\U0001f3f4\U000e0062\U000e006f\U000e0068\U000e007f" - FLAG_FOR_GUMUSHANE_TR_29 = "\U0001f3f4\U000e0074\U000e0072\U000e0032\U000e0039\U000e007f" - FLAG_FOR_PANJSHIR_AF_PAN = "\U0001f3f4\U000e0061\U000e0066\U000e0070\U000e0061\U000e006e\U000e007f" - FLAG_FOR_COCHABAMBA_BO_C = "\U0001f3f4\U000e0062\U000e006f\U000e0063\U000e007f" - FLAG_FOR_ROCHE_CAIMAN_SC_25 = "\U0001f3f4\U000e0073\U000e0063\U000e0032\U000e0035\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f467\U0001f3ff" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - FLAG_FOR_BRCKO_DISTRICT_BA_BRC = "\U0001f3f4\U000e0062\U000e0061\U000e0062\U000e0072\U000e0063\U000e007f" - FLAG_FOR_BRETAGNE_FR_BRE = "\U0001f3f4\U000e0066\U000e0072\U000e0062\U000e0072\U000e0065\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FLAG_FOR_CHECHEN_RU_CE = "\U0001f3f4\U000e0072\U000e0075\U000e0063\U000e0065\U000e007f" - FLAG_FOR_KICEVO_MK_40 = "\U0001f3f4\U000e006d\U000e006b\U000e0034\U000e0030\U000e007f" - FLAG_FOR_SAINT_JOHN_BB_05 = "\U0001f3f4\U000e0062\U000e0062\U000e0030\U000e0035\U000e007f" - FLAG_FOR_NORTHERN_MARIANA_ISLANDS_US_MP = "\U0001f3f4\U000e0075\U000e0073\U000e006d\U000e0070\U000e007f" - KISS_WOMAN_MAN_LIGHT_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - FLAG_FOR_KAUNAS_COUNTY_LT_KU = "\U0001f3f4\U000e006c\U000e0074\U000e006b\U000e0075\U000e007f" - FLAG_FOR_GJIROKASTER_COUNTY_AL_05 = "\U0001f3f4\U000e0061\U000e006c\U000e0030\U000e0035\U000e007f" - KISS_MAN_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - KISS_MAN_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - KISS_WOMAN_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - FLAG_FOR_LENART_SI_058 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0035\U000e0038\U000e007f" - FLAG_FOR_TEMBURONG_BN_TE = "\U0001f3f4\U000e0062\U000e006e\U000e0074\U000e0065\U000e007f" - FLAG_FOR_BELAIT_BN_BE = "\U0001f3f4\U000e0062\U000e006e\U000e0062\U000e0065\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - KISS_WOMAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - FAMILY_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_POTOSI_BO_P = "\U0001f3f4\U000e0062\U000e006f\U000e0070\U000e007f" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - MAN_WITH_HEADSCARF_DARK_SKIN_TONE = "\U0001f9d5\U0001f3ff\u200d\u2642\ufe0f" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f467\U0001f3fe" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - SQUARE_FOUR_CORNERS = "\u26f6" - KISS_WOMAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - KISS_MAN_MEDIUM_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - MAHJONG_TILE_ONE_OF_BAMBOOS = "\U0001f010" - FLAG_FOR_TARIJA_BO_T = "\U0001f3f4\U000e0062\U000e006f\U000e0074\U000e007f" - BLACK_CHESS_ROOK = "\u265c" - FLAG_FOR_PREAH_VIHEAR_KH_13 = "\U0001f3f4\U000e006b\U000e0068\U000e0031\U000e0033\U000e007f" - TRIGRAM_FOR_WATER = "\u2635" - FLAG_FOR_VICTORIA_AU_VIC = "\U0001f3f4\U000e0061\U000e0075\U000e0076\U000e0069\U000e0063\U000e007f" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - FLAG_FOR_ANDORRA_LA_VELLA_AD_07 = "\U0001f3f4\U000e0061\U000e0064\U000e0030\U000e0037\U000e007f" - KISS_WOMAN_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - FLAG_FOR_ACRE_BR_AC = "\U0001f3f4\U000e0062\U000e0072\U000e0061\U000e0063\U000e007f" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - FLAG_FOR_URI_CH_UR = "\U0001f3f4\U000e0063\U000e0068\U000e0075\U000e0072\U000e007f" - KISS_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - KISS_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f467\U0001f3fc" - KISS_WOMAN_DARK_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - FLAG_FOR_SAN_SALVADOR_SV_SS = "\U0001f3f4\U000e0073\U000e0076\U000e0073\U000e0073\U000e007f" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - FLAG_FOR_MADRID_AUTONOMOUS_COMMUNITY_ES_MD = "\U0001f3f4\U000e0065\U000e0073\U000e006d\U000e0064\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_COLLINES_BJ_CO = "\U0001f3f4\U000e0062\U000e006a\U000e0063\U000e006f\U000e007f" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - FLAG_FOR_KAYANZA_BI_KY = "\U0001f3f4\U000e0062\U000e0069\U000e006b\U000e0079\U000e007f" - FLAG_FOR_AOMORI_JP_02 = "\U0001f3f4\U000e006a\U000e0070\U000e0030\U000e0032\U000e007f" - TURNED_OK_HAND_SIGN = "\U0001f58f" - BOOK = "\U0001f56e" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - KISS_WOMAN_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - FLAG_FOR_FARO_PT_08 = "\U0001f3f4\U000e0070\U000e0074\U000e0030\U000e0038\U000e007f" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FALLING_DIAGONAL_IN_WHITE_CIRCLE_IN_BLACK_SQUARE = "\u26de" - FLAG_FOR_FRENCH_SOUTHERN_TERRITORIES_FR_TF = "\U0001f3f4\U000e0066\U000e0072\U000e0074\U000e0066\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - FLAG_FOR_ISTANBUL_TR_34 = "\U0001f3f4\U000e0074\U000e0072\U000e0033\U000e0034\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_SUD_OUEST_BF_13 = "\U0001f3f4\U000e0062\U000e0066\U000e0031\U000e0033\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_FEDERAL_DEPENDENCIES_VE_W = "\U0001f3f4\U000e0076\U000e0065\U000e0077\U000e007f" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - FAMILY_MAN_WOMAN_GIRL_BABY = "\U0001f468\u200d\U0001f469\u200d\U0001f467\u200d\U0001f476" - FLAG_FOR_LONG_ISLAND_BS_LI = "\U0001f3f4\U000e0062\U000e0073\U000e006c\U000e0069\U000e007f" - FLAG_FOR_RANGPUR_DIVISION_BD_F = "\U0001f3f4\U000e0062\U000e0064\U000e0066\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - FLAG_FOR_ALAGOAS_BR_AL = "\U0001f3f4\U000e0062\U000e0072\U000e0061\U000e006c\U000e007f" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - KISS_WOMAN_MAN_DARK_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - FLAG_FOR_MAIDAN_WARDAK_AF_WAR = "\U0001f3f4\U000e0061\U000e0066\U000e0077\U000e0061\U000e0072\U000e007f" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f467\U0001f3fb" - COUPLE_WITH_HEART_WOMAN_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - FLAG_FOR_JALISCO_MX_JAL = "\U0001f3f4\U000e006d\U000e0078\U000e006a\U000e0061\U000e006c\U000e007f" - FLAG_FOR_LAZIO_IT_62 = "\U0001f3f4\U000e0069\U000e0074\U000e0036\U000e0032\U000e007f" - FLAG_FOR_SERGIPE_BR_SE = "\U0001f3f4\U000e0062\U000e0072\U000e0073\U000e0065\U000e007f" - KISS_MAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - FLAG_FOR_KOUFFO_BJ_KO = "\U0001f3f4\U000e0062\U000e006a\U000e006b\U000e006f\U000e007f" - TAG_LATIN_SMALL_LETTER_L = "\U000e006c" - TAG_LATIN_SMALL_LETTER_J = "\U000e006a" - FLAG_FOR_BAKU_AZ_BA = "\U0001f3f4\U000e0061\U000e007a\U000e0062\U000e0061\U000e007f" - FLAG_FOR_DAUGAVPILS_MUNICIPALITY_LV_025 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0032\U000e0035\U000e007f" - KISS_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - FLAG_FOR_VINH_LONG_VN_49 = "\U0001f3f4\U000e0076\U000e006e\U000e0034\U000e0039\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - FLAG_FOR_STRASENI_MD_ST = "\U0001f3f4\U000e006d\U000e0064\U000e0073\U000e0074\U000e007f" - FLAG_FOR_RORAIMA_BR_RR = "\U0001f3f4\U000e0062\U000e0072\U000e0072\U000e0072\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f466\U0001f3fb" - FLAG_FOR_BIMINI_BS_BI = "\U0001f3f4\U000e0062\U000e0073\U000e0062\U000e0069\U000e007f" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - FLAG_FOR_NORTHERN_RED_SEA_ER_SK = "\U0001f3f4\U000e0065\U000e0072\U000e0073\U000e006b\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - FLAG_FOR_TIARET_DZ_14 = "\U0001f3f4\U000e0064\U000e007a\U000e0031\U000e0034\U000e007f" - FLAG_FOR_SOGN_OG_FJORDANE_NO_14 = "\U0001f3f4\U000e006e\U000e006f\U000e0031\U000e0034\U000e007f" - WHITE_LEFT_LANE_MERGE = "\u26d9" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_KHACHMAZ_AZ_XAC = "\U0001f3f4\U000e0061\U000e007a\U000e0078\U000e0061\U000e0063\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - FLAG_FOR_SVETI_ANDRAZ_V_SLOVENSKIH_GORICAH_SI_182 = "\U0001f3f4\U000e0073\U000e0069\U000e0031\U000e0038\U000e0032\U000e007f" - FLAG_FOR_BALOCHISTAN_PK_BA = "\U0001f3f4\U000e0070\U000e006b\U000e0062\U000e0061\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_TOCANTINS_BR_TO = "\U0001f3f4\U000e0062\U000e0072\U000e0074\U000e006f\U000e007f" - FAMILY_WOMAN_MAN_BABY_GIRL = "\U0001f469\u200d\U0001f468\u200d\U0001f476\u200d\U0001f467" - TAG_SEMICOLON = "\U000e003b" - FLAG_FOR_EAST_GRAND_BAHAMA_BS_EG = "\U0001f3f4\U000e0062\U000e0073\U000e0065\U000e0067\U000e007f" - FLAG_FOR_SOUTH_AEGEAN_GR_L = "\U0001f3f4\U000e0067\U000e0072\U000e006c\U000e007f" - WOMAN_IN_BUSINESS_SUIT_LEVITATING = "\U0001f574\ufe0f\u200d\u2640\ufe0f" - FLAG_FOR_MAKAMBA_BI_MA = "\U0001f3f4\U000e0062\U000e0069\U000e006d\U000e0061\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - FLAG_FOR_CROOKED_ISLAND_BS_CK = "\U0001f3f4\U000e0062\U000e0073\U000e0063\U000e006b\U000e007f" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - TAG_LATIN_SMALL_LETTER_K = "\U000e006b" - FLAG_FOR_EXUMA_BS_EX = "\U0001f3f4\U000e0062\U000e0073\U000e0065\U000e0078\U000e007f" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FAMILY_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_PLATEAU_BJ_PL = "\U0001f3f4\U000e0062\U000e006a\U000e0070\U000e006c\U000e007f" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - FLAG_FOR_FEDERAL_DISTRICT_BR_DF = "\U0001f3f4\U000e0062\U000e0072\U000e0064\U000e0066\U000e007f" - FLAG_FOR_NEW_SOUTH_WALES_AU_NSW = "\U0001f3f4\U000e0061\U000e0075\U000e006e\U000e0073\U000e0077\U000e007f" - FLAG_FOR_NORTH_ABACO_BS_NO = "\U0001f3f4\U000e0062\U000e0073\U000e006e\U000e006f\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_JERUSALEM_IL_JM = "\U0001f3f4\U000e0069\U000e006c\U000e006a\U000e006d\U000e007f" - FLAG_FOR_INAGUA_BS_IN = "\U0001f3f4\U000e0062\U000e0073\U000e0069\U000e006e\U000e007f" - FLAG_FOR_BOHINJ_SI_004 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0030\U000e0034\U000e007f" - FLAG_FOR_FREEPORT_BS_FP = "\U0001f3f4\U000e0062\U000e0073\U000e0066\U000e0070\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_CENTRAL_ELEUTHERA_BS_CE = "\U0001f3f4\U000e0062\U000e0073\U000e0063\U000e0065\U000e007f" - FLAG_FOR_GRAND_CAY_BS_GC = "\U0001f3f4\U000e0062\U000e0073\U000e0067\U000e0063\U000e007f" - TAG_LATIN_SMALL_LETTER_A = "\U000e0061" - FLAG_FOR_MAYAGUANA_BS_MG = "\U0001f3f4\U000e0062\U000e0073\U000e006d\U000e0067\U000e007f" - FLAG_FOR_SOUTH_AUSTRALIA_AU_SA = "\U0001f3f4\U000e0061\U000e0075\U000e0073\U000e0061\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f466\U0001f3fb" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_MAN = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - FLAG_FOR_KAOHSIUNG_TW_KHH = "\U0001f3f4\U000e0074\U000e0077\U000e006b\U000e0068\U000e0068\U000e007f" - WOMAN_IN_BUSINESS_SUIT_LEVITATING_MEDIUM_DARK_SKIN_TONE = "\U0001f574\U0001f3fe\u200d\u2640\ufe0f" - FLAG_FOR_TRANS_NZOIA_KE_42 = "\U0001f3f4\U000e006b\U000e0065\U000e0034\U000e0032\U000e007f" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - FLAG_FOR_NORTH_ANDROS_BS_NS = "\U0001f3f4\U000e0062\U000e0073\U000e006e\U000e0073\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - FAMILY_WOMAN_MAN_BOY_BABY = "\U0001f469\u200d\U0001f468\u200d\U0001f466\u200d\U0001f476" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f476\U0001f3fd" - FAMILY_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_OREGON_US_OR = "\U0001f3f4\U000e0075\U000e0073\U000e006f\U000e0072\U000e007f" - KISS_MAN_LIGHT_SKIN_TONE_MAN = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - FAMILY_MAN_BOY_BABY = "\U0001f468\u200d\U0001f466\u200d\U0001f476" - FAMILY_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f467\U0001f3fb" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - FLAG_FOR_OCCITANIE_FR_OCC = "\U0001f3f4\U000e0066\U000e0072\U000e006f\U000e0063\U000e0063\U000e007f" - FLAG_FOR_EAST_AZERBAIJAN_IR_01 = "\U0001f3f4\U000e0069\U000e0072\U000e0030\U000e0031\U000e007f" - FLAG_FOR_SOUTH_ANDROS_BS_SA = "\U0001f3f4\U000e0062\U000e0073\U000e0073\U000e0061\U000e007f" - FLAG_FOR_AMAZONAS_BR_AM = "\U0001f3f4\U000e0062\U000e0072\U000e0061\U000e006d\U000e007f" - FLAG_FOR_TANA_RIVER_KE_40 = "\U0001f3f4\U000e006b\U000e0065\U000e0034\U000e0030\U000e007f" - KISS_MAN_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - GEAR_WITH_HANDLES = "\u26ee" - FLAG_FOR_SOUTH_ELEUTHERA_BS_SE = "\U0001f3f4\U000e0062\U000e0073\U000e0073\U000e0065\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_WOMAN = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f469" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - KISS_MAN_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - KISS_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - KISS_WOMAN_LIGHT_SKIN_TONE_MAN = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" - COUPLE_WITH_HEART_MAN_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f467\U0001f3fe" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_MAN = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468" - KISS_WOMAN_MEDIUM_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - FLAG_FOR_BUDAPEST_HU_BU = "\U0001f3f4\U000e0068\U000e0075\U000e0062\U000e0075\U000e007f" - KISS_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - KISS_MAN_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - SIDEWAYS_BLACK_RIGHT_POINTING_INDEX = "\U0001f59b" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - KISS_WOMAN_LIGHT_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - KISS_WOMAN_DARK_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fc" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_SOUTH_ABACO_BS_SO = "\U0001f3f4\U000e0062\U000e0073\U000e0073\U000e006f\U000e007f" - KISS_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - FLAG_FOR_RUM_CAY_BS_RC = "\U0001f3f4\U000e0062\U000e0073\U000e0072\U000e0063\U000e007f" - TAG_SOLIDUS = "\U000e002f" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - FAMILY_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f467\U0001f3ff" - FAMILY_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f476\U0001f3ff" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FAMILY_WOMAN_BOY_GIRL = "\U0001f469\u200d\U0001f466\u200d\U0001f467" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - FLAG_FOR_ANSE_ROYALE_SC_05 = "\U0001f3f4\U000e0073\U000e0063\U000e0030\U000e0035\U000e007f" - FLAG_FOR_DELHI_IN_DL = "\U0001f3f4\U000e0069\U000e006e\U000e0064\U000e006c\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f476\U0001f3fc" - FAMILY_MAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f476\U0001f3fb" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fd" - FLAG_FOR_THIMPHU_BT_15 = "\U0001f3f4\U000e0062\U000e0074\U000e0031\U000e0035\U000e007f" - FLAG_FOR_CIEGO_DE_AVILA_CU_08 = "\U0001f3f4\U000e0063\U000e0075\U000e0030\U000e0038\U000e007f" - FLAG_FOR_PARO_BT_11 = "\U0001f3f4\U000e0062\U000e0074\U000e0031\U000e0031\U000e007f" - KISS_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fe" - FLAG_FOR_HAA_BT_13 = "\U0001f3f4\U000e0062\U000e0074\U000e0031\U000e0033\U000e007f" - FLAG_FOR_MADHYA_PRADESH_IN_MP = "\U0001f3f4\U000e0069\U000e006e\U000e006d\U000e0070\U000e007f" - KISS_MAN_LIGHT_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - FAMILY_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_WEST_GRAND_BAHAMA_BS_WG = "\U0001f3f4\U000e0062\U000e0073\U000e0077\U000e0067\U000e007f" - FLAG_FOR_PYONGYANG_KP_01 = "\U0001f3f4\U000e006b\U000e0070\U000e0030\U000e0031\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f469\U0001f3fd\u200d\U0001f466\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_DAGANA_BT_22 = "\U0001f3f4\U000e0062\U000e0074\U000e0032\U000e0032\U000e007f" - FLAG_FOR_ZHEMGANG_BT_34 = "\U0001f3f4\U000e0062\U000e0074\U000e0033\U000e0034\U000e007f" - FLAG_FOR_SARPANG_BT_31 = "\U0001f3f4\U000e0062\U000e0074\U000e0033\U000e0031\U000e007f" - KISS_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - FLAG_FOR_KUNDUZ_AF_KDZ = "\U0001f3f4\U000e0061\U000e0066\U000e006b\U000e0064\U000e007a\U000e007f" - FLAG_FOR_TRASHIGANG_BT_41 = "\U0001f3f4\U000e0062\U000e0074\U000e0034\U000e0031\U000e007f" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - FLAG_FOR_TRONGSA_BT_32 = "\U0001f3f4\U000e0062\U000e0074\U000e0033\U000e0032\U000e007f" - FLAG_FOR_BUMTHANG_BT_33 = "\U0001f3f4\U000e0062\U000e0074\U000e0033\U000e0033\U000e007f" - FLAG_FOR_MONGAR_BT_42 = "\U0001f3f4\U000e0062\U000e0074\U000e0034\U000e0032\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f466\U0001f3ff" - KISS_WOMAN_LIGHT_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fd" - FLAG_FOR_PEMAGATSHEL_BT_43 = "\U0001f3f4\U000e0062\U000e0074\U000e0034\U000e0033\U000e007f" - FLAG_FOR_ACKLINS_BS_AK = "\U0001f3f4\U000e0062\U000e0073\U000e0061\U000e006b\U000e007f" - FLAG_FOR_CHOBE_BW_CH = "\U0001f3f4\U000e0062\U000e0077\U000e0063\U000e0068\U000e007f" - FLAG_FOR_SALTA_AR_A = "\U0001f3f4\U000e0061\U000e0072\U000e0061\U000e007f" - FLAG_FOR_LHUNTSE_BT_44 = "\U0001f3f4\U000e0062\U000e0074\U000e0034\U000e0034\U000e007f" - FLAG_FOR_TRASHIYANGTSE_BT_TY = "\U0001f3f4\U000e0062\U000e0074\U000e0074\U000e0079\U000e007f" - COUPLE_WITH_HEART_MAN_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - FLAG_FOR_NEW_MEXICO_US_NM = "\U0001f3f4\U000e0075\U000e0073\U000e006e\U000e006d\U000e007f" - FAMILY_MAN_MAN_BABY = "\U0001f468\u200d\U0001f468\u200d\U0001f476" - LIGHTNING_MOOD_BUBBLE = "\U0001f5f1" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_JWANENG_BW_JW = "\U0001f3f4\U000e0062\U000e0077\U000e006a\U000e0077\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3fb" - COUPLE_WITH_HEART_MAN_MEDIUM_SKIN_TONE_MAN = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468" - FLAG_FOR_SOUTH_EAST_BW_SE = "\U0001f3f4\U000e0062\U000e0077\U000e0073\U000e0065\U000e007f" - LEFT_HANDED_INTERLACED_PENTAGRAM = "\u26e6" - FLAG_FOR_ATLANTIQUE_BJ_AQ = "\U0001f3f4\U000e0062\U000e006a\U000e0061\U000e0071\U000e007f" - FLAG_FOR_CENTRAL_BW_CE = "\U0001f3f4\U000e0062\U000e0077\U000e0063\U000e0065\U000e007f" - FLAG_FOR_WANGDUE_PHODRANG_BT_24 = "\U0001f3f4\U000e0062\U000e0074\U000e0032\U000e0034\U000e007f" - FLAG_FOR_KGATLENG_BW_KL = "\U0001f3f4\U000e0062\U000e0077\U000e006b\U000e006c\U000e007f" - FLAG_FOR_RONDONIA_BR_RO = "\U0001f3f4\U000e0062\U000e0072\U000e0072\U000e006f\U000e007f" - FLAG_FOR_CENTRAL_FINLAND_FI_08 = "\U0001f3f4\U000e0066\U000e0069\U000e0030\U000e0038\U000e007f" - KISS_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - FLAG_FOR_RUTANA_BI_RT = "\U0001f3f4\U000e0062\U000e0069\U000e0072\U000e0074\U000e007f" - FLAG_FOR_GHANZI_BW_GH = "\U0001f3f4\U000e0062\U000e0077\U000e0067\U000e0068\U000e007f" - FLAG_FOR_KGALAGADI_BW_KG = "\U0001f3f4\U000e0062\U000e0077\U000e006b\U000e0067\U000e007f" - FLAG_FOR_NORTH_EAST_BW_NE = "\U0001f3f4\U000e0062\U000e0077\U000e006e\U000e0065\U000e007f" - FLAG_FOR_TISINA_SI_010 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0031\U000e0030\U000e007f" - FLAG_FOR_KWENENG_BW_KW = "\U0001f3f4\U000e0062\U000e0077\U000e006b\U000e0077\U000e007f" - COUPLE_WITH_HEART_WOMAN_MAN_LIGHT_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - FLAG_FOR_SAMDRUP_JONGKHAR_BT_45 = "\U0001f3f4\U000e0062\U000e0074\U000e0034\U000e0035\U000e007f" - FLAG_FOR_SAMTSE_BT_14 = "\U0001f3f4\U000e0062\U000e0074\U000e0031\U000e0034\U000e007f" - FLAG_FOR_JIHOCESKY_KRAJ_CZ_31 = "\U0001f3f4\U000e0063\U000e007a\U000e0033\U000e0031\U000e007f" - FLAG_FOR_CHRIST_CHURCH_BB_01 = "\U0001f3f4\U000e0062\U000e0062\U000e0030\U000e0031\U000e007f" - FLAG_FOR_SELIBE_PHIKWE_BW_SP = "\U0001f3f4\U000e0062\U000e0077\U000e0073\U000e0070\U000e007f" - KISS_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - FAMILY_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f466\U0001f3ff" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_NORTH_WEST_BW_NW = "\U0001f3f4\U000e0062\U000e0077\U000e006e\U000e0077\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468" - FLAG_FOR_SOWA_TOWN_BW_ST = "\U0001f3f4\U000e0062\U000e0077\U000e0073\U000e0074\U000e007f" - FAMILY_WOMAN_MAN_BABY_BABY = "\U0001f469\u200d\U0001f468\u200d\U0001f476\u200d\U0001f476" - WHITE_CHESS_KING = "\u2654" - FLAG_FOR_ORURO_BO_O = "\U0001f3f4\U000e0062\U000e006f\U000e006f\U000e007f" - FLAG_FOR_PHOENIX_ISLANDS_KI_P = "\U0001f3f4\U000e006b\U000e0069\U000e0070\U000e007f" - FLAG_FOR_PIAUI_BR_PI = "\U0001f3f4\U000e0062\U000e0072\U000e0070\U000e0069\U000e007f" - FLAG_FOR_HRODNA_BY_HR = "\U0001f3f4\U000e0062\U000e0079\U000e0068\U000e0072\U000e007f" - FLAG_FOR_HOMEL_BY_HO = "\U0001f3f4\U000e0062\U000e0079\U000e0068\U000e006f\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_MINSK_BY_HM = "\U0001f3f4\U000e0062\U000e0079\U000e0068\U000e006d\U000e007f" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - FLAG_FOR_CHITTAGONG_DIVISION_BD_B = "\U0001f3f4\U000e0062\U000e0064\U000e0062\U000e007f" - MAP_SYMBOL_FOR_LIGHTHOUSE = "\u26ef" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_MOORE_S_ISLAND_BS_MI = "\U0001f3f4\U000e0062\U000e0073\U000e006d\U000e0069\U000e007f" - FLAG_FOR_MINSK_REGION_BY_MI = "\U0001f3f4\U000e0062\U000e0079\U000e006d\U000e0069\U000e007f" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_WOMAN = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_GUARDA_PT_09 = "\U0001f3f4\U000e0070\U000e0074\U000e0030\U000e0039\U000e007f" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb" - FAMILY_WOMAN_BABY_GIRL = "\U0001f469\u200d\U0001f476\u200d\U0001f467" - FAMILY_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE_BOY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f466\U0001f3fb\u200d\U0001f466\U0001f3fb" - FLAG_FOR_VITEBSK_BY_VI = "\U0001f3f4\U000e0062\U000e0079\U000e0076\U000e0069\U000e007f" - FLAG_FOR_CASTILE_LA_MANCHA_ES_CM = "\U0001f3f4\U000e0065\U000e0073\U000e0063\U000e006d\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_ALMATY_KZ_ALA = "\U0001f3f4\U000e006b\U000e007a\U000e0061\U000e006c\U000e0061\U000e007f" - FLAG_FOR_METRO_MANILA_PH_00 = "\U0001f3f4\U000e0070\U000e0068\U000e0030\U000e0030\U000e007f" - FLAG_FOR_MAGILEU_BY_MA = "\U0001f3f4\U000e0062\U000e0079\U000e006d\U000e0061\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f476\U0001f3fb" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_WOMAN = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469" - FLAG_FOR_SILISTRA_BG_19 = "\U0001f3f4\U000e0062\U000e0067\U000e0031\U000e0039\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_STANN_CREEK_BZ_SC = "\U0001f3f4\U000e0062\U000e007a\U000e0073\U000e0063\U000e007f" - FLAG_FOR_NORTH_ELEUTHERA_BS_NE = "\U0001f3f4\U000e0062\U000e0073\U000e006e\U000e0065\U000e007f" - FLAG_FOR_NEW_BRUNSWICK_CA_NB = "\U0001f3f4\U000e0063\U000e0061\U000e006e\U000e0062\U000e007f" - FAMILY_MAN_GIRL_BABY = "\U0001f468\u200d\U0001f467\u200d\U0001f476" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_MAN = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468" - COUPLE_WITH_HEART_WOMAN_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3ff" - FLAG_FOR_TOLEDO_BZ_TOL = "\U0001f3f4\U000e0062\U000e007a\U000e0074\U000e006f\U000e006c\U000e007f" - KISS_WOMAN_MEDIUM_SKIN_TONE_WOMAN = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - KISS_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - FAMILY_MAN_MAN_BABY_BABY = "\U0001f468\u200d\U0001f468\u200d\U0001f476\u200d\U0001f476" - FLAG_FOR_TAMAULIPAS_MX_TAM = "\U0001f3f4\U000e006d\U000e0078\U000e0074\U000e0061\U000e006d\U000e007f" - FLAG_FOR_TRISTAN_DA_CUNHA_SH_TA = "\U0001f3f4\U000e0073\U000e0068\U000e0074\U000e0061\U000e007f" - FAMILY_MAN_WOMAN_BABY_BABY = "\U0001f468\u200d\U0001f469\u200d\U0001f476\u200d\U0001f476" - FLAG_FOR_SAN_LUIS_POTOSI_MX_SLP = "\U0001f3f4\U000e006d\U000e0078\U000e0073\U000e006c\U000e0070\U000e007f" - FLAG_FOR_VIENTIANE_PROVINCE_LA_VI = "\U0001f3f4\U000e006c\U000e0061\U000e0076\U000e0069\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_SOUTHERN_BW_SO = "\U0001f3f4\U000e0062\U000e0077\U000e0073\U000e006f\U000e007f" - FLAG_FOR_MAMBERE_KADEI_CF_HS = "\U0001f3f4\U000e0063\U000e0066\U000e0068\U000e0073\U000e007f" - FLAG_FOR_ITURI_CD_IT = "\U0001f3f4\U000e0063\U000e0064\U000e0069\U000e0074\U000e007f" - NOTCHED_LEFT_SEMICIRCLE_WITH_THREE_DOTS = "\U0001f543" - FLAG_FOR_MAI_NDOMBE_CD_MN = "\U0001f3f4\U000e0063\U000e0064\U000e006d\U000e006e\U000e007f" - FLAG_FOR_SOUTH_KIVU_CD_SK = "\U0001f3f4\U000e0063\U000e0064\U000e0073\U000e006b\U000e007f" - FLAG_FOR_KASAI_CENTRAL_CD_KC = "\U0001f3f4\U000e0063\U000e0064\U000e006b\U000e0063\U000e007f" - FLAG_FOR_HAUT_UELE_CD_HU = "\U0001f3f4\U000e0063\U000e0064\U000e0068\U000e0075\U000e007f" - FLAG_FOR_KWANGO_CD_KG = "\U0001f3f4\U000e0063\U000e0064\U000e006b\U000e0067\U000e007f" - FLAG_FOR_SWIETOKRZYSKIE_PL_SK = "\U0001f3f4\U000e0070\U000e006c\U000e0073\U000e006b\U000e007f" - FLAG_FOR_KASAI_CD_KS = "\U0001f3f4\U000e0063\U000e0064\U000e006b\U000e0073\U000e007f" - FLAG_FOR_RAGGED_ISLAND_BS_RI = "\U0001f3f4\U000e0062\U000e0073\U000e0072\U000e0069\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_MANIEMA_CD_MA = "\U0001f3f4\U000e0063\U000e0064\U000e006d\U000e0061\U000e007f" - FLAG_FOR_SANKURU_CD_SA = "\U0001f3f4\U000e0063\U000e0064\U000e0073\U000e0061\U000e007f" - FLAG_FOR_MONTANA_BG_12 = "\U0001f3f4\U000e0062\U000e0067\U000e0031\U000e0032\U000e007f" - FLAG_FOR_OUHAM_CF_AC = "\U0001f3f4\U000e0063\U000e0066\U000e0061\U000e0063\U000e007f" - FLAG_FOR_HAUT_LOMAMI_CD_HL = "\U0001f3f4\U000e0063\U000e0064\U000e0068\U000e006c\U000e007f" - FLAG_FOR_BAMINGUI_BANGORAN_CF_BB = "\U0001f3f4\U000e0063\U000e0066\U000e0062\U000e0062\U000e007f" - FLAG_FOR_BUBANZA_BI_BB = "\U0001f3f4\U000e0062\U000e0069\U000e0062\U000e0062\U000e007f" - FLAG_FOR_KINSHASA_CD_KN = "\U0001f3f4\U000e0063\U000e0064\U000e006b\U000e006e\U000e007f" - FLAG_FOR_KASAI_ORIENTAL_CD_KE = "\U0001f3f4\U000e0063\U000e0064\U000e006b\U000e0065\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_MONGALA_CD_MO = "\U0001f3f4\U000e0063\U000e0064\U000e006d\U000e006f\U000e007f" - FLAG_FOR_TSHUAPA_CD_TU = "\U0001f3f4\U000e0063\U000e0064\U000e0074\U000e0075\U000e007f" - FLAG_FOR_TSHOPO_CD_TO = "\U0001f3f4\U000e0063\U000e0064\U000e0074\U000e006f\U000e007f" - FLAG_FOR_LUCERNE_CH_LU = "\U0001f3f4\U000e0063\U000e0068\U000e006c\U000e0075\U000e007f" - FLAG_FOR_RIO_GRANDE_DO_NORTE_BR_RN = "\U0001f3f4\U000e0062\U000e0072\U000e0072\U000e006e\U000e007f" - WOMAN_WITH_HEADSCARF_LIGHT_SKIN_TONE = "\U0001f9d5\U0001f3fb\u200d\u2640\ufe0f" - FAMILY_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_LOBAYE_CF_LB = "\U0001f3f4\U000e0063\U000e0066\U000e006c\U000e0062\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_LOMAMI_CD_LO = "\U0001f3f4\U000e0063\U000e0064\U000e006c\U000e006f\U000e007f" - FLAG_FOR_KWILU_CD_KL = "\U0001f3f4\U000e0063\U000e0064\U000e006b\U000e006c\U000e007f" - FLAG_FOR_LOBATSE_BW_LO = "\U0001f3f4\U000e0062\U000e0077\U000e006c\U000e006f\U000e007f" - FLAG_FOR_SANGHA_CG_13 = "\U0001f3f4\U000e0063\U000e0067\U000e0031\U000e0033\U000e007f" - FLAG_FOR_KOUILOU_CG_5 = "\U0001f3f4\U000e0063\U000e0067\U000e0035\U000e007f" - FLAG_FOR_LIKOUALA_CG_7 = "\U0001f3f4\U000e0063\U000e0067\U000e0037\U000e007f" - FLAG_FOR_BANGUI_CF_BGF = "\U0001f3f4\U000e0063\U000e0066\U000e0062\U000e0067\U000e0066\U000e007f" - FLAG_FOR_SANGHA_MBAERE_CF_SE = "\U0001f3f4\U000e0063\U000e0066\U000e0073\U000e0065\U000e007f" - FLAG_FOR_NIDWALDEN_CH_NW = "\U0001f3f4\U000e0063\U000e0068\U000e006e\U000e0077\U000e007f" - FLAG_FOR_ST_GALLEN_CH_SG = "\U0001f3f4\U000e0063\U000e0068\U000e0073\U000e0067\U000e007f" - FLAG_FOR_LEKOUMOU_CG_2 = "\U0001f3f4\U000e0063\U000e0067\U000e0032\U000e007f" - FLAG_FOR_MONO_BJ_MO = "\U0001f3f4\U000e0062\U000e006a\U000e006d\U000e006f\U000e007f" - FLAG_FOR_APPENZELL_INNERRHODEN_CH_AI = "\U0001f3f4\U000e0063\U000e0068\U000e0061\U000e0069\U000e007f" - FLAG_FOR_AARGAU_CH_AG = "\U0001f3f4\U000e0063\U000e0068\U000e0061\U000e0067\U000e007f" - FLAG_FOR_CUVETTE_OUEST_CG_15 = "\U0001f3f4\U000e0063\U000e0067\U000e0031\U000e0035\U000e007f" - FLAG_FOR_BRAZZAVILLE_CG_BZV = "\U0001f3f4\U000e0063\U000e0067\U000e0062\U000e007a\U000e0076\U000e007f" - FLAG_FOR_CUVETTE_CG_8 = "\U0001f3f4\U000e0063\U000e0067\U000e0038\U000e007f" - FLAG_FOR_LOS_RIOS_CL_LR = "\U0001f3f4\U000e0063\U000e006c\U000e006c\U000e0072\U000e007f" - FLAG_FOR_MONTAGNES_CI_MG = "\U0001f3f4\U000e0063\U000e0069\U000e006d\U000e0067\U000e007f" - FLAG_FOR_BAS_SASSANDRA_CI_BS = "\U0001f3f4\U000e0063\U000e0069\U000e0062\U000e0073\U000e007f" - FLAG_FOR_BASEL_STADT_CH_BS = "\U0001f3f4\U000e0063\U000e0068\U000e0062\U000e0073\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_LITTORAL_CM_LT = "\U0001f3f4\U000e0063\U000e006d\U000e006c\U000e0074\U000e007f" - FLAG_FOR_NORTHWEST_CM_NW = "\U0001f3f4\U000e0063\U000e006d\U000e006e\U000e0077\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_FRIBOURG_CH_FR = "\U0001f3f4\U000e0063\U000e0068\U000e0066\U000e0072\U000e007f" - FLAG_FOR_ATACAMA_CL_AT = "\U0001f3f4\U000e0063\U000e006c\U000e0061\U000e0074\U000e007f" - FLAG_FOR_SAVANES_CI_SV = "\U0001f3f4\U000e0063\U000e0069\U000e0073\U000e0076\U000e007f" - FLAG_FOR_COQUIMBO_CL_CO = "\U0001f3f4\U000e0063\U000e006c\U000e0063\U000e006f\U000e007f" - FLAG_FOR_ADAMAWA_CM_AD = "\U0001f3f4\U000e0063\U000e006d\U000e0061\U000e0064\U000e007f" - FLAG_FOR_AL_MADINAH_SA_03 = "\U0001f3f4\U000e0073\U000e0061\U000e0030\U000e0033\U000e007f" - FLAG_FOR_SOUTHWEST_CM_SW = "\U0001f3f4\U000e0063\U000e006d\U000e0073\U000e0077\U000e007f" - FLAG_FOR_NORTH_CM_NO = "\U0001f3f4\U000e0063\U000e006d\U000e006e\U000e006f\U000e007f" - COUPLE_WITH_HEART_MAN_WOMAN = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f469" - FLAG_FOR_DENGUELE_CI_DN = "\U0001f3f4\U000e0063\U000e0069\U000e0064\U000e006e\U000e007f" - FLAG_FOR_MAGALLANES_REGION_CL_MA = "\U0001f3f4\U000e0063\U000e006c\U000e006d\U000e0061\U000e007f" - FLAG_FOR_HAUT_KATANGA_CD_HK = "\U0001f3f4\U000e0063\U000e0064\U000e0068\U000e006b\U000e007f" - FLAG_FOR_GOH_DJIBOUA_CI_GD = "\U0001f3f4\U000e0063\U000e0069\U000e0067\U000e0064\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_WOROBA_CI_WR = "\U0001f3f4\U000e0063\U000e0069\U000e0077\U000e0072\U000e007f" - FLAG_FOR_COMOE_CI_CM = "\U0001f3f4\U000e0063\U000e0069\U000e0063\U000e006d\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_YAMOUSSOUKRO_CI_YM = "\U0001f3f4\U000e0063\U000e0069\U000e0079\U000e006d\U000e007f" - FLAG_FOR_LACS_CI_LC = "\U0001f3f4\U000e0063\U000e0069\U000e006c\U000e0063\U000e007f" - FLAG_FOR_TARAPACA_CL_TA = "\U0001f3f4\U000e0063\U000e006c\U000e0074\U000e0061\U000e007f" - FLAG_FOR_PANEVEZYS_COUNTY_LT_PN = "\U0001f3f4\U000e006c\U000e0074\U000e0070\U000e006e\U000e007f" - FLAG_FOR_CENTRE_CM_CE = "\U0001f3f4\U000e0063\U000e006d\U000e0063\U000e0065\U000e007f" - FLAG_FOR_GUANGXI_CN_45 = "\U0001f3f4\U000e0063\U000e006e\U000e0034\U000e0035\U000e007f" - FLAG_FOR_HENAN_CN_41 = "\U0001f3f4\U000e0063\U000e006e\U000e0034\U000e0031\U000e007f" - FLAG_FOR_JIANGSU_CN_32 = "\U0001f3f4\U000e0063\U000e006e\U000e0033\U000e0032\U000e007f" - BLACK_CHESS_KNIGHT = "\u265e" - WHITE_HARD_SHELL_FLOPPY_DISK = "\U0001f5ab" - FLAG_FOR_BOYACA_CO_BOY = "\U0001f3f4\U000e0063\U000e006f\U000e0062\U000e006f\U000e0079\U000e007f" - FLAG_FOR_FUJIAN_CN_35 = "\U0001f3f4\U000e0063\U000e006e\U000e0033\U000e0035\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_CAQUETA_CO_CAQ = "\U0001f3f4\U000e0063\U000e006f\U000e0063\U000e0061\U000e0071\U000e007f" - FLAG_FOR_JIANGXI_CN_36 = "\U0001f3f4\U000e0063\U000e006e\U000e0033\U000e0036\U000e007f" - FLAG_FOR_OMBELLA_M_POKO_CF_MP = "\U0001f3f4\U000e0063\U000e0066\U000e006d\U000e0070\U000e007f" - FLAG_FOR_RUSE_BG_18 = "\U0001f3f4\U000e0062\U000e0067\U000e0031\U000e0038\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_LIBERTADOR_GENERAL_BERNARDO_O_HIGGINS_CL_LI = "\U0001f3f4\U000e0063\U000e006c\U000e006c\U000e0069\U000e007f" - FLAG_FOR_HAINAN_CN_46 = "\U0001f3f4\U000e0063\U000e006e\U000e0034\U000e0036\U000e007f" - FLAG_FOR_BATMAN_TR_72 = "\U0001f3f4\U000e0074\U000e0072\U000e0037\U000e0032\U000e007f" - FLAG_FOR_CALDAS_CO_CAL = "\U0001f3f4\U000e0063\U000e006f\U000e0063\U000e0061\U000e006c\U000e007f" - FLAG_FOR_QINGHAI_CN_63 = "\U0001f3f4\U000e0063\U000e006e\U000e0036\U000e0033\U000e007f" - FLAG_FOR_ARAUCA_CO_ARA = "\U0001f3f4\U000e0063\U000e006f\U000e0061\U000e0072\U000e0061\U000e007f" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - FLAG_FOR_GUAVIARE_CO_GUV = "\U0001f3f4\U000e0063\U000e006f\U000e0067\U000e0075\U000e0076\U000e007f" - FLAG_FOR_VAUPES_CO_VAU = "\U0001f3f4\U000e0063\U000e006f\U000e0076\U000e0061\U000e0075\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - FLAG_FOR_CARTAGO_CR_C = "\U0001f3f4\U000e0063\U000e0072\U000e0063\U000e007f" - FLAG_FOR_LA_GUAJIRA_CO_LAG = "\U0001f3f4\U000e0063\U000e006f\U000e006c\U000e0061\U000e0067\U000e007f" - FLAG_FOR_MATANZAS_CU_04 = "\U0001f3f4\U000e0063\U000e0075\U000e0030\U000e0034\U000e007f" - FLAG_FOR_ARIANA_TN_12 = "\U0001f3f4\U000e0074\U000e006e\U000e0031\U000e0032\U000e007f" - FLAG_FOR_LIMON_CR_L = "\U0001f3f4\U000e0063\U000e0072\U000e006c\U000e007f" - FLAG_FOR_FEDERALLY_ADMINISTERED_TRIBAL_AREAS_PK_TA = "\U0001f3f4\U000e0070\U000e006b\U000e0074\U000e0061\U000e007f" - FLAG_FOR_CIENFUEGOS_CU_06 = "\U0001f3f4\U000e0063\U000e0075\U000e0030\U000e0036\U000e007f" - FLAG_FOR_CORDOBA_CO_COR = "\U0001f3f4\U000e0063\U000e006f\U000e0063\U000e006f\U000e0072\U000e007f" - FLAG_FOR_NORTE_DE_SANTANDER_CO_NSA = "\U0001f3f4\U000e0063\U000e006f\U000e006e\U000e0073\U000e0061\U000e007f" - FLAG_FOR_HUBEI_CN_42 = "\U0001f3f4\U000e0063\U000e006e\U000e0034\U000e0032\U000e007f" - FLAG_FOR_PUNTARENAS_CR_P = "\U0001f3f4\U000e0063\U000e0072\U000e0070\U000e007f" - FLAG_FOR_CAMAGUEY_CU_09 = "\U0001f3f4\U000e0063\U000e0075\U000e0030\U000e0039\U000e007f" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - FLAG_FOR_SAN_SALVADOR_BS_SS = "\U0001f3f4\U000e0062\U000e0073\U000e0073\U000e0073\U000e007f" - FLAG_FOR_LIMASSOL_CY_02 = "\U0001f3f4\U000e0063\U000e0079\U000e0030\U000e0032\U000e007f" - FLAG_FOR_TSIRANG_BT_21 = "\U0001f3f4\U000e0062\U000e0074\U000e0032\U000e0031\U000e007f" - FLAG_FOR_MORAVSKOSLEZSKY_KRAJ_CZ_80 = "\U0001f3f4\U000e0063\U000e007a\U000e0038\U000e0030\U000e007f" - FLAG_FOR_SLIVEN_BG_20 = "\U0001f3f4\U000e0062\U000e0067\U000e0032\U000e0030\U000e007f" - FLAG_FOR_BURGAS_BG_02 = "\U0001f3f4\U000e0062\U000e0067\U000e0030\U000e0032\U000e007f" - FLAG_FOR_SOTAVENTO_ISLANDS_CV_S = "\U0001f3f4\U000e0063\U000e0076\U000e0073\U000e007f" - FLAG_FOR_SALZBURG_AT_5 = "\U0001f3f4\U000e0061\U000e0074\U000e0035\U000e007f" - FLAG_FOR_KRAJ_VYSOCINA_CZ_63 = "\U0001f3f4\U000e0063\U000e007a\U000e0036\U000e0033\U000e007f" - FLAG_FOR_HOLGUIN_CU_11 = "\U0001f3f4\U000e0063\U000e0075\U000e0031\U000e0031\U000e007f" - KISS_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" - FLAG_FOR_PARANA_BR_PR = "\U0001f3f4\U000e0062\U000e0072\U000e0070\U000e0072\U000e007f" - FLAG_FOR_GUANTANAMO_CU_14 = "\U0001f3f4\U000e0063\U000e0075\U000e0031\U000e0034\U000e007f" - FLAG_FOR_XINJIANG_CN_65 = "\U0001f3f4\U000e0063\U000e006e\U000e0036\U000e0035\U000e007f" - FLAG_FOR_KRALOVEHRADECKY_KRAJ_CZ_52 = "\U0001f3f4\U000e0063\U000e007a\U000e0035\U000e0032\U000e007f" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f476\U0001f3fb" - FLAG_FOR_KARLOVARSKY_KRAJ_CZ_41 = "\U0001f3f4\U000e0063\U000e007a\U000e0034\U000e0031\U000e007f" - FLAG_FOR_AMAPA_BR_AP = "\U0001f3f4\U000e0062\U000e0072\U000e0061\U000e0070\U000e007f" - FLAG_FOR_GASA_BT_GA = "\U0001f3f4\U000e0062\U000e0074\U000e0067\U000e0061\U000e007f" - FLAG_FOR_BARLAVENTO_ISLANDS_CV_B = "\U0001f3f4\U000e0063\U000e0076\U000e0062\U000e007f" - FLAG_FOR_MAYABEQUE_CU_16 = "\U0001f3f4\U000e0063\U000e0075\U000e0031\U000e0036\U000e007f" - KISS_MAN_DARK_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - FLAG_FOR_LIBERECKY_KRAJ_CZ_51 = "\U0001f3f4\U000e0063\U000e007a\U000e0035\U000e0031\U000e007f" - FLAG_FOR_CIBAO_NOROESTE_DO_34 = "\U0001f3f4\U000e0064\U000e006f\U000e0033\U000e0034\U000e007f" - FLAG_FOR_RISARALDA_CO_RIS = "\U0001f3f4\U000e0063\U000e006f\U000e0072\U000e0069\U000e0073\U000e007f" - FLAG_FOR_HOPE_TOWN_BS_HT = "\U0001f3f4\U000e0062\U000e0073\U000e0068\U000e0074\U000e007f" - FLAG_FOR_BRITISH_COLUMBIA_CA_BC = "\U0001f3f4\U000e0063\U000e0061\U000e0062\U000e0063\U000e007f" - FLAG_FOR_NICOSIA_CY_01 = "\U0001f3f4\U000e0063\U000e0079\U000e0030\U000e0031\U000e007f" - FLAG_FOR_SHANXI_CN_14 = "\U0001f3f4\U000e0063\U000e006e\U000e0031\U000e0034\U000e007f" - FLAG_FOR_SAXONY_ANHALT_DE_ST = "\U0001f3f4\U000e0064\U000e0065\U000e0073\U000e0074\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_TADJOURAH_DJ_TA = "\U0001f3f4\U000e0064\U000e006a\U000e0074\U000e0061\U000e007f" - FLAG_FOR_CAPITAL_REGION_DK_84 = "\U0001f3f4\U000e0064\U000e006b\U000e0038\U000e0034\U000e007f" - FLAG_FOR_HIGUAMO_DO_39 = "\U0001f3f4\U000e0064\U000e006f\U000e0033\U000e0039\U000e007f" - FLAG_FOR_CIBAO_NORDESTE_DO_33 = "\U0001f3f4\U000e0064\U000e006f\U000e0033\U000e0033\U000e007f" - FLAG_FOR_CIBAO_SUR_DO_36 = "\U0001f3f4\U000e0064\U000e006f\U000e0033\U000e0036\U000e007f" - COUPLE_WITH_HEART_MAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - FLAG_FOR_POHNPEI_FM_PNI = "\U0001f3f4\U000e0066\U000e006d\U000e0070\U000e006e\U000e0069\U000e007f" - FLAG_FOR_VALDESIA_DO_41 = "\U0001f3f4\U000e0064\U000e006f\U000e0034\U000e0031\U000e007f" - FLAG_FOR_YOZGAT_TR_66 = "\U0001f3f4\U000e0074\U000e0072\U000e0036\U000e0036\U000e007f" - FLAG_FOR_CAUCA_CO_CAU = "\U0001f3f4\U000e0063\U000e006f\U000e0063\U000e0061\U000e0075\U000e007f" - FLAG_FOR_OLOMOUCKY_KRAJ_CZ_71 = "\U0001f3f4\U000e0063\U000e007a\U000e0037\U000e0031\U000e007f" - FLAG_FOR_SAINT_MARK_DM_08 = "\U0001f3f4\U000e0064\U000e006d\U000e0030\U000e0038\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f466\U0001f3fe" - FAMILY_WOMAN_LIGHT_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f469\U0001f3fb\u200d\U0001f467\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_KHENCHELA_DZ_40 = "\U0001f3f4\U000e0064\U000e007a\U000e0034\U000e0030\U000e007f" - FAMILY_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_TIZI_OUZOU_DZ_15 = "\U0001f3f4\U000e0064\U000e007a\U000e0031\U000e0035\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f467\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_MOSTAGANEM_DZ_27 = "\U0001f3f4\U000e0064\U000e007a\U000e0032\U000e0037\U000e007f" - FLAG_FOR_OUARGLA_DZ_30 = "\U0001f3f4\U000e0064\U000e007a\U000e0033\U000e0030\U000e007f" - FLAG_FOR_BOUMERDES_DZ_35 = "\U0001f3f4\U000e0064\U000e007a\U000e0033\U000e0035\U000e007f" - FLAG_FOR_TIPASA_DZ_42 = "\U0001f3f4\U000e0064\U000e007a\U000e0034\U000e0032\U000e007f" - FLAG_FOR_BISKRA_DZ_07 = "\U0001f3f4\U000e0064\U000e007a\U000e0030\U000e0037\U000e007f" - FLAG_FOR_MEDEA_DZ_26 = "\U0001f3f4\U000e0064\U000e007a\U000e0032\U000e0036\U000e007f" - FLAG_FOR_SOUK_AHRAS_DZ_41 = "\U0001f3f4\U000e0064\U000e007a\U000e0034\U000e0031\U000e007f" - FLAG_FOR_ANNABA_DZ_23 = "\U0001f3f4\U000e0064\U000e007a\U000e0032\U000e0033\U000e007f" - FLAG_FOR_WESTERN_HIGHLANDS_PG_WHM = "\U0001f3f4\U000e0070\U000e0067\U000e0077\U000e0068\U000e006d\U000e007f" - FLAG_FOR_TINDOUF_DZ_37 = "\U0001f3f4\U000e0064\U000e007a\U000e0033\U000e0037\U000e007f" - FLAG_FOR_DJELFA_DZ_17 = "\U0001f3f4\U000e0064\U000e007a\U000e0031\U000e0037\U000e007f" - FLAG_FOR_MILA_DZ_43 = "\U0001f3f4\U000e0064\U000e007a\U000e0034\U000e0033\U000e007f" - FLAG_FOR_BATNA_DZ_05 = "\U0001f3f4\U000e0064\U000e007a\U000e0030\U000e0035\U000e007f" - FLAG_FOR_TISSEMSILT_DZ_38 = "\U0001f3f4\U000e0064\U000e007a\U000e0033\U000e0038\U000e007f" - FLAG_FOR_EL_BAYADH_DZ_32 = "\U0001f3f4\U000e0064\U000e007a\U000e0033\U000e0032\U000e007f" - FLAG_FOR_HUILA_CO_HUI = "\U0001f3f4\U000e0063\U000e006f\U000e0068\U000e0075\U000e0069\U000e007f" - FLAG_FOR_ENRIQUILLO_DO_38 = "\U0001f3f4\U000e0064\U000e006f\U000e0033\U000e0038\U000e007f" - FLAG_FOR_SUDUR_PASHCHIMANCHAL_NP_5 = "\U0001f3f4\U000e006e\U000e0070\U000e0035\U000e007f" - FLAG_FOR_BEJAIA_DZ_06 = "\U0001f3f4\U000e0064\U000e007a\U000e0030\U000e0036\U000e007f" - FLAG_FOR_BOUIRA_DZ_10 = "\U0001f3f4\U000e0064\U000e007a\U000e0031\U000e0030\U000e007f" - FLAG_FOR_ILLIZI_DZ_33 = "\U0001f3f4\U000e0064\U000e007a\U000e0033\U000e0033\U000e007f" - FLAG_FOR_PLATEAUX_CG_14 = "\U0001f3f4\U000e0063\U000e0067\U000e0031\U000e0034\U000e007f" - FLAG_FOR_SAINT_DAVID_DM_03 = "\U0001f3f4\U000e0064\U000e006d\U000e0030\U000e0033\U000e007f" - FLAG_FOR_TAMANGHASSET_DZ_11 = "\U0001f3f4\U000e0064\U000e007a\U000e0031\U000e0031\U000e007f" - FLAG_FOR_MORONA_SANTIAGO_EC_S = "\U0001f3f4\U000e0065\U000e0063\U000e0073\U000e007f" - FLAG_FOR_VALGA_EE_82 = "\U0001f3f4\U000e0065\U000e0065\U000e0038\U000e0032\U000e007f" - FLAG_FOR_RELIZANE_DZ_48 = "\U0001f3f4\U000e0064\U000e007a\U000e0034\U000e0038\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_LOJA_EC_L = "\U0001f3f4\U000e0065\U000e0063\U000e006c\U000e007f" - FLAG_FOR_GHARDAIA_DZ_47 = "\U0001f3f4\U000e0064\U000e007a\U000e0034\U000e0037\U000e007f" - FLAG_FOR_PASTAZA_EC_Y = "\U0001f3f4\U000e0065\U000e0063\U000e0079\U000e007f" - FLAG_FOR_AIN_TEMOUCHENT_DZ_46 = "\U0001f3f4\U000e0064\U000e007a\U000e0034\U000e0036\U000e007f" - FLAG_FOR_LOS_RIOS_EC_R = "\U0001f3f4\U000e0065\U000e0063\U000e0072\U000e007f" - FLAG_FOR_LAANE_EE_57 = "\U0001f3f4\U000e0065\U000e0065\U000e0035\U000e0037\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_SAARE_EE_74 = "\U0001f3f4\U000e0065\U000e0065\U000e0037\U000e0034\U000e007f" - FLAG_FOR_JOGEVA_EE_49 = "\U0001f3f4\U000e0065\U000e0065\U000e0034\U000e0039\U000e007f" - FLAG_FOR_POLVA_EE_65 = "\U0001f3f4\U000e0065\U000e0065\U000e0036\U000e0035\U000e007f" - FLAG_FOR_JARVA_EE_51 = "\U0001f3f4\U000e0065\U000e0065\U000e0035\U000e0031\U000e007f" - FLAG_FOR_PAPHOS_CY_05 = "\U0001f3f4\U000e0063\U000e0079\U000e0030\U000e0035\U000e007f" - FLAG_FOR_PARNU_EE_67 = "\U0001f3f4\U000e0065\U000e0065\U000e0036\U000e0037\U000e007f" - FLAG_FOR_CARCHI_EC_C = "\U0001f3f4\U000e0065\U000e0063\U000e0063\U000e007f" - FLAG_FOR_SUCUMBIOS_EC_U = "\U0001f3f4\U000e0065\U000e0063\U000e0075\U000e007f" - FLAG_FOR_OUM_EL_BOUAGHI_DZ_04 = "\U0001f3f4\U000e0064\U000e007a\U000e0030\U000e0034\U000e007f" - FLAG_FOR_GALAPAGOS_EC_W = "\U0001f3f4\U000e0065\U000e0063\U000e0077\U000e007f" - FLAG_FOR_GHARBIA_EG_GH = "\U0001f3f4\U000e0065\U000e0067\U000e0067\U000e0068\U000e007f" - FLAG_FOR_DAKAHLIA_EG_DK = "\U0001f3f4\U000e0065\U000e0067\U000e0064\U000e006b\U000e007f" - FLAG_FOR_AL_SHARQIA_EG_SHR = "\U0001f3f4\U000e0065\U000e0067\U000e0073\U000e0068\U000e0072\U000e007f" - FLAG_FOR_QALYUBIA_EG_KB = "\U0001f3f4\U000e0065\U000e0067\U000e006b\U000e0062\U000e007f" - FLAG_FOR_FEDERATION_OF_BOSNIA_AND_HERZEGOVINA_BA_BIH = "\U0001f3f4\U000e0062\U000e0061\U000e0062\U000e0069\U000e0068\U000e007f" - FLAG_FOR_CENTRAL_ABACO_BS_CO = "\U0001f3f4\U000e0062\U000e0073\U000e0063\U000e006f\U000e007f" - FLAG_FOR_MONUFIA_EG_MNF = "\U0001f3f4\U000e0065\U000e0067\U000e006d\U000e006e\U000e0066\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE_GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe\u200d\U0001f467\U0001f3fe" - FLAG_FOR_BUJUMBURA_RURAL_BI_BL = "\U0001f3f4\U000e0062\U000e0069\U000e0062\U000e006c\U000e007f" - FLAG_FOR_MAEKEL_ER_MA = "\U0001f3f4\U000e0065\U000e0072\U000e006d\U000e0061\U000e007f" - FLAG_FOR_ISMAILIA_EG_IS = "\U0001f3f4\U000e0065\U000e0067\U000e0069\U000e0073\U000e007f" - FLAG_FOR_SAIDA_DZ_20 = "\U0001f3f4\U000e0064\U000e007a\U000e0032\U000e0030\U000e007f" - FLAG_FOR_QENA_EG_KN = "\U0001f3f4\U000e0065\U000e0067\U000e006b\U000e006e\U000e007f" - FLAG_FOR_TARTU_EE_78 = "\U0001f3f4\U000e0065\U000e0065\U000e0037\U000e0038\U000e007f" - FLAG_FOR_ANSEBA_ER_AN = "\U0001f3f4\U000e0065\U000e0072\U000e0061\U000e006e\U000e007f" - FLAG_FOR_ASWAN_EG_ASN = "\U0001f3f4\U000e0065\U000e0067\U000e0061\U000e0073\U000e006e\U000e007f" - FLAG_FOR_DEBUB_ER_DU = "\U0001f3f4\U000e0065\U000e0072\U000e0064\U000e0075\U000e007f" - FLAG_FOR_ASYUT_EG_AST = "\U0001f3f4\U000e0065\U000e0067\U000e0061\U000e0073\U000e0074\U000e007f" - FLAG_FOR_BEHEIRA_EG_BH = "\U0001f3f4\U000e0065\U000e0067\U000e0062\U000e0068\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f476\U0001f3fe" - FLAG_FOR_IMBABURA_EC_I = "\U0001f3f4\U000e0065\U000e0063\U000e0069\U000e007f" - FLAG_FOR_VILJANDI_EE_84 = "\U0001f3f4\U000e0065\U000e0065\U000e0038\U000e0034\U000e007f" - FLAG_FOR_VORU_EE_86 = "\U0001f3f4\U000e0065\U000e0065\U000e0038\U000e0036\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FLAG_FOR_HAUTE_KOTTO_CF_HK = "\U0001f3f4\U000e0063\U000e0066\U000e0068\U000e006b\U000e007f" - FLAG_FOR_GUAINIA_CO_GUA = "\U0001f3f4\U000e0063\U000e006f\U000e0067\U000e0075\U000e0061\U000e007f" - FLAG_FOR_DAMIETTA_EG_DT = "\U0001f3f4\U000e0065\U000e0067\U000e0064\U000e0074\U000e007f" - FLAG_FOR_SAINT_PAUL_DM_10 = "\U0001f3f4\U000e0064\U000e006d\U000e0031\U000e0030\U000e007f" - FLAG_FOR_KAINUU_FI_05 = "\U0001f3f4\U000e0066\U000e0069\U000e0030\U000e0035\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f467\U0001f3fd" - FLAG_FOR_KYMENLAAKSO_FI_09 = "\U0001f3f4\U000e0066\U000e0069\U000e0030\U000e0039\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fd" - FLAG_FOR_BENISHANGUL_GUMUZ_ET_BE = "\U0001f3f4\U000e0065\U000e0074\U000e0062\U000e0065\U000e007f" - FLAG_FOR_SOUTH_KARELIA_FI_02 = "\U0001f3f4\U000e0066\U000e0069\U000e0030\U000e0032\U000e007f" - FLAG_FOR_PUNAKHA_BT_23 = "\U0001f3f4\U000e0062\U000e0074\U000e0032\U000e0033\U000e007f" - FLAG_FOR_YUMA_DO_42 = "\U0001f3f4\U000e0064\U000e006f\U000e0034\U000e0032\U000e007f" - FLAG_FOR_SANTA_ELENA_EC_SE = "\U0001f3f4\U000e0065\U000e0063\U000e0073\U000e0065\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f467\U0001f3fc" - KISS_MAN_MEDIUM_SKIN_TONE_WOMAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469\U0001f3ff" - FLAG_FOR_BISTRITA_NASAUD_RO_BN = "\U0001f3f4\U000e0072\U000e006f\U000e0062\U000e006e\U000e007f" - FLAG_FOR_KEMO_CF_KG = "\U0001f3f4\U000e0063\U000e0066\U000e006b\U000e0067\U000e007f" - FLAG_FOR_BLIDA_DZ_09 = "\U0001f3f4\U000e0064\U000e007a\U000e0030\U000e0039\U000e007f" - FLAG_FOR_HARARI_ET_HA = "\U0001f3f4\U000e0065\U000e0074\U000e0068\U000e0061\U000e007f" - FLAG_FOR_ARTEMISA_CU_15 = "\U0001f3f4\U000e0063\U000e0075\U000e0031\U000e0035\U000e007f" - FLAG_FOR_SOUTHERN_OSTROBOTHNIA_FI_03 = "\U0001f3f4\U000e0066\U000e0069\U000e0030\U000e0033\U000e007f" - FLAG_FOR_OBOCK_DJ_OB = "\U0001f3f4\U000e0064\U000e006a\U000e006f\U000e0062\U000e007f" - FLAG_FOR_MATROUH_EG_MT = "\U0001f3f4\U000e0065\U000e0067\U000e006d\U000e0074\U000e007f" - TAG_LATIN_CAPITAL_LETTER_W = "\U000e0057" - FLAG_FOR_VILLA_CLARA_CU_05 = "\U0001f3f4\U000e0063\U000e0075\U000e0030\U000e0035\U000e007f" - FLAG_FOR_CENTRAL_FJ_C = "\U0001f3f4\U000e0066\U000e006a\U000e0063\U000e007f" - FLAG_FOR_NORTH_KARELIA_FI_13 = "\U0001f3f4\U000e0066\U000e0069\U000e0031\U000e0033\U000e007f" - FLAG_FOR_CHUKHA_BT_12 = "\U0001f3f4\U000e0062\U000e0074\U000e0031\U000e0032\U000e007f" - FLAG_FOR_BENI_BO_B = "\U0001f3f4\U000e0062\U000e006f\U000e0062\U000e007f" - FLAG_FOR_ORAN_DZ_31 = "\U0001f3f4\U000e0064\U000e007a\U000e0033\U000e0031\U000e007f" - FLAG_FOR_NORTHERN_SAVONIA_FI_15 = "\U0001f3f4\U000e0066\U000e0069\U000e0031\U000e0035\U000e007f" - FLAG_FOR_APPENZELL_AUSSERRHODEN_CH_AR = "\U0001f3f4\U000e0063\U000e0068\U000e0061\U000e0072\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_PIRKANMAA_FI_11 = "\U0001f3f4\U000e0066\U000e0069\U000e0031\U000e0031\U000e007f" - FLAG_FOR_KOSRAE_FM_KSA = "\U0001f3f4\U000e0066\U000e006d\U000e006b\U000e0073\U000e0061\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_OUHAM_PENDE_CF_OP = "\U0001f3f4\U000e0063\U000e0066\U000e006f\U000e0070\U000e007f" - FLAG_FOR_BIO_BIO_CL_BI = "\U0001f3f4\U000e0063\U000e006c\U000e0062\U000e0069\U000e007f" - HORIZONTAL_MALE_WITH_STROKE_SIGN = "\u26a9" - FLAG_FOR_NOUVELLE_AQUITAINE_FR_NAQ = "\U0001f3f4\U000e0066\U000e0072\U000e006e\U000e0061\U000e0071\U000e007f" - FLAG_FOR_ANSE_AUX_PINS_SC_01 = "\U0001f3f4\U000e0073\U000e0063\U000e0030\U000e0031\U000e007f" - FLAG_FOR_SAINT_DAVID_GD_02 = "\U0001f3f4\U000e0067\U000e0064\U000e0030\U000e0032\U000e007f" - FLAG_FOR_OGOOUE_IVINDO_GA_6 = "\U0001f3f4\U000e0067\U000e0061\U000e0036\U000e007f" - FLAG_FOR_ZAMORA_CHINCHIPE_EC_Z = "\U0001f3f4\U000e0065\U000e0063\U000e007a\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FLAG_FOR_MOYEN_OGOOUE_GA_3 = "\U0001f3f4\U000e0067\U000e0061\U000e0033\U000e007f" - FLAG_FOR_SATAKUNTA_FI_17 = "\U0001f3f4\U000e0066\U000e0069\U000e0031\U000e0037\U000e007f" - FLAG_FOR_BRONG_AHAFO_GH_BA = "\U0001f3f4\U000e0067\U000e0068\U000e0062\U000e0061\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_VAN_TR_65 = "\U0001f3f4\U000e0074\U000e0072\U000e0036\U000e0035\U000e007f" - FLAG_FOR_MTSKHETA_MTIANETI_GE_MM = "\U0001f3f4\U000e0067\U000e0065\U000e006d\U000e006d\U000e007f" - FLAG_FOR_TEBESSA_DZ_12 = "\U0001f3f4\U000e0064\U000e007a\U000e0031\U000e0032\U000e007f" - FLAG_FOR_WOLEU_NTEM_GA_9 = "\U0001f3f4\U000e0067\U000e0061\U000e0039\U000e007f" - FLAG_FOR_SAMEGRELO_ZEMO_SVANETI_GE_SZ = "\U0001f3f4\U000e0067\U000e0065\U000e0073\U000e007a\U000e007f" - FLAG_FOR_IMERETI_GE_IM = "\U0001f3f4\U000e0067\U000e0065\U000e0069\U000e006d\U000e007f" - FLAG_FOR_SAMTSKHE_JAVAKHETI_GE_SJ = "\U0001f3f4\U000e0067\U000e0065\U000e0073\U000e006a\U000e007f" - FLAG_FOR_ABIDJAN_CI_AB = "\U0001f3f4\U000e0063\U000e0069\U000e0061\U000e0062\U000e007f" - FLAG_FOR_SHIRAK_AM_SH = "\U0001f3f4\U000e0061\U000e006d\U000e0073\U000e0068\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_GUELMA_DZ_24 = "\U0001f3f4\U000e0064\U000e007a\U000e0032\U000e0034\U000e007f" - FLAG_FOR_HAUT_OGOOUE_GA_2 = "\U0001f3f4\U000e0067\U000e0061\U000e0032\U000e007f" - FLAG_FOR_JIHOMORAVSKY_KRAJ_CZ_64 = "\U0001f3f4\U000e0063\U000e007a\U000e0036\U000e0034\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_KUJALLEQ_GL_KU = "\U0001f3f4\U000e0067\U000e006c\U000e006b\U000e0075\U000e007f" - FLAG_FOR_THESSALY_GR_E = "\U0001f3f4\U000e0067\U000e0072\U000e0065\U000e007f" - FLAG_FOR_EPIRUS_GR_D = "\U0001f3f4\U000e0067\U000e0072\U000e0064\U000e007f" - FLAG_FOR_PICHINCHA_EC_P = "\U0001f3f4\U000e0065\U000e0063\U000e0070\U000e007f" - FLAG_FOR_ALI_SABIEH_DJ_AS = "\U0001f3f4\U000e0064\U000e006a\U000e0061\U000e0073\U000e007f" - FLAG_FOR_NORTHERN_FJ_N = "\U0001f3f4\U000e0066\U000e006a\U000e006e\U000e007f" - FLAG_FOR_NORTHERN_GH_NP = "\U0001f3f4\U000e0067\U000e0068\U000e006e\U000e0070\U000e007f" - FLAG_FOR_UPPER_WEST_GH_UW = "\U0001f3f4\U000e0067\U000e0068\U000e0075\U000e0077\U000e007f" - FLAG_FOR_UPPER_EAST_GH_UE = "\U0001f3f4\U000e0067\U000e0068\U000e0075\U000e0065\U000e007f" - FLAG_FOR_KINDIA_REGION_GN_D = "\U0001f3f4\U000e0067\U000e006e\U000e0064\U000e007f" - FLAG_FOR_CONAKRY_GN_C = "\U0001f3f4\U000e0067\U000e006e\U000e0063\U000e007f" - FLAG_FOR_IONIAN_ISLANDS_GR_F = "\U0001f3f4\U000e0067\U000e0072\U000e0066\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - FLAG_FOR_SINOE_LR_SI = "\U0001f3f4\U000e006c\U000e0072\U000e0073\U000e0069\U000e007f" - FLAG_FOR_FARANAH_REGION_GN_F = "\U0001f3f4\U000e0067\U000e006e\U000e0066\U000e007f" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fc" - FLAG_FOR_HEILONGJIANG_CN_23 = "\U0001f3f4\U000e0063\U000e006e\U000e0032\U000e0033\U000e007f" - FLAG_FOR_RIO_MUNI_GQ_C = "\U0001f3f4\U000e0067\U000e0071\U000e0063\U000e007f" - WHITE_DOWN_POINTING_LEFT_HAND_INDEX = "\U0001f597" - FLAG_FOR_VOLTA_GH_TV = "\U0001f3f4\U000e0067\U000e0068\U000e0074\U000e0076\U000e007f" - FLAG_FOR_QAASUITSUP_GL_QA = "\U0001f3f4\U000e0067\U000e006c\U000e0071\U000e0061\U000e007f" - KISS_MAN_LIGHT_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3ff" - FLAG_FOR_QUICHE_GT_QC = "\U0001f3f4\U000e0067\U000e0074\U000e0071\U000e0063\U000e007f" - FLAG_FOR_HUNAN_CN_43 = "\U0001f3f4\U000e0063\U000e006e\U000e0034\U000e0033\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fe" - FLAG_FOR_QUETZALTENANGO_GT_QZ = "\U0001f3f4\U000e0067\U000e0074\U000e0071\U000e007a\U000e007f" - FLAG_FOR_LESTE_GW_L = "\U0001f3f4\U000e0067\U000e0077\U000e006c\U000e007f" - FLAG_FOR_CUYUNI_MAZARUNI_GY_CU = "\U0001f3f4\U000e0067\U000e0079\U000e0063\U000e0075\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f476\U0001f3ff" - FLAG_FOR_PETEN_GT_PE = "\U0001f3f4\U000e0067\U000e0074\U000e0070\U000e0065\U000e007f" - FLAG_FOR_ZACAPA_GT_ZA = "\U0001f3f4\U000e0067\U000e0074\U000e007a\U000e0061\U000e007f" - FLAG_FOR_LIAONING_CN_21 = "\U0001f3f4\U000e0063\U000e006e\U000e0032\U000e0031\U000e007f" - FLAG_FOR_CHOLUTECA_HN_CH = "\U0001f3f4\U000e0068\U000e006e\U000e0063\U000e0068\U000e007f" - FLAG_FOR_CHIMALTENANGO_GT_CM = "\U0001f3f4\U000e0067\U000e0074\U000e0063\U000e006d\U000e007f" - FLAG_FOR_SOLOLA_GT_SO = "\U0001f3f4\U000e0067\U000e0074\U000e0073\U000e006f\U000e007f" - FLAG_FOR_HUEHUETENANGO_GT_HU = "\U0001f3f4\U000e0067\U000e0074\U000e0068\U000e0075\U000e007f" - KISS_MAN_MAN_LIGHT_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - FLAG_FOR_ESCUINTLA_GT_ES = "\U0001f3f4\U000e0067\U000e0074\U000e0065\U000e0073\U000e007f" - FLAG_FOR_CHIQUIMULA_GT_CQ = "\U0001f3f4\U000e0067\U000e0074\U000e0063\U000e0071\U000e007f" - FLAG_FOR_IZABAL_GT_IZ = "\U0001f3f4\U000e0067\U000e0074\U000e0069\U000e007a\U000e007f" - FLAG_FOR_ATLANTIDA_HN_AT = "\U0001f3f4\U000e0068\U000e006e\U000e0061\U000e0074\U000e007f" - FLAG_FOR_NEW_JERSEY_US_NJ = "\U0001f3f4\U000e0075\U000e0073\U000e006e\U000e006a\U000e007f" - FLAG_FOR_ESSEQUIBO_ISLANDS_WEST_DEMERARA_GY_ES = "\U0001f3f4\U000e0067\U000e0079\U000e0065\U000e0073\U000e007f" - FLAG_FOR_POTARO_SIPARUNI_GY_PT = "\U0001f3f4\U000e0067\U000e0079\U000e0070\U000e0074\U000e007f" - FLAG_FOR_BISSAU_GW_BS = "\U0001f3f4\U000e0067\U000e0077\U000e0062\U000e0073\U000e007f" - FLAG_FOR_DEMERARA_MAHAICA_GY_DE = "\U0001f3f4\U000e0067\U000e0079\U000e0064\U000e0065\U000e007f" - FLAG_FOR_IDA_VIRU_EE_44 = "\U0001f3f4\U000e0065\U000e0065\U000e0034\U000e0034\U000e007f" - FLAG_FOR_LIKA_SENJ_HR_09 = "\U0001f3f4\U000e0068\U000e0072\U000e0030\U000e0039\U000e007f" - FLAG_FOR_KRAPINA_ZAGORJE_HR_02 = "\U0001f3f4\U000e0068\U000e0072\U000e0030\U000e0032\U000e007f" - FLAG_FOR_ARTIBONITE_HT_AR = "\U0001f3f4\U000e0068\U000e0074\U000e0061\U000e0072\U000e007f" - FLAG_FOR_OCOTEPEQUE_HN_OC = "\U0001f3f4\U000e0068\U000e006e\U000e006f\U000e0063\U000e007f" - FLAG_FOR_CENTRE_HT_CE = "\U0001f3f4\U000e0068\U000e0074\U000e0063\U000e0065\U000e007f" - FLAG_FOR_SOLOTHURN_CH_SO = "\U0001f3f4\U000e0063\U000e0068\U000e0073\U000e006f\U000e007f" - FLAG_FOR_JALAPA_GT_JA = "\U0001f3f4\U000e0067\U000e0074\U000e006a\U000e0061\U000e007f" - FLAG_FOR_DUBROVNIK_NERETVA_HR_19 = "\U0001f3f4\U000e0068\U000e0072\U000e0031\U000e0039\U000e007f" - FLAG_FOR_VUKOVAR_SYRMIA_HR_16 = "\U0001f3f4\U000e0068\U000e0072\U000e0031\U000e0036\U000e007f" - FLAG_FOR_OSIJEK_BARANJA_HR_14 = "\U0001f3f4\U000e0068\U000e0072\U000e0031\U000e0034\U000e007f" - FLAG_FOR_KOPRIVNICA_KRIZEVCI_HR_06 = "\U0001f3f4\U000e0068\U000e0072\U000e0030\U000e0036\U000e007f" - FLAG_FOR_INTIBUCA_HN_IN = "\U0001f3f4\U000e0068\U000e006e\U000e0069\U000e006e\U000e007f" - FLAG_FOR_POZEGA_SLAVONIA_HR_11 = "\U0001f3f4\U000e0068\U000e0072\U000e0031\U000e0031\U000e007f" - FLAG_FOR_BERAT_COUNTY_AL_01 = "\U0001f3f4\U000e0061\U000e006c\U000e0030\U000e0031\U000e007f" - FLAG_FOR_SAINT_LUKE_DM_07 = "\U0001f3f4\U000e0064\U000e006d\U000e0030\U000e0037\U000e007f" - FLAG_FOR_COMAYAGUA_HN_CM = "\U0001f3f4\U000e0068\U000e006e\U000e0063\U000e006d\U000e007f" - FLAG_FOR_YORO_HN_YO = "\U0001f3f4\U000e0068\U000e006e\U000e0079\U000e006f\U000e007f" - FLAG_FOR_COPAN_HN_CP = "\U0001f3f4\U000e0068\U000e006e\U000e0063\U000e0070\U000e007f" - FLAG_FOR_VALLE_HN_VA = "\U0001f3f4\U000e0068\U000e006e\U000e0076\U000e0061\U000e007f" - FLAG_FOR_LEMPIRA_HN_LE = "\U0001f3f4\U000e0068\U000e006e\U000e006c\U000e0065\U000e007f" - FLAG_FOR_ME_IMURJE_HR_20 = "\U0001f3f4\U000e0068\U000e0072\U000e0032\U000e0030\U000e007f" - FLAG_FOR_SIBENIK_KNIN_HR_15 = "\U0001f3f4\U000e0068\U000e0072\U000e0031\U000e0035\U000e007f" - MERCURY = "\u263f\ufe0f" - FLAG_FOR_FRANCISCO_MORAZAN_HN_FM = "\U0001f3f4\U000e0068\U000e006e\U000e0066\U000e006d\U000e007f" - FLAG_FOR_OLANCHO_HN_OL = "\U0001f3f4\U000e0068\U000e006e\U000e006f\U000e006c\U000e007f" - FLAG_FOR_CORTES_HN_CR = "\U0001f3f4\U000e0068\U000e006e\U000e0063\U000e0072\U000e007f" - FLAG_FOR_ZAGREB_COUNTY_HR_01 = "\U0001f3f4\U000e0068\U000e0072\U000e0030\U000e0031\U000e007f" - FLAG_FOR_ISTRIA_HR_18 = "\U0001f3f4\U000e0068\U000e0072\U000e0031\U000e0038\U000e007f" - FLAG_FOR_ZADAR_HR_13 = "\U0001f3f4\U000e0068\U000e0072\U000e0031\U000e0033\U000e007f" - FLAG_FOR_PEST_HU_PE = "\U0001f3f4\U000e0068\U000e0075\U000e0070\U000e0065\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_GIRL_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f467\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_HAJDU_BIHAR_HU_HB = "\U0001f3f4\U000e0068\U000e0075\U000e0068\U000e0062\U000e007f" - COUPLE_WITH_HEART_MAN_DARK_SKIN_TONE_MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3ff" - FLAG_FOR_OUEST_HT_OU = "\U0001f3f4\U000e0068\U000e0074\U000e006f\U000e0075\U000e007f" - FLAG_FOR_SZOLNOK_HU_SK = "\U0001f3f4\U000e0068\U000e0075\U000e0073\U000e006b\U000e007f" - FLAG_FOR_NOGRAD_HU_NO = "\U0001f3f4\U000e0068\U000e0075\U000e006e\U000e006f\U000e007f" - FLAG_FOR_BORSOD_ABAUJ_ZEMPLEN_HU_BZ = "\U0001f3f4\U000e0068\U000e0075\U000e0062\U000e007a\U000e007f" - FLAG_FOR_SOPRON_HU_SN = "\U0001f3f4\U000e0068\U000e0075\U000e0073\U000e006e\U000e007f" - FLAG_FOR_JIJEL_DZ_18 = "\U0001f3f4\U000e0064\U000e007a\U000e0031\U000e0038\U000e007f" - FLAG_FOR_BEKESCSABA_HU_BC = "\U0001f3f4\U000e0068\U000e0075\U000e0062\U000e0063\U000e007f" - FLAG_FOR_NYIREGYHAZA_HU_NY = "\U0001f3f4\U000e0068\U000e0075\U000e006e\U000e0079\U000e007f" - FLAG_FOR_NORD_HT_ND = "\U0001f3f4\U000e0068\U000e0074\U000e006e\U000e0064\U000e007f" - FLAG_FOR_FEJER_HU_FE = "\U0001f3f4\U000e0068\U000e0075\U000e0066\U000e0065\U000e007f" - FLAG_FOR_NIPPES_HT_NI = "\U0001f3f4\U000e0068\U000e0074\U000e006e\U000e0069\U000e007f" - FLAG_FOR_ERD_HU_ER = "\U0001f3f4\U000e0068\U000e0075\U000e0065\U000e0072\U000e007f" - FLAG_FOR_SZOMBATHELY_HU_SH = "\U0001f3f4\U000e0068\U000e0075\U000e0073\U000e0068\U000e007f" - FLAG_FOR_EASTERN_GH_EP = "\U0001f3f4\U000e0067\U000e0068\U000e0065\U000e0070\U000e007f" - FLAG_FOR_DIRE_DAWA_ET_DD = "\U0001f3f4\U000e0065\U000e0074\U000e0064\U000e0064\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469" - FLAG_FOR_SZEKESFEHERVAR_HU_SF = "\U0001f3f4\U000e0068\U000e0075\U000e0073\U000e0066\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fb" - FLAG_FOR_KOMAROM_ESZTERGOM_HU_KE = "\U0001f3f4\U000e0068\U000e0075\U000e006b\U000e0065\U000e007f" - FLAG_FOR_MISKOLC_HU_MI = "\U0001f3f4\U000e0068\U000e0075\U000e006d\U000e0069\U000e007f" - FLAG_FOR_DEBRECEN_HU_DE = "\U0001f3f4\U000e0068\U000e0075\U000e0064\U000e0065\U000e007f" - FLAG_FOR_BACS_KISKUN_HU_BK = "\U0001f3f4\U000e0068\U000e0075\U000e0062\U000e006b\U000e007f" - FLAG_FOR_GYOR_HU_GY = "\U0001f3f4\U000e0068\U000e0075\U000e0067\U000e0079\U000e007f" - FLAG_FOR_DUNAUJVAROS_HU_DU = "\U0001f3f4\U000e0068\U000e0075\U000e0064\U000e0075\U000e007f" - FLAG_FOR_HEVES_HU_HE = "\U0001f3f4\U000e0068\U000e0075\U000e0068\U000e0065\U000e007f" - FLAG_FOR_BEKES_HU_BE = "\U0001f3f4\U000e0068\U000e0075\U000e0062\U000e0065\U000e007f" - FLAG_FOR_JASZ_NAGYKUN_SZOLNOK_HU_JN = "\U0001f3f4\U000e0068\U000e0075\U000e006a\U000e006e\U000e007f" - FLAG_FOR_RAPLA_EE_70 = "\U0001f3f4\U000e0065\U000e0065\U000e0037\U000e0030\U000e007f" - FLAG_FOR_ZALAEGERSZEG_HU_ZE = "\U0001f3f4\U000e0068\U000e0075\U000e007a\U000e0065\U000e007f" - FLAG_FOR_CONNACHT_IE_C = "\U0001f3f4\U000e0069\U000e0065\U000e0063\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fd" - FLAG_FOR_CENTRAL_DISTRICT_IL_M = "\U0001f3f4\U000e0069\U000e006c\U000e006d\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_GREATER_ACCRA_GH_AA = "\U0001f3f4\U000e0067\U000e0068\U000e0061\U000e0061\U000e007f" - FLAG_FOR_HAIFA_DISTRICT_IL_HA = "\U0001f3f4\U000e0069\U000e006c\U000e0068\U000e0061\U000e007f" - FLAG_FOR_BARANYA_HU_BA = "\U0001f3f4\U000e0068\U000e0075\U000e0062\U000e0061\U000e007f" - FLAG_FOR_VESZPREM_HU_VM = "\U0001f3f4\U000e0068\U000e0075\U000e0076\U000e006d\U000e007f" - FLAG_FOR_VESZPREM_COUNTY_HU_VE = "\U0001f3f4\U000e0068\U000e0075\U000e0076\U000e0065\U000e007f" - FLAG_FOR_MAGDALENA_CO_MAG = "\U0001f3f4\U000e0063\U000e006f\U000e006d\U000e0061\U000e0067\U000e007f" - FLAG_FOR_NAGYKANIZSA_HU_NK = "\U0001f3f4\U000e0068\U000e0075\U000e006e\U000e006b\U000e007f" - FLAG_FOR_SOMOGY_HU_SO = "\U0001f3f4\U000e0068\U000e0075\U000e0073\U000e006f\U000e007f" - FLAG_FOR_SOUTHERN_DISTRICT_IL_D = "\U0001f3f4\U000e0069\U000e006c\U000e0064\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - FLAG_FOR_SAINT_PETER_DM_11 = "\U0001f3f4\U000e0064\U000e006d\U000e0031\U000e0031\U000e007f" - KISS_WOMAN_MEDIUM_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fb" - FLAG_FOR_TOLNA_HU_TO = "\U0001f3f4\U000e0068\U000e0075\U000e0074\U000e006f\U000e007f" - FLAG_FOR_ODISHA_IN_OR = "\U0001f3f4\U000e0069\U000e006e\U000e006f\U000e0072\U000e007f" - FLAG_FOR_PUTUMAYO_CO_PUT = "\U0001f3f4\U000e0063\U000e006f\U000e0070\U000e0075\U000e0074\U000e007f" - FLAG_FOR_DOHUK_IQ_DA = "\U0001f3f4\U000e0069\U000e0071\U000e0064\U000e0061\U000e007f" - FLAG_FOR_AL_MUTHANNA_IQ_MU = "\U0001f3f4\U000e0069\U000e0071\U000e006d\U000e0075\U000e007f" - WHITE_DIAMOND_SUIT = "\u2662" - BLACK_CHESS_QUEEN = "\u265b" - FLAG_FOR_SALADIN_IQ_SD = "\U0001f3f4\U000e0069\U000e0071\U000e0073\U000e0064\U000e007f" - TAG_LATIN_SMALL_LETTER_V = "\U000e0076" - FAMILY_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_SHANDONG_CN_37 = "\U0001f3f4\U000e0063\U000e006e\U000e0033\U000e0037\U000e007f" - FLAG_FOR_AL_ANBAR_IQ_AN = "\U0001f3f4\U000e0069\U000e0071\U000e0061\U000e006e\U000e007f" - FLAG_FOR_NAJAF_IQ_NA = "\U0001f3f4\U000e0069\U000e0071\U000e006e\U000e0061\U000e007f" - FLAG_FOR_KARBALA_IQ_KA = "\U0001f3f4\U000e0069\U000e0071\U000e006b\U000e0061\U000e007f" - FLAG_FOR_SULAWESI_ID_SL = "\U0001f3f4\U000e0069\U000e0064\U000e0073\U000e006c\U000e007f" - FLAG_FOR_ATLANTICO_CO_ATL = "\U0001f3f4\U000e0063\U000e006f\U000e0061\U000e0074\U000e006c\U000e007f" - FAMILY_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_DIYALA_IQ_DI = "\U0001f3f4\U000e0069\U000e0071\U000e0064\U000e0069\U000e007f" - FLAG_FOR_AL_QADISIYYAH_IQ_QA = "\U0001f3f4\U000e0069\U000e0071\U000e0071\U000e0061\U000e007f" - FLAG_FOR_NAGALAND_IN_NL = "\U0001f3f4\U000e0069\U000e006e\U000e006e\U000e006c\U000e007f" - FLAG_FOR_SULAYMANIYAH_IQ_SU = "\U0001f3f4\U000e0069\U000e0071\U000e0073\U000e0075\U000e007f" - FLAG_FOR_SUEZ_EG_SUZ = "\U0001f3f4\U000e0065\U000e0067\U000e0073\U000e0075\U000e007a\U000e007f" - FLAG_FOR_MEGHALAYA_IN_ML = "\U0001f3f4\U000e0069\U000e006e\U000e006d\U000e006c\U000e007f" - FLAG_FOR_NINEVEH_IQ_NI = "\U0001f3f4\U000e0069\U000e0071\U000e006e\U000e0069\U000e007f" - FLAG_FOR_NEUCHATEL_CH_NE = "\U0001f3f4\U000e0063\U000e0068\U000e006e\U000e0065\U000e007f" - FLAG_FOR_MIZORAM_IN_MZ = "\U0001f3f4\U000e0069\U000e006e\U000e006d\U000e007a\U000e007f" - FLAG_FOR_OBWALDEN_CH_OW = "\U0001f3f4\U000e0063\U000e0068\U000e006f\U000e0077\U000e007f" - FLAG_FOR_LAKSHADWEEP_IN_LD = "\U0001f3f4\U000e0069\U000e006e\U000e006c\U000e0064\U000e007f" - FLAG_FOR_HORMOZGAN_IR_23 = "\U0001f3f4\U000e0069\U000e0072\U000e0032\U000e0033\U000e007f" - FLAG_FOR_QAZVIN_IR_28 = "\U0001f3f4\U000e0069\U000e0072\U000e0032\U000e0038\U000e007f" - FLAG_FOR_MAYSAN_IQ_MA = "\U0001f3f4\U000e0069\U000e0071\U000e006d\U000e0061\U000e007f" - FLAG_FOR_SEMNAN_IR_12 = "\U0001f3f4\U000e0069\U000e0072\U000e0031\U000e0032\U000e007f" - FLAG_FOR_ALAJUELA_CR_A = "\U0001f3f4\U000e0063\U000e0072\U000e0061\U000e007f" - FLAG_FOR_MARKAZI_IR_22 = "\U0001f3f4\U000e0069\U000e0072\U000e0032\U000e0032\U000e007f" - COUPLE_WITH_HEART_WOMAN_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - FLAG_FOR_RHODE_ISLAND_US_RI = "\U0001f3f4\U000e0075\U000e0073\U000e0072\U000e0069\U000e007f" - FLAG_FOR_PIRAN_SI_090 = "\U0001f3f4\U000e0073\U000e0069\U000e0030\U000e0039\U000e0030\U000e007f" - FLAG_FOR_LEINSTER_IE_L = "\U0001f3f4\U000e0069\U000e0065\U000e006c\U000e007f" - FLAG_FOR_BANJUL_GM_B = "\U0001f3f4\U000e0067\U000e006d\U000e0062\U000e007f" - FLAG_FOR_NORTHWESTERN_IS_5 = "\U0001f3f4\U000e0069\U000e0073\U000e0035\U000e007f" - FAMILY_WOMAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f467\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_MAHAICA_BERBICE_GY_MA = "\U0001f3f4\U000e0067\U000e0079\U000e006d\U000e0061\U000e007f" - FLAG_FOR_YAZD_IR_25 = "\U0001f3f4\U000e0069\U000e0072\U000e0032\U000e0035\U000e007f" - FLAG_FOR_WASIT_IQ_WA = "\U0001f3f4\U000e0069\U000e0071\U000e0077\U000e0061\U000e007f" - FLAG_FOR_SAINT_ANDREW_DM_02 = "\U0001f3f4\U000e0064\U000e006d\U000e0030\U000e0032\U000e007f" - FLAG_FOR_SUMATRA_ID_SM = "\U0001f3f4\U000e0069\U000e0064\U000e0073\U000e006d\U000e007f" - FLAG_FOR_ZALA_HU_ZA = "\U0001f3f4\U000e0068\U000e0075\U000e007a\U000e0061\U000e007f" - COUPLE_WITH_HEART_WOMAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469\U0001f3fe" - FLAG_FOR_BOLIVAR_CO_BOL = "\U0001f3f4\U000e0063\U000e006f\U000e0062\U000e006f\U000e006c\U000e007f" - FLAG_FOR_SAINT_ELIZABETH_JM_11 = "\U0001f3f4\U000e006a\U000e006d\U000e0031\U000e0031\U000e007f" - FLAG_FOR_WESTERN_GH_WP = "\U0001f3f4\U000e0067\U000e0068\U000e0077\U000e0070\U000e007f" - FLAG_FOR_JERASH_JO_JA = "\U0001f3f4\U000e006a\U000e006f\U000e006a\U000e0061\U000e007f" - FLAG_FOR_TRELAWNY_JM_07 = "\U0001f3f4\U000e006a\U000e006d\U000e0030\U000e0037\U000e007f" - FLAG_FOR_MOLISE_IT_67 = "\U0001f3f4\U000e0069\U000e0074\U000e0036\U000e0037\U000e007f" - FLAG_FOR_NORTHEASTERN_IS_6 = "\U0001f3f4\U000e0069\U000e0073\U000e0036\U000e007f" - FLAG_FOR_AMMAN_JO_AM = "\U0001f3f4\U000e006a\U000e006f\U000e0061\U000e006d\U000e007f" - FLAG_FOR_UMM_AL_QUWAIN_AE_UQ = "\U0001f3f4\U000e0061\U000e0065\U000e0075\U000e0071\U000e007f" - FLAG_FOR_GOLESTAN_IR_27 = "\U0001f3f4\U000e0069\U000e0072\U000e0032\U000e0037\U000e007f" - FLAG_FOR_TAFILAH_JO_AT = "\U0001f3f4\U000e006a\U000e006f\U000e0061\U000e0074\U000e007f" - FLAG_FOR_KECSKEMET_HU_KM = "\U0001f3f4\U000e0068\U000e0075\U000e006b\U000e006d\U000e007f" - FLAG_FOR_UMBRIA_IT_55 = "\U0001f3f4\U000e0069\U000e0074\U000e0035\U000e0035\U000e007f" - FLAG_FOR_SAINT_ANN_JM_06 = "\U0001f3f4\U000e006a\U000e006d\U000e0030\U000e0036\U000e007f" - FLAG_FOR_SUD_HT_SD = "\U0001f3f4\U000e0068\U000e0074\U000e0073\U000e0064\U000e007f" - COUPLE_WITH_HEART_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN = "\U0001f468\U0001f3fe\u200d\u2764\ufe0f\u200d\U0001f469" - FLAG_FOR_CHAHARMAHAL_AND_BAKHTIARI_IR_08 = "\U0001f3f4\U000e0069\U000e0072\U000e0030\U000e0038\U000e007f" - FLAG_FOR_WESTMORELAND_JM_10 = "\U0001f3f4\U000e006a\U000e006d\U000e0031\U000e0030\U000e007f" - FLAG_FOR_LIGURIA_IT_42 = "\U0001f3f4\U000e0069\U000e0074\U000e0034\U000e0032\U000e007f" - FLAG_FOR_GRACIAS_A_DIOS_HN_GD = "\U0001f3f4\U000e0068\U000e006e\U000e0067\U000e0064\U000e007f" - FLAG_FOR_CLARENDON_JM_13 = "\U0001f3f4\U000e006a\U000e006d\U000e0031\U000e0033\U000e007f" - FLAG_FOR_AQABA_JO_AQ = "\U0001f3f4\U000e006a\U000e006f\U000e0061\U000e0071\U000e007f" - FLAG_FOR_IRBID_JO_IR = "\U0001f3f4\U000e006a\U000e006f\U000e0069\U000e0072\U000e007f" - FLAG_FOR_BALQA_JO_BA = "\U0001f3f4\U000e006a\U000e006f\U000e0062\U000e0061\U000e007f" - FLAG_FOR_ZARQA_JO_AZ = "\U0001f3f4\U000e006a\U000e006f\U000e0061\U000e007a\U000e007f" - FLAG_FOR_OSTROBOTHNIA_FI_12 = "\U0001f3f4\U000e0066\U000e0069\U000e0031\U000e0032\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_MAFRAQ_JO_MA = "\U0001f3f4\U000e006a\U000e006f\U000e006d\U000e0061\U000e007f" - FLAG_FOR_ARAUCANIA_CL_AR = "\U0001f3f4\U000e0063\U000e006c\U000e0061\U000e0072\U000e007f" - FLAG_FOR_EAST_CM_ES = "\U0001f3f4\U000e0063\U000e006d\U000e0065\U000e0073\U000e007f" - FLAG_FOR_YAMAGUCHI_JP_35 = "\U0001f3f4\U000e006a\U000e0070\U000e0033\U000e0035\U000e007f" - FLAG_FOR_NAGANO_JP_20 = "\U0001f3f4\U000e006a\U000e0070\U000e0032\U000e0030\U000e007f" - FLAG_FOR_TOCHIGI_JP_09 = "\U0001f3f4\U000e006a\U000e0070\U000e0030\U000e0039\U000e007f" - FLAG_FOR_SHIMANE_JP_32 = "\U0001f3f4\U000e006a\U000e0070\U000e0033\U000e0032\U000e007f" - FLAG_FOR_ILAM_IR_05 = "\U0001f3f4\U000e0069\U000e0072\U000e0030\U000e0035\U000e007f" - FLAG_FOR_NARA_JP_29 = "\U0001f3f4\U000e006a\U000e0070\U000e0032\U000e0039\U000e007f" - FLAG_FOR_SPLIT_DALMATIA_HR_17 = "\U0001f3f4\U000e0068\U000e0072\U000e0031\U000e0037\U000e007f" - FLAG_FOR_EHIME_JP_38 = "\U0001f3f4\U000e006a\U000e0070\U000e0033\U000e0038\U000e007f" - FLAG_FOR_ORELLANA_EC_D = "\U0001f3f4\U000e0065\U000e0063\U000e0064\U000e007f" - FLAG_FOR_LA_RIOJA_ES_RI = "\U0001f3f4\U000e0065\U000e0073\U000e0072\U000e0069\U000e007f" - FLAG_FOR_IBARAKI_JP_08 = "\U0001f3f4\U000e006a\U000e0070\U000e0030\U000e0038\U000e007f" - FLAG_FOR_GRANMA_CU_12 = "\U0001f3f4\U000e0063\U000e0075\U000e0031\U000e0032\U000e007f" - FLAG_FOR_SHIZUOKA_JP_22 = "\U0001f3f4\U000e006a\U000e0070\U000e0032\U000e0032\U000e007f" - FLAG_FOR_IWATE_JP_03 = "\U0001f3f4\U000e006a\U000e0070\U000e0030\U000e0033\U000e007f" - FLAG_FOR_TOYAMA_JP_16 = "\U0001f3f4\U000e006a\U000e0070\U000e0031\U000e0036\U000e007f" - FLAG_FOR_MADABA_JO_MD = "\U0001f3f4\U000e006a\U000e006f\U000e006d\U000e0064\U000e007f" - FLAG_FOR_YAMANASHI_JP_19 = "\U0001f3f4\U000e006a\U000e0070\U000e0031\U000e0039\U000e007f" - FLAG_FOR_TOKUSHIMA_JP_36 = "\U0001f3f4\U000e006a\U000e0070\U000e0033\U000e0036\U000e007f" - FLAG_FOR_ISHIKAWA_JP_17 = "\U0001f3f4\U000e006a\U000e0070\U000e0031\U000e0037\U000e007f" - FLAG_FOR_KANAGAWA_JP_14 = "\U0001f3f4\U000e006a\U000e0070\U000e0031\U000e0034\U000e007f" - FLAG_FOR_MIE_JP_24 = "\U0001f3f4\U000e006a\U000e0070\U000e0032\U000e0034\U000e007f" - FLAG_FOR_NIIGATA_JP_15 = "\U0001f3f4\U000e006a\U000e0070\U000e0031\U000e0035\U000e007f" - FLAG_FOR_HYOGO_JP_28 = "\U0001f3f4\U000e006a\U000e0070\U000e0032\U000e0038\U000e007f" - FLAG_FOR_DHI_QAR_IQ_DQ = "\U0001f3f4\U000e0069\U000e0071\U000e0064\U000e0071\U000e007f" - FLAG_FOR_SHIGA_JP_25 = "\U0001f3f4\U000e006a\U000e0070\U000e0032\U000e0035\U000e007f" - FLAG_FOR_TOTTORI_JP_31 = "\U0001f3f4\U000e006a\U000e0070\U000e0033\U000e0031\U000e007f" - FLAG_FOR_OKAYAMA_JP_33 = "\U0001f3f4\U000e006a\U000e0070\U000e0033\U000e0033\U000e007f" - FLAG_FOR_CHIBA_JP_12 = "\U0001f3f4\U000e006a\U000e0070\U000e0031\U000e0032\U000e007f" - FLAG_FOR_MURANG_A_KE_29 = "\U0001f3f4\U000e006b\U000e0065\U000e0032\U000e0039\U000e007f" - FLAG_FOR_SOUTH_SINAI_EG_JS = "\U0001f3f4\U000e0065\U000e0067\U000e006a\U000e0073\U000e007f" - FLAG_FOR_KAJIADO_KE_10 = "\U0001f3f4\U000e006b\U000e0065\U000e0031\U000e0030\U000e007f" - FLAG_FOR_KOCHI_JP_39 = "\U0001f3f4\U000e006a\U000e0070\U000e0033\U000e0039\U000e007f" - FLAG_FOR_BASRA_IQ_BA = "\U0001f3f4\U000e0069\U000e0071\U000e0062\U000e0061\U000e007f" - FLAG_FOR_NAROK_KE_33 = "\U0001f3f4\U000e006b\U000e0065\U000e0033\U000e0033\U000e007f" - FLAG_FOR_FUKUOKA_JP_40 = "\U0001f3f4\U000e006a\U000e0070\U000e0034\U000e0030\U000e007f" - FLAG_FOR_BUNGOMA_KE_03 = "\U0001f3f4\U000e006b\U000e0065\U000e0030\U000e0033\U000e007f" - FLAG_FOR_GUNMA_JP_10 = "\U0001f3f4\U000e006a\U000e0070\U000e0031\U000e0030\U000e007f" - FLAG_FOR_MERU_KE_26 = "\U0001f3f4\U000e006b\U000e0065\U000e0032\U000e0036\U000e007f" - FLAG_FOR_ELGEYO_MARAKWET_KE_05 = "\U0001f3f4\U000e006b\U000e0065\U000e0030\U000e0035\U000e007f" - FLAG_FOR_LAIKIPIA_KE_20 = "\U0001f3f4\U000e006b\U000e0065\U000e0032\U000e0030\U000e007f" - FLAG_FOR_ISIOLO_KE_09 = "\U0001f3f4\U000e006b\U000e0065\U000e0030\U000e0039\U000e007f" - FLAG_FOR_KISII_KE_16 = "\U0001f3f4\U000e006b\U000e0065\U000e0031\U000e0036\U000e007f" - FLAG_FOR_SOUTHERN_PENINSULA_IS_2 = "\U0001f3f4\U000e0069\U000e0073\U000e0032\U000e007f" - FLAG_FOR_KAKAMEGA_KE_11 = "\U0001f3f4\U000e006b\U000e0065\U000e0031\U000e0031\U000e007f" - FLAG_FOR_MAKUENI_KE_23 = "\U0001f3f4\U000e006b\U000e0065\U000e0032\U000e0033\U000e007f" - FLAG_FOR_BITOLA_MK_04 = "\U0001f3f4\U000e006d\U000e006b\U000e0030\U000e0034\U000e007f" - FLAG_FOR_MIGORI_KE_27 = "\U0001f3f4\U000e006b\U000e0065\U000e0032\U000e0037\U000e007f" - FLAG_FOR_KILIFI_KE_14 = "\U0001f3f4\U000e006b\U000e0065\U000e0031\U000e0034\U000e007f" - FLAG_FOR_LAMU_KE_21 = "\U0001f3f4\U000e006b\U000e0065\U000e0032\U000e0031\U000e007f" - FLAG_FOR_MOMBASA_KE_28 = "\U0001f3f4\U000e006b\U000e0065\U000e0032\U000e0038\U000e007f" - FLAG_FOR_TATABANYA_HU_TB = "\U0001f3f4\U000e0068\U000e0075\U000e0074\U000e0062\U000e007f" - FLAG_FOR_BOMET_KE_02 = "\U0001f3f4\U000e006b\U000e0065\U000e0030\U000e0032\U000e007f" - FLAG_FOR_KUMAMOTO_JP_43 = "\U0001f3f4\U000e006a\U000e0070\U000e0034\U000e0033\U000e007f" - FLAG_FOR_KIAMBU_KE_13 = "\U0001f3f4\U000e006b\U000e0065\U000e0031\U000e0033\U000e007f" - FLAG_FOR_NANDI_KE_32 = "\U0001f3f4\U000e006b\U000e0065\U000e0033\U000e0032\U000e007f" - FLAG_FOR_YAMAGATA_JP_06 = "\U0001f3f4\U000e006a\U000e0070\U000e0030\U000e0036\U000e007f" - FLAG_FOR_BUSIA_KE_04 = "\U0001f3f4\U000e006b\U000e0065\U000e0030\U000e0034\U000e007f" - FLAG_FOR_MANDERA_KE_24 = "\U0001f3f4\U000e006b\U000e0065\U000e0032\U000e0034\U000e007f" - FLAG_FOR_TURKANA_KE_43 = "\U0001f3f4\U000e006b\U000e0065\U000e0034\U000e0033\U000e007f" - FLAG_FOR_NARYN_KG_N = "\U0001f3f4\U000e006b\U000e0067\U000e006e\U000e007f" - FLAG_FOR_SIAYA_KE_38 = "\U0001f3f4\U000e006b\U000e0065\U000e0033\U000e0038\U000e007f" - FLAG_FOR_UASIN_GISHU_KE_44 = "\U0001f3f4\U000e006b\U000e0065\U000e0034\U000e0034\U000e007f" - FLAG_FOR_JALAL_ABAD_KG_J = "\U0001f3f4\U000e006b\U000e0067\U000e006a\U000e007f" - FLAG_FOR_MONDULKIRI_KH_11 = "\U0001f3f4\U000e006b\U000e0068\U000e0031\U000e0031\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_VIHIGA_KE_45 = "\U0001f3f4\U000e006b\U000e0065\U000e0034\U000e0035\U000e007f" - FLAG_FOR_WEST_POKOT_KE_47 = "\U0001f3f4\U000e006b\U000e0065\U000e0034\U000e0037\U000e007f" - FLAG_FOR_PREY_VENG_KH_14 = "\U0001f3f4\U000e006b\U000e0068\U000e0031\U000e0034\U000e007f" - FLAG_FOR_TALAS_KG_T = "\U0001f3f4\U000e006b\U000e0067\U000e0074\U000e007f" - FLAG_FOR_HOMA_BAY_KE_08 = "\U0001f3f4\U000e006b\U000e0065\U000e0030\U000e0038\U000e007f" - FLAG_FOR_KRATIE_KH_10 = "\U0001f3f4\U000e006b\U000e0068\U000e0031\U000e0030\U000e007f" - FLAG_FOR_TBONG_KHMUM_KH_25 = "\U0001f3f4\U000e006b\U000e0068\U000e0032\U000e0035\U000e007f" - FLAG_FOR_BISHKEK_KG_GB = "\U0001f3f4\U000e006b\U000e0067\U000e0067\U000e0062\U000e007f" - FLAG_FOR_ODDAR_MEANCHEY_KH_22 = "\U0001f3f4\U000e006b\U000e0068\U000e0032\U000e0032\U000e007f" - FLAG_FOR_PHNOM_PENH_KH_12 = "\U0001f3f4\U000e006b\U000e0068\U000e0031\U000e0032\U000e007f" - FLAG_FOR_NYERI_KE_36 = "\U0001f3f4\U000e006b\U000e0065\U000e0033\U000e0036\U000e007f" - FLAG_FOR_STUNG_TRENG_KH_19 = "\U0001f3f4\U000e006b\U000e0068\U000e0031\U000e0039\U000e007f" - FLAG_FOR_PURSAT_KH_15 = "\U0001f3f4\U000e006b\U000e0068\U000e0031\U000e0035\U000e007f" - FLAG_FOR_NYANDARUA_KE_35 = "\U0001f3f4\U000e006b\U000e0065\U000e0033\U000e0035\U000e007f" - FLAG_FOR_SAMBURU_KE_37 = "\U0001f3f4\U000e006b\U000e0065\U000e0033\U000e0037\U000e007f" - FLAG_FOR_MACHAKOS_KE_22 = "\U0001f3f4\U000e006b\U000e0065\U000e0032\U000e0032\U000e007f" - FLAG_FOR_BATTAMBANG_KH_2 = "\U0001f3f4\U000e006b\U000e0068\U000e0032\U000e007f" - FLAG_FOR_TAITA_TAVETA_KE_39 = "\U0001f3f4\U000e006b\U000e0065\U000e0033\U000e0039\U000e007f" - FLAG_FOR_TAKEO_KH_21 = "\U0001f3f4\U000e006b\U000e0068\U000e0032\U000e0031\U000e007f" - FLAG_FOR_SIHANOUKVILLE_KH_18 = "\U0001f3f4\U000e006b\U000e0068\U000e0031\U000e0038\U000e007f" - FLAG_FOR_NYAMIRA_KE_34 = "\U0001f3f4\U000e006b\U000e0065\U000e0033\U000e0034\U000e007f" - FLAG_FOR_KEP_KH_23 = "\U0001f3f4\U000e006b\U000e0068\U000e0032\U000e0033\U000e007f" - FLAG_FOR_THARAKA_NITHI_KE_41 = "\U0001f3f4\U000e006b\U000e0065\U000e0034\U000e0031\U000e007f" - FAMILY_MAN_MEDIUM_DARK_SKIN_TONE_WOMAN_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE_BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f469\U0001f3fe\u200d\U0001f466\U0001f3fe\u200d\U0001f466\U0001f3fe" - FLAG_FOR_SUCHITEPEQUEZ_GT_SU = "\U0001f3f4\U000e0067\U000e0074\U000e0073\U000e0075\U000e007f" - FLAG_FOR_AGUASCALIENTES_MX_AGU = "\U0001f3f4\U000e006d\U000e0078\U000e0061\U000e0067\U000e0075\U000e007f" - FLAG_FOR_COLON_HN_CL = "\U0001f3f4\U000e0068\U000e006e\U000e0063\U000e006c\U000e007f" - FLAG_FOR_KAMPOT_KH_7 = "\U0001f3f4\U000e006b\U000e0068\U000e0037\U000e007f" - FLAG_FOR_SIRNAK_TR_73 = "\U0001f3f4\U000e0074\U000e0072\U000e0037\U000e0033\U000e007f" - FLAG_FOR_ZAGREB_HR_21 = "\U0001f3f4\U000e0068\U000e0072\U000e0032\U000e0031\U000e007f" - FLAG_FOR_GRAND_ANSE_HT_GA = "\U0001f3f4\U000e0068\U000e0074\U000e0067\U000e0061\U000e007f" - FLAG_FOR_LISBON_PT_11 = "\U0001f3f4\U000e0070\U000e0074\U000e0031\U000e0031\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f468\U0001f3fc\u200d\U0001f476\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_CHAGANG_KP_04 = "\U0001f3f4\U000e006b\U000e0070\U000e0030\U000e0034\U000e007f" - FLAG_FOR_SOUTH_HAMGYONG_KP_08 = "\U0001f3f4\U000e006b\U000e0070\U000e0030\U000e0038\U000e007f" - FLAG_FOR_SOUTH_CHUNGCHEONG_KR_44 = "\U0001f3f4\U000e006b\U000e0072\U000e0034\U000e0034\U000e007f" - FLAG_FOR_MOUNT_ATHOS_GR_69 = "\U0001f3f4\U000e0067\U000e0072\U000e0036\U000e0039\U000e007f" - WOMAN_IN_BUSINESS_SUIT_LEVITATING_MEDIUM_SKIN_TONE = "\U0001f574\U0001f3fd\u200d\u2640\ufe0f" - FLAG_FOR_RASON_KP_13 = "\U0001f3f4\U000e006b\U000e0070\U000e0031\U000e0033\U000e007f" - FLAG_FOR_INCHEON_KR_28 = "\U0001f3f4\U000e006b\U000e0072\U000e0032\U000e0038\U000e007f" - FLAG_FOR_KAMPONG_THOM_KH_6 = "\U0001f3f4\U000e006b\U000e0068\U000e0036\U000e007f" - FLAG_FOR_EAST_MACEDONIA_AND_THRACE_GR_A = "\U0001f3f4\U000e0067\U000e0072\U000e0061\U000e007f" - FLAG_FOR_AIN_DEFLA_DZ_44 = "\U0001f3f4\U000e0064\U000e007a\U000e0034\U000e0034\U000e007f" - FLAG_FOR_NORTH_PYONGAN_KP_03 = "\U0001f3f4\U000e006b\U000e0070\U000e0030\U000e0033\U000e007f" - FLAG_FOR_GANGWON_KR_42 = "\U0001f3f4\U000e006b\U000e0072\U000e0034\U000e0032\U000e007f" - FLAG_FOR_KAMPONG_SPEU_KH_5 = "\U0001f3f4\U000e006b\U000e0068\U000e0035\U000e007f" - FLAG_FOR_CENTRAL_OSTROBOTHNIA_FI_07 = "\U0001f3f4\U000e0066\U000e0069\U000e0030\U000e0037\U000e007f" - FLAG_FOR_SOUTH_HWANGHAE_KP_05 = "\U0001f3f4\U000e006b\U000e0070\U000e0030\U000e0035\U000e007f" - FLAG_FOR_ULSAN_KR_31 = "\U0001f3f4\U000e006b\U000e0072\U000e0033\U000e0031\U000e007f" - FLAG_FOR_NORTH_BANK_DIVISION_GM_N = "\U0001f3f4\U000e0067\U000e006d\U000e006e\U000e007f" - COUPLE_WITH_HEART_WOMAN_DARK_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fc" - FLAG_FOR_AL_FARWANIYAH_KW_FA = "\U0001f3f4\U000e006b\U000e0077\U000e0066\U000e0061\U000e007f" - FLAG_FOR_KARAGANDY_KZ_KAR = "\U0001f3f4\U000e006b\U000e007a\U000e006b\U000e0061\U000e0072\U000e007f" - FLAG_FOR_SERMERSOOQ_GL_SM = "\U0001f3f4\U000e0067\U000e006c\U000e0073\U000e006d\U000e007f" - FLAG_FOR_PHONGSALY_LA_PH = "\U0001f3f4\U000e006c\U000e0061\U000e0070\U000e0068\U000e007f" - FLAG_FOR_OUDOMXAY_LA_OU = "\U0001f3f4\U000e006c\U000e0061\U000e006f\U000e0075\U000e007f" - FLAG_FOR_ATYRAU_KZ_ATY = "\U0001f3f4\U000e006b\U000e007a\U000e0061\U000e0074\U000e0079\U000e007f" - FLAG_FOR_LUANG_NAMTHA_LA_LM = "\U0001f3f4\U000e006c\U000e0061\U000e006c\U000e006d\U000e007f" - FLAG_FOR_LUANG_PRABANG_LA_LP = "\U0001f3f4\U000e006c\U000e0061\U000e006c\U000e0070\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_WOMAN_DARK_SKIN_TONE_BABY_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f469\U0001f3ff\u200d\U0001f476\U0001f3ff\u200d\U0001f466\U0001f3ff" - FLAG_FOR_HONG_KONG_SAR_CHINA_CN_91 = "\U0001f3f4\U000e0063\U000e006e\U000e0039\U000e0031\U000e007f" - FLAG_FOR_VIENTIANE_LA_VT = "\U0001f3f4\U000e006c\U000e0061\U000e0076\U000e0074\U000e007f" - FLAG_FOR_NORTH_CHUNGCHEONG_KR_43 = "\U0001f3f4\U000e006b\U000e0072\U000e0034\U000e0033\U000e007f" - FLAG_FOR_JAMBYL_KZ_ZHA = "\U0001f3f4\U000e006b\U000e007a\U000e007a\U000e0068\U000e0061\U000e007f" - FLAG_FOR_QOM_IR_26 = "\U0001f3f4\U000e0069\U000e0072\U000e0032\U000e0036\U000e007f" - FLAG_FOR_MUBARAK_AL_KABEER_KW_MU = "\U0001f3f4\U000e006b\U000e0077\U000e006d\U000e0075\U000e007f" - FLAG_FOR_KYZYLORDA_KZ_KZY = "\U0001f3f4\U000e006b\U000e007a\U000e006b\U000e007a\U000e0079\U000e007f" - FLAG_FOR_AL_JAHRA_KW_JA = "\U0001f3f4\U000e006b\U000e0077\U000e006a\U000e0061\U000e007f" - FLAG_FOR_AL_ASIMAH_KW_KU = "\U0001f3f4\U000e006b\U000e0077\U000e006b\U000e0075\U000e007f" - FLAG_FOR_GYEONGGI_KR_41 = "\U0001f3f4\U000e006b\U000e0072\U000e0034\U000e0031\U000e007f" - FLAG_FOR_PAVLODAR_KZ_PAV = "\U0001f3f4\U000e006b\U000e007a\U000e0070\U000e0061\U000e0076\U000e007f" - FLAG_FOR_ANJOUAN_KM_A = "\U0001f3f4\U000e006b\U000e006d\U000e0061\U000e007f" - FLAG_FOR_CHAMPASAK_LA_CH = "\U0001f3f4\U000e006c\U000e0061\U000e0063\U000e0068\U000e007f" - FLAG_FOR_SEJONG_KR_50 = "\U0001f3f4\U000e006b\U000e0072\U000e0035\U000e0030\U000e007f" - FLAG_FOR_NORTH_KAZAKHSTAN_KZ_SEV = "\U0001f3f4\U000e006b\U000e007a\U000e0073\U000e0065\U000e0076\U000e007f" - FLAG_FOR_HANOVER_JM_09 = "\U0001f3f4\U000e006a\U000e006d\U000e0030\U000e0039\U000e007f" - FLAG_FOR_UPPER_RIVER_DIVISION_GM_U = "\U0001f3f4\U000e0067\U000e006d\U000e0075\U000e007f" - FLAG_FOR_MAUREN_LI_04 = "\U0001f3f4\U000e006c\U000e0069\U000e0030\U000e0034\U000e007f" - FLAG_FOR_BAALBEK_HERMEL_LB_BH = "\U0001f3f4\U000e006c\U000e0062\U000e0062\U000e0068\U000e007f" - FLAG_FOR_NORTH_CENTRAL_LK_7 = "\U0001f3f4\U000e006c\U000e006b\U000e0037\U000e007f" - FLAG_FOR_SOUFRIERE_LC_10 = "\U0001f3f4\U000e006c\U000e0063\U000e0031\U000e0030\U000e007f" - FLAG_FOR_NORTHERN_LK_4 = "\U0001f3f4\U000e006c\U000e006b\U000e0034\U000e007f" - FLAG_FOR_TRIESEN_LI_09 = "\U0001f3f4\U000e006c\U000e0069\U000e0030\U000e0039\U000e007f" - FLAG_FOR_BJELOVAR_BILOGORA_HR_07 = "\U0001f3f4\U000e0068\U000e0072\U000e0030\U000e0037\U000e007f" - FLAG_FOR_SAINYABULI_LA_XA = "\U0001f3f4\U000e006c\U000e0061\U000e0078\U000e0061\U000e007f" - FLAG_FOR_SOUTHERN_SAVONIA_FI_04 = "\U0001f3f4\U000e0066\U000e0069\U000e0030\U000e0034\U000e007f" - FLAG_FOR_UVA_LK_8 = "\U0001f3f4\U000e006c\U000e006b\U000e0038\U000e007f" - FLAG_FOR_GAMPRIN_LI_03 = "\U0001f3f4\U000e006c\U000e0069\U000e0030\U000e0033\U000e007f" - FLAG_FOR_ESCHEN_LI_02 = "\U0001f3f4\U000e006c\U000e0069\U000e0030\U000e0032\U000e007f" - FLAG_FOR_SOUTH_LB_JA = "\U0001f3f4\U000e006c\U000e0062\U000e006a\U000e0061\U000e007f" - FLAG_FOR_NORTH_LB_AS = "\U0001f3f4\U000e006c\U000e0062\U000e0061\U000e0073\U000e007f" - FLAG_FOR_RUGGELL_LI_06 = "\U0001f3f4\U000e006c\U000e0069\U000e0030\U000e0036\U000e007f" - FLAG_FOR_NORTH_WESTERN_LK_6 = "\U0001f3f4\U000e006c\U000e006b\U000e0036\U000e007f" - FLAG_FOR_GROS_ISLET_LC_06 = "\U0001f3f4\U000e006c\U000e0063\U000e0030\U000e0036\U000e007f" - FLAG_FOR_NABATIEH_LB_NA = "\U0001f3f4\U000e006c\U000e0062\U000e006e\U000e0061\U000e007f" - FLAG_FOR_GRANDE_COMORE_KM_G = "\U0001f3f4\U000e006b\U000e006d\U000e0067\U000e007f" - FLAG_FOR_CASTRIES_LC_02 = "\U0001f3f4\U000e006c\U000e0063\U000e0030\U000e0032\U000e007f" - FLAG_FOR_VADUZ_LI_11 = "\U0001f3f4\U000e006c\U000e0069\U000e0031\U000e0031\U000e007f" - FLAG_FOR_KOSTANAY_KZ_KUS = "\U0001f3f4\U000e006b\U000e007a\U000e006b\U000e0075\U000e0073\U000e007f" - FLAG_FOR_CHOISEUL_LC_03 = "\U0001f3f4\U000e006c\U000e0063\U000e0030\U000e0033\U000e007f" - FLAG_FOR_CENTRAL_LK_2 = "\U0001f3f4\U000e006c\U000e006b\U000e0032\U000e007f" - FLAG_FOR_DENNERY_LC_05 = "\U0001f3f4\U000e006c\U000e0063\U000e0030\U000e0035\U000e007f" - FLAG_FOR_GARISSA_KE_07 = "\U0001f3f4\U000e006b\U000e0065\U000e0030\U000e0037\U000e007f" - FLAG_FOR_ANSE_LA_RAYE_LC_01 = "\U0001f3f4\U000e006c\U000e0063\U000e0030\U000e0031\U000e007f" - FLAG_FOR_RYANGGANG_KP_10 = "\U0001f3f4\U000e006b\U000e0070\U000e0031\U000e0030\U000e007f" - FLAG_FOR_JONAVA_LT_10 = "\U0001f3f4\U000e006c\U000e0074\U000e0031\U000e0030\U000e007f" - FLAG_FOR_MOHALE_S_HOEK_LS_F = "\U0001f3f4\U000e006c\U000e0073\U000e0066\U000e007f" - FLAG_FOR_KALVARIJA_LT_14 = "\U0001f3f4\U000e006c\U000e0074\U000e0031\U000e0034\U000e007f" - FLAG_FOR_GBARPOLU_LR_GP = "\U0001f3f4\U000e006c\U000e0072\U000e0067\U000e0070\U000e007f" - TAG_LATIN_CAPITAL_LETTER_F = "\U000e0046" - FLAG_FOR_NORTH_KIVU_CD_NK = "\U0001f3f4\U000e0063\U000e0064\U000e006e\U000e006b\U000e007f" - FLAG_FOR_IGNALINA_LT_09 = "\U0001f3f4\U000e006c\U000e0074\U000e0030\U000e0039\U000e007f" - FLAG_FOR_MAFETENG_LS_E = "\U0001f3f4\U000e006c\U000e0073\U000e0065\U000e007f" - UNIVERSAL_RECYCLING_SYMBOL = "\u2672" - FLAG_FOR_BIHAR_IN_BR = "\U0001f3f4\U000e0069\U000e006e\U000e0062\U000e0072\U000e007f" - FLAG_FOR_THABA_TSEKA_LS_K = "\U0001f3f4\U000e006c\U000e0073\U000e006b\U000e007f" - FLAG_FOR_ALYTUS_LT_03 = "\U0001f3f4\U000e006c\U000e0074\U000e0030\U000e0033\U000e007f" - FLAG_FOR_DRUSKININKAI_LT_07 = "\U0001f3f4\U000e006c\U000e0074\U000e0030\U000e0037\U000e007f" - FLAG_FOR_MOKHOTLONG_LS_J = "\U0001f3f4\U000e006c\U000e0073\U000e006a\U000e007f" - FLAG_FOR_KAUNO_MUNICIPALITY_LT_15 = "\U0001f3f4\U000e006c\U000e0074\U000e0031\U000e0035\U000e007f" - FLAG_FOR_JONISKIS_LT_11 = "\U0001f3f4\U000e006c\U000e0074\U000e0031\U000e0031\U000e007f" - FLAG_FOR_QACHA_S_NEK_LS_H = "\U0001f3f4\U000e006c\U000e0073\U000e0068\U000e007f" - FLAG_FOR_BEREA_LS_D = "\U0001f3f4\U000e006c\U000e0073\U000e0064\U000e007f" - FLAG_FOR_NIMBA_LR_NI = "\U0001f3f4\U000e006c\U000e0072\U000e006e\U000e0069\U000e007f" - FLAG_FOR_ELEKTRENAI_LT_08 = "\U0001f3f4\U000e006c\U000e0074\U000e0030\U000e0038\U000e007f" - FLAG_FOR_ERBIL_IQ_AR = "\U0001f3f4\U000e0069\U000e0071\U000e0061\U000e0072\U000e007f" - FLAG_FOR_KANGWON_KP_07 = "\U0001f3f4\U000e006b\U000e0070\U000e0030\U000e0037\U000e007f" - FLAG_FOR_KAISIADORYS_LT_13 = "\U0001f3f4\U000e006c\U000e0074\U000e0031\U000e0033\U000e007f" - FLAG_FOR_BUTHA_BUTHE_LS_B = "\U0001f3f4\U000e006c\U000e0073\U000e0062\U000e007f" - FLAG_FOR_BIRSTONAS_LT_05 = "\U0001f3f4\U000e006c\U000e0074\U000e0030\U000e0035\U000e007f" - FLAG_FOR_KIRINYAGA_KE_15 = "\U0001f3f4\U000e006b\U000e0065\U000e0031\U000e0035\U000e007f" - FLAG_FOR_ANYKSCIAI_LT_04 = "\U0001f3f4\U000e006c\U000e0074\U000e0030\U000e0034\U000e007f" - FLAG_FOR_JURBARKAS_LT_12 = "\U0001f3f4\U000e006c\U000e0074\U000e0031\U000e0032\U000e007f" - FLAG_FOR_UTENA_LT_54 = "\U0001f3f4\U000e006c\U000e0074\U000e0035\U000e0034\U000e007f" - FLAG_FOR_PASVALYS_LT_34 = "\U0001f3f4\U000e006c\U000e0074\U000e0033\U000e0034\U000e007f" - FLAG_FOR_PRIENAI_LT_36 = "\U0001f3f4\U000e006c\U000e0074\U000e0033\U000e0036\U000e007f" - FLAG_FOR_KUPISKIS_LT_23 = "\U0001f3f4\U000e006c\U000e0074\U000e0032\U000e0033\U000e007f" - FLAG_FOR_ROKISKIS_LT_40 = "\U0001f3f4\U000e006c\U000e0074\U000e0034\U000e0030\U000e007f" - FLAG_FOR_SIAULIU_MUNICIPALITY_LT_43 = "\U0001f3f4\U000e006c\U000e0074\U000e0034\U000e0033\U000e007f" - FLAG_FOR_KAZLU_RUDA_LT_17 = "\U0001f3f4\U000e006c\U000e0074\U000e0031\U000e0037\U000e007f" - FLAG_FOR_TELSIAI_LT_51 = "\U0001f3f4\U000e006c\U000e0074\U000e0035\U000e0031\U000e007f" - FLAG_FOR_KLAIPEDA_LT_21 = "\U0001f3f4\U000e006c\U000e0074\U000e0032\U000e0031\U000e007f" - FLAG_FOR_KEDAINIAI_LT_18 = "\U0001f3f4\U000e006c\U000e0074\U000e0031\U000e0038\U000e007f" - FLAG_FOR_SIAULIAI_LT_44 = "\U0001f3f4\U000e006c\U000e0074\U000e0034\U000e0034\U000e007f" - FLAG_FOR_PALANGA_LT_31 = "\U0001f3f4\U000e006c\U000e0074\U000e0033\U000e0031\U000e007f" - FLAG_FOR_PANEVEZYS_LT_33 = "\U0001f3f4\U000e006c\U000e0074\U000e0033\U000e0033\U000e007f" - FLAG_FOR_SILALE_LT_45 = "\U0001f3f4\U000e006c\U000e0074\U000e0034\U000e0035\U000e007f" - FLAG_FOR_SAKIAI_LT_41 = "\U0001f3f4\U000e006c\U000e0074\U000e0034\U000e0031\U000e007f" - FLAG_FOR_TAURAGE_LT_50 = "\U0001f3f4\U000e006c\U000e0074\U000e0035\U000e0030\U000e007f" - FLAG_FOR_MOLETAI_LT_27 = "\U0001f3f4\U000e006c\U000e0074\U000e0032\U000e0037\U000e007f" - FLAG_FOR_SKUODAS_LT_48 = "\U0001f3f4\U000e006c\U000e0074\U000e0034\U000e0038\U000e007f" - FLAG_FOR_UKMERGE_LT_53 = "\U0001f3f4\U000e006c\U000e0074\U000e0035\U000e0033\U000e007f" - FLAG_FOR_VILKAVISKIS_LT_56 = "\U0001f3f4\U000e006c\U000e0074\U000e0035\U000e0036\U000e007f" - FLAG_FOR_PAGEGIAI_LT_29 = "\U0001f3f4\U000e006c\U000e0074\U000e0032\U000e0039\U000e007f" - FLAG_FOR_RIETAVAS_LT_39 = "\U0001f3f4\U000e006c\U000e0074\U000e0033\U000e0039\U000e007f" - FLAG_FOR_SILUTE_LT_46 = "\U0001f3f4\U000e006c\U000e0074\U000e0034\U000e0036\U000e007f" - FLAG_FOR_SVENCIONYS_LT_49 = "\U0001f3f4\U000e006c\U000e0074\U000e0034\U000e0039\U000e007f" - FLAG_FOR_GRAND_BASSA_LR_GB = "\U0001f3f4\U000e006c\U000e0072\U000e0067\U000e0062\U000e007f" - FLAG_FOR_TRAKAI_LT_52 = "\U0001f3f4\U000e006c\U000e0074\U000e0035\U000e0032\U000e007f" - FLAG_FOR_LAZDIJAI_LT_24 = "\U0001f3f4\U000e006c\U000e0074\U000e0032\U000e0034\U000e007f" - FLAG_FOR_MARIJAMPOLE_LT_25 = "\U0001f3f4\U000e006c\U000e0074\U000e0032\U000e0035\U000e007f" - FLAG_FOR_VARENA_LT_55 = "\U0001f3f4\U000e006c\U000e0074\U000e0035\U000e0035\U000e007f" - FLAG_FOR_MAZEIKIAI_LT_26 = "\U0001f3f4\U000e006c\U000e0074\U000e0032\U000e0036\U000e007f" - FLAG_FOR_PLUNGE_LT_35 = "\U0001f3f4\U000e006c\U000e0074\U000e0033\U000e0035\U000e007f" - FLAG_FOR_RADVILISKIS_LT_37 = "\U0001f3f4\U000e006c\U000e0074\U000e0033\U000e0037\U000e007f" - FLAG_FOR_KRETINGA_LT_22 = "\U0001f3f4\U000e006c\U000e0074\U000e0032\U000e0032\U000e007f" - FLAG_FOR_KELME_LT_19 = "\U0001f3f4\U000e006c\U000e0074\U000e0031\U000e0039\U000e007f" - FLAG_FOR_SIRVINTOS_LT_47 = "\U0001f3f4\U000e006c\U000e0074\U000e0034\U000e0037\U000e007f" - FLAG_FOR_NERINGA_LT_28 = "\U0001f3f4\U000e006c\U000e0074\U000e0032\U000e0038\U000e007f" - FLAG_FOR_AIZPUTE_LV_003 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0030\U000e0033\U000e007f" - FLAG_FOR_GREVENMACHER_LU_GR = "\U0001f3f4\U000e006c\U000e0075\U000e0067\U000e0072\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_MAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f468\U0001f3fd\u200d\U0001f476\U0001f3fd" - FLAG_FOR_BALDONE_LV_013 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0031\U000e0033\U000e007f" - FLAG_FOR_AKNISTE_LV_004 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0030\U000e0034\U000e007f" - FLAG_FOR_UTENA_COUNTY_LT_UT = "\U0001f3f4\U000e006c\U000e0074\U000e0075\U000e0074\U000e007f" - FLAG_FOR_ALYTUS_COUNTY_LT_AL = "\U0001f3f4\U000e006c\U000e0074\U000e0061\U000e006c\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f467\U0001f3fc" - FLAG_FOR_VISAGINAS_LT_59 = "\U0001f3f4\U000e006c\U000e0074\U000e0035\U000e0039\U000e007f" - KISS_WOMAN_MEDIUM_LIGHT_SKIN_TONE_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fc" - FLAG_FOR_KLAIPEDA_COUNTY_LT_KL = "\U0001f3f4\U000e006c\U000e0074\U000e006b\U000e006c\U000e007f" - FLAG_FOR_REMICH_LU_RM = "\U0001f3f4\U000e006c\U000e0075\U000e0072\U000e006d\U000e007f" - FLAG_FOR_RATANAKIRI_KH_16 = "\U0001f3f4\U000e006b\U000e0068\U000e0031\U000e0036\U000e007f" - FLAG_FOR_AMATA_LV_008 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0030\U000e0038\U000e007f" - FLAG_FOR_RASEINIAI_LT_38 = "\U0001f3f4\U000e006c\U000e0074\U000e0033\U000e0038\U000e007f" - FLAG_FOR_MERSCH_LU_ME = "\U0001f3f4\U000e006c\U000e0075\U000e006d\U000e0065\U000e007f" - FLAG_FOR_VIANDEN_LU_VD = "\U0001f3f4\U000e006c\U000e0075\U000e0076\U000e0064\U000e007f" - FLAG_FOR_CLERVAUX_LU_CL = "\U0001f3f4\U000e006c\U000e0075\U000e0063\U000e006c\U000e007f" - FLAG_FOR_VILNIUS_COUNTY_LT_VL = "\U0001f3f4\U000e006c\U000e0074\U000e0076\U000e006c\U000e007f" - FLAG_FOR_ECHTERNACH_LU_EC = "\U0001f3f4\U000e006c\U000e0075\U000e0065\U000e0063\U000e007f" - FLAG_FOR_DIEKIRCH_LU_DI = "\U0001f3f4\U000e006c\U000e0075\U000e0064\U000e0069\U000e007f" - FLAG_FOR_SIAULIAI_COUNTY_LT_SA = "\U0001f3f4\U000e006c\U000e0074\U000e0073\U000e0061\U000e007f" - FLAG_FOR_TAURAGE_COUNTY_LT_TA = "\U0001f3f4\U000e006c\U000e0074\U000e0074\U000e0061\U000e007f" - FLAG_FOR_MARIJAMPOLE_COUNTY_LT_MR = "\U0001f3f4\U000e006c\U000e0074\U000e006d\U000e0072\U000e007f" - FLAG_FOR_ADAZI_LV_011 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0031\U000e0031\U000e007f" - FLAG_FOR_ALUKSNE_LV_007 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0030\U000e0037\U000e007f" - FLAG_FOR_KULDIGA_LV_050 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0035\U000e0030\U000e007f" - FLAG_FOR_BALVI_LV_015 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0031\U000e0035\U000e007f" - FLAG_FOR_LABORIE_LC_07 = "\U0001f3f4\U000e006c\U000e0063\U000e0030\U000e0037\U000e007f" - FLAG_FOR_KARSAVA_LV_044 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0034\U000e0034\U000e007f" - FLAG_FOR_KEGUMS_LV_051 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0035\U000e0031\U000e007f" - FLAG_FOR_BALTINAVA_LV_014 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0031\U000e0034\U000e007f" - FLAG_FOR_KRUSTPILS_LV_049 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0034\U000e0039\U000e007f" - FLAG_FOR_GROBINA_LV_032 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0033\U000e0032\U000e007f" - FLAG_FOR_BAUSKA_LV_016 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0031\U000e0036\U000e007f" - FLAG_FOR_DOBELE_LV_026 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0032\U000e0036\U000e007f" - FLAG_FOR_BROCENI_LV_018 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0031\U000e0038\U000e007f" - FLAG_FOR_IECAVA_LV_034 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0033\U000e0034\U000e007f" - FLAG_FOR_CESVAINE_LV_021 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0032\U000e0031\U000e007f" - FLAG_FOR_AJLOUN_JO_AJ = "\U0001f3f4\U000e006a\U000e006f\U000e0061\U000e006a\U000e007f" - FLAG_FOR_JAUNJELGAVA_LV_038 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0033\U000e0038\U000e007f" - FLAG_FOR_KOCENI_LV_045 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0034\U000e0035\U000e007f" - FLAG_FOR_GARKALNE_LV_031 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0033\U000e0031\U000e007f" - FLAG_FOR_AIZKRAUKLE_LV_002 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0030\U000e0032\U000e007f" - FLAG_FOR_CIBLA_LV_023 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0032\U000e0033\U000e007f" - FLAG_FOR_JAUNPIEBALGA_LV_039 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0033\U000e0039\U000e007f" - FLAG_FOR_DUNDAGA_LV_027 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0032\U000e0037\U000e007f" - FLAG_FOR_CESIS_LV_022 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0032\U000e0032\U000e007f" - FLAG_FOR_KRIMULDA_LV_048 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0034\U000e0038\U000e007f" - FLAG_FOR_CARNIKAVA_LV_020 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0032\U000e0030\U000e007f" - FLAG_FOR_IKSKILE_LV_035 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0033\U000e0035\U000e007f" - FLAG_FOR_GULBENE_LV_033 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0033\U000e0033\U000e007f" - FLAG_FOR_KRASLAVA_LV_047 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0034\U000e0037\U000e007f" - FLAG_FOR_JAUNPILS_LV_040 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0034\U000e0030\U000e007f" - FLAG_FOR_BURTNIEKI_LV_019 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0031\U000e0039\U000e007f" - FLAG_FOR_BEVERINA_LV_017 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0031\U000e0037\U000e007f" - FLAG_FOR_KANDAVA_LV_043 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0034\U000e0033\U000e007f" - FLAG_FOR_LIGATNE_LV_055 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0035\U000e0035\U000e007f" - FLAG_FOR_SAULKRASTI_LV_089 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0038\U000e0039\U000e007f" - FLAG_FOR_SALASPILS_LV_087 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0038\U000e0037\U000e007f" - FLAG_FOR_PRIEKULI_LV_075 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0037\U000e0035\U000e007f" - FLAG_FOR_RUCAVA_LV_081 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0038\U000e0031\U000e007f" - FLAG_FOR_NAUKSENI_LV_064 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0036\U000e0034\U000e007f" - FLAG_FOR_PRIEKULE_LV_074 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0037\U000e0034\U000e007f" - FLAG_FOR_SEJA_LV_090 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0039\U000e0030\U000e007f" - FLAG_FOR_NERETA_LV_065 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0036\U000e0035\U000e007f" - FLAG_FOR_PARGAUJA_LV_070 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0037\U000e0030\U000e007f" - FLAG_FOR_MARUPE_LV_062 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0036\U000e0032\U000e007f" - FLAG_FOR_PAVILOSTA_LV_071 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0037\U000e0031\U000e007f" - FLAG_FOR_OLAINE_LV_068 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0036\U000e0038\U000e007f" - FLAG_FOR_LIMBAZI_LV_054 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0035\U000e0034\U000e007f" - FLAG_FOR_RUJIENA_LV_084 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0038\U000e0034\U000e007f" - FLAG_FOR_PLAVINAS_LV_072 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0037\U000e0032\U000e007f" - FLAG_FOR_RUNDALE_LV_083 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0038\U000e0033\U000e007f" - FLAG_FOR_PREILI_LV_073 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0037\U000e0033\U000e007f" - FLAG_FOR_RUGAJI_LV_082 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0038\U000e0032\U000e007f" - FLAG_FOR_MERSRAGS_LV_063 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0036\U000e0033\U000e007f" - FLAG_FOR_SALDUS_LV_088 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0038\U000e0038\U000e007f" - FLAG_FOR_LUDZA_LV_058 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0035\U000e0038\U000e007f" - FLAG_FOR_LIVANI_LV_056 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0035\U000e0036\U000e007f" - FLAG_FOR_ROPAZI_LV_080 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0038\U000e0030\U000e007f" - FLAG_FOR_KOH_KONG_KH_9 = "\U0001f3f4\U000e006b\U000e0068\U000e0039\U000e007f" - FLAG_FOR_RIEBINI_LV_078 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0037\U000e0038\U000e007f" - FLAG_FOR_LIELVARDE_LV_053 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0035\U000e0033\U000e007f" - FLAG_FOR_KEKAVA_LV_052 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0035\U000e0032\U000e007f" - FLAG_FOR_NICA_LV_066 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0036\U000e0036\U000e007f" - FLAG_FOR_LUBANA_LV_057 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0035\U000e0037\U000e007f" - FLAG_FOR_GRAND_EST_FR_GES = "\U0001f3f4\U000e0066\U000e0072\U000e0067\U000e0065\U000e0073\U000e007f" - FLAG_FOR_RAUNA_LV_076 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0037\U000e0036\U000e007f" - FLAG_FOR_ROJA_LV_079 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0037\U000e0039\U000e007f" - FLAG_FOR_MALPILS_LV_061 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0036\U000e0031\U000e007f" - FLAG_FOR_SMILTENE_LV_094 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0039\U000e0034\U000e007f" - FLAG_FOR_VARAKLANI_LV_102 = "\U0001f3f4\U000e006c\U000e0076\U000e0031\U000e0030\U000e0032\U000e007f" - FLAG_FOR_JABAL_AL_GHARBI_LY_JG = "\U0001f3f4\U000e006c\U000e0079\U000e006a\U000e0067\U000e007f" - FLAG_FOR_VARKAVA_LV_103 = "\U0001f3f4\U000e006c\U000e0076\U000e0031\U000e0030\U000e0033\U000e007f" - FLAG_FOR_VIESITE_LV_107 = "\U0001f3f4\U000e006c\U000e0076\U000e0031\U000e0030\U000e0037\U000e007f" - FLAG_FOR_DAUGAVPILS_LV_DGV = "\U0001f3f4\U000e006c\U000e0076\U000e0064\U000e0067\U000e0076\U000e007f" - FLAG_FOR_KUFRA_LY_KF = "\U0001f3f4\U000e006c\U000e0079\U000e006b\U000e0066\U000e007f" - FLAG_FOR_VILANI_LV_109 = "\U0001f3f4\U000e006c\U000e0076\U000e0031\U000e0030\U000e0039\U000e007f" - FLAG_FOR_JURMALA_LV_JUR = "\U0001f3f4\U000e006c\U000e0076\U000e006a\U000e0075\U000e0072\U000e007f" - FLAG_FOR_VILAKA_LV_108 = "\U0001f3f4\U000e006c\U000e0076\U000e0031\U000e0030\U000e0038\U000e007f" - FLAG_FOR_VENTSPILS_LV_VEN = "\U0001f3f4\U000e006c\U000e0076\U000e0076\U000e0065\U000e006e\U000e007f" - FLAG_FOR_MURQUB_LY_MB = "\U0001f3f4\U000e006c\U000e0079\U000e006d\U000e0062\U000e007f" - FLAG_FOR_VECPIEBALGA_LV_104 = "\U0001f3f4\U000e006c\U000e0076\U000e0031\U000e0030\U000e0034\U000e007f" - FLAG_FOR_TUKUMS_LV_099 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0039\U000e0039\U000e007f" - FLAG_FOR_BENGHAZI_LY_BA = "\U0001f3f4\U000e006c\U000e0079\U000e0062\U000e0061\U000e007f" - FLAG_FOR_LIEPAJA_LV_LPX = "\U0001f3f4\U000e006c\U000e0076\U000e006c\U000e0070\U000e0078\U000e007f" - FLAG_FOR_JABAL_AL_AKHDAR_LY_JA = "\U0001f3f4\U000e006c\U000e0079\U000e006a\U000e0061\U000e007f" - FLAG_FOR_ZARASAI_LT_60 = "\U0001f3f4\U000e006c\U000e0074\U000e0036\U000e0030\U000e007f" - FLAG_FOR_VECUMNIEKI_LV_105 = "\U0001f3f4\U000e006c\U000e0076\U000e0031\U000e0030\U000e0035\U000e007f" - FLAG_FOR_GHAT_LY_GT = "\U0001f3f4\U000e006c\U000e0079\U000e0067\U000e0074\U000e007f" - FLAG_FOR_TALSI_LV_097 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0039\U000e0037\U000e007f" - FLAG_FOR_JELGAVA_LV_JEL = "\U0001f3f4\U000e006c\U000e0076\U000e006a\U000e0065\U000e006c\U000e007f" - FLAG_FOR_STRENCI_LV_096 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0039\U000e0036\U000e007f" - FLAG_FOR_NORTH_HAMGYONG_KP_09 = "\U0001f3f4\U000e006b\U000e0070\U000e0030\U000e0039\U000e007f" - FLAG_FOR_VALMIERA_LV_VMR = "\U0001f3f4\U000e006c\U000e0076\U000e0076\U000e006d\U000e0072\U000e007f" - FLAG_FOR_TERVETE_LV_098 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0039\U000e0038\U000e007f" - FLAG_FOR_REZEKNE_LV_REZ = "\U0001f3f4\U000e006c\U000e0076\U000e0072\U000e0065\U000e007a\U000e007f" - FLAG_FOR_ZILUPE_LV_110 = "\U0001f3f4\U000e006c\U000e0076\U000e0031\U000e0031\U000e0030\U000e007f" - FLAG_FOR_JEKABPILS_LV_JKB = "\U0001f3f4\U000e006c\U000e0076\U000e006a\U000e006b\U000e0062\U000e007f" - FLAG_FOR_SIGULDA_LV_091 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0039\U000e0031\U000e007f" - FLAG_FOR_STOPINI_LV_095 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0039\U000e0035\U000e007f" - FLAG_FOR_ENGURE_LV_029 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0032\U000e0039\U000e007f" - FLAG_FOR_WADI_AL_HAYAA_LY_WD = "\U0001f3f4\U000e006c\U000e0079\U000e0077\U000e0064\U000e007f" - FLAG_FOR_AL_WAHAT_LY_WA = "\U0001f3f4\U000e006c\U000e0079\U000e0077\U000e0061\U000e007f" - FLAG_FOR_LABE_REGION_GN_L = "\U0001f3f4\U000e0067\U000e006e\U000e006c\U000e007f" - FLAG_FOR_NALUT_LY_NL = "\U0001f3f4\U000e006c\U000e0079\U000e006e\U000e006c\U000e007f" - FLAG_FOR_MONEGHETTI_MC_MG = "\U0001f3f4\U000e006d\U000e0063\U000e006d\U000e0067\U000e007f" - FLAG_FOR_MARRAKESH_TENSIFT_EL_HAOUZ_MA_11 = "\U0001f3f4\U000e006d\U000e0061\U000e0031\U000e0031\U000e007f" - FLAG_FOR_LA_COLLE_MC_CL = "\U0001f3f4\U000e006d\U000e0063\U000e0063\U000e006c\U000e007f" - FLAG_FOR_ZAWIYA_LY_ZA = "\U0001f3f4\U000e006c\U000e0079\U000e007a\U000e0061\U000e007f" - FLAG_FOR_EL_TARF_DZ_36 = "\U0001f3f4\U000e0064\U000e007a\U000e0033\U000e0036\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_MURZUQ_LY_MQ = "\U0001f3f4\U000e006c\U000e0079\U000e006d\U000e0071\U000e007f" - FLAG_FOR_CHAOUIA_OUARDIGHA_MA_09 = "\U0001f3f4\U000e006d\U000e0061\U000e0030\U000e0039\U000e007f" - FLAG_FOR_SIRTE_LY_SR = "\U0001f3f4\U000e006c\U000e0079\U000e0073\U000e0072\U000e007f" - FLAG_FOR_NUQAT_AL_KHAMS_LY_NQ = "\U0001f3f4\U000e006c\U000e0079\U000e006e\U000e0071\U000e007f" - FLAG_FOR_LA_CONDAMINE_MC_CO = "\U0001f3f4\U000e006d\U000e0063\U000e0063\U000e006f\U000e007f" - FLAG_FOR_MEKNES_TAFILALET_MA_06 = "\U0001f3f4\U000e006d\U000e0061\U000e0030\U000e0036\U000e007f" - FLAG_FOR_LA_GARE_MC_GA = "\U0001f3f4\U000e006d\U000e0063\U000e0067\U000e0061\U000e007f" - FLAG_FOR_GUELMIM_ES_SEMARA_MA_14 = "\U0001f3f4\U000e006d\U000e0061\U000e0031\U000e0034\U000e007f" - COUPLE_WITH_HEART_WOMAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2764\ufe0f\u200d\U0001f468\U0001f3fb" - FLAG_FOR_GHARB_CHRARDA_BENI_HSSEN_MA_02 = "\U0001f3f4\U000e006d\U000e0061\U000e0030\U000e0032\U000e007f" - FLAG_FOR_FONTVIEILLE_MC_FO = "\U0001f3f4\U000e006d\U000e0063\U000e0066\U000e006f\U000e007f" - FLAG_FOR_TADLA_AZILAL_MA_12 = "\U0001f3f4\U000e006d\U000e0061\U000e0031\U000e0032\U000e007f" - FAMILY_MAN_DARK_SKIN_TONE_BOY_DARK_SKIN_TONE_GIRL_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f466\U0001f3ff\u200d\U0001f467\U0001f3ff" - FLAG_FOR_RABAT_SALE_ZEMMOUR_ZAER_MA_07 = "\U0001f3f4\U000e006d\U000e0061\U000e0030\U000e0037\U000e007f" - FLAG_FOR_MALBOUSQUET_MC_MA = "\U0001f3f4\U000e006d\U000e0063\U000e006d\U000e0061\U000e007f" - FLAG_FOR_OUED_ED_DAHAB_LAGOUIRA_MA_16 = "\U0001f3f4\U000e006d\U000e0061\U000e0031\U000e0036\U000e007f" - FLAG_FOR_CALARASI_MD_CL = "\U0001f3f4\U000e006d\U000e0064\U000e0063\U000e006c\U000e007f" - FLAG_FOR_SOLDANESTI_MD_SD = "\U0001f3f4\U000e006d\U000e0064\U000e0073\U000e0064\U000e007f" - FLAG_FOR_IALOVENI_MD_IA = "\U0001f3f4\U000e006d\U000e0064\U000e0069\U000e0061\U000e007f" - FLAG_FOR_LEOVA_MD_LE = "\U0001f3f4\U000e006d\U000e0064\U000e006c\U000e0065\U000e007f" - FLAG_FOR_BALTI_MD_BA = "\U0001f3f4\U000e006d\U000e0064\U000e0062\U000e0061\U000e007f" - FLAG_FOR_CRIULENI_MD_CR = "\U0001f3f4\U000e006d\U000e0064\U000e0063\U000e0072\U000e007f" - FLAG_FOR_CENTRE_VAL_DE_LOIRE_FR_CVL = "\U0001f3f4\U000e0066\U000e0072\U000e0063\U000e0076\U000e006c\U000e007f" - FLAG_FOR_CANTEMIR_MD_CT = "\U0001f3f4\U000e006d\U000e0064\U000e0063\U000e0074\U000e007f" - FLAG_FOR_CHISINAU_MD_CU = "\U0001f3f4\U000e006d\U000e0064\U000e0063\U000e0075\U000e007f" - FLAG_FOR_FALESTI_MD_FA = "\U0001f3f4\U000e006d\U000e0064\U000e0066\U000e0061\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_GIRL_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f467\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_DONDUSENI_MD_DO = "\U0001f3f4\U000e006d\U000e0064\U000e0064\U000e006f\U000e007f" - FLAG_FOR_MELILLA_ES_ML = "\U0001f3f4\U000e0065\U000e0073\U000e006d\U000e006c\U000e007f" - FLAG_FOR_OCNITA_MD_OC = "\U0001f3f4\U000e006d\U000e0064\U000e006f\U000e0063\U000e007f" - FLAG_FOR_SOROCA_MD_SO = "\U0001f3f4\U000e006d\U000e0064\U000e0073\U000e006f\U000e007f" - FLAG_FOR_DUBASARI_MD_DU = "\U0001f3f4\U000e006d\U000e0064\U000e0064\U000e0075\U000e007f" - FLAG_FOR_SINGEREI_MD_SI = "\U0001f3f4\U000e006d\U000e0064\U000e0073\U000e0069\U000e007f" - FLAG_FOR_EDINET_MD_ED = "\U0001f3f4\U000e006d\U000e0064\U000e0065\U000e0064\U000e007f" - FLAG_FOR_SABHA_LY_SB = "\U0001f3f4\U000e006c\U000e0079\U000e0073\U000e0062\U000e007f" - FLAG_FOR_NISPORENI_MD_NI = "\U0001f3f4\U000e006d\U000e0064\U000e006e\U000e0069\U000e007f" - FLAG_FOR_BRICENI_MD_BR = "\U0001f3f4\U000e006d\U000e0064\U000e0062\U000e0072\U000e007f" - FAMILY_WOMAN_MEDIUM_SKIN_TONE_BABY_MEDIUM_SKIN_TONE_BOY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f476\U0001f3fd\u200d\U0001f466\U0001f3fd" - FLAG_FOR_ORHEI_MD_OR = "\U0001f3f4\U000e006d\U000e0064\U000e006f\U000e0072\U000e007f" - FLAG_FOR_CIMISLIA_MD_CM = "\U0001f3f4\U000e006d\U000e0064\U000e0063\U000e006d\U000e007f" - FLAG_FOR_GLODENI_MD_GL = "\U0001f3f4\U000e006d\U000e0064\U000e0067\U000e006c\U000e007f" - FLAG_FOR_RISCANI_MD_RI = "\U0001f3f4\U000e006d\U000e0064\U000e0072\U000e0069\U000e007f" - FLAG_FOR_BENDER_MD_BD = "\U0001f3f4\U000e006d\U000e0064\U000e0062\U000e0064\U000e007f" - FLAG_FOR_BASARABEASCA_MD_BS = "\U0001f3f4\U000e006d\U000e0064\U000e0062\U000e0073\U000e007f" - FLAG_FOR_JARDIN_EXOTIQUE_DE_MONACO_MC_JE = "\U0001f3f4\U000e006d\U000e0063\U000e006a\U000e0065\U000e007f" - FLAG_FOR_ERGLI_LV_030 = "\U0001f3f4\U000e006c\U000e0076\U000e0030\U000e0033\U000e0030\U000e007f" - FLAG_FOR_CAHUL_MD_CA = "\U0001f3f4\U000e006d\U000e0064\U000e0063\U000e0061\U000e007f" - FLAG_FOR_FLORESTI_MD_FL = "\U0001f3f4\U000e006d\U000e0064\U000e0066\U000e006c\U000e007f" - FLAG_FOR_HINCESTI_MD_HI = "\U0001f3f4\U000e006d\U000e0064\U000e0068\U000e0069\U000e007f" - FLAG_FOR_TOAMASINA_MG_A = "\U0001f3f4\U000e006d\U000e0067\U000e0061\U000e007f" - TAG_APOSTROPHE = "\U000e0027" - FLAG_FOR_TRIPOLI_LY_TB = "\U0001f3f4\U000e006c\U000e0079\U000e0074\U000e0062\U000e007f" - FLAG_FOR_BOGOVINJE_MK_06 = "\U0001f3f4\U000e006d\U000e006b\U000e0030\U000e0036\U000e007f" - FLAG_FOR_MOJKOVAC_ME_11 = "\U0001f3f4\U000e006d\U000e0065\U000e0031\U000e0031\U000e007f" - FLAG_FOR_PLUZINE_ME_15 = "\U0001f3f4\U000e006d\U000e0065\U000e0031\U000e0035\U000e007f" - FLAG_FOR_BOGDANCI_MK_05 = "\U0001f3f4\U000e006d\U000e006b\U000e0030\U000e0035\U000e007f" - FLAG_FOR_ISFAHAN_IR_04 = "\U0001f3f4\U000e0069\U000e0072\U000e0030\U000e0034\U000e007f" - FLAG_FOR_BUDVA_ME_05 = "\U0001f3f4\U000e006d\U000e0065\U000e0030\U000e0035\U000e007f" - FLAG_FOR_FIANARANTSOA_MG_F = "\U0001f3f4\U000e006d\U000e0067\U000e0066\U000e007f" - FLAG_FOR_PLJEVLJA_ME_14 = "\U0001f3f4\U000e006d\U000e0065\U000e0031\U000e0034\U000e007f" - FAMILY_MAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f476\U0001f3fc" - FLAG_FOR_BIJELO_POLJE_ME_04 = "\U0001f3f4\U000e006d\U000e0065\U000e0030\U000e0034\U000e007f" - FLAG_FOR_ANTSIRANANA_MG_D = "\U0001f3f4\U000e006d\U000e0067\U000e0064\U000e007f" - FLAG_FOR_SAVNIK_ME_18 = "\U0001f3f4\U000e006d\U000e0065\U000e0031\U000e0038\U000e007f" - FLAG_FOR_BEROVO_MK_03 = "\U0001f3f4\U000e006d\U000e006b\U000e0030\U000e0033\U000e007f" - FLAG_FOR_TOLIARA_MG_U = "\U0001f3f4\U000e006d\U000e0067\U000e0075\U000e007f" - FLAG_FOR_KOLASIN_ME_09 = "\U0001f3f4\U000e006d\U000e0065\U000e0030\U000e0039\U000e007f" - FLAG_FOR_ANDRIJEVICA_ME_01 = "\U0001f3f4\U000e006d\U000e0065\U000e0030\U000e0031\U000e007f" - FLAG_FOR_DERNA_LY_DR = "\U0001f3f4\U000e006c\U000e0079\U000e0064\U000e0072\U000e007f" - FLAG_FOR_ANTANANARIVO_MG_T = "\U0001f3f4\U000e006d\U000e0067\U000e0074\U000e007f" - FLAG_FOR_QEQQATA_GL_QE = "\U0001f3f4\U000e0067\U000e006c\U000e0071\U000e0065\U000e007f" - FLAG_FOR_MAHAJANGA_MG_M = "\U0001f3f4\U000e006d\U000e0067\U000e006d\U000e007f" - FLAG_FOR_NIKSIC_ME_12 = "\U0001f3f4\U000e006d\U000e0065\U000e0031\U000e0032\U000e007f" - FLAG_FOR_PETNJICA_ME_23 = "\U0001f3f4\U000e006d\U000e0065\U000e0032\U000e0033\U000e007f" - FLAG_FOR_BOSILOVO_MK_07 = "\U0001f3f4\U000e006d\U000e006b\U000e0030\U000e0037\U000e007f" - FLAG_FOR_FES_BOULEMANE_MA_05 = "\U0001f3f4\U000e006d\U000e0061\U000e0030\U000e0035\U000e007f" - FLAG_FOR_HOUAPHANH_LA_HO = "\U0001f3f4\U000e006c\U000e0061\U000e0068\U000e006f\U000e007f" - FLAG_FOR_STEFAN_VODA_MD_SV = "\U0001f3f4\U000e006d\U000e0064\U000e0073\U000e0076\U000e007f" - FAMILY_MAN_LIGHT_SKIN_TONE_MAN_LIGHT_SKIN_TONE_BABY_LIGHT_SKIN_TONE_GIRL_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f468\U0001f3fb\u200d\U0001f476\U0001f3fb\u200d\U0001f467\U0001f3fb" - FLAG_FOR_WADI_AL_SHATII_LY_WS = "\U0001f3f4\U000e006c\U000e0079\U000e0077\U000e0073\U000e007f" - FLAG_FOR_PODGORICA_ME_16 = "\U0001f3f4\U000e006d\U000e0065\U000e0031\U000e0036\U000e007f" - FLAG_FOR_KOTOR_ME_10 = "\U0001f3f4\U000e006d\U000e0065\U000e0031\U000e0030\U000e007f" - FLAG_FOR_MARANHAO_BR_MA = "\U0001f3f4\U000e0062\U000e0072\U000e006d\U000e0061\U000e007f" - FLAG_FOR_KRIVOGASTANI_MK_45 = "\U0001f3f4\U000e006d\U000e006b\U000e0034\U000e0035\U000e007f" - FLAG_FOR_KARBINCI_MK_37 = "\U0001f3f4\U000e006d\U000e006b\U000e0033\U000e0037\U000e007f" - FLAG_FOR_KAVADARCI_MK_36 = "\U0001f3f4\U000e006d\U000e006b\U000e0033\U000e0036\U000e007f" - FLAG_FOR_MAVROVO_AND_ROSTUSA_MK_50 = "\U0001f3f4\U000e006d\U000e006b\U000e0035\U000e0030\U000e007f" - FLAG_FOR_ZELINO_MK_30 = "\U0001f3f4\U000e006d\U000e006b\U000e0033\U000e0030\U000e007f" - FLAG_FOR_DOJRAN_MK_26 = "\U0001f3f4\U000e006d\U000e006b\U000e0032\U000e0036\U000e007f" - FLAG_FOR_KOCANI_MK_42 = "\U0001f3f4\U000e006d\U000e006b\U000e0034\U000e0032\U000e007f" - FLAG_FOR_NEGOTINO_MK_54 = "\U0001f3f4\U000e006d\U000e006b\U000e0035\U000e0034\U000e007f" - FLAG_FOR_ILINDEN_MK_34 = "\U0001f3f4\U000e006d\U000e006b\U000e0033\U000e0034\U000e007f" - FLAG_FOR_DEBAR_MK_21 = "\U0001f3f4\U000e006d\U000e006b\U000e0032\U000e0031\U000e007f" - FLAG_FOR_LOZOVO_MK_49 = "\U0001f3f4\U000e006d\U000e006b\U000e0034\U000e0039\U000e007f" - FLAG_FOR_GEVGELIJA_MK_18 = "\U0001f3f4\U000e006d\U000e006b\U000e0031\U000e0038\U000e007f" - FLAG_FOR_NOVACI_MK_55 = "\U0001f3f4\U000e006d\U000e006b\U000e0035\U000e0035\U000e007f" - FLAG_FOR_VINICA_MK_14 = "\U0001f3f4\U000e006d\U000e006b\U000e0031\U000e0034\U000e007f" - FLAG_FOR_VASILEVO_MK_11 = "\U0001f3f4\U000e006d\U000e006b\U000e0031\U000e0031\U000e007f" - FLAG_FOR_NOVO_SELO_MK_56 = "\U0001f3f4\U000e006d\U000e006b\U000e0035\U000e0036\U000e007f" - FLAG_FOR_KUMANOVO_MK_47 = "\U0001f3f4\U000e006d\U000e006b\U000e0034\U000e0037\U000e007f" - FLAG_FOR_GRADSKO_MK_20 = "\U0001f3f4\U000e006d\U000e006b\U000e0032\U000e0030\U000e007f" - FLAG_FOR_KONCE_MK_41 = "\U0001f3f4\U000e006d\U000e006b\U000e0034\U000e0031\U000e007f" - FLAG_FOR_ZELENIKOVO_MK_32 = "\U0001f3f4\U000e006d\U000e006b\U000e0033\U000e0032\U000e007f" - FLAG_FOR_JEGUNOVCE_MK_35 = "\U0001f3f4\U000e006d\U000e006b\U000e0033\U000e0035\U000e007f" - FLAG_FOR_MAKEDONSKA_KAMENICA_MK_51 = "\U0001f3f4\U000e006d\U000e006b\U000e0035\U000e0031\U000e007f" - FLAG_FOR_VEVCANI_MK_12 = "\U0001f3f4\U000e006d\U000e006b\U000e0031\U000e0032\U000e007f" - FLAG_FOR_GOSTIVAR_MK_19 = "\U0001f3f4\U000e006d\U000e006b\U000e0031\U000e0039\U000e007f" - FLAG_FOR_KRUSEVO_MK_46 = "\U0001f3f4\U000e006d\U000e006b\U000e0034\U000e0036\U000e007f" - FLAG_FOR_BRVENICA_MK_08 = "\U0001f3f4\U000e006d\U000e006b\U000e0030\U000e0038\U000e007f" - FLAG_FOR_LIPKOVO_MK_48 = "\U0001f3f4\U000e006d\U000e006b\U000e0034\U000e0038\U000e007f" - FLAG_FOR_VALANDOVO_MK_10 = "\U0001f3f4\U000e006d\U000e006b\U000e0031\U000e0030\U000e007f" - FLAG_FOR_KRATOVO_MK_43 = "\U0001f3f4\U000e006d\U000e006b\U000e0034\U000e0033\U000e007f" - FLAG_FOR_KRIVA_PALANKA_MK_44 = "\U0001f3f4\U000e006d\U000e006b\U000e0034\U000e0034\U000e007f" - FLAG_FOR_ZRNOVCI_MK_33 = "\U0001f3f4\U000e006d\U000e006b\U000e0033\U000e0033\U000e007f" - FLAG_FOR_TEL_AVIV_DISTRICT_IL_TA = "\U0001f3f4\U000e0069\U000e006c\U000e0074\U000e0061\U000e007f" - FLAG_FOR_DANILOVGRAD_ME_07 = "\U0001f3f4\U000e006d\U000e0065\U000e0030\U000e0037\U000e007f" - FLAG_FOR_DEBARCA_MK_22 = "\U0001f3f4\U000e006d\U000e006b\U000e0032\U000e0032\U000e007f" - FLAG_FOR_VRAPCISTE_MK_16 = "\U0001f3f4\U000e006d\U000e006b\U000e0031\U000e0036\U000e007f" - FLAG_FOR_DELCEVO_MK_23 = "\U0001f3f4\U000e006d\U000e006b\U000e0032\U000e0033\U000e007f" - FLAG_FOR_VELES_MK_13 = "\U0001f3f4\U000e006d\U000e006b\U000e0031\U000e0033\U000e007f" - FLAG_FOR_AYEYARWADY_MM_07 = "\U0001f3f4\U000e006d\U000e006d\U000e0030\U000e0037\U000e007f" - FLAG_FOR_KAYAH_MM_12 = "\U0001f3f4\U000e006d\U000e006d\U000e0031\U000e0032\U000e007f" - FLAG_FOR_STARO_NAGORICANE_MK_71 = "\U0001f3f4\U000e006d\U000e006b\U000e0037\U000e0031\U000e007f" - FLAG_FOR_STIP_MK_83 = "\U0001f3f4\U000e006d\U000e006b\U000e0038\U000e0033\U000e007f" - FLAG_FOR_DAEJEON_KR_30 = "\U0001f3f4\U000e006b\U000e0072\U000e0033\U000e0030\U000e007f" - FLAG_FOR_TETOVO_MK_76 = "\U0001f3f4\U000e006d\U000e006b\U000e0037\U000e0036\U000e007f" - FLAG_FOR_SZEGED_HU_SD = "\U0001f3f4\U000e0068\U000e0075\U000e0073\U000e0064\U000e007f" - FLAG_FOR_MOPTI_ML_5 = "\U0001f3f4\U000e006d\U000e006c\U000e0035\U000e007f" - FLAG_FOR_SIKASSO_ML_3 = "\U0001f3f4\U000e006d\U000e006c\U000e0033\U000e007f" - FLAG_FOR_U_S_OUTLYING_ISLANDS_US_UM = "\U0001f3f4\U000e0075\U000e0073\U000e0075\U000e006d\U000e007f" - FLAG_FOR_CASKA_MK_80 = "\U0001f3f4\U000e006d\U000e006b\U000e0038\U000e0030\U000e007f" - FLAG_FOR_STRUGA_MK_72 = "\U0001f3f4\U000e006d\U000e006b\U000e0037\U000e0032\U000e007f" - FLAG_FOR_KOULIKORO_ML_2 = "\U0001f3f4\U000e006d\U000e006c\U000e0032\U000e007f" - FLAG_FOR_PETROVEC_MK_59 = "\U0001f3f4\U000e006d\U000e006b\U000e0035\U000e0039\U000e007f" - KISS_MAN_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468\U0001f3fe" - FLAG_FOR_CUCER_SANDEVO_MK_82 = "\U0001f3f4\U000e006d\U000e006b\U000e0038\U000e0032\U000e007f" - FLAG_FOR_SOPISTE_MK_70 = "\U0001f3f4\U000e006d\U000e006b\U000e0037\U000e0030\U000e007f" - FLAG_FOR_MANDALAY_MM_04 = "\U0001f3f4\U000e006d\U000e006d\U000e0030\U000e0034\U000e007f" - FLAG_FOR_GENEVA_CH_GE = "\U0001f3f4\U000e0063\U000e0068\U000e0067\U000e0065\U000e007f" - FLAG_FOR_KACHIN_MM_11 = "\U0001f3f4\U000e006d\U000e006d\U000e0031\U000e0031\U000e007f" - FLAG_FOR_PROBISTIP_MK_63 = "\U0001f3f4\U000e006d\U000e006b\U000e0036\U000e0033\U000e007f" - FLAG_FOR_RESEN_MK_66 = "\U0001f3f4\U000e006d\U000e006b\U000e0036\U000e0036\U000e007f" - FLAG_FOR_TANINTHARYI_MM_05 = "\U0001f3f4\U000e006d\U000e006d\U000e0030\U000e0035\U000e007f" - FLAG_FOR_ROSOMAN_MK_67 = "\U0001f3f4\U000e006d\U000e006b\U000e0036\U000e0037\U000e007f" - FLAG_FOR_CESINOVO_OBLESEVO_MK_81 = "\U0001f3f4\U000e006d\U000e006b\U000e0038\U000e0031\U000e007f" - FLAG_FOR_PEHCEVO_MK_60 = "\U0001f3f4\U000e006d\U000e006b\U000e0036\U000e0030\U000e007f" - FLAG_FOR_SAGAING_MM_01 = "\U0001f3f4\U000e006d\U000e006d\U000e0030\U000e0031\U000e007f" - FLAG_FOR_ZAVKHAN_MN_057 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0035\U000e0037\U000e007f" - FLAG_FOR_TOV_MN_047 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0034\U000e0037\U000e007f" - FLAG_FOR_INCHIRI_MR_12 = "\U0001f3f4\U000e006d\U000e0072\U000e0031\U000e0032\U000e007f" - FLAG_FOR_TAGANT_MR_09 = "\U0001f3f4\U000e006d\U000e0072\U000e0030\U000e0039\U000e007f" - FLAG_FOR_DAKHLET_NOUADHIBOU_MR_08 = "\U0001f3f4\U000e006d\U000e0072\U000e0030\U000e0038\U000e007f" - FLAG_FOR_OVORKHANGAI_MN_055 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0035\U000e0035\U000e007f" - TAG_DOLLAR_SIGN = "\U000e0024" - FLAG_FOR_HODH_EL_GHARBI_MR_02 = "\U0001f3f4\U000e006d\U000e0072\U000e0030\U000e0032\U000e007f" - FLAG_FOR_BAYAN_OLGII_MN_071 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0037\U000e0031\U000e007f" - FLAG_FOR_DUNDGOVI_MN_059 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0035\U000e0039\U000e007f" - FLAG_FOR_SCHWYZ_CH_SZ = "\U0001f3f4\U000e0063\U000e0068\U000e0073\U000e007a\U000e007f" - FLAG_FOR_BULGAN_MN_067 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0036\U000e0037\U000e007f" - TAG_TILDE = "\U000e007e" - FLAG_FOR_KAYIN_MM_13 = "\U0001f3f4\U000e006d\U000e006d\U000e0031\U000e0033\U000e007f" - FLAG_FOR_GAO_ML_7 = "\U0001f3f4\U000e006d\U000e006c\U000e0037\U000e007f" - FLAG_FOR_DORNOD_MN_061 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0036\U000e0031\U000e007f" - FLAG_FOR_TRARZA_MR_06 = "\U0001f3f4\U000e006d\U000e0072\U000e0030\U000e0036\U000e007f" - FLAG_FOR_DARKHAN_UUL_MN_037 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0033\U000e0037\U000e007f" - FLAG_FOR_UVS_MN_046 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0034\U000e0036\U000e007f" - FLAG_FOR_KHOVSGOL_MN_041 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0034\U000e0031\U000e007f" - FLAG_FOR_BAYANKHONGOR_MN_069 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0036\U000e0039\U000e007f" - FLAG_FOR_HODH_ECH_CHARGUI_MR_01 = "\U0001f3f4\U000e006d\U000e0072\U000e0030\U000e0031\U000e007f" - FLAG_FOR_NAYPYIDAW_MM_18 = "\U0001f3f4\U000e006d\U000e006d\U000e0031\U000e0038\U000e007f" - FLAG_FOR_DORNOGOVI_MN_063 = "\U0001f3f4\U000e006d\U000e006e\U000e0030\U000e0036\U000e0033\U000e007f" - FAMILY_WOMAN_MEDIUM_LIGHT_SKIN_TONE_WOMAN_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE_BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f469\U0001f3fc\u200d\U0001f466\U0001f3fc\u200d\U0001f466\U0001f3fc" - FLAG_FOR_SAN_MIGUEL_SV_SM = "\U0001f3f4\U000e0073\U000e0076\U000e0073\U000e006d\U000e007f" - FLAG_FOR_MANCHESTER_JM_12 = "\U0001f3f4\U000e006a\U000e006d\U000e0031\U000e0032\U000e007f" - WHITE_RIGHT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_1_2 = "\u261e\U0001f3fb" - REVERSED_THUMBS_DOWN_SIGN_EMOJI_MODIFIER_FITZPATRICK_TYPE_1_2 = "\U0001f593\U0001f3fb" - BLACK_RIGHT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_1_2 = "\u261b\U0001f3fb" - REVERSED_RAISED_HAND_WITH_FINGERS_SPLAYED_EMOJI_MODIFIER_FITZPATRICK_TYPE_1_2 = "\U0001f591\U0001f3fb" - WHITE_DOWN_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_1_2 = "\u261f\U0001f3fb" - BLACK_LEFT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_1_2 = "\u261a\U0001f3fb" - REVERSED_VICTORY_HAND_EMOJI_MODIFIER_FITZPATRICK_TYPE_1_2 = "\U0001f594\U0001f3fb" - WHITE_LEFT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_1_2 = "\u261c\U0001f3fb" - REVERSED_THUMBS_UP_SIGN_EMOJI_MODIFIER_FITZPATRICK_TYPE_1_2 = "\U0001f592\U0001f3fb" - LEFT_WRITING_HAND_EMOJI_MODIFIER_FITZPATRICK_TYPE_1_2 = "\U0001f58e\U0001f3fb" - WHITE_LEFT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_3 = "\u261c\U0001f3fc" - BLACK_RIGHT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_3 = "\u261b\U0001f3fc" - REVERSED_THUMBS_UP_SIGN_EMOJI_MODIFIER_FITZPATRICK_TYPE_3 = "\U0001f592\U0001f3fc" - WHITE_RIGHT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_3 = "\u261e\U0001f3fc" - LEFT_WRITING_HAND_EMOJI_MODIFIER_FITZPATRICK_TYPE_3 = "\U0001f58e\U0001f3fc" - REVERSED_VICTORY_HAND_EMOJI_MODIFIER_FITZPATRICK_TYPE_3 = "\U0001f594\U0001f3fc" - WHITE_DOWN_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_3 = "\u261f\U0001f3fc" - BLACK_LEFT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_3 = "\u261a\U0001f3fc" - REVERSED_THUMBS_DOWN_SIGN_EMOJI_MODIFIER_FITZPATRICK_TYPE_3 = "\U0001f593\U0001f3fc" - REVERSED_RAISED_HAND_WITH_FINGERS_SPLAYED_EMOJI_MODIFIER_FITZPATRICK_TYPE_3 = "\U0001f591\U0001f3fc" - REVERSED_RAISED_HAND_WITH_FINGERS_SPLAYED_EMOJI_MODIFIER_FITZPATRICK_TYPE_4 = "\U0001f591\U0001f3fd" - BLACK_LEFT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_4 = "\u261a\U0001f3fd" - REVERSED_THUMBS_DOWN_SIGN_EMOJI_MODIFIER_FITZPATRICK_TYPE_4 = "\U0001f593\U0001f3fd" - WHITE_DOWN_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_4 = "\u261f\U0001f3fd" - REVERSED_THUMBS_UP_SIGN_EMOJI_MODIFIER_FITZPATRICK_TYPE_4 = "\U0001f592\U0001f3fd" - BLACK_RIGHT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_4 = "\u261b\U0001f3fd" - REVERSED_VICTORY_HAND_EMOJI_MODIFIER_FITZPATRICK_TYPE_4 = "\U0001f594\U0001f3fd" - WHITE_LEFT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_4 = "\u261c\U0001f3fd" - LEFT_WRITING_HAND_EMOJI_MODIFIER_FITZPATRICK_TYPE_4 = "\U0001f58e\U0001f3fd" - WHITE_RIGHT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_4 = "\u261e\U0001f3fd" - LEFT_WRITING_HAND_EMOJI_MODIFIER_FITZPATRICK_TYPE_5 = "\U0001f58e\U0001f3fe" - WHITE_RIGHT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_5 = "\u261e\U0001f3fe" - WHITE_LEFT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_5 = "\u261c\U0001f3fe" - BLACK_LEFT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_5 = "\u261a\U0001f3fe" - WHITE_DOWN_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_5 = "\u261f\U0001f3fe" - REVERSED_THUMBS_DOWN_SIGN_EMOJI_MODIFIER_FITZPATRICK_TYPE_5 = "\U0001f593\U0001f3fe" - REVERSED_RAISED_HAND_WITH_FINGERS_SPLAYED_EMOJI_MODIFIER_FITZPATRICK_TYPE_5 = "\U0001f591\U0001f3fe" - REVERSED_VICTORY_HAND_EMOJI_MODIFIER_FITZPATRICK_TYPE_5 = "\U0001f594\U0001f3fe" - BLACK_RIGHT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_5 = "\u261b\U0001f3fe" - REVERSED_THUMBS_UP_SIGN_EMOJI_MODIFIER_FITZPATRICK_TYPE_5 = "\U0001f592\U0001f3fe" - REVERSED_THUMBS_DOWN_SIGN_EMOJI_MODIFIER_FITZPATRICK_TYPE_6 = "\U0001f593\U0001f3ff" - WHITE_LEFT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_6 = "\u261c\U0001f3ff" - WHITE_RIGHT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_6 = "\u261e\U0001f3ff" - BLACK_LEFT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_6 = "\u261a\U0001f3ff" - BLACK_RIGHT_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_6 = "\u261b\U0001f3ff" - REVERSED_RAISED_HAND_WITH_FINGERS_SPLAYED_EMOJI_MODIFIER_FITZPATRICK_TYPE_6 = "\U0001f591\U0001f3ff" - WHITE_DOWN_POINTING_INDEX_EMOJI_MODIFIER_FITZPATRICK_TYPE_6 = "\u261f\U0001f3ff" - REVERSED_THUMBS_UP_SIGN_EMOJI_MODIFIER_FITZPATRICK_TYPE_6 = "\U0001f592\U0001f3ff" - LEFT_WRITING_HAND_EMOJI_MODIFIER_FITZPATRICK_TYPE_6 = "\U0001f58e\U0001f3ff" - REVERSED_VICTORY_HAND_EMOJI_MODIFIER_FITZPATRICK_TYPE_6 = "\U0001f594\U0001f3ff" diff --git a/pyrogram/client/ext/file_data.py b/pyrogram/client/ext/file_data.py deleted file mode 100644 index ea9de6e1..00000000 --- a/pyrogram/client/ext/file_data.py +++ /dev/null @@ -1,41 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2020 Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -class FileData: - def __init__( - self, *, media_type: int = None, dc_id: int = None, document_id: int = None, access_hash: int = None, - thumb_size: str = None, peer_id: int = None, peer_type: str = None, peer_access_hash: int = None, - volume_id: int = None, local_id: int = None, is_big: bool = None, file_size: int = None, mime_type: str = None, - file_name: str = None, date: int = None, file_ref: str = None - ): - self.media_type = media_type - self.dc_id = dc_id - self.document_id = document_id - self.access_hash = access_hash - self.thumb_size = thumb_size - self.peer_id = peer_id - self.peer_type = peer_type - self.peer_access_hash = peer_access_hash - self.volume_id = volume_id - self.local_id = local_id - self.is_big = is_big - self.file_size = file_size - self.mime_type = mime_type - self.file_name = file_name - self.date = date - self.file_ref = file_ref diff --git a/pyrogram/client/ext/link.py b/pyrogram/client/ext/link.py deleted file mode 100644 index bd2d82cf..00000000 --- a/pyrogram/client/ext/link.py +++ /dev/null @@ -1,52 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2020 Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -import html - - -class Link(str): - HTML = "{text}" - MD = "[{text}]({url})" - - def __init__(self, url: str, text: str, style: str): - super().__init__() - - self.url = url - self.text = text - self.style = style - - @staticmethod - def format(url: str, text: str, style: str): - if style in ["md", "markdown"]: - fmt = Link.MD - elif style in ["combined", "html", None]: - fmt = Link.HTML - else: - raise ValueError("{} is not a valid style/parse mode".format(style)) - - return fmt.format(url=url, text=html.escape(text)) - - # noinspection PyArgumentList - def __new__(cls, url, text, style): - return str.__new__(cls, Link.format(url, text, style)) - - def __call__(self, other: str = None, *, style: str = None): - return Link.format(self.url, other or self.text, style or self.style) - - def __str__(self): - return Link.format(self.url, self.text, self.style) diff --git a/pyrogram/client/filters/__init__.py b/pyrogram/client/filters/__init__.py deleted file mode 100644 index bdb72abc..00000000 --- a/pyrogram/client/filters/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2020 Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -from .filters import Filters diff --git a/pyrogram/client/filters/filter.py b/pyrogram/client/filters/filter.py deleted file mode 100644 index 67067e03..00000000 --- a/pyrogram/client/filters/filter.py +++ /dev/null @@ -1,84 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2020 Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -import asyncio - - -class Filter: - def __call__(self, message): - raise NotImplementedError - - def __invert__(self): - return InvertFilter(self) - - def __and__(self, other): - return AndFilter(self, other) - - def __or__(self, other): - return OrFilter(self, other) - - -class InvertFilter(Filter): - def __init__(self, base): - self.base = base - - async def __call__(self, message): - if asyncio.iscoroutinefunction(self.base.__call__): - x = await self.base(message) - else: - x = self.base(message) - - return not x - - -class AndFilter(Filter): - def __init__(self, base, other): - self.base = base - self.other = other - - async def __call__(self, message): - if asyncio.iscoroutinefunction(self.base.__call__): - x = await self.base(message) - else: - x = self.base(message) - - if asyncio.iscoroutinefunction(self.other.__call__): - y = await self.other(message) - else: - y = self.other(message) - - return x and y - - -class OrFilter(Filter): - def __init__(self, base, other): - self.base = base - self.other = other - - async def __call__(self, message): - if asyncio.iscoroutinefunction(self.base.__call__): - x = await self.base(message) - else: - x = self.base(message) - - if asyncio.iscoroutinefunction(self.other.__call__): - y = await self.other(message) - else: - y = self.other(message) - - return x or y diff --git a/pyrogram/client/filters/filters.py b/pyrogram/client/filters/filters.py deleted file mode 100644 index 3a798874..00000000 --- a/pyrogram/client/filters/filters.py +++ /dev/null @@ -1,404 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2020 Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -import re -from typing import Callable, Union - -from .filter import Filter -from ..types import Message, CallbackQuery, InlineQuery -from ..types.bots_and_keyboards import InlineKeyboardMarkup, ReplyKeyboardMarkup - -CUSTOM_FILTER_NAME = "CustomFilter" - - -def create(func: Callable, name: str = None, **kwargs) -> Filter: - """Easily create a custom filter. - - Custom filters give you extra control over which updates are allowed or not to be processed by your handlers. - - Parameters: - func (``callable``): - A function that accepts two positional arguments *(filter, update)* and returns a boolean: True if the - update should be handled, False otherwise. The *filter* argument refers to the filter itself and can be used - to access keyword arguments (read below). The *update* argument type will vary depending on which - `Handler `_ is coming from. For example, in a :obj:`MessageHandler` the *update* argument will be - a :obj:`Message`; in a :obj:`CallbackQueryHandler` the *update* will be a :obj:`CallbackQuery`. Your - function body can then access the incoming update attributes and decide whether to allow it or not. - - name (``str``, *optional*): - Your filter's name. Can be anything you like. - Defaults to "CustomFilter". - - **kwargs (``any``, *optional*): - Any keyword argument you would like to pass. Useful when creating parameterized custom filters, such as - :meth:`~Filters.command` or :meth:`~Filters.regex`. - """ - # TODO: unpack kwargs using **kwargs into the dict itself. For Python 3.5+ only - d = {"__call__": func} - d.update(kwargs) - - return type(name or CUSTOM_FILTER_NAME, (Filter,), d)() - - -class Filters: - """This class provides access to all library-defined Filters available in Pyrogram. - - The Filters listed here are currently intended to be used with the :obj:`MessageHandler` only. - At the moment, if you want to filter updates coming from different `Handlers `_ you have to create - your own filters with :meth:`~Filters.create` and use them in the same way. - """ - - create = create - - all = create(lambda _, m: True, "AllFilter") - """Filter all messages.""" - - me = create(lambda _, m: bool(m.from_user and m.from_user.is_self), "MeFilter") - """Filter messages generated by you yourself.""" - - bot = create(lambda _, m: bool(m.from_user and m.from_user.is_bot), "BotFilter") - """Filter messages coming from bots.""" - - incoming = create(lambda _, m: not m.outgoing, "IncomingFilter") - """Filter incoming messages. Messages sent to your own chat (Saved Messages) are also recognised as incoming.""" - - outgoing = create(lambda _, m: m.outgoing, "OutgoingFilter") - """Filter outgoing messages. Messages sent to your own chat (Saved Messages) are not recognized as outgoing.""" - - text = create(lambda _, m: bool(m.text), "TextFilter") - """Filter text messages.""" - - reply = create(lambda _, m: bool(m.reply_to_message), "ReplyFilter") - """Filter messages that are replies to other messages.""" - - forwarded = create(lambda _, m: bool(m.forward_date), "ForwardedFilter") - """Filter messages that are forwarded.""" - - caption = create(lambda _, m: bool(m.caption), "CaptionFilter") - """Filter media messages that contain captions.""" - - edited = create(lambda _, m: bool(m.edit_date), "EditedFilter") - """Filter edited messages.""" - - audio = create(lambda _, m: bool(m.audio), "AudioFilter") - """Filter messages that contain :obj:`Audio` objects.""" - - document = create(lambda _, m: bool(m.document), "DocumentFilter") - """Filter messages that contain :obj:`Document` objects.""" - - photo = create(lambda _, m: bool(m.photo), "PhotoFilter") - """Filter messages that contain :obj:`Photo` objects.""" - - sticker = create(lambda _, m: bool(m.sticker), "StickerFilter") - """Filter messages that contain :obj:`Sticker` objects.""" - - animation = create(lambda _, m: bool(m.animation), "AnimationFilter") - """Filter messages that contain :obj:`Animation` objects.""" - - game = create(lambda _, m: bool(m.game), "GameFilter") - """Filter messages that contain :obj:`Game` objects.""" - - video = create(lambda _, m: bool(m.video), "VideoFilter") - """Filter messages that contain :obj:`Video` objects.""" - - media_group = create(lambda _, m: bool(m.media_group_id), "MediaGroupFilter") - """Filter messages containing photos or videos being part of an album.""" - - voice = create(lambda _, m: bool(m.voice), "VoiceFilter") - """Filter messages that contain :obj:`Voice` note objects.""" - - video_note = create(lambda _, m: bool(m.video_note), "VideoNoteFilter") - """Filter messages that contain :obj:`VideoNote` objects.""" - - contact = create(lambda _, m: bool(m.contact), "ContactFilter") - """Filter messages that contain :obj:`Contact` objects.""" - - location = create(lambda _, m: bool(m.location), "LocationFilter") - """Filter messages that contain :obj:`Location` objects.""" - - venue = create(lambda _, m: bool(m.venue), "VenueFilter") - """Filter messages that contain :obj:`Venue` objects.""" - - web_page = create(lambda _, m: m.web_page, "WebPageFilter") - """Filter messages sent with a webpage preview.""" - - poll = create(lambda _, m: m.poll, "PollFilter") - """Filter messages that contain :obj:`Poll` objects.""" - - private = create(lambda _, m: bool(m.chat and m.chat.type in {"private", "bot"}), "PrivateFilter") - """Filter messages sent in private chats.""" - - group = create(lambda _, m: bool(m.chat and m.chat.type in {"group", "supergroup"}), "GroupFilter") - """Filter messages sent in group or supergroup chats.""" - - channel = create(lambda _, m: bool(m.chat and m.chat.type == "channel"), "ChannelFilter") - """Filter messages sent in channels.""" - - new_chat_members = create(lambda _, m: bool(m.new_chat_members), "NewChatMembersFilter") - """Filter service messages for new chat members.""" - - left_chat_member = create(lambda _, m: bool(m.left_chat_member), "LeftChatMemberFilter") - """Filter service messages for members that left the chat.""" - - new_chat_title = create(lambda _, m: bool(m.new_chat_title), "NewChatTitleFilter") - """Filter service messages for new chat titles.""" - - new_chat_photo = create(lambda _, m: bool(m.new_chat_photo), "NewChatPhotoFilter") - """Filter service messages for new chat photos.""" - - delete_chat_photo = create(lambda _, m: bool(m.delete_chat_photo), "DeleteChatPhotoFilter") - """Filter service messages for deleted photos.""" - - group_chat_created = create(lambda _, m: bool(m.group_chat_created), "GroupChatCreatedFilter") - """Filter service messages for group chat creations.""" - - supergroup_chat_created = create(lambda _, m: bool(m.supergroup_chat_created), "SupergroupChatCreatedFilter") - """Filter service messages for supergroup chat creations.""" - - channel_chat_created = create(lambda _, m: bool(m.channel_chat_created), "ChannelChatCreatedFilter") - """Filter service messages for channel chat creations.""" - - migrate_to_chat_id = create(lambda _, m: bool(m.migrate_to_chat_id), "MigrateToChatIdFilter") - """Filter service messages that contain migrate_to_chat_id.""" - - migrate_from_chat_id = create(lambda _, m: bool(m.migrate_from_chat_id), "MigrateFromChatIdFilter") - """Filter service messages that contain migrate_from_chat_id.""" - - pinned_message = create(lambda _, m: bool(m.pinned_message), "PinnedMessageFilter") - """Filter service messages for pinned messages.""" - - game_high_score = create(lambda _, m: bool(m.game_high_score), "GameHighScoreFilter") - """Filter service messages for game high scores.""" - - reply_keyboard = create(lambda _, m: isinstance(m.reply_markup, ReplyKeyboardMarkup), "ReplyKeyboardFilter") - """Filter messages containing reply keyboard markups""" - - inline_keyboard = create(lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup), "InlineKeyboardFilter") - """Filter messages containing inline keyboard markups""" - - mentioned = create(lambda _, m: bool(m.mentioned), "MentionedFilter") - """Filter messages containing mentions""" - - via_bot = create(lambda _, m: bool(m.via_bot), "ViaBotFilter") - """Filter messages sent via inline bots""" - - service = create(lambda _, m: bool(m.service), "ServiceFilter") - """Filter service messages. - - A service message contains any of the following fields set: *left_chat_member*, - *new_chat_title*, *new_chat_photo*, *delete_chat_photo*, *group_chat_created*, *supergroup_chat_created*, - *channel_chat_created*, *migrate_to_chat_id*, *migrate_from_chat_id*, *pinned_message*, *game_score*. - """ - - media = create(lambda _, m: bool(m.media), "MediaFilter") - """Filter media messages. - - A media message contains any of the following fields set: *audio*, *document*, *photo*, *sticker*, *video*, - *animation*, *voice*, *video_note*, *contact*, *location*, *venue*, *poll*. - """ - - scheduled = create(lambda _, m: bool(m.scheduled), "ScheduledFilter") - """Filter messages that have been scheduled (not yet sent).""" - - from_scheduled = create(lambda _, m: bool(m.from_scheduled), "FromScheduledFilter") - """Filter new automatically sent messages that were previously scheduled.""" - - # Messages from linked channels are forwarded automatically by Telegram and have no sender (from_user is None). - linked_channel = create(lambda _, m: bool(m.forward_from_chat and not m.from_user), "LinkedChannelFilter") - """Filter messages that are automatically forwarded from the linked channel to the group chat.""" - - @staticmethod - def command( - commands: str or list, - prefixes: str or list = "/", - case_sensitive: bool = False - ): - """Filter commands, i.e.: text messages starting with "/" or any other custom prefix. - - Parameters: - commands (``str`` | ``list``): - The command or list of commands as string the filter should look for. - Examples: "start", ["start", "help", "settings"]. When a message text containing - a command arrives, the command itself and its arguments will be stored in the *command* - field of the :obj:`Message`. - - prefixes (``str`` | ``list``, *optional*): - A prefix or a list of prefixes as string the filter should look for. - Defaults to "/" (slash). Examples: ".", "!", ["/", "!", "."], list(".:!"). - Pass None or "" (empty string) to allow commands with no prefix at all. - - case_sensitive (``bool``, *optional*): - Pass True if you want your command(s) to be case sensitive. Defaults to False. - Examples: when True, command="Start" would trigger /Start but not /start. - """ - command_re = re.compile(r"([\"'])(.*?)(?`_ are - stored in the ``matches`` field of the update object itself. - - Parameters: - pattern (``str`` | ``Pattern``): - The regex pattern as string or as pre-compiled pattern. - - flags (``int``, *optional*): - Regex flags. - """ - - def func(flt, update): - if isinstance(update, Message): - value = update.text or update.caption - elif isinstance(update, CallbackQuery): - value = update.data - elif isinstance(update, InlineQuery): - value = update.query - else: - raise ValueError("Regex filter doesn't work with {}".format(type(update))) - - if value: - update.matches = list(flt.p.finditer(value)) or None - - return bool(update.matches) - - return create( - func, - "RegexFilter", - p=pattern if isinstance(pattern, re.Pattern) else re.compile(pattern, flags) - ) - - # noinspection PyPep8Naming - class user(Filter, set): - """Filter messages coming from one or more users. - - You can use `set bound methods `_ to manipulate the - users container. - - Parameters: - users (``int`` | ``str`` | ``list``): - Pass one or more user ids/usernames to filter users. - For you yourself, "me" or "self" can be used as well. - Defaults to None (no users). - """ - - def __init__(self, users: int or str or list = None): - users = [] if users is None else users if isinstance(users, list) else [users] - - super().__init__( - "me" if u in ["me", "self"] - else u.lower().strip("@") if isinstance(u, str) - else u for u in users - ) - - def __call__(self, message): - return (message.from_user - and (message.from_user.id in self - or (message.from_user.username - and message.from_user.username.lower() in self) - or ("me" in self - and message.from_user.is_self))) - - # noinspection PyPep8Naming - class chat(Filter, set): - """Filter messages coming from one or more chats. - - You can use `set bound methods `_ to manipulate the - chats container. - - Parameters: - chats (``int`` | ``str`` | ``list``): - Pass one or more chat ids/usernames to filter chats. - For your personal cloud (Saved Messages) you can simply use "me" or "self". - Defaults to None (no chats). - """ - - def __init__(self, chats: int or str or list = None): - chats = [] if chats is None else chats if isinstance(chats, list) else [chats] - - super().__init__( - "me" if c in ["me", "self"] - else c.lower().strip("@") if isinstance(c, str) - else c for c in chats - ) - - def __call__(self, message): - return (message.chat - and (message.chat.id in self - or (message.chat.username - and message.chat.username.lower() in self) - or ("me" in self - and message.from_user - and message.from_user.is_self - and not message.outgoing))) - - dan = create(lambda _, m: bool(m.from_user and m.from_user.id == 23122162), "DanFilter") diff --git a/pyrogram/client/methods/password/utils.py b/pyrogram/client/methods/password/utils.py deleted file mode 100644 index 30c36796..00000000 --- a/pyrogram/client/methods/password/utils.py +++ /dev/null @@ -1,104 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2020 Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -import hashlib -import os - -from pyrogram.api import types - - -def btoi(b: bytes) -> int: - return int.from_bytes(b, "big") - - -def itob(i: int) -> bytes: - return i.to_bytes(256, "big") - - -def sha256(data: bytes) -> bytes: - return hashlib.sha256(data).digest() - - -def xor(a: bytes, b: bytes) -> bytes: - return bytes(i ^ j for i, j in zip(a, b)) - - -def compute_hash(algo: types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow, password: str) -> bytes: - hash1 = sha256(algo.salt1 + password.encode() + algo.salt1) - hash2 = sha256(algo.salt2 + hash1 + algo.salt2) - hash3 = hashlib.pbkdf2_hmac("sha512", hash2, algo.salt1, 100000) - - return sha256(algo.salt2 + hash3 + algo.salt2) - - -# noinspection PyPep8Naming -def compute_check(r: types.account.Password, password: str) -> types.InputCheckPasswordSRP: - algo = r.current_algo - - p_bytes = algo.p - p = btoi(algo.p) - - g_bytes = itob(algo.g) - g = algo.g - - B_bytes = r.srp_B - B = btoi(B_bytes) - - srp_id = r.srp_id - - x_bytes = compute_hash(algo, password) - x = btoi(x_bytes) - - g_x = pow(g, x, p) - - k_bytes = sha256(p_bytes + g_bytes) - k = btoi(k_bytes) - - kg_x = (k * g_x) % p - - while True: - a_bytes = os.urandom(256) - a = btoi(a_bytes) - - A = pow(g, a, p) - A_bytes = itob(A) - - u = btoi(sha256(A_bytes + B_bytes)) - - if u > 0: - break - - g_b = (B - kg_x) % p - - ux = u * x - a_ux = a + ux - S = pow(g_b, a_ux, p) - S_bytes = itob(S) - - K_bytes = sha256(S_bytes) - - M1_bytes = sha256( - xor(sha256(p_bytes), sha256(g_bytes)) - + sha256(algo.salt1) - + sha256(algo.salt2) - + A_bytes - + B_bytes - + K_bytes - ) - - return types.InputCheckPasswordSRP(srp_id=srp_id, A=A_bytes, M1=M1_bytes) diff --git a/pyrogram/client/types/inline_mode/inline_query_result.py b/pyrogram/client/types/inline_mode/inline_query_result.py deleted file mode 100644 index 6525585b..00000000 --- a/pyrogram/client/types/inline_mode/inline_query_result.py +++ /dev/null @@ -1,71 +0,0 @@ -# Pyrogram - Telegram MTProto API Client Library for Python -# Copyright (C) 2017-2020 Dan -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . - -from uuid import uuid4 - -from ..bots_and_keyboards import InlineKeyboardMarkup -from ..input_message_content import InputMessageContent -from ..object import Object - -"""- :obj:`InlineQueryResultCachedAudio` - - :obj:`InlineQueryResultCachedDocument` - - :obj:`InlineQueryResultCachedGif` - - :obj:`InlineQueryResultCachedMpeg4Gif` - - :obj:`InlineQueryResultCachedPhoto` - - :obj:`InlineQueryResultCachedSticker` - - :obj:`InlineQueryResultCachedVideo` - - :obj:`InlineQueryResultCachedVoice` - - :obj:`InlineQueryResultAudio` - - :obj:`InlineQueryResultContact` - - :obj:`InlineQueryResultGame` - - :obj:`InlineQueryResultDocument` - - :obj:`InlineQueryResultGif` - - :obj:`InlineQueryResultLocation` - - :obj:`InlineQueryResultMpeg4Gif` - - :obj:`InlineQueryResultPhoto` - - :obj:`InlineQueryResultVenue` - - :obj:`InlineQueryResultVideo` - - :obj:`InlineQueryResultVoice`""" - - -class InlineQueryResult(Object): - """One result of an inline query. - - Pyrogram currently supports results of the following types: - - - :obj:`InlineQueryResultArticle` - - :obj:`InlineQueryResultPhoto` - - :obj:`InlineQueryResultAnimation` - """ - - def __init__( - self, - type: str, - id: str, - input_message_content: InputMessageContent, - reply_markup: InlineKeyboardMarkup - ): - super().__init__() - - self.type = type - self.id = str(uuid4()) if id is None else str(id) - self.input_message_content = input_message_content - self.reply_markup = reply_markup - - async def write(self): - pass diff --git a/pyrogram/connection/transport/tcp/tcp.py b/pyrogram/connection/transport/tcp/tcp.py index 070907f4..b2ff5391 100644 --- a/pyrogram/connection/transport/tcp/tcp.py +++ b/pyrogram/connection/transport/tcp/tcp.py @@ -68,7 +68,7 @@ class TCP: password=proxy.get("password", None) ) - log.info("Using proxy {}:{}".format(hostname, port)) + log.info(f"Using proxy {hostname}:{port}") else: self.socket = socks.socksocket( socket.AF_INET6 if ipv6 diff --git a/pyrogram/connection/transport/tcp/tcp_abridged_o.py b/pyrogram/connection/transport/tcp/tcp_abridged_o.py index e8f8fba0..c7b24159 100644 --- a/pyrogram/connection/transport/tcp/tcp_abridged_o.py +++ b/pyrogram/connection/transport/tcp/tcp_abridged_o.py @@ -19,8 +19,8 @@ import logging import os +from pyrogram.crypto import aes from .tcp import TCP -from ....crypto.aes import AES log = logging.getLogger(__name__) @@ -49,7 +49,7 @@ class TCPAbridgedO(TCP): self.encrypt = (nonce[8:40], nonce[40:56], bytearray(1)) self.decrypt = (temp[0:32], temp[32:48], bytearray(1)) - nonce[56:64] = AES.ctr256_encrypt(nonce, *self.encrypt)[56:64] + nonce[56:64] = aes.ctr256_encrypt(nonce, *self.encrypt)[56:64] await super().send(nonce) @@ -57,7 +57,7 @@ class TCPAbridgedO(TCP): length = len(data) // 4 await super().send( - AES.ctr256_encrypt( + aes.ctr256_encrypt( (bytes([length]) if length <= 126 else b"\x7f" + length.to_bytes(3, "little")) @@ -72,7 +72,7 @@ class TCPAbridgedO(TCP): if length is None: return None - length = AES.ctr256_decrypt(length, *self.decrypt) + length = aes.ctr256_decrypt(length, *self.decrypt) if length == b"\x7f": length = await super().recv(3) @@ -80,11 +80,11 @@ class TCPAbridgedO(TCP): if length is None: return None - length = AES.ctr256_decrypt(length, *self.decrypt) + length = aes.ctr256_decrypt(length, *self.decrypt) data = await super().recv(int.from_bytes(length, "little") * 4) if data is None: return None - return AES.ctr256_decrypt(data, *self.decrypt) + return aes.ctr256_decrypt(data, *self.decrypt) diff --git a/pyrogram/connection/transport/tcp/tcp_intermediate_o.py b/pyrogram/connection/transport/tcp/tcp_intermediate_o.py index 4b4f4610..c0c1d915 100644 --- a/pyrogram/connection/transport/tcp/tcp_intermediate_o.py +++ b/pyrogram/connection/transport/tcp/tcp_intermediate_o.py @@ -20,8 +20,8 @@ import logging import os from struct import pack, unpack +from pyrogram.crypto import aes from .tcp import TCP -from ....crypto.aes import AES log = logging.getLogger(__name__) @@ -50,13 +50,13 @@ class TCPIntermediateO(TCP): self.encrypt = (nonce[8:40], nonce[40:56], bytearray(1)) self.decrypt = (temp[0:32], temp[32:48], bytearray(1)) - nonce[56:64] = AES.ctr256_encrypt(nonce, *self.encrypt)[56:64] + nonce[56:64] = aes.ctr256_encrypt(nonce, *self.encrypt)[56:64] await super().send(nonce) async def send(self, data: bytes, *args): await super().send( - AES.ctr256_encrypt( + aes.ctr256_encrypt( pack(". - -from .aes import AES -from .kdf import KDF -from .mtproto import MTProto -from .prime import Prime -from .rsa import RSA diff --git a/pyrogram/crypto/aes.py b/pyrogram/crypto/aes.py index 47c9c094..c094fd22 100644 --- a/pyrogram/crypto/aes.py +++ b/pyrogram/crypto/aes.py @@ -26,30 +26,28 @@ try: log.info("Using TgCrypto") - class AES: - @classmethod - def ige256_encrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes: - return tgcrypto.ige256_encrypt(data, key, iv) + def ige256_encrypt(data: bytes, key: bytes, iv: bytes) -> bytes: + return tgcrypto.ige256_encrypt(data, key, iv) - @classmethod - def ige256_decrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes: - return tgcrypto.ige256_decrypt(data, key, iv) - @staticmethod - def ctr256_encrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes: - return tgcrypto.ctr256_encrypt(data, key, iv, state or bytearray(1)) + def ige256_decrypt(data: bytes, key: bytes, iv: bytes) -> bytes: + return tgcrypto.ige256_decrypt(data, key, iv) - @staticmethod - def ctr256_decrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes: - return tgcrypto.ctr256_decrypt(data, key, iv, state or bytearray(1)) - @staticmethod - def xor(a: bytes, b: bytes) -> bytes: - return int.to_bytes( - int.from_bytes(a, "big") ^ int.from_bytes(b, "big"), - len(a), - "big", - ) + def ctr256_encrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes: + return tgcrypto.ctr256_encrypt(data, key, iv, state or bytearray(1)) + + + def ctr256_decrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes: + return tgcrypto.ctr256_decrypt(data, key, iv, state or bytearray(1)) + + + def xor(a: bytes, b: bytes) -> bytes: + return int.to_bytes( + int.from_bytes(a, "big") ^ int.from_bytes(b, "big"), + len(a), + "big", + ) except ImportError: import pyaes @@ -60,75 +58,73 @@ except ImportError: ) - class AES: - @classmethod - def ige256_encrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes: - return cls.ige(data, key, iv, True) + def ige256_encrypt(data: bytes, key: bytes, iv: bytes) -> bytes: + return ige(data, key, iv, True) - @classmethod - def ige256_decrypt(cls, data: bytes, key: bytes, iv: bytes) -> bytes: - return cls.ige(data, key, iv, False) - @classmethod - def ctr256_encrypt(cls, data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes: - return cls.ctr(data, key, iv, state or bytearray(1)) + def ige256_decrypt(data: bytes, key: bytes, iv: bytes) -> bytes: + return ige(data, key, iv, False) - @classmethod - def ctr256_decrypt(cls, data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes: - return cls.ctr(data, key, iv, state or bytearray(1)) - @staticmethod - def xor(a: bytes, b: bytes) -> bytes: - return int.to_bytes( - int.from_bytes(a, "big") ^ int.from_bytes(b, "big"), - len(a), - "big", - ) + def ctr256_encrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes: + return ctr(data, key, iv, state or bytearray(1)) - @classmethod - def ige(cls, data: bytes, key: bytes, iv: bytes, encrypt: bool) -> bytes: - cipher = pyaes.AES(key) - iv_1 = iv[:16] - iv_2 = iv[16:] + def ctr256_decrypt(data: bytes, key: bytes, iv: bytearray, state: bytearray = None) -> bytes: + return ctr(data, key, iv, state or bytearray(1)) - data = [data[i: i + 16] for i in range(0, len(data), 16)] - if encrypt: - for i, chunk in enumerate(data): - iv_1 = data[i] = cls.xor(cipher.encrypt(cls.xor(chunk, iv_1)), iv_2) - iv_2 = chunk - else: - for i, chunk in enumerate(data): - iv_2 = data[i] = cls.xor(cipher.decrypt(cls.xor(chunk, iv_2)), iv_1) - iv_1 = chunk + def xor(a: bytes, b: bytes) -> bytes: + return int.to_bytes( + int.from_bytes(a, "big") ^ int.from_bytes(b, "big"), + len(a), + "big", + ) - return b"".join(data) - @classmethod - def ctr(cls, data: bytes, key: bytes, iv: bytearray, state: bytearray) -> bytes: - cipher = pyaes.AES(key) + def ige(data: bytes, key: bytes, iv: bytes, encrypt: bool) -> bytes: + cipher = pyaes.AES(key) - out = bytearray(data) - chunk = cipher.encrypt(iv) + iv_1 = iv[:16] + iv_2 = iv[16:] - for i in range(0, len(data), 16): - for j in range(0, min(len(data) - i, 16)): - out[i + j] ^= chunk[state[0]] + data = [data[i: i + 16] for i in range(0, len(data), 16)] - state[0] += 1 + if encrypt: + for i, chunk in enumerate(data): + iv_1 = data[i] = xor(cipher.encrypt(xor(chunk, iv_1)), iv_2) + iv_2 = chunk + else: + for i, chunk in enumerate(data): + iv_2 = data[i] = xor(cipher.decrypt(xor(chunk, iv_2)), iv_1) + iv_1 = chunk - if state[0] >= 16: - state[0] = 0 + return b"".join(data) - if state[0] == 0: - for k in range(15, -1, -1): - try: - iv[k] += 1 - break - except ValueError: - iv[k] = 0 - chunk = cipher.encrypt(iv) + def ctr(data: bytes, key: bytes, iv: bytearray, state: bytearray) -> bytes: + cipher = pyaes.AES(key) - return out + out = bytearray(data) + chunk = cipher.encrypt(iv) + + for i in range(0, len(data), 16): + for j in range(0, min(len(data) - i, 16)): + out[i + j] ^= chunk[state[0]] + + state[0] += 1 + + if state[0] >= 16: + state[0] = 0 + + if state[0] == 0: + for k in range(15, -1, -1): + try: + iv[k] += 1 + break + except ValueError: + iv[k] = 0 + + chunk = cipher.encrypt(iv) + + return out diff --git a/pyrogram/crypto/mtproto.py b/pyrogram/crypto/mtproto.py index 539976d6..b67b49f1 100644 --- a/pyrogram/crypto/mtproto.py +++ b/pyrogram/crypto/mtproto.py @@ -20,43 +20,54 @@ from hashlib import sha256 from io import BytesIO from os import urandom -from pyrogram.api.core import Message, Long -from . import AES, KDF +from pyrogram.raw.core import Message, Long +from . import aes -class MTProto: - @staticmethod - def pack(message: Message, salt: int, session_id: bytes, auth_key: bytes, auth_key_id: bytes) -> bytes: - data = Long(salt) + session_id + message.write() - padding = urandom(-(len(data) + 12) % 16 + 12) +def kdf(auth_key: bytes, msg_key: bytes, outgoing: bool) -> tuple: + # https://core.telegram.org/mtproto/description#defining-aes-key-and-initialization-vector + x = 0 if outgoing else 8 - # 88 = 88 + 0 (outgoing message) - msg_key_large = sha256(auth_key[88: 88 + 32] + data + padding).digest() - msg_key = msg_key_large[8:24] - aes_key, aes_iv = KDF(auth_key, msg_key, True) + sha256_a = sha256(msg_key + auth_key[x: x + 36]).digest() + sha256_b = sha256(auth_key[x + 40:x + 76] + msg_key).digest() # 76 = 40 + 36 - return auth_key_id + msg_key + AES.ige256_encrypt(data + padding, aes_key, aes_iv) + aes_key = sha256_a[:8] + sha256_b[8:24] + sha256_a[24:32] + aes_iv = sha256_b[:8] + sha256_a[8:24] + sha256_b[24:32] - @staticmethod - def unpack(b: BytesIO, session_id: bytes, auth_key: bytes, auth_key_id: bytes) -> Message: - assert b.read(8) == auth_key_id, b.getvalue() + return aes_key, aes_iv - msg_key = b.read(16) - aes_key, aes_iv = KDF(auth_key, msg_key, False) - data = BytesIO(AES.ige256_decrypt(b.read(), aes_key, aes_iv)) - data.read(8) - # https://core.telegram.org/mtproto/security_guidelines#checking-session-id - assert data.read(8) == session_id +def pack(message: Message, salt: int, session_id: bytes, auth_key: bytes, auth_key_id: bytes) -> bytes: + data = Long(salt) + session_id + message.write() + padding = urandom(-(len(data) + 12) % 16 + 12) - message = Message.read(data) + # 88 = 88 + 0 (outgoing message) + msg_key_large = sha256(auth_key[88: 88 + 32] + data + padding).digest() + msg_key = msg_key_large[8:24] + aes_key, aes_iv = kdf(auth_key, msg_key, True) - # https://core.telegram.org/mtproto/security_guidelines#checking-sha256-hash-value-of-msg-key - # https://core.telegram.org/mtproto/security_guidelines#checking-message-length - # 96 = 88 + 8 (incoming message) - assert msg_key == sha256(auth_key[96:96 + 32] + data.getvalue()).digest()[8:24] + return auth_key_id + msg_key + aes.ige256_encrypt(data + padding, aes_key, aes_iv) - # https://core.telegram.org/mtproto/security_guidelines#checking-msg-id - assert message.msg_id % 2 != 0 - return message +def unpack(b: BytesIO, session_id: bytes, auth_key: bytes, auth_key_id: bytes) -> Message: + assert b.read(8) == auth_key_id, b.getvalue() + + msg_key = b.read(16) + aes_key, aes_iv = kdf(auth_key, msg_key, False) + data = BytesIO(aes.ige256_decrypt(b.read(), aes_key, aes_iv)) + data.read(8) + + # https://core.telegram.org/mtproto/security_guidelines#checking-session-id + assert data.read(8) == session_id + + message = Message.read(data) + + # https://core.telegram.org/mtproto/security_guidelines#checking-sha256-hash-value-of-msg-key + # https://core.telegram.org/mtproto/security_guidelines#checking-message-length + # 96 = 88 + 8 (incoming message) + assert msg_key == sha256(auth_key[96:96 + 32] + data.getvalue()).digest()[8:24] + + # https://core.telegram.org/mtproto/security_guidelines#checking-msg-id + assert message.msg_id % 2 != 0 + + return message diff --git a/pyrogram/crypto/prime.py b/pyrogram/crypto/prime.py index 0ca59ea7..22210726 100644 --- a/pyrogram/crypto/prime.py +++ b/pyrogram/crypto/prime.py @@ -18,68 +18,65 @@ from random import randint +CURRENT_DH_PRIME = int( + "C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F" + "48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C37" + "20FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F64" + "2477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4" + "A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754" + "FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4" + "E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F" + "0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5B", + 16 +) -class Prime: - CURRENT_DH_PRIME = int( - "C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F" - "48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C37" - "20FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F64" - "2477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4" - "A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754" - "FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4" - "E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F" - "0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5B", - 16 - ) - # Recursive variant - # @classmethod - # def gcd(cls, a: int, b: int) -> int: - # return cls.gcd(b, a % b) if b else a +# Recursive variant +# def gcd(cls, a: int, b: int) -> int: +# return cls.gcd(b, a % b) if b else a - @staticmethod - def gcd(a: int, b: int) -> int: - while b: - a, b = b, a % b +def gcd(a: int, b: int) -> int: + while b: + a, b = b, a % b - return a + return a - @classmethod - def decompose(cls, pq: int) -> int: - # https://comeoncodeon.wordpress.com/2010/09/18/pollard-rho-brent-integer-factorization/ - if pq % 2 == 0: - return 2 - y, c, m = randint(1, pq - 1), randint(1, pq - 1), randint(1, pq - 1) - g = r = q = 1 - x = ys = 0 +def decompose(pq: int) -> int: + # https://comeoncodeon.wordpress.com/2010/09/18/pollard-rho-brent-integer-factorization/ + if pq % 2 == 0: + return 2 - while g == 1: - x = y + y, c, m = randint(1, pq - 1), randint(1, pq - 1), randint(1, pq - 1) + g = r = q = 1 + x = ys = 0 - for i in range(r): + while g == 1: + x = y + + for i in range(r): + y = (pow(y, 2, pq) + c) % pq + + k = 0 + + while k < r and g == 1: + ys = y + + for i in range(min(m, r - k)): y = (pow(y, 2, pq) + c) % pq + q = q * (abs(x - y)) % pq - k = 0 + g = gcd(q, pq) + k += m - while k < r and g == 1: - ys = y + r *= 2 - for i in range(min(m, r - k)): - y = (pow(y, 2, pq) + c) % pq - q = q * (abs(x - y)) % pq + if g == pq: + while True: + ys = (pow(ys, 2, pq) + c) % pq + g = gcd(abs(x - ys), pq) - g = cls.gcd(q, pq) - k += m + if g > 1: + break - r *= 2 - - if g == pq: - while True: - ys = (pow(ys, 2, pq) + c) % pq - g = cls.gcd(abs(x - ys), pq) - - if g > 1: - break - - return g + return g diff --git a/pyrogram/crypto/rsa.py b/pyrogram/crypto/rsa.py index 268a91e4..aaec8df6 100644 --- a/pyrogram/crypto/rsa.py +++ b/pyrogram/crypto/rsa.py @@ -20,194 +20,192 @@ from collections import namedtuple PublicKey = namedtuple("PublicKey", ["m", "e"]) +# To get modulus and exponent: +# +# [RSA PUBLIC KEY]: +# grep -v -- - public.key | tr -d \\n | base64 -d | openssl asn1parse -inform DER -i +# +# [PUBLIC KEY]: +# openssl rsa -pubin -in key -text -noout -class RSA: - # To get modulus and exponent: - # - # [RSA PUBLIC KEY]: - # grep -v -- - public.key | tr -d \\n | base64 -d | openssl asn1parse -inform DER -i - # - # [PUBLIC KEY]: - # openssl rsa -pubin -in key -text -noout +server_public_keys = { + # -4344800451088585951 + 0xc3b42b026ce86b21 - (1 << 64): PublicKey( # Telegram servers #1 + # -----BEGIN RSA PUBLIC KEY----- + # MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6 + # lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS + # an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw + # Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+ + # 8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n + # Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB + # -----END RSA PUBLIC KEY----- + int( + "C150023E2F70DB7985DED064759CFECF0AF328E69A41DAF4D6F01B538135A6F9" + "1F8F8B2A0EC9BA9720CE352EFCF6C5680FFC424BD634864902DE0B4BD6D49F4E" + "580230E3AE97D95C8B19442B3C0A10D8F5633FECEDD6926A7F6DAB0DDB7D457F" + "9EA81B8465FCD6FFFEED114011DF91C059CAEDAF97625F6C96ECC74725556934" + "EF781D866B34F011FCE4D835A090196E9A5F0E4449AF7EB697DDB9076494CA5F" + "81104A305B6DD27665722C46B60E5DF680FB16B210607EF217652E60236C255F" + "6A28315F4083A96791D7214BF64C1DF4FD0DB1944FB26A2A57031B32EEE64AD1" + "5A8BA68885CDE74A5BFC920F6ABF59BA5C75506373E7130F9042DA922179251F", + 16 + ), # Modulus + int("010001", 16) # Exponent + ), - server_public_keys = { - # -4344800451088585951 - 0xc3b42b026ce86b21 - (1 << 64): PublicKey( # Telegram servers #1 - # -----BEGIN RSA PUBLIC KEY----- - # MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6 - # lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS - # an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw - # Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+ - # 8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n - # Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB - # -----END RSA PUBLIC KEY----- - int( - "C150023E2F70DB7985DED064759CFECF0AF328E69A41DAF4D6F01B538135A6F9" - "1F8F8B2A0EC9BA9720CE352EFCF6C5680FFC424BD634864902DE0B4BD6D49F4E" - "580230E3AE97D95C8B19442B3C0A10D8F5633FECEDD6926A7F6DAB0DDB7D457F" - "9EA81B8465FCD6FFFEED114011DF91C059CAEDAF97625F6C96ECC74725556934" - "EF781D866B34F011FCE4D835A090196E9A5F0E4449AF7EB697DDB9076494CA5F" - "81104A305B6DD27665722C46B60E5DF680FB16B210607EF217652E60236C255F" - "6A28315F4083A96791D7214BF64C1DF4FD0DB1944FB26A2A57031B32EEE64AD1" - "5A8BA68885CDE74A5BFC920F6ABF59BA5C75506373E7130F9042DA922179251F", - 16 - ), # Modulus - int("010001", 16) # Exponent - ), + # 847625836280919973 + 0x10bc35f3509f7b7a5 - (1 << 64): PublicKey( # Telegram servers #2 + # -----BEGIN PUBLIC KEY----- + # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAruw2yP/BCcsJliRoW5eB + # VBVle9dtjJw+OYED160Wybum9SXtBBLXriwt4rROd9csv0t0OHCaTmRqBcQ0J8fx + # hN6/cpR1GWgOZRUAiQxoMnlt0R93LCX/j1dnVa/gVbCjdSxpbrfY2g2L4frzjJvd + # l84Kd9ORYjDEAyFnEA7dD556OptgLQQ2e2iVNq8NZLYTzLp5YpOdO1doK+ttrltg + # gTCy5SrKeLoCPPbOgGsdxJxyz5KKcZnSLj16yE5HvJQn0CNpRdENvRUXe6tBP78O + # 39oJ8BTHp9oIjd6XWXAsp2CvK45Ol8wFXGF710w9lwCGNbmNxNYhtIkdqfsEcwR5 + # JwIDAQAB + # -----END PUBLIC KEY----- + int( + "AEEC36C8FFC109CB099624685B97815415657BD76D8C9C3E398103D7AD16C9BB" + "A6F525ED0412D7AE2C2DE2B44E77D72CBF4B7438709A4E646A05C43427C7F184" + "DEBF72947519680E651500890C6832796DD11F772C25FF8F576755AFE055B0A3" + "752C696EB7D8DA0D8BE1FAF38C9BDD97CE0A77D3916230C4032167100EDD0F9E" + "7A3A9B602D04367B689536AF0D64B613CCBA7962939D3B57682BEB6DAE5B6081" + "30B2E52ACA78BA023CF6CE806B1DC49C72CF928A7199D22E3D7AC84E47BC9427" + "D0236945D10DBD15177BAB413FBF0EDFDA09F014C7A7DA088DDE9759702CA760" + "AF2B8E4E97CC055C617BD74C3D97008635B98DC4D621B4891DA9FB0473047927", + 16 + ), # Modulus + int("010001", 16) # Exponent + ), - # 847625836280919973 - 0x10bc35f3509f7b7a5 - (1 << 64): PublicKey( # Telegram servers #2 - # -----BEGIN PUBLIC KEY----- - # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAruw2yP/BCcsJliRoW5eB - # VBVle9dtjJw+OYED160Wybum9SXtBBLXriwt4rROd9csv0t0OHCaTmRqBcQ0J8fx - # hN6/cpR1GWgOZRUAiQxoMnlt0R93LCX/j1dnVa/gVbCjdSxpbrfY2g2L4frzjJvd - # l84Kd9ORYjDEAyFnEA7dD556OptgLQQ2e2iVNq8NZLYTzLp5YpOdO1doK+ttrltg - # gTCy5SrKeLoCPPbOgGsdxJxyz5KKcZnSLj16yE5HvJQn0CNpRdENvRUXe6tBP78O - # 39oJ8BTHp9oIjd6XWXAsp2CvK45Ol8wFXGF710w9lwCGNbmNxNYhtIkdqfsEcwR5 - # JwIDAQAB - # -----END PUBLIC KEY----- - int( - "AEEC36C8FFC109CB099624685B97815415657BD76D8C9C3E398103D7AD16C9BB" - "A6F525ED0412D7AE2C2DE2B44E77D72CBF4B7438709A4E646A05C43427C7F184" - "DEBF72947519680E651500890C6832796DD11F772C25FF8F576755AFE055B0A3" - "752C696EB7D8DA0D8BE1FAF38C9BDD97CE0A77D3916230C4032167100EDD0F9E" - "7A3A9B602D04367B689536AF0D64B613CCBA7962939D3B57682BEB6DAE5B6081" - "30B2E52ACA78BA023CF6CE806B1DC49C72CF928A7199D22E3D7AC84E47BC9427" - "D0236945D10DBD15177BAB413FBF0EDFDA09F014C7A7DA088DDE9759702CA760" - "AF2B8E4E97CC055C617BD74C3D97008635B98DC4D621B4891DA9FB0473047927", - 16 - ), # Modulus - int("010001", 16) # Exponent - ), + # 1562291298945373506 + 0x115ae5fa8b5529542 - (1 << 64): PublicKey( # Telegram servers #3 + # -----BEGIN PUBLIC KEY----- + # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvfLHfYH2r9R70w8prHbl + # Wt/nDkh+XkgpflqQVcnAfSuTtO05lNPspQmL8Y2XjVT4t8cT6xAkdgfmmvnvRPOO + # KPi0OfJXoRVylFzAQG/j83u5K3kRLbae7fLccVhKZhY46lvsueI1hQdLgNV9n1cQ + # 3TDS2pQOCtovG4eDl9wacrXOJTG2990VjgnIKNA0UMoP+KF03qzryqIt3oTvZq03 + # DyWdGK+AZjgBLaDKSnC6qD2cFY81UryRWOab8zKkWAnhw2kFpcqhI0jdV5QaSCEx + # vnsjVaX0Y1N0870931/5Jb9ICe4nweZ9kSDF/gip3kWLG0o8XQpChDfyvsqB9OLV + # /wIDAQAB + # -----END PUBLIC KEY----- + int( + "BDF2C77D81F6AFD47BD30F29AC76E55ADFE70E487E5E48297E5A9055C9C07D2B" + "93B4ED3994D3ECA5098BF18D978D54F8B7C713EB10247607E69AF9EF44F38E28" + "F8B439F257A11572945CC0406FE3F37BB92B79112DB69EEDF2DC71584A661638" + "EA5BECB9E23585074B80D57D9F5710DD30D2DA940E0ADA2F1B878397DC1A72B5" + "CE2531B6F7DD158E09C828D03450CA0FF8A174DEACEBCAA22DDE84EF66AD370F" + "259D18AF806638012DA0CA4A70BAA83D9C158F3552BC9158E69BF332A45809E1" + "C36905A5CAA12348DD57941A482131BE7B2355A5F4635374F3BD3DDF5FF925BF" + "4809EE27C1E67D9120C5FE08A9DE458B1B4A3C5D0A428437F2BECA81F4E2D5FF", + 16 + ), # Modulus + int("010001", 16) # Exponent + ), - # 1562291298945373506 - 0x115ae5fa8b5529542 - (1 << 64): PublicKey( # Telegram servers #3 - # -----BEGIN PUBLIC KEY----- - # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvfLHfYH2r9R70w8prHbl - # Wt/nDkh+XkgpflqQVcnAfSuTtO05lNPspQmL8Y2XjVT4t8cT6xAkdgfmmvnvRPOO - # KPi0OfJXoRVylFzAQG/j83u5K3kRLbae7fLccVhKZhY46lvsueI1hQdLgNV9n1cQ - # 3TDS2pQOCtovG4eDl9wacrXOJTG2990VjgnIKNA0UMoP+KF03qzryqIt3oTvZq03 - # DyWdGK+AZjgBLaDKSnC6qD2cFY81UryRWOab8zKkWAnhw2kFpcqhI0jdV5QaSCEx - # vnsjVaX0Y1N0870931/5Jb9ICe4nweZ9kSDF/gip3kWLG0o8XQpChDfyvsqB9OLV - # /wIDAQAB - # -----END PUBLIC KEY----- - int( - "BDF2C77D81F6AFD47BD30F29AC76E55ADFE70E487E5E48297E5A9055C9C07D2B" - "93B4ED3994D3ECA5098BF18D978D54F8B7C713EB10247607E69AF9EF44F38E28" - "F8B439F257A11572945CC0406FE3F37BB92B79112DB69EEDF2DC71584A661638" - "EA5BECB9E23585074B80D57D9F5710DD30D2DA940E0ADA2F1B878397DC1A72B5" - "CE2531B6F7DD158E09C828D03450CA0FF8A174DEACEBCAA22DDE84EF66AD370F" - "259D18AF806638012DA0CA4A70BAA83D9C158F3552BC9158E69BF332A45809E1" - "C36905A5CAA12348DD57941A482131BE7B2355A5F4635374F3BD3DDF5FF925BF" - "4809EE27C1E67D9120C5FE08A9DE458B1B4A3C5D0A428437F2BECA81F4E2D5FF", - 16 - ), # Modulus - int("010001", 16) # Exponent - ), + # -5859577972006586033 + 0xaeae98e13cd7f94f - (1 << 64): PublicKey( # Telegram servers #4 + # -----BEGIN PUBLIC KEY----- + # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/ditzm+mPND6xkhzwFI + # z6J/968CtkcSE/7Z2qAJiXbmZ3UDJPGrzqTDHkO30R8VeRM/Kz2f4nR05GIFiITl + # 4bEjvpy7xqRDspJcCFIOcyXm8abVDhF+th6knSU0yLtNKuQVP6voMrnt9MV1X92L + # GZQLgdHZbPQz0Z5qIpaKhdyA8DEvWWvSUwwc+yi1/gGaybwlzZwqXYoPOhwMebzK + # Uk0xW14htcJrRrq+PXXQbRzTMynseCoPIoke0dtCodbA3qQxQovE16q9zz4Otv2k + # 4j63cz53J+mhkVWAeWxVGI0lltJmWtEYK6er8VqqWot3nqmWMXogrgRLggv/Nbbo + # oQIDAQAB + # -----END PUBLIC KEY----- + int( + "B3F762B739BE98F343EB1921CF0148CFA27FF7AF02B6471213FED9DAA0098976" + "E667750324F1ABCEA4C31E43B7D11F1579133F2B3D9FE27474E462058884E5E1" + "B123BE9CBBC6A443B2925C08520E7325E6F1A6D50E117EB61EA49D2534C8BB4D" + "2AE4153FABE832B9EDF4C5755FDD8B19940B81D1D96CF433D19E6A22968A85DC" + "80F0312F596BD2530C1CFB28B5FE019AC9BC25CD9C2A5D8A0F3A1C0C79BCCA52" + "4D315B5E21B5C26B46BABE3D75D06D1CD33329EC782A0F22891ED1DB42A1D6C0" + "DEA431428BC4D7AABDCF3E0EB6FDA4E23EB7733E7727E9A1915580796C55188D" + "2596D2665AD1182BA7ABF15AAA5A8B779EA996317A20AE044B820BFF35B6E8A1", + 16 + ), # Modulus + int("010001", 16) # Exponent + ), - # -5859577972006586033 - 0xaeae98e13cd7f94f - (1 << 64): PublicKey( # Telegram servers #4 - # -----BEGIN PUBLIC KEY----- - # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/ditzm+mPND6xkhzwFI - # z6J/968CtkcSE/7Z2qAJiXbmZ3UDJPGrzqTDHkO30R8VeRM/Kz2f4nR05GIFiITl - # 4bEjvpy7xqRDspJcCFIOcyXm8abVDhF+th6knSU0yLtNKuQVP6voMrnt9MV1X92L - # GZQLgdHZbPQz0Z5qIpaKhdyA8DEvWWvSUwwc+yi1/gGaybwlzZwqXYoPOhwMebzK - # Uk0xW14htcJrRrq+PXXQbRzTMynseCoPIoke0dtCodbA3qQxQovE16q9zz4Otv2k - # 4j63cz53J+mhkVWAeWxVGI0lltJmWtEYK6er8VqqWot3nqmWMXogrgRLggv/Nbbo - # oQIDAQAB - # -----END PUBLIC KEY----- - int( - "B3F762B739BE98F343EB1921CF0148CFA27FF7AF02B6471213FED9DAA0098976" - "E667750324F1ABCEA4C31E43B7D11F1579133F2B3D9FE27474E462058884E5E1" - "B123BE9CBBC6A443B2925C08520E7325E6F1A6D50E117EB61EA49D2534C8BB4D" - "2AE4153FABE832B9EDF4C5755FDD8B19940B81D1D96CF433D19E6A22968A85DC" - "80F0312F596BD2530C1CFB28B5FE019AC9BC25CD9C2A5D8A0F3A1C0C79BCCA52" - "4D315B5E21B5C26B46BABE3D75D06D1CD33329EC782A0F22891ED1DB42A1D6C0" - "DEA431428BC4D7AABDCF3E0EB6FDA4E23EB7733E7727E9A1915580796C55188D" - "2596D2665AD1182BA7ABF15AAA5A8B779EA996317A20AE044B820BFF35B6E8A1", - 16 - ), # Modulus - int("010001", 16) # Exponent - ), + # 6491968696586960280 + 0x15a181b2235057d98 - (1 << 64): PublicKey( # Telegram servers #5 + # -----BEGIN PUBLIC KEY----- + # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvmpxVY7ld/8DAjz6F6q0 + # 5shjg8/4p6047bn6/m8yPy1RBsvIyvuDuGnP/RzPEhzXQ9UJ5Ynmh2XJZgHoE9xb + # nfxL5BXHplJhMtADXKM9bWB11PU1Eioc3+AXBB8QiNFBn2XI5UkO5hPhbb9mJpjA + # 9Uhw8EdfqJP8QetVsI/xrCEbwEXe0xvifRLJbY08/Gp66KpQvy7g8w7VB8wlgePe + # xW3pT13Ap6vuC+mQuJPyiHvSxjEKHgqePji9NP3tJUFQjcECqcm0yV7/2d0t/pbC + # m+ZH1sadZspQCEPPrtbkQBlvHb4OLiIWPGHKSMeRFvp3IWcmdJqXahxLCUS1Eh6M + # AQIDAQAB + # -----END PUBLIC KEY----- + int( + "BE6A71558EE577FF03023CFA17AAB4E6C86383CFF8A7AD38EDB9FAFE6F323F2D" + "5106CBC8CAFB83B869CFFD1CCF121CD743D509E589E68765C96601E813DC5B9D" + "FC4BE415C7A6526132D0035CA33D6D6075D4F535122A1CDFE017041F1088D141" + "9F65C8E5490EE613E16DBF662698C0F54870F0475FA893FC41EB55B08FF1AC21" + "1BC045DED31BE27D12C96D8D3CFC6A7AE8AA50BF2EE0F30ED507CC2581E3DEC5" + "6DE94F5DC0A7ABEE0BE990B893F2887BD2C6310A1E0A9E3E38BD34FDED254150" + "8DC102A9C9B4C95EFFD9DD2DFE96C29BE647D6C69D66CA500843CFAED6E44019" + "6F1DBE0E2E22163C61CA48C79116FA77216726749A976A1C4B0944B5121E8C01", + 16 + ), # Modulus + int("010001", 16) # Exponent + ), - # 6491968696586960280 - 0x15a181b2235057d98 - (1 << 64): PublicKey( # Telegram servers #5 - # -----BEGIN PUBLIC KEY----- - # MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvmpxVY7ld/8DAjz6F6q0 - # 5shjg8/4p6047bn6/m8yPy1RBsvIyvuDuGnP/RzPEhzXQ9UJ5Ynmh2XJZgHoE9xb - # nfxL5BXHplJhMtADXKM9bWB11PU1Eioc3+AXBB8QiNFBn2XI5UkO5hPhbb9mJpjA - # 9Uhw8EdfqJP8QetVsI/xrCEbwEXe0xvifRLJbY08/Gp66KpQvy7g8w7VB8wlgePe - # xW3pT13Ap6vuC+mQuJPyiHvSxjEKHgqePji9NP3tJUFQjcECqcm0yV7/2d0t/pbC - # m+ZH1sadZspQCEPPrtbkQBlvHb4OLiIWPGHKSMeRFvp3IWcmdJqXahxLCUS1Eh6M - # AQIDAQAB - # -----END PUBLIC KEY----- - int( - "BE6A71558EE577FF03023CFA17AAB4E6C86383CFF8A7AD38EDB9FAFE6F323F2D" - "5106CBC8CAFB83B869CFFD1CCF121CD743D509E589E68765C96601E813DC5B9D" - "FC4BE415C7A6526132D0035CA33D6D6075D4F535122A1CDFE017041F1088D141" - "9F65C8E5490EE613E16DBF662698C0F54870F0475FA893FC41EB55B08FF1AC21" - "1BC045DED31BE27D12C96D8D3CFC6A7AE8AA50BF2EE0F30ED507CC2581E3DEC5" - "6DE94F5DC0A7ABEE0BE990B893F2887BD2C6310A1E0A9E3E38BD34FDED254150" - "8DC102A9C9B4C95EFFD9DD2DFE96C29BE647D6C69D66CA500843CFAED6E44019" - "6F1DBE0E2E22163C61CA48C79116FA77216726749A976A1C4B0944B5121E8C01", - 16 - ), # Modulus - int("010001", 16) # Exponent - ), + # 6427105915145367799 + 0x15931aac70e0d30f7 - (1 << 64): PublicKey( # CDN DC-121 + # -----BEGIN RSA PUBLIC KEY----- + # MIIBCgKCAQEA+Lf3PvgE1yxbJUCMaEAkV0QySTVpnaDjiednB5RbtNWjCeqSVakY + # HbqqGMIIv5WCGdFdrqOfMNcNSstPtSU6R9UmRw6tquOIykpSuUOje9H+4XVIKquj + # yL2ISdK+4ZOMl4hCMkqauw4bP1Sbr03vZRQbU6qEA04V4j879BAyBVhr3WG9+Zi+ + # t5XfGSTgSExPYEl8rZNHYNV5RB+BuroVH2HLTOpT/mJVfikYpgjfWF5ldezV4Wo9 + # LSH0cZGSFIaeJl8d0A8Eiy5B9gtBO8mL+XfQRKOOmr7a4BM4Ro2de5rr2i2od7hY + # Xd3DO9FRSl4y1zA8Am48Rfd95WHF3N/OmQIDAQAB + # -----END RSA PUBLIC KEY----- + int( + "F8B7F73EF804D72C5B25408C6840245744324935699DA0E389E76707945BB4D5" + "A309EA9255A9181DBAAA18C208BF958219D15DAEA39F30D70D4ACB4FB5253A47" + "D526470EADAAE388CA4A52B943A37BD1FEE175482AABA3C8BD8849D2BEE1938C" + "978842324A9ABB0E1B3F549BAF4DEF65141B53AA84034E15E23F3BF410320558" + "6BDD61BDF998BEB795DF1924E0484C4F60497CAD934760D579441F81BABA151F" + "61CB4CEA53FE62557E2918A608DF585E6575ECD5E16A3D2D21F471919214869E" + "265F1DD00F048B2E41F60B413BC98BF977D044A38E9ABEDAE01338468D9D7B9A" + "EBDA2DA877B8585DDDC33BD1514A5E32D7303C026E3C45F77DE561C5DCDFCE99", + 16 + ), # Modulus + int("010001", 16) # Exponent + ), - # 6427105915145367799 - 0x15931aac70e0d30f7 - (1 << 64): PublicKey( # CDN DC-121 - # -----BEGIN RSA PUBLIC KEY----- - # MIIBCgKCAQEA+Lf3PvgE1yxbJUCMaEAkV0QySTVpnaDjiednB5RbtNWjCeqSVakY - # HbqqGMIIv5WCGdFdrqOfMNcNSstPtSU6R9UmRw6tquOIykpSuUOje9H+4XVIKquj - # yL2ISdK+4ZOMl4hCMkqauw4bP1Sbr03vZRQbU6qEA04V4j879BAyBVhr3WG9+Zi+ - # t5XfGSTgSExPYEl8rZNHYNV5RB+BuroVH2HLTOpT/mJVfikYpgjfWF5ldezV4Wo9 - # LSH0cZGSFIaeJl8d0A8Eiy5B9gtBO8mL+XfQRKOOmr7a4BM4Ro2de5rr2i2od7hY - # Xd3DO9FRSl4y1zA8Am48Rfd95WHF3N/OmQIDAQAB - # -----END RSA PUBLIC KEY----- - int( - "F8B7F73EF804D72C5B25408C6840245744324935699DA0E389E76707945BB4D5" - "A309EA9255A9181DBAAA18C208BF958219D15DAEA39F30D70D4ACB4FB5253A47" - "D526470EADAAE388CA4A52B943A37BD1FEE175482AABA3C8BD8849D2BEE1938C" - "978842324A9ABB0E1B3F549BAF4DEF65141B53AA84034E15E23F3BF410320558" - "6BDD61BDF998BEB795DF1924E0484C4F60497CAD934760D579441F81BABA151F" - "61CB4CEA53FE62557E2918A608DF585E6575ECD5E16A3D2D21F471919214869E" - "265F1DD00F048B2E41F60B413BC98BF977D044A38E9ABEDAE01338468D9D7B9A" - "EBDA2DA877B8585DDDC33BD1514A5E32D7303C026E3C45F77DE561C5DCDFCE99", - 16 - ), # Modulus - int("010001", 16) # Exponent - ), + # 2685959930972952888 + 0x1254672538e935938 - (1 << 64): PublicKey( # CDN DC-140 + # -----BEGIN RSA PUBLIC KEY----- + # MIIBCgKCAQEAzuHVC7sE50Kho/yDVZtWnlmA5Bf/aM8KZY3WzS16w6w1sBqipj8o + # gMGG7ULbGBtYmKEaI7IIJO6WM2m1MaXVnsqS8d7PaGAZiy8rSN3S7S2a8wp4RXZe + # hs0JAXvZeIz45iByCMBfycbJKmSweYkesRUI7hUO8eQhmm/UYUEpJY7VOt0Iemiu + # URSpqlRQ2FlcyHahYUNcvbICb4+/AP7coKBn6cB5FyzM7MCcKxbEKOx3Y3MUnbZq + # q5pN6/eRazkegyrlp4kuJ94KsbRFHFX5Dx8uzjrO9wi8LF7gIgZu5DRMcmjXJKq6 + # rGZ2Z9cnrD8pVu1L2vcInd4K6ximZS2hbwIDAQAB + # -----END RSA PUBLIC KEY----- + int( + "CEE1D50BBB04E742A1A3FC83559B569E5980E417FF68CF0A658DD6CD2D7AC3AC" + "35B01AA2A63F2880C186ED42DB181B5898A11A23B20824EE963369B531A5D59E" + "CA92F1DECF6860198B2F2B48DDD2ED2D9AF30A7845765E86CD09017BD9788CF8" + "E6207208C05FC9C6C92A64B079891EB11508EE150EF1E4219A6FD4614129258E" + "D53ADD087A68AE5114A9AA5450D8595CC876A161435CBDB2026F8FBF00FEDCA0" + "A067E9C079172CCCECC09C2B16C428EC776373149DB66AAB9A4DEBF7916B391E" + "832AE5A7892E27DE0AB1B4451C55F90F1F2ECE3ACEF708BC2C5EE022066EE434" + "4C7268D724AABAAC667667D727AC3F2956ED4BDAF7089DDE0AEB18A6652DA16F", + 16 + ), # Modulus + int("010001", 16) # Exponent + ) +} - # 2685959930972952888 - 0x1254672538e935938 - (1 << 64): PublicKey( # CDN DC-140 - # -----BEGIN RSA PUBLIC KEY----- - # MIIBCgKCAQEAzuHVC7sE50Kho/yDVZtWnlmA5Bf/aM8KZY3WzS16w6w1sBqipj8o - # gMGG7ULbGBtYmKEaI7IIJO6WM2m1MaXVnsqS8d7PaGAZiy8rSN3S7S2a8wp4RXZe - # hs0JAXvZeIz45iByCMBfycbJKmSweYkesRUI7hUO8eQhmm/UYUEpJY7VOt0Iemiu - # URSpqlRQ2FlcyHahYUNcvbICb4+/AP7coKBn6cB5FyzM7MCcKxbEKOx3Y3MUnbZq - # q5pN6/eRazkegyrlp4kuJ94KsbRFHFX5Dx8uzjrO9wi8LF7gIgZu5DRMcmjXJKq6 - # rGZ2Z9cnrD8pVu1L2vcInd4K6ximZS2hbwIDAQAB - # -----END RSA PUBLIC KEY----- - int( - "CEE1D50BBB04E742A1A3FC83559B569E5980E417FF68CF0A658DD6CD2D7AC3AC" - "35B01AA2A63F2880C186ED42DB181B5898A11A23B20824EE963369B531A5D59E" - "CA92F1DECF6860198B2F2B48DDD2ED2D9AF30A7845765E86CD09017BD9788CF8" - "E6207208C05FC9C6C92A64B079891EB11508EE150EF1E4219A6FD4614129258E" - "D53ADD087A68AE5114A9AA5450D8595CC876A161435CBDB2026F8FBF00FEDCA0" - "A067E9C079172CCCECC09C2B16C428EC776373149DB66AAB9A4DEBF7916B391E" - "832AE5A7892E27DE0AB1B4451C55F90F1F2ECE3ACEF708BC2C5EE022066EE434" - "4C7268D724AABAAC667667D727AC3F2956ED4BDAF7089DDE0AEB18A6652DA16F", - 16 - ), # Modulus - int("010001", 16) # Exponent - ) - } - @classmethod - def encrypt(cls, data: bytes, fingerprint: int) -> bytes: - return pow( - int.from_bytes(data, "big"), - cls.server_public_keys[fingerprint].e, - cls.server_public_keys[fingerprint].m - ).to_bytes(256, "big") +def encrypt(data: bytes, fingerprint: int) -> bytes: + return pow( + int.from_bytes(data, "big"), + server_public_keys[fingerprint].e, + server_public_keys[fingerprint].m + ).to_bytes(256, "big") diff --git a/pyrogram/client/ext/dispatcher.py b/pyrogram/dispatcher.py similarity index 72% rename from pyrogram/client/ext/dispatcher.py rename to pyrogram/dispatcher.py index d8308944..40a6dcf4 100644 --- a/pyrogram/client/ext/dispatcher.py +++ b/pyrogram/dispatcher.py @@ -21,7 +21,13 @@ import logging from collections import OrderedDict import pyrogram -from pyrogram.api.types import ( +from pyrogram import utils +from pyrogram.handlers import ( + CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, + UserStatusHandler, RawUpdateHandler, InlineQueryHandler, PollHandler, + ChosenInlineResultHandler +) +from pyrogram.raw.types import ( UpdateNewMessage, UpdateNewChannelMessage, UpdateNewScheduledMessage, UpdateEditMessage, UpdateEditChannelMessage, UpdateDeleteMessages, UpdateDeleteChannelMessages, @@ -29,12 +35,6 @@ from pyrogram.api.types import ( UpdateUserStatus, UpdateBotInlineQuery, UpdateMessagePoll, UpdateBotInlineSend ) -from . import utils -from ..handlers import ( - CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, - UserStatusHandler, RawUpdateHandler, InlineQueryHandler, PollHandler, - ChosenInlineResultHandler -) log = logging.getLogger(__name__) @@ -63,18 +63,18 @@ class Dispatcher: MESSAGE_UPDATES = NEW_MESSAGE_UPDATES + EDIT_MESSAGE_UPDATES - def __init__(self, client, workers: int): + def __init__(self, client: "pyrogram.Client"): self.client = client - self.workers = workers + self.loop = asyncio.get_event_loop() - self.update_worker_tasks = [] + self.handler_worker_tasks = [] self.locks_list = [] self.updates_queue = asyncio.Queue() self.groups = OrderedDict() async def message_parser(update, users, chats): - return await pyrogram.Message._parse( + return await pyrogram.types.Message._parse( self.client, update.message, users, chats, isinstance(update, UpdateNewScheduledMessage) ), MessageHandler @@ -83,19 +83,19 @@ class Dispatcher: return utils.parse_deleted_messages(self.client, update), DeletedMessagesHandler async def callback_query_parser(update, users, chats): - return await pyrogram.CallbackQuery._parse(self.client, update, users), CallbackQueryHandler + return await pyrogram.types.CallbackQuery._parse(self.client, update, users), CallbackQueryHandler async def user_status_parser(update, users, chats): - return pyrogram.User._parse_user_status(self.client, update), UserStatusHandler + return pyrogram.types.User._parse_user_status(self.client, update), UserStatusHandler async def inline_query_parser(update, users, chats): - return pyrogram.InlineQuery._parse(self.client, update, users), InlineQueryHandler + return pyrogram.types.InlineQuery._parse(self.client, update, users), InlineQueryHandler async def poll_parser(update, users, chats): - return pyrogram.Poll._parse_update(self.client, update), PollHandler + return pyrogram.types.Poll._parse_update(self.client, update), PollHandler async def chosen_inline_result_parser(update, users, chats): - return pyrogram.ChosenInlineResult._parse(self.client, update, users), ChosenInlineResultHandler + return pyrogram.types.ChosenInlineResult._parse(self.client, update, users), ChosenInlineResultHandler self.update_parsers = { Dispatcher.MESSAGE_UPDATES: message_parser, @@ -110,26 +110,28 @@ class Dispatcher: self.update_parsers = {key: value for key_tuple, value in self.update_parsers.items() for key in key_tuple} async def start(self): - for i in range(self.workers): - self.locks_list.append(asyncio.Lock()) + if not self.client.no_updates: + for i in range(self.client.workers): + self.locks_list.append(asyncio.Lock()) - self.update_worker_tasks.append( - asyncio.ensure_future(self.update_worker(self.locks_list[-1])) - ) + self.handler_worker_tasks.append( + asyncio.ensure_future(self.handler_worker(self.locks_list[-1])) + ) - logging.info("Started {} UpdateWorkerTasks".format(self.workers)) + logging.info(f"Started {self.client.workers} HandlerTasks") async def stop(self): - for i in range(self.workers): - self.updates_queue.put_nowait(None) + if not self.client.no_updates: + for i in range(self.client.workers): + self.updates_queue.put_nowait(None) - for i in self.update_worker_tasks: - await i + for i in self.handler_worker_tasks: + await i - self.update_worker_tasks.clear() - self.groups.clear() + self.handler_worker_tasks.clear() + self.groups.clear() - logging.info("Stopped {} UpdateWorkerTasks".format(self.workers)) + logging.info(f"Stopped {self.client.workers} HandlerTasks") def add_handler(self, handler, group: int): async def fn(): @@ -155,7 +157,7 @@ class Dispatcher: try: if group not in self.groups: - raise ValueError("Group {} does not exist. Handler was not removed.".format(group)) + raise ValueError(f"Group {group} does not exist. Handler was not removed.") self.groups[group].remove(handler) finally: @@ -164,7 +166,7 @@ class Dispatcher: asyncio.ensure_future(fn()) - async def update_worker(self, lock): + async def handler_worker(self, lock): while True: packet = await self.updates_queue.get() @@ -188,9 +190,8 @@ class Dispatcher: if isinstance(handler, handler_type): try: - if (await handler.check(parsed_update)): + if await handler.check(self.client, parsed_update): args = (parsed_update,) - except Exception as e: log.error(e, exc_info=True) continue @@ -202,7 +203,15 @@ class Dispatcher: continue try: - await handler.callback(self.client, *args) + if asyncio.iscoroutinefunction(handler.callback): + await handler.callback(self.client, *args) + else: + await self.loop.run_in_executor( + self.client.executor, + handler.callback, + self.client, + *args + ) except pyrogram.StopPropagation: raise except pyrogram.ContinuePropagation: diff --git a/pyrogram/emoji.py b/pyrogram/emoji.py new file mode 100644 index 00000000..7c55df60 --- /dev/null +++ b/pyrogram/emoji.py @@ -0,0 +1,3521 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +GRINNING_FACE = "\U0001f600" +GRINNING_FACE_WITH_BIG_EYES = "\U0001f603" +GRINNING_FACE_WITH_SMILING_EYES = "\U0001f604" +BEAMING_FACE_WITH_SMILING_EYES = "\U0001f601" +GRINNING_SQUINTING_FACE = "\U0001f606" +GRINNING_FACE_WITH_SWEAT = "\U0001f605" +ROLLING_ON_THE_FLOOR_LAUGHING = "\U0001f923" +FACE_WITH_TEARS_OF_JOY = "\U0001f602" +SLIGHTLY_SMILING_FACE = "\U0001f642" +UPSIDE_DOWN_FACE = "\U0001f643" +WINKING_FACE = "\U0001f609" +SMILING_FACE_WITH_SMILING_EYES = "\U0001f60a" +SMILING_FACE_WITH_HALO = "\U0001f607" +SMILING_FACE_WITH_HEARTS = "\U0001f970" +SMILING_FACE_WITH_HEART_EYES = "\U0001f60d" +STAR_STRUCK = "\U0001f929" +FACE_BLOWING_A_KISS = "\U0001f618" +KISSING_FACE = "\U0001f617" +SMILING_FACE = "\u263a\ufe0f" +KISSING_FACE_WITH_CLOSED_EYES = "\U0001f61a" +KISSING_FACE_WITH_SMILING_EYES = "\U0001f619" +SMILING_FACE_WITH_TEAR = "\U0001f972" +FACE_SAVORING_FOOD = "\U0001f60b" +FACE_WITH_TONGUE = "\U0001f61b" +WINKING_FACE_WITH_TONGUE = "\U0001f61c" +ZANY_FACE = "\U0001f92a" +SQUINTING_FACE_WITH_TONGUE = "\U0001f61d" +MONEY_MOUTH_FACE = "\U0001f911" +HUGGING_FACE = "\U0001f917" +FACE_WITH_HAND_OVER_MOUTH = "\U0001f92d" +SHUSHING_FACE = "\U0001f92b" +THINKING_FACE = "\U0001f914" +ZIPPER_MOUTH_FACE = "\U0001f910" +FACE_WITH_RAISED_EYEBROW = "\U0001f928" +NEUTRAL_FACE = "\U0001f610" +EXPRESSIONLESS_FACE = "\U0001f611" +FACE_WITHOUT_MOUTH = "\U0001f636" +SMIRKING_FACE = "\U0001f60f" +UNAMUSED_FACE = "\U0001f612" +FACE_WITH_ROLLING_EYES = "\U0001f644" +GRIMACING_FACE = "\U0001f62c" +LYING_FACE = "\U0001f925" +RELIEVED_FACE = "\U0001f60c" +PENSIVE_FACE = "\U0001f614" +SLEEPY_FACE = "\U0001f62a" +DROOLING_FACE = "\U0001f924" +SLEEPING_FACE = "\U0001f634" +FACE_WITH_MEDICAL_MASK = "\U0001f637" +FACE_WITH_THERMOMETER = "\U0001f912" +FACE_WITH_HEAD_BANDAGE = "\U0001f915" +NAUSEATED_FACE = "\U0001f922" +FACE_VOMITING = "\U0001f92e" +SNEEZING_FACE = "\U0001f927" +HOT_FACE = "\U0001f975" +COLD_FACE = "\U0001f976" +WOOZY_FACE = "\U0001f974" +DIZZY_FACE = "\U0001f635" +EXPLODING_HEAD = "\U0001f92f" +COWBOY_HAT_FACE = "\U0001f920" +PARTYING_FACE = "\U0001f973" +DISGUISED_FACE = "\U0001f978" +SMILING_FACE_WITH_SUNGLASSES = "\U0001f60e" +NERD_FACE = "\U0001f913" +FACE_WITH_MONOCLE = "\U0001f9d0" +CONFUSED_FACE = "\U0001f615" +WORRIED_FACE = "\U0001f61f" +SLIGHTLY_FROWNING_FACE = "\U0001f641" +FROWNING_FACE = "\u2639\ufe0f" +FACE_WITH_OPEN_MOUTH = "\U0001f62e" +HUSHED_FACE = "\U0001f62f" +ASTONISHED_FACE = "\U0001f632" +FLUSHED_FACE = "\U0001f633" +PLEADING_FACE = "\U0001f97a" +FROWNING_FACE_WITH_OPEN_MOUTH = "\U0001f626" +ANGUISHED_FACE = "\U0001f627" +FEARFUL_FACE = "\U0001f628" +ANXIOUS_FACE_WITH_SWEAT = "\U0001f630" +SAD_BUT_RELIEVED_FACE = "\U0001f625" +CRYING_FACE = "\U0001f622" +LOUDLY_CRYING_FACE = "\U0001f62d" +FACE_SCREAMING_IN_FEAR = "\U0001f631" +CONFOUNDED_FACE = "\U0001f616" +PERSEVERING_FACE = "\U0001f623" +DISAPPOINTED_FACE = "\U0001f61e" +DOWNCAST_FACE_WITH_SWEAT = "\U0001f613" +WEARY_FACE = "\U0001f629" +TIRED_FACE = "\U0001f62b" +YAWNING_FACE = "\U0001f971" +FACE_WITH_STEAM_FROM_NOSE = "\U0001f624" +POUTING_FACE = "\U0001f621" +ANGRY_FACE = "\U0001f620" +FACE_WITH_SYMBOLS_ON_MOUTH = "\U0001f92c" +SMILING_FACE_WITH_HORNS = "\U0001f608" +ANGRY_FACE_WITH_HORNS = "\U0001f47f" +SKULL = "\U0001f480" +SKULL_AND_CROSSBONES = "\u2620\ufe0f" +PILE_OF_POO = "\U0001f4a9" +CLOWN_FACE = "\U0001f921" +OGRE = "\U0001f479" +GOBLIN = "\U0001f47a" +GHOST = "\U0001f47b" +ALIEN = "\U0001f47d" +ALIEN_MONSTER = "\U0001f47e" +ROBOT = "\U0001f916" +GRINNING_CAT = "\U0001f63a" +GRINNING_CAT_WITH_SMILING_EYES = "\U0001f638" +CAT_WITH_TEARS_OF_JOY = "\U0001f639" +SMILING_CAT_WITH_HEART_EYES = "\U0001f63b" +CAT_WITH_WRY_SMILE = "\U0001f63c" +KISSING_CAT = "\U0001f63d" +WEARY_CAT = "\U0001f640" +CRYING_CAT = "\U0001f63f" +POUTING_CAT = "\U0001f63e" +SEE_NO_EVIL_MONKEY = "\U0001f648" +HEAR_NO_EVIL_MONKEY = "\U0001f649" +SPEAK_NO_EVIL_MONKEY = "\U0001f64a" +KISS_MARK = "\U0001f48b" +LOVE_LETTER = "\U0001f48c" +HEART_WITH_ARROW = "\U0001f498" +HEART_WITH_RIBBON = "\U0001f49d" +SPARKLING_HEART = "\U0001f496" +GROWING_HEART = "\U0001f497" +BEATING_HEART = "\U0001f493" +REVOLVING_HEARTS = "\U0001f49e" +TWO_HEARTS = "\U0001f495" +HEART_DECORATION = "\U0001f49f" +HEART_EXCLAMATION = "\u2763\ufe0f" +BROKEN_HEART = "\U0001f494" +RED_HEART = "\u2764\ufe0f" +ORANGE_HEART = "\U0001f9e1" +YELLOW_HEART = "\U0001f49b" +GREEN_HEART = "\U0001f49a" +BLUE_HEART = "\U0001f499" +PURPLE_HEART = "\U0001f49c" +BROWN_HEART = "\U0001f90e" +BLACK_HEART = "\U0001f5a4" +WHITE_HEART = "\U0001f90d" +HUNDRED_POINTS = "\U0001f4af" +ANGER_SYMBOL = "\U0001f4a2" +COLLISION = "\U0001f4a5" +DIZZY = "\U0001f4ab" +SWEAT_DROPLETS = "\U0001f4a6" +DASHING_AWAY = "\U0001f4a8" +HOLE = "\U0001f573\ufe0f" +BOMB = "\U0001f4a3" +SPEECH_BALLOON = "\U0001f4ac" +EYE_IN_SPEECH_BUBBLE = "\U0001f441\ufe0f\u200d\U0001f5e8\ufe0f" +LEFT_SPEECH_BUBBLE = "\U0001f5e8\ufe0f" +RIGHT_ANGER_BUBBLE = "\U0001f5ef\ufe0f" +THOUGHT_BALLOON = "\U0001f4ad" +ZZZ = "\U0001f4a4" +WAVING_HAND = "\U0001f44b" +WAVING_HAND_LIGHT_SKIN_TONE = "\U0001f44b\U0001f3fb" +WAVING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44b\U0001f3fc" +WAVING_HAND_MEDIUM_SKIN_TONE = "\U0001f44b\U0001f3fd" +WAVING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f44b\U0001f3fe" +WAVING_HAND_DARK_SKIN_TONE = "\U0001f44b\U0001f3ff" +RAISED_BACK_OF_HAND = "\U0001f91a" +RAISED_BACK_OF_HAND_LIGHT_SKIN_TONE = "\U0001f91a\U0001f3fb" +RAISED_BACK_OF_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f91a\U0001f3fc" +RAISED_BACK_OF_HAND_MEDIUM_SKIN_TONE = "\U0001f91a\U0001f3fd" +RAISED_BACK_OF_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f91a\U0001f3fe" +RAISED_BACK_OF_HAND_DARK_SKIN_TONE = "\U0001f91a\U0001f3ff" +HAND_WITH_FINGERS_SPLAYED = "\U0001f590\ufe0f" +HAND_WITH_FINGERS_SPLAYED_LIGHT_SKIN_TONE = "\U0001f590\U0001f3fb" +HAND_WITH_FINGERS_SPLAYED_MEDIUM_LIGHT_SKIN_TONE = "\U0001f590\U0001f3fc" +HAND_WITH_FINGERS_SPLAYED_MEDIUM_SKIN_TONE = "\U0001f590\U0001f3fd" +HAND_WITH_FINGERS_SPLAYED_MEDIUM_DARK_SKIN_TONE = "\U0001f590\U0001f3fe" +HAND_WITH_FINGERS_SPLAYED_DARK_SKIN_TONE = "\U0001f590\U0001f3ff" +RAISED_HAND = "\u270b" +RAISED_HAND_LIGHT_SKIN_TONE = "\u270b\U0001f3fb" +RAISED_HAND_MEDIUM_LIGHT_SKIN_TONE = "\u270b\U0001f3fc" +RAISED_HAND_MEDIUM_SKIN_TONE = "\u270b\U0001f3fd" +RAISED_HAND_MEDIUM_DARK_SKIN_TONE = "\u270b\U0001f3fe" +RAISED_HAND_DARK_SKIN_TONE = "\u270b\U0001f3ff" +VULCAN_SALUTE = "\U0001f596" +VULCAN_SALUTE_LIGHT_SKIN_TONE = "\U0001f596\U0001f3fb" +VULCAN_SALUTE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f596\U0001f3fc" +VULCAN_SALUTE_MEDIUM_SKIN_TONE = "\U0001f596\U0001f3fd" +VULCAN_SALUTE_MEDIUM_DARK_SKIN_TONE = "\U0001f596\U0001f3fe" +VULCAN_SALUTE_DARK_SKIN_TONE = "\U0001f596\U0001f3ff" +OK_HAND = "\U0001f44c" +OK_HAND_LIGHT_SKIN_TONE = "\U0001f44c\U0001f3fb" +OK_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44c\U0001f3fc" +OK_HAND_MEDIUM_SKIN_TONE = "\U0001f44c\U0001f3fd" +OK_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f44c\U0001f3fe" +OK_HAND_DARK_SKIN_TONE = "\U0001f44c\U0001f3ff" +PINCHED_FINGERS = "\U0001f90c" +PINCHED_FINGERS_LIGHT_SKIN_TONE = "\U0001f90c\U0001f3fb" +PINCHED_FINGERS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f90c\U0001f3fc" +PINCHED_FINGERS_MEDIUM_SKIN_TONE = "\U0001f90c\U0001f3fd" +PINCHED_FINGERS_MEDIUM_DARK_SKIN_TONE = "\U0001f90c\U0001f3fe" +PINCHED_FINGERS_DARK_SKIN_TONE = "\U0001f90c\U0001f3ff" +PINCHING_HAND = "\U0001f90f" +PINCHING_HAND_LIGHT_SKIN_TONE = "\U0001f90f\U0001f3fb" +PINCHING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f90f\U0001f3fc" +PINCHING_HAND_MEDIUM_SKIN_TONE = "\U0001f90f\U0001f3fd" +PINCHING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f90f\U0001f3fe" +PINCHING_HAND_DARK_SKIN_TONE = "\U0001f90f\U0001f3ff" +VICTORY_HAND = "\u270c\ufe0f" +VICTORY_HAND_LIGHT_SKIN_TONE = "\u270c\U0001f3fb" +VICTORY_HAND_MEDIUM_LIGHT_SKIN_TONE = "\u270c\U0001f3fc" +VICTORY_HAND_MEDIUM_SKIN_TONE = "\u270c\U0001f3fd" +VICTORY_HAND_MEDIUM_DARK_SKIN_TONE = "\u270c\U0001f3fe" +VICTORY_HAND_DARK_SKIN_TONE = "\u270c\U0001f3ff" +CROSSED_FINGERS = "\U0001f91e" +CROSSED_FINGERS_LIGHT_SKIN_TONE = "\U0001f91e\U0001f3fb" +CROSSED_FINGERS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f91e\U0001f3fc" +CROSSED_FINGERS_MEDIUM_SKIN_TONE = "\U0001f91e\U0001f3fd" +CROSSED_FINGERS_MEDIUM_DARK_SKIN_TONE = "\U0001f91e\U0001f3fe" +CROSSED_FINGERS_DARK_SKIN_TONE = "\U0001f91e\U0001f3ff" +LOVE_YOU_GESTURE = "\U0001f91f" +LOVE_YOU_GESTURE_LIGHT_SKIN_TONE = "\U0001f91f\U0001f3fb" +LOVE_YOU_GESTURE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f91f\U0001f3fc" +LOVE_YOU_GESTURE_MEDIUM_SKIN_TONE = "\U0001f91f\U0001f3fd" +LOVE_YOU_GESTURE_MEDIUM_DARK_SKIN_TONE = "\U0001f91f\U0001f3fe" +LOVE_YOU_GESTURE_DARK_SKIN_TONE = "\U0001f91f\U0001f3ff" +SIGN_OF_THE_HORNS = "\U0001f918" +SIGN_OF_THE_HORNS_LIGHT_SKIN_TONE = "\U0001f918\U0001f3fb" +SIGN_OF_THE_HORNS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f918\U0001f3fc" +SIGN_OF_THE_HORNS_MEDIUM_SKIN_TONE = "\U0001f918\U0001f3fd" +SIGN_OF_THE_HORNS_MEDIUM_DARK_SKIN_TONE = "\U0001f918\U0001f3fe" +SIGN_OF_THE_HORNS_DARK_SKIN_TONE = "\U0001f918\U0001f3ff" +CALL_ME_HAND = "\U0001f919" +CALL_ME_HAND_LIGHT_SKIN_TONE = "\U0001f919\U0001f3fb" +CALL_ME_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f919\U0001f3fc" +CALL_ME_HAND_MEDIUM_SKIN_TONE = "\U0001f919\U0001f3fd" +CALL_ME_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f919\U0001f3fe" +CALL_ME_HAND_DARK_SKIN_TONE = "\U0001f919\U0001f3ff" +BACKHAND_INDEX_POINTING_LEFT = "\U0001f448" +BACKHAND_INDEX_POINTING_LEFT_LIGHT_SKIN_TONE = "\U0001f448\U0001f3fb" +BACKHAND_INDEX_POINTING_LEFT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f448\U0001f3fc" +BACKHAND_INDEX_POINTING_LEFT_MEDIUM_SKIN_TONE = "\U0001f448\U0001f3fd" +BACKHAND_INDEX_POINTING_LEFT_MEDIUM_DARK_SKIN_TONE = "\U0001f448\U0001f3fe" +BACKHAND_INDEX_POINTING_LEFT_DARK_SKIN_TONE = "\U0001f448\U0001f3ff" +BACKHAND_INDEX_POINTING_RIGHT = "\U0001f449" +BACKHAND_INDEX_POINTING_RIGHT_LIGHT_SKIN_TONE = "\U0001f449\U0001f3fb" +BACKHAND_INDEX_POINTING_RIGHT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f449\U0001f3fc" +BACKHAND_INDEX_POINTING_RIGHT_MEDIUM_SKIN_TONE = "\U0001f449\U0001f3fd" +BACKHAND_INDEX_POINTING_RIGHT_MEDIUM_DARK_SKIN_TONE = "\U0001f449\U0001f3fe" +BACKHAND_INDEX_POINTING_RIGHT_DARK_SKIN_TONE = "\U0001f449\U0001f3ff" +BACKHAND_INDEX_POINTING_UP = "\U0001f446" +BACKHAND_INDEX_POINTING_UP_LIGHT_SKIN_TONE = "\U0001f446\U0001f3fb" +BACKHAND_INDEX_POINTING_UP_MEDIUM_LIGHT_SKIN_TONE = "\U0001f446\U0001f3fc" +BACKHAND_INDEX_POINTING_UP_MEDIUM_SKIN_TONE = "\U0001f446\U0001f3fd" +BACKHAND_INDEX_POINTING_UP_MEDIUM_DARK_SKIN_TONE = "\U0001f446\U0001f3fe" +BACKHAND_INDEX_POINTING_UP_DARK_SKIN_TONE = "\U0001f446\U0001f3ff" +MIDDLE_FINGER = "\U0001f595" +MIDDLE_FINGER_LIGHT_SKIN_TONE = "\U0001f595\U0001f3fb" +MIDDLE_FINGER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f595\U0001f3fc" +MIDDLE_FINGER_MEDIUM_SKIN_TONE = "\U0001f595\U0001f3fd" +MIDDLE_FINGER_MEDIUM_DARK_SKIN_TONE = "\U0001f595\U0001f3fe" +MIDDLE_FINGER_DARK_SKIN_TONE = "\U0001f595\U0001f3ff" +BACKHAND_INDEX_POINTING_DOWN = "\U0001f447" +BACKHAND_INDEX_POINTING_DOWN_LIGHT_SKIN_TONE = "\U0001f447\U0001f3fb" +BACKHAND_INDEX_POINTING_DOWN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f447\U0001f3fc" +BACKHAND_INDEX_POINTING_DOWN_MEDIUM_SKIN_TONE = "\U0001f447\U0001f3fd" +BACKHAND_INDEX_POINTING_DOWN_MEDIUM_DARK_SKIN_TONE = "\U0001f447\U0001f3fe" +BACKHAND_INDEX_POINTING_DOWN_DARK_SKIN_TONE = "\U0001f447\U0001f3ff" +INDEX_POINTING_UP = "\u261d\ufe0f" +INDEX_POINTING_UP_LIGHT_SKIN_TONE = "\u261d\U0001f3fb" +INDEX_POINTING_UP_MEDIUM_LIGHT_SKIN_TONE = "\u261d\U0001f3fc" +INDEX_POINTING_UP_MEDIUM_SKIN_TONE = "\u261d\U0001f3fd" +INDEX_POINTING_UP_MEDIUM_DARK_SKIN_TONE = "\u261d\U0001f3fe" +INDEX_POINTING_UP_DARK_SKIN_TONE = "\u261d\U0001f3ff" +THUMBS_UP = "\U0001f44d" +THUMBS_UP_LIGHT_SKIN_TONE = "\U0001f44d\U0001f3fb" +THUMBS_UP_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44d\U0001f3fc" +THUMBS_UP_MEDIUM_SKIN_TONE = "\U0001f44d\U0001f3fd" +THUMBS_UP_MEDIUM_DARK_SKIN_TONE = "\U0001f44d\U0001f3fe" +THUMBS_UP_DARK_SKIN_TONE = "\U0001f44d\U0001f3ff" +THUMBS_DOWN = "\U0001f44e" +THUMBS_DOWN_LIGHT_SKIN_TONE = "\U0001f44e\U0001f3fb" +THUMBS_DOWN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44e\U0001f3fc" +THUMBS_DOWN_MEDIUM_SKIN_TONE = "\U0001f44e\U0001f3fd" +THUMBS_DOWN_MEDIUM_DARK_SKIN_TONE = "\U0001f44e\U0001f3fe" +THUMBS_DOWN_DARK_SKIN_TONE = "\U0001f44e\U0001f3ff" +RAISED_FIST = "\u270a" +RAISED_FIST_LIGHT_SKIN_TONE = "\u270a\U0001f3fb" +RAISED_FIST_MEDIUM_LIGHT_SKIN_TONE = "\u270a\U0001f3fc" +RAISED_FIST_MEDIUM_SKIN_TONE = "\u270a\U0001f3fd" +RAISED_FIST_MEDIUM_DARK_SKIN_TONE = "\u270a\U0001f3fe" +RAISED_FIST_DARK_SKIN_TONE = "\u270a\U0001f3ff" +ONCOMING_FIST = "\U0001f44a" +ONCOMING_FIST_LIGHT_SKIN_TONE = "\U0001f44a\U0001f3fb" +ONCOMING_FIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44a\U0001f3fc" +ONCOMING_FIST_MEDIUM_SKIN_TONE = "\U0001f44a\U0001f3fd" +ONCOMING_FIST_MEDIUM_DARK_SKIN_TONE = "\U0001f44a\U0001f3fe" +ONCOMING_FIST_DARK_SKIN_TONE = "\U0001f44a\U0001f3ff" +LEFT_FACING_FIST = "\U0001f91b" +LEFT_FACING_FIST_LIGHT_SKIN_TONE = "\U0001f91b\U0001f3fb" +LEFT_FACING_FIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f91b\U0001f3fc" +LEFT_FACING_FIST_MEDIUM_SKIN_TONE = "\U0001f91b\U0001f3fd" +LEFT_FACING_FIST_MEDIUM_DARK_SKIN_TONE = "\U0001f91b\U0001f3fe" +LEFT_FACING_FIST_DARK_SKIN_TONE = "\U0001f91b\U0001f3ff" +RIGHT_FACING_FIST = "\U0001f91c" +RIGHT_FACING_FIST_LIGHT_SKIN_TONE = "\U0001f91c\U0001f3fb" +RIGHT_FACING_FIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f91c\U0001f3fc" +RIGHT_FACING_FIST_MEDIUM_SKIN_TONE = "\U0001f91c\U0001f3fd" +RIGHT_FACING_FIST_MEDIUM_DARK_SKIN_TONE = "\U0001f91c\U0001f3fe" +RIGHT_FACING_FIST_DARK_SKIN_TONE = "\U0001f91c\U0001f3ff" +CLAPPING_HANDS = "\U0001f44f" +CLAPPING_HANDS_LIGHT_SKIN_TONE = "\U0001f44f\U0001f3fb" +CLAPPING_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f44f\U0001f3fc" +CLAPPING_HANDS_MEDIUM_SKIN_TONE = "\U0001f44f\U0001f3fd" +CLAPPING_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f44f\U0001f3fe" +CLAPPING_HANDS_DARK_SKIN_TONE = "\U0001f44f\U0001f3ff" +RAISING_HANDS = "\U0001f64c" +RAISING_HANDS_LIGHT_SKIN_TONE = "\U0001f64c\U0001f3fb" +RAISING_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64c\U0001f3fc" +RAISING_HANDS_MEDIUM_SKIN_TONE = "\U0001f64c\U0001f3fd" +RAISING_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f64c\U0001f3fe" +RAISING_HANDS_DARK_SKIN_TONE = "\U0001f64c\U0001f3ff" +OPEN_HANDS = "\U0001f450" +OPEN_HANDS_LIGHT_SKIN_TONE = "\U0001f450\U0001f3fb" +OPEN_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f450\U0001f3fc" +OPEN_HANDS_MEDIUM_SKIN_TONE = "\U0001f450\U0001f3fd" +OPEN_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f450\U0001f3fe" +OPEN_HANDS_DARK_SKIN_TONE = "\U0001f450\U0001f3ff" +PALMS_UP_TOGETHER = "\U0001f932" +PALMS_UP_TOGETHER_LIGHT_SKIN_TONE = "\U0001f932\U0001f3fb" +PALMS_UP_TOGETHER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f932\U0001f3fc" +PALMS_UP_TOGETHER_MEDIUM_SKIN_TONE = "\U0001f932\U0001f3fd" +PALMS_UP_TOGETHER_MEDIUM_DARK_SKIN_TONE = "\U0001f932\U0001f3fe" +PALMS_UP_TOGETHER_DARK_SKIN_TONE = "\U0001f932\U0001f3ff" +HANDSHAKE = "\U0001f91d" +FOLDED_HANDS = "\U0001f64f" +FOLDED_HANDS_LIGHT_SKIN_TONE = "\U0001f64f\U0001f3fb" +FOLDED_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64f\U0001f3fc" +FOLDED_HANDS_MEDIUM_SKIN_TONE = "\U0001f64f\U0001f3fd" +FOLDED_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f64f\U0001f3fe" +FOLDED_HANDS_DARK_SKIN_TONE = "\U0001f64f\U0001f3ff" +WRITING_HAND = "\u270d\ufe0f" +WRITING_HAND_LIGHT_SKIN_TONE = "\u270d\U0001f3fb" +WRITING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\u270d\U0001f3fc" +WRITING_HAND_MEDIUM_SKIN_TONE = "\u270d\U0001f3fd" +WRITING_HAND_MEDIUM_DARK_SKIN_TONE = "\u270d\U0001f3fe" +WRITING_HAND_DARK_SKIN_TONE = "\u270d\U0001f3ff" +NAIL_POLISH = "\U0001f485" +NAIL_POLISH_LIGHT_SKIN_TONE = "\U0001f485\U0001f3fb" +NAIL_POLISH_MEDIUM_LIGHT_SKIN_TONE = "\U0001f485\U0001f3fc" +NAIL_POLISH_MEDIUM_SKIN_TONE = "\U0001f485\U0001f3fd" +NAIL_POLISH_MEDIUM_DARK_SKIN_TONE = "\U0001f485\U0001f3fe" +NAIL_POLISH_DARK_SKIN_TONE = "\U0001f485\U0001f3ff" +SELFIE = "\U0001f933" +SELFIE_LIGHT_SKIN_TONE = "\U0001f933\U0001f3fb" +SELFIE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f933\U0001f3fc" +SELFIE_MEDIUM_SKIN_TONE = "\U0001f933\U0001f3fd" +SELFIE_MEDIUM_DARK_SKIN_TONE = "\U0001f933\U0001f3fe" +SELFIE_DARK_SKIN_TONE = "\U0001f933\U0001f3ff" +FLEXED_BICEPS = "\U0001f4aa" +FLEXED_BICEPS_LIGHT_SKIN_TONE = "\U0001f4aa\U0001f3fb" +FLEXED_BICEPS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f4aa\U0001f3fc" +FLEXED_BICEPS_MEDIUM_SKIN_TONE = "\U0001f4aa\U0001f3fd" +FLEXED_BICEPS_MEDIUM_DARK_SKIN_TONE = "\U0001f4aa\U0001f3fe" +FLEXED_BICEPS_DARK_SKIN_TONE = "\U0001f4aa\U0001f3ff" +MECHANICAL_ARM = "\U0001f9be" +MECHANICAL_LEG = "\U0001f9bf" +LEG = "\U0001f9b5" +LEG_LIGHT_SKIN_TONE = "\U0001f9b5\U0001f3fb" +LEG_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b5\U0001f3fc" +LEG_MEDIUM_SKIN_TONE = "\U0001f9b5\U0001f3fd" +LEG_MEDIUM_DARK_SKIN_TONE = "\U0001f9b5\U0001f3fe" +LEG_DARK_SKIN_TONE = "\U0001f9b5\U0001f3ff" +FOOT = "\U0001f9b6" +FOOT_LIGHT_SKIN_TONE = "\U0001f9b6\U0001f3fb" +FOOT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b6\U0001f3fc" +FOOT_MEDIUM_SKIN_TONE = "\U0001f9b6\U0001f3fd" +FOOT_MEDIUM_DARK_SKIN_TONE = "\U0001f9b6\U0001f3fe" +FOOT_DARK_SKIN_TONE = "\U0001f9b6\U0001f3ff" +EAR = "\U0001f442" +EAR_LIGHT_SKIN_TONE = "\U0001f442\U0001f3fb" +EAR_MEDIUM_LIGHT_SKIN_TONE = "\U0001f442\U0001f3fc" +EAR_MEDIUM_SKIN_TONE = "\U0001f442\U0001f3fd" +EAR_MEDIUM_DARK_SKIN_TONE = "\U0001f442\U0001f3fe" +EAR_DARK_SKIN_TONE = "\U0001f442\U0001f3ff" +EAR_WITH_HEARING_AID = "\U0001f9bb" +EAR_WITH_HEARING_AID_LIGHT_SKIN_TONE = "\U0001f9bb\U0001f3fb" +EAR_WITH_HEARING_AID_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9bb\U0001f3fc" +EAR_WITH_HEARING_AID_MEDIUM_SKIN_TONE = "\U0001f9bb\U0001f3fd" +EAR_WITH_HEARING_AID_MEDIUM_DARK_SKIN_TONE = "\U0001f9bb\U0001f3fe" +EAR_WITH_HEARING_AID_DARK_SKIN_TONE = "\U0001f9bb\U0001f3ff" +NOSE = "\U0001f443" +NOSE_LIGHT_SKIN_TONE = "\U0001f443\U0001f3fb" +NOSE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f443\U0001f3fc" +NOSE_MEDIUM_SKIN_TONE = "\U0001f443\U0001f3fd" +NOSE_MEDIUM_DARK_SKIN_TONE = "\U0001f443\U0001f3fe" +NOSE_DARK_SKIN_TONE = "\U0001f443\U0001f3ff" +BRAIN = "\U0001f9e0" +ANATOMICAL_HEART = "\U0001fac0" +LUNGS = "\U0001fac1" +TOOTH = "\U0001f9b7" +BONE = "\U0001f9b4" +EYES = "\U0001f440" +EYE = "\U0001f441\ufe0f" +TONGUE = "\U0001f445" +MOUTH = "\U0001f444" +BABY = "\U0001f476" +BABY_LIGHT_SKIN_TONE = "\U0001f476\U0001f3fb" +BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f476\U0001f3fc" +BABY_MEDIUM_SKIN_TONE = "\U0001f476\U0001f3fd" +BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f476\U0001f3fe" +BABY_DARK_SKIN_TONE = "\U0001f476\U0001f3ff" +CHILD = "\U0001f9d2" +CHILD_LIGHT_SKIN_TONE = "\U0001f9d2\U0001f3fb" +CHILD_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d2\U0001f3fc" +CHILD_MEDIUM_SKIN_TONE = "\U0001f9d2\U0001f3fd" +CHILD_MEDIUM_DARK_SKIN_TONE = "\U0001f9d2\U0001f3fe" +CHILD_DARK_SKIN_TONE = "\U0001f9d2\U0001f3ff" +BOY = "\U0001f466" +BOY_LIGHT_SKIN_TONE = "\U0001f466\U0001f3fb" +BOY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f466\U0001f3fc" +BOY_MEDIUM_SKIN_TONE = "\U0001f466\U0001f3fd" +BOY_MEDIUM_DARK_SKIN_TONE = "\U0001f466\U0001f3fe" +BOY_DARK_SKIN_TONE = "\U0001f466\U0001f3ff" +GIRL = "\U0001f467" +GIRL_LIGHT_SKIN_TONE = "\U0001f467\U0001f3fb" +GIRL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f467\U0001f3fc" +GIRL_MEDIUM_SKIN_TONE = "\U0001f467\U0001f3fd" +GIRL_MEDIUM_DARK_SKIN_TONE = "\U0001f467\U0001f3fe" +GIRL_DARK_SKIN_TONE = "\U0001f467\U0001f3ff" +PERSON = "\U0001f9d1" +PERSON_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb" +PERSON_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc" +PERSON_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd" +PERSON_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe" +PERSON_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff" +PERSON_BLOND_HAIR = "\U0001f471" +PERSON_LIGHT_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fb" +PERSON_MEDIUM_LIGHT_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fc" +PERSON_MEDIUM_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fd" +PERSON_MEDIUM_DARK_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fe" +PERSON_DARK_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3ff" +MAN = "\U0001f468" +MAN_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb" +MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc" +MAN_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd" +MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe" +MAN_DARK_SKIN_TONE = "\U0001f468\U0001f3ff" +MAN_BEARD = "\U0001f9d4" +MAN_LIGHT_SKIN_TONE_BEARD = "\U0001f9d4\U0001f3fb" +MAN_MEDIUM_LIGHT_SKIN_TONE_BEARD = "\U0001f9d4\U0001f3fc" +MAN_MEDIUM_SKIN_TONE_BEARD = "\U0001f9d4\U0001f3fd" +MAN_MEDIUM_DARK_SKIN_TONE_BEARD = "\U0001f9d4\U0001f3fe" +MAN_DARK_SKIN_TONE_BEARD = "\U0001f9d4\U0001f3ff" +MAN_RED_HAIR = "\U0001f468\u200d\U0001f9b0" +MAN_LIGHT_SKIN_TONE_RED_HAIR = "\U0001f468\U0001f3fb\u200d\U0001f9b0" +MAN_MEDIUM_LIGHT_SKIN_TONE_RED_HAIR = "\U0001f468\U0001f3fc\u200d\U0001f9b0" +MAN_MEDIUM_SKIN_TONE_RED_HAIR = "\U0001f468\U0001f3fd\u200d\U0001f9b0" +MAN_MEDIUM_DARK_SKIN_TONE_RED_HAIR = "\U0001f468\U0001f3fe\u200d\U0001f9b0" +MAN_DARK_SKIN_TONE_RED_HAIR = "\U0001f468\U0001f3ff\u200d\U0001f9b0" +MAN_CURLY_HAIR = "\U0001f468\u200d\U0001f9b1" +MAN_LIGHT_SKIN_TONE_CURLY_HAIR = "\U0001f468\U0001f3fb\u200d\U0001f9b1" +MAN_MEDIUM_LIGHT_SKIN_TONE_CURLY_HAIR = "\U0001f468\U0001f3fc\u200d\U0001f9b1" +MAN_MEDIUM_SKIN_TONE_CURLY_HAIR = "\U0001f468\U0001f3fd\u200d\U0001f9b1" +MAN_MEDIUM_DARK_SKIN_TONE_CURLY_HAIR = "\U0001f468\U0001f3fe\u200d\U0001f9b1" +MAN_DARK_SKIN_TONE_CURLY_HAIR = "\U0001f468\U0001f3ff\u200d\U0001f9b1" +MAN_WHITE_HAIR = "\U0001f468\u200d\U0001f9b3" +MAN_LIGHT_SKIN_TONE_WHITE_HAIR = "\U0001f468\U0001f3fb\u200d\U0001f9b3" +MAN_MEDIUM_LIGHT_SKIN_TONE_WHITE_HAIR = "\U0001f468\U0001f3fc\u200d\U0001f9b3" +MAN_MEDIUM_SKIN_TONE_WHITE_HAIR = "\U0001f468\U0001f3fd\u200d\U0001f9b3" +MAN_MEDIUM_DARK_SKIN_TONE_WHITE_HAIR = "\U0001f468\U0001f3fe\u200d\U0001f9b3" +MAN_DARK_SKIN_TONE_WHITE_HAIR = "\U0001f468\U0001f3ff\u200d\U0001f9b3" +MAN_BALD = "\U0001f468\u200d\U0001f9b2" +MAN_LIGHT_SKIN_TONE_BALD = "\U0001f468\U0001f3fb\u200d\U0001f9b2" +MAN_MEDIUM_LIGHT_SKIN_TONE_BALD = "\U0001f468\U0001f3fc\u200d\U0001f9b2" +MAN_MEDIUM_SKIN_TONE_BALD = "\U0001f468\U0001f3fd\u200d\U0001f9b2" +MAN_MEDIUM_DARK_SKIN_TONE_BALD = "\U0001f468\U0001f3fe\u200d\U0001f9b2" +MAN_DARK_SKIN_TONE_BALD = "\U0001f468\U0001f3ff\u200d\U0001f9b2" +WOMAN = "\U0001f469" +WOMAN_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb" +WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc" +WOMAN_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd" +WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe" +WOMAN_DARK_SKIN_TONE = "\U0001f469\U0001f3ff" +WOMAN_RED_HAIR = "\U0001f469\u200d\U0001f9b0" +WOMAN_LIGHT_SKIN_TONE_RED_HAIR = "\U0001f469\U0001f3fb\u200d\U0001f9b0" +WOMAN_MEDIUM_LIGHT_SKIN_TONE_RED_HAIR = "\U0001f469\U0001f3fc\u200d\U0001f9b0" +WOMAN_MEDIUM_SKIN_TONE_RED_HAIR = "\U0001f469\U0001f3fd\u200d\U0001f9b0" +WOMAN_MEDIUM_DARK_SKIN_TONE_RED_HAIR = "\U0001f469\U0001f3fe\u200d\U0001f9b0" +WOMAN_DARK_SKIN_TONE_RED_HAIR = "\U0001f469\U0001f3ff\u200d\U0001f9b0" +PERSON_RED_HAIR = "\U0001f9d1\u200d\U0001f9b0" +PERSON_LIGHT_SKIN_TONE_RED_HAIR = "\U0001f9d1\U0001f3fb\u200d\U0001f9b0" +PERSON_MEDIUM_LIGHT_SKIN_TONE_RED_HAIR = "\U0001f9d1\U0001f3fc\u200d\U0001f9b0" +PERSON_MEDIUM_SKIN_TONE_RED_HAIR = "\U0001f9d1\U0001f3fd\u200d\U0001f9b0" +PERSON_MEDIUM_DARK_SKIN_TONE_RED_HAIR = "\U0001f9d1\U0001f3fe\u200d\U0001f9b0" +PERSON_DARK_SKIN_TONE_RED_HAIR = "\U0001f9d1\U0001f3ff\u200d\U0001f9b0" +WOMAN_CURLY_HAIR = "\U0001f469\u200d\U0001f9b1" +WOMAN_LIGHT_SKIN_TONE_CURLY_HAIR = "\U0001f469\U0001f3fb\u200d\U0001f9b1" +WOMAN_MEDIUM_LIGHT_SKIN_TONE_CURLY_HAIR = "\U0001f469\U0001f3fc\u200d\U0001f9b1" +WOMAN_MEDIUM_SKIN_TONE_CURLY_HAIR = "\U0001f469\U0001f3fd\u200d\U0001f9b1" +WOMAN_MEDIUM_DARK_SKIN_TONE_CURLY_HAIR = "\U0001f469\U0001f3fe\u200d\U0001f9b1" +WOMAN_DARK_SKIN_TONE_CURLY_HAIR = "\U0001f469\U0001f3ff\u200d\U0001f9b1" +PERSON_CURLY_HAIR = "\U0001f9d1\u200d\U0001f9b1" +PERSON_LIGHT_SKIN_TONE_CURLY_HAIR = "\U0001f9d1\U0001f3fb\u200d\U0001f9b1" +PERSON_MEDIUM_LIGHT_SKIN_TONE_CURLY_HAIR = "\U0001f9d1\U0001f3fc\u200d\U0001f9b1" +PERSON_MEDIUM_SKIN_TONE_CURLY_HAIR = "\U0001f9d1\U0001f3fd\u200d\U0001f9b1" +PERSON_MEDIUM_DARK_SKIN_TONE_CURLY_HAIR = "\U0001f9d1\U0001f3fe\u200d\U0001f9b1" +PERSON_DARK_SKIN_TONE_CURLY_HAIR = "\U0001f9d1\U0001f3ff\u200d\U0001f9b1" +WOMAN_WHITE_HAIR = "\U0001f469\u200d\U0001f9b3" +WOMAN_LIGHT_SKIN_TONE_WHITE_HAIR = "\U0001f469\U0001f3fb\u200d\U0001f9b3" +WOMAN_MEDIUM_LIGHT_SKIN_TONE_WHITE_HAIR = "\U0001f469\U0001f3fc\u200d\U0001f9b3" +WOMAN_MEDIUM_SKIN_TONE_WHITE_HAIR = "\U0001f469\U0001f3fd\u200d\U0001f9b3" +WOMAN_MEDIUM_DARK_SKIN_TONE_WHITE_HAIR = "\U0001f469\U0001f3fe\u200d\U0001f9b3" +WOMAN_DARK_SKIN_TONE_WHITE_HAIR = "\U0001f469\U0001f3ff\u200d\U0001f9b3" +PERSON_WHITE_HAIR = "\U0001f9d1\u200d\U0001f9b3" +PERSON_LIGHT_SKIN_TONE_WHITE_HAIR = "\U0001f9d1\U0001f3fb\u200d\U0001f9b3" +PERSON_MEDIUM_LIGHT_SKIN_TONE_WHITE_HAIR = "\U0001f9d1\U0001f3fc\u200d\U0001f9b3" +PERSON_MEDIUM_SKIN_TONE_WHITE_HAIR = "\U0001f9d1\U0001f3fd\u200d\U0001f9b3" +PERSON_MEDIUM_DARK_SKIN_TONE_WHITE_HAIR = "\U0001f9d1\U0001f3fe\u200d\U0001f9b3" +PERSON_DARK_SKIN_TONE_WHITE_HAIR = "\U0001f9d1\U0001f3ff\u200d\U0001f9b3" +WOMAN_BALD = "\U0001f469\u200d\U0001f9b2" +WOMAN_LIGHT_SKIN_TONE_BALD = "\U0001f469\U0001f3fb\u200d\U0001f9b2" +WOMAN_MEDIUM_LIGHT_SKIN_TONE_BALD = "\U0001f469\U0001f3fc\u200d\U0001f9b2" +WOMAN_MEDIUM_SKIN_TONE_BALD = "\U0001f469\U0001f3fd\u200d\U0001f9b2" +WOMAN_MEDIUM_DARK_SKIN_TONE_BALD = "\U0001f469\U0001f3fe\u200d\U0001f9b2" +WOMAN_DARK_SKIN_TONE_BALD = "\U0001f469\U0001f3ff\u200d\U0001f9b2" +PERSON_BALD = "\U0001f9d1\u200d\U0001f9b2" +PERSON_LIGHT_SKIN_TONE_BALD = "\U0001f9d1\U0001f3fb\u200d\U0001f9b2" +PERSON_MEDIUM_LIGHT_SKIN_TONE_BALD = "\U0001f9d1\U0001f3fc\u200d\U0001f9b2" +PERSON_MEDIUM_SKIN_TONE_BALD = "\U0001f9d1\U0001f3fd\u200d\U0001f9b2" +PERSON_MEDIUM_DARK_SKIN_TONE_BALD = "\U0001f9d1\U0001f3fe\u200d\U0001f9b2" +PERSON_DARK_SKIN_TONE_BALD = "\U0001f9d1\U0001f3ff\u200d\U0001f9b2" +WOMAN_BLOND_HAIR = "\U0001f471\u200d\u2640\ufe0f" +WOMAN_LIGHT_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_MEDIUM_LIGHT_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_MEDIUM_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_MEDIUM_DARK_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_DARK_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3ff\u200d\u2640\ufe0f" +MAN_BLOND_HAIR = "\U0001f471\u200d\u2642\ufe0f" +MAN_LIGHT_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fb\u200d\u2642\ufe0f" +MAN_MEDIUM_LIGHT_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fc\u200d\u2642\ufe0f" +MAN_MEDIUM_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fd\u200d\u2642\ufe0f" +MAN_MEDIUM_DARK_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3fe\u200d\u2642\ufe0f" +MAN_DARK_SKIN_TONE_BLOND_HAIR = "\U0001f471\U0001f3ff\u200d\u2642\ufe0f" +OLDER_PERSON = "\U0001f9d3" +OLDER_PERSON_LIGHT_SKIN_TONE = "\U0001f9d3\U0001f3fb" +OLDER_PERSON_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d3\U0001f3fc" +OLDER_PERSON_MEDIUM_SKIN_TONE = "\U0001f9d3\U0001f3fd" +OLDER_PERSON_MEDIUM_DARK_SKIN_TONE = "\U0001f9d3\U0001f3fe" +OLDER_PERSON_DARK_SKIN_TONE = "\U0001f9d3\U0001f3ff" +OLD_MAN = "\U0001f474" +OLD_MAN_LIGHT_SKIN_TONE = "\U0001f474\U0001f3fb" +OLD_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f474\U0001f3fc" +OLD_MAN_MEDIUM_SKIN_TONE = "\U0001f474\U0001f3fd" +OLD_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f474\U0001f3fe" +OLD_MAN_DARK_SKIN_TONE = "\U0001f474\U0001f3ff" +OLD_WOMAN = "\U0001f475" +OLD_WOMAN_LIGHT_SKIN_TONE = "\U0001f475\U0001f3fb" +OLD_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f475\U0001f3fc" +OLD_WOMAN_MEDIUM_SKIN_TONE = "\U0001f475\U0001f3fd" +OLD_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f475\U0001f3fe" +OLD_WOMAN_DARK_SKIN_TONE = "\U0001f475\U0001f3ff" +PERSON_FROWNING = "\U0001f64d" +PERSON_FROWNING_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fb" +PERSON_FROWNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fc" +PERSON_FROWNING_MEDIUM_SKIN_TONE = "\U0001f64d\U0001f3fd" +PERSON_FROWNING_MEDIUM_DARK_SKIN_TONE = "\U0001f64d\U0001f3fe" +PERSON_FROWNING_DARK_SKIN_TONE = "\U0001f64d\U0001f3ff" +MAN_FROWNING = "\U0001f64d\u200d\u2642\ufe0f" +MAN_FROWNING_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fb\u200d\u2642\ufe0f" +MAN_FROWNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fc\u200d\u2642\ufe0f" +MAN_FROWNING_MEDIUM_SKIN_TONE = "\U0001f64d\U0001f3fd\u200d\u2642\ufe0f" +MAN_FROWNING_MEDIUM_DARK_SKIN_TONE = "\U0001f64d\U0001f3fe\u200d\u2642\ufe0f" +MAN_FROWNING_DARK_SKIN_TONE = "\U0001f64d\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_FROWNING = "\U0001f64d\u200d\u2640\ufe0f" +WOMAN_FROWNING_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_FROWNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64d\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_FROWNING_MEDIUM_SKIN_TONE = "\U0001f64d\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_FROWNING_MEDIUM_DARK_SKIN_TONE = "\U0001f64d\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_FROWNING_DARK_SKIN_TONE = "\U0001f64d\U0001f3ff\u200d\u2640\ufe0f" +PERSON_POUTING = "\U0001f64e" +PERSON_POUTING_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fb" +PERSON_POUTING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fc" +PERSON_POUTING_MEDIUM_SKIN_TONE = "\U0001f64e\U0001f3fd" +PERSON_POUTING_MEDIUM_DARK_SKIN_TONE = "\U0001f64e\U0001f3fe" +PERSON_POUTING_DARK_SKIN_TONE = "\U0001f64e\U0001f3ff" +MAN_POUTING = "\U0001f64e\u200d\u2642\ufe0f" +MAN_POUTING_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fb\u200d\u2642\ufe0f" +MAN_POUTING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fc\u200d\u2642\ufe0f" +MAN_POUTING_MEDIUM_SKIN_TONE = "\U0001f64e\U0001f3fd\u200d\u2642\ufe0f" +MAN_POUTING_MEDIUM_DARK_SKIN_TONE = "\U0001f64e\U0001f3fe\u200d\u2642\ufe0f" +MAN_POUTING_DARK_SKIN_TONE = "\U0001f64e\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_POUTING = "\U0001f64e\u200d\u2640\ufe0f" +WOMAN_POUTING_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_POUTING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64e\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_POUTING_MEDIUM_SKIN_TONE = "\U0001f64e\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_POUTING_MEDIUM_DARK_SKIN_TONE = "\U0001f64e\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_POUTING_DARK_SKIN_TONE = "\U0001f64e\U0001f3ff\u200d\u2640\ufe0f" +PERSON_GESTURING_NO = "\U0001f645" +PERSON_GESTURING_NO_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fb" +PERSON_GESTURING_NO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fc" +PERSON_GESTURING_NO_MEDIUM_SKIN_TONE = "\U0001f645\U0001f3fd" +PERSON_GESTURING_NO_MEDIUM_DARK_SKIN_TONE = "\U0001f645\U0001f3fe" +PERSON_GESTURING_NO_DARK_SKIN_TONE = "\U0001f645\U0001f3ff" +MAN_GESTURING_NO = "\U0001f645\u200d\u2642\ufe0f" +MAN_GESTURING_NO_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fb\u200d\u2642\ufe0f" +MAN_GESTURING_NO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fc\u200d\u2642\ufe0f" +MAN_GESTURING_NO_MEDIUM_SKIN_TONE = "\U0001f645\U0001f3fd\u200d\u2642\ufe0f" +MAN_GESTURING_NO_MEDIUM_DARK_SKIN_TONE = "\U0001f645\U0001f3fe\u200d\u2642\ufe0f" +MAN_GESTURING_NO_DARK_SKIN_TONE = "\U0001f645\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_GESTURING_NO = "\U0001f645\u200d\u2640\ufe0f" +WOMAN_GESTURING_NO_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_GESTURING_NO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f645\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_GESTURING_NO_MEDIUM_SKIN_TONE = "\U0001f645\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_GESTURING_NO_MEDIUM_DARK_SKIN_TONE = "\U0001f645\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_GESTURING_NO_DARK_SKIN_TONE = "\U0001f645\U0001f3ff\u200d\u2640\ufe0f" +PERSON_GESTURING_OK = "\U0001f646" +PERSON_GESTURING_OK_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fb" +PERSON_GESTURING_OK_MEDIUM_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fc" +PERSON_GESTURING_OK_MEDIUM_SKIN_TONE = "\U0001f646\U0001f3fd" +PERSON_GESTURING_OK_MEDIUM_DARK_SKIN_TONE = "\U0001f646\U0001f3fe" +PERSON_GESTURING_OK_DARK_SKIN_TONE = "\U0001f646\U0001f3ff" +MAN_GESTURING_OK = "\U0001f646\u200d\u2642\ufe0f" +MAN_GESTURING_OK_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fb\u200d\u2642\ufe0f" +MAN_GESTURING_OK_MEDIUM_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fc\u200d\u2642\ufe0f" +MAN_GESTURING_OK_MEDIUM_SKIN_TONE = "\U0001f646\U0001f3fd\u200d\u2642\ufe0f" +MAN_GESTURING_OK_MEDIUM_DARK_SKIN_TONE = "\U0001f646\U0001f3fe\u200d\u2642\ufe0f" +MAN_GESTURING_OK_DARK_SKIN_TONE = "\U0001f646\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_GESTURING_OK = "\U0001f646\u200d\u2640\ufe0f" +WOMAN_GESTURING_OK_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_GESTURING_OK_MEDIUM_LIGHT_SKIN_TONE = "\U0001f646\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_GESTURING_OK_MEDIUM_SKIN_TONE = "\U0001f646\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_GESTURING_OK_MEDIUM_DARK_SKIN_TONE = "\U0001f646\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_GESTURING_OK_DARK_SKIN_TONE = "\U0001f646\U0001f3ff\u200d\u2640\ufe0f" +PERSON_TIPPING_HAND = "\U0001f481" +PERSON_TIPPING_HAND_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fb" +PERSON_TIPPING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fc" +PERSON_TIPPING_HAND_MEDIUM_SKIN_TONE = "\U0001f481\U0001f3fd" +PERSON_TIPPING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f481\U0001f3fe" +PERSON_TIPPING_HAND_DARK_SKIN_TONE = "\U0001f481\U0001f3ff" +MAN_TIPPING_HAND = "\U0001f481\u200d\u2642\ufe0f" +MAN_TIPPING_HAND_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fb\u200d\u2642\ufe0f" +MAN_TIPPING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fc\u200d\u2642\ufe0f" +MAN_TIPPING_HAND_MEDIUM_SKIN_TONE = "\U0001f481\U0001f3fd\u200d\u2642\ufe0f" +MAN_TIPPING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f481\U0001f3fe\u200d\u2642\ufe0f" +MAN_TIPPING_HAND_DARK_SKIN_TONE = "\U0001f481\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_TIPPING_HAND = "\U0001f481\u200d\u2640\ufe0f" +WOMAN_TIPPING_HAND_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_TIPPING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f481\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_TIPPING_HAND_MEDIUM_SKIN_TONE = "\U0001f481\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_TIPPING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f481\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_TIPPING_HAND_DARK_SKIN_TONE = "\U0001f481\U0001f3ff\u200d\u2640\ufe0f" +PERSON_RAISING_HAND = "\U0001f64b" +PERSON_RAISING_HAND_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fb" +PERSON_RAISING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fc" +PERSON_RAISING_HAND_MEDIUM_SKIN_TONE = "\U0001f64b\U0001f3fd" +PERSON_RAISING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f64b\U0001f3fe" +PERSON_RAISING_HAND_DARK_SKIN_TONE = "\U0001f64b\U0001f3ff" +MAN_RAISING_HAND = "\U0001f64b\u200d\u2642\ufe0f" +MAN_RAISING_HAND_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fb\u200d\u2642\ufe0f" +MAN_RAISING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fc\u200d\u2642\ufe0f" +MAN_RAISING_HAND_MEDIUM_SKIN_TONE = "\U0001f64b\U0001f3fd\u200d\u2642\ufe0f" +MAN_RAISING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f64b\U0001f3fe\u200d\u2642\ufe0f" +MAN_RAISING_HAND_DARK_SKIN_TONE = "\U0001f64b\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_RAISING_HAND = "\U0001f64b\u200d\u2640\ufe0f" +WOMAN_RAISING_HAND_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_RAISING_HAND_MEDIUM_LIGHT_SKIN_TONE = "\U0001f64b\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_RAISING_HAND_MEDIUM_SKIN_TONE = "\U0001f64b\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_RAISING_HAND_MEDIUM_DARK_SKIN_TONE = "\U0001f64b\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_RAISING_HAND_DARK_SKIN_TONE = "\U0001f64b\U0001f3ff\u200d\u2640\ufe0f" +DEAF_PERSON = "\U0001f9cf" +DEAF_PERSON_LIGHT_SKIN_TONE = "\U0001f9cf\U0001f3fb" +DEAF_PERSON_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9cf\U0001f3fc" +DEAF_PERSON_MEDIUM_SKIN_TONE = "\U0001f9cf\U0001f3fd" +DEAF_PERSON_MEDIUM_DARK_SKIN_TONE = "\U0001f9cf\U0001f3fe" +DEAF_PERSON_DARK_SKIN_TONE = "\U0001f9cf\U0001f3ff" +DEAF_MAN = "\U0001f9cf\u200d\u2642\ufe0f" +DEAF_MAN_LIGHT_SKIN_TONE = "\U0001f9cf\U0001f3fb\u200d\u2642\ufe0f" +DEAF_MAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9cf\U0001f3fc\u200d\u2642\ufe0f" +DEAF_MAN_MEDIUM_SKIN_TONE = "\U0001f9cf\U0001f3fd\u200d\u2642\ufe0f" +DEAF_MAN_MEDIUM_DARK_SKIN_TONE = "\U0001f9cf\U0001f3fe\u200d\u2642\ufe0f" +DEAF_MAN_DARK_SKIN_TONE = "\U0001f9cf\U0001f3ff\u200d\u2642\ufe0f" +DEAF_WOMAN = "\U0001f9cf\u200d\u2640\ufe0f" +DEAF_WOMAN_LIGHT_SKIN_TONE = "\U0001f9cf\U0001f3fb\u200d\u2640\ufe0f" +DEAF_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9cf\U0001f3fc\u200d\u2640\ufe0f" +DEAF_WOMAN_MEDIUM_SKIN_TONE = "\U0001f9cf\U0001f3fd\u200d\u2640\ufe0f" +DEAF_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f9cf\U0001f3fe\u200d\u2640\ufe0f" +DEAF_WOMAN_DARK_SKIN_TONE = "\U0001f9cf\U0001f3ff\u200d\u2640\ufe0f" +PERSON_BOWING = "\U0001f647" +PERSON_BOWING_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fb" +PERSON_BOWING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fc" +PERSON_BOWING_MEDIUM_SKIN_TONE = "\U0001f647\U0001f3fd" +PERSON_BOWING_MEDIUM_DARK_SKIN_TONE = "\U0001f647\U0001f3fe" +PERSON_BOWING_DARK_SKIN_TONE = "\U0001f647\U0001f3ff" +MAN_BOWING = "\U0001f647\u200d\u2642\ufe0f" +MAN_BOWING_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fb\u200d\u2642\ufe0f" +MAN_BOWING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fc\u200d\u2642\ufe0f" +MAN_BOWING_MEDIUM_SKIN_TONE = "\U0001f647\U0001f3fd\u200d\u2642\ufe0f" +MAN_BOWING_MEDIUM_DARK_SKIN_TONE = "\U0001f647\U0001f3fe\u200d\u2642\ufe0f" +MAN_BOWING_DARK_SKIN_TONE = "\U0001f647\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_BOWING = "\U0001f647\u200d\u2640\ufe0f" +WOMAN_BOWING_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_BOWING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f647\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_BOWING_MEDIUM_SKIN_TONE = "\U0001f647\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_BOWING_MEDIUM_DARK_SKIN_TONE = "\U0001f647\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_BOWING_DARK_SKIN_TONE = "\U0001f647\U0001f3ff\u200d\u2640\ufe0f" +PERSON_FACEPALMING = "\U0001f926" +PERSON_FACEPALMING_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fb" +PERSON_FACEPALMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fc" +PERSON_FACEPALMING_MEDIUM_SKIN_TONE = "\U0001f926\U0001f3fd" +PERSON_FACEPALMING_MEDIUM_DARK_SKIN_TONE = "\U0001f926\U0001f3fe" +PERSON_FACEPALMING_DARK_SKIN_TONE = "\U0001f926\U0001f3ff" +MAN_FACEPALMING = "\U0001f926\u200d\u2642\ufe0f" +MAN_FACEPALMING_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fb\u200d\u2642\ufe0f" +MAN_FACEPALMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fc\u200d\u2642\ufe0f" +MAN_FACEPALMING_MEDIUM_SKIN_TONE = "\U0001f926\U0001f3fd\u200d\u2642\ufe0f" +MAN_FACEPALMING_MEDIUM_DARK_SKIN_TONE = "\U0001f926\U0001f3fe\u200d\u2642\ufe0f" +MAN_FACEPALMING_DARK_SKIN_TONE = "\U0001f926\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_FACEPALMING = "\U0001f926\u200d\u2640\ufe0f" +WOMAN_FACEPALMING_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_FACEPALMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f926\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_FACEPALMING_MEDIUM_SKIN_TONE = "\U0001f926\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_FACEPALMING_MEDIUM_DARK_SKIN_TONE = "\U0001f926\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_FACEPALMING_DARK_SKIN_TONE = "\U0001f926\U0001f3ff\u200d\u2640\ufe0f" +PERSON_SHRUGGING = "\U0001f937" +PERSON_SHRUGGING_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fb" +PERSON_SHRUGGING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fc" +PERSON_SHRUGGING_MEDIUM_SKIN_TONE = "\U0001f937\U0001f3fd" +PERSON_SHRUGGING_MEDIUM_DARK_SKIN_TONE = "\U0001f937\U0001f3fe" +PERSON_SHRUGGING_DARK_SKIN_TONE = "\U0001f937\U0001f3ff" +MAN_SHRUGGING = "\U0001f937\u200d\u2642\ufe0f" +MAN_SHRUGGING_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fb\u200d\u2642\ufe0f" +MAN_SHRUGGING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fc\u200d\u2642\ufe0f" +MAN_SHRUGGING_MEDIUM_SKIN_TONE = "\U0001f937\U0001f3fd\u200d\u2642\ufe0f" +MAN_SHRUGGING_MEDIUM_DARK_SKIN_TONE = "\U0001f937\U0001f3fe\u200d\u2642\ufe0f" +MAN_SHRUGGING_DARK_SKIN_TONE = "\U0001f937\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_SHRUGGING = "\U0001f937\u200d\u2640\ufe0f" +WOMAN_SHRUGGING_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_SHRUGGING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f937\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_SHRUGGING_MEDIUM_SKIN_TONE = "\U0001f937\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_SHRUGGING_MEDIUM_DARK_SKIN_TONE = "\U0001f937\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_SHRUGGING_DARK_SKIN_TONE = "\U0001f937\U0001f3ff\u200d\u2640\ufe0f" +HEALTH_WORKER = "\U0001f9d1\u200d\u2695\ufe0f" +HEALTH_WORKER_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\u2695\ufe0f" +HEALTH_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\u2695\ufe0f" +HEALTH_WORKER_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\u2695\ufe0f" +HEALTH_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\u2695\ufe0f" +HEALTH_WORKER_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\u2695\ufe0f" +MAN_HEALTH_WORKER = "\U0001f468\u200d\u2695\ufe0f" +MAN_HEALTH_WORKER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2695\ufe0f" +MAN_HEALTH_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2695\ufe0f" +MAN_HEALTH_WORKER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2695\ufe0f" +MAN_HEALTH_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2695\ufe0f" +MAN_HEALTH_WORKER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2695\ufe0f" +WOMAN_HEALTH_WORKER = "\U0001f469\u200d\u2695\ufe0f" +WOMAN_HEALTH_WORKER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2695\ufe0f" +WOMAN_HEALTH_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2695\ufe0f" +WOMAN_HEALTH_WORKER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2695\ufe0f" +WOMAN_HEALTH_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2695\ufe0f" +WOMAN_HEALTH_WORKER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2695\ufe0f" +STUDENT = "\U0001f9d1\u200d\U0001f393" +STUDENT_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f393" +STUDENT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f393" +STUDENT_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f393" +STUDENT_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f393" +STUDENT_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f393" +MAN_STUDENT = "\U0001f468\u200d\U0001f393" +MAN_STUDENT_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f393" +MAN_STUDENT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f393" +MAN_STUDENT_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f393" +MAN_STUDENT_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f393" +MAN_STUDENT_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f393" +WOMAN_STUDENT = "\U0001f469\u200d\U0001f393" +WOMAN_STUDENT_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f393" +WOMAN_STUDENT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f393" +WOMAN_STUDENT_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f393" +WOMAN_STUDENT_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f393" +WOMAN_STUDENT_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f393" +TEACHER = "\U0001f9d1\u200d\U0001f3eb" +TEACHER_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f3eb" +TEACHER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f3eb" +TEACHER_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f3eb" +TEACHER_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f3eb" +TEACHER_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f3eb" +MAN_TEACHER = "\U0001f468\u200d\U0001f3eb" +MAN_TEACHER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f3eb" +MAN_TEACHER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f3eb" +MAN_TEACHER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f3eb" +MAN_TEACHER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f3eb" +MAN_TEACHER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f3eb" +WOMAN_TEACHER = "\U0001f469\u200d\U0001f3eb" +WOMAN_TEACHER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f3eb" +WOMAN_TEACHER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f3eb" +WOMAN_TEACHER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f3eb" +WOMAN_TEACHER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f3eb" +WOMAN_TEACHER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f3eb" +JUDGE = "\U0001f9d1\u200d\u2696\ufe0f" +JUDGE_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\u2696\ufe0f" +JUDGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\u2696\ufe0f" +JUDGE_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\u2696\ufe0f" +JUDGE_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\u2696\ufe0f" +JUDGE_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\u2696\ufe0f" +MAN_JUDGE = "\U0001f468\u200d\u2696\ufe0f" +MAN_JUDGE_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2696\ufe0f" +MAN_JUDGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2696\ufe0f" +MAN_JUDGE_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2696\ufe0f" +MAN_JUDGE_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2696\ufe0f" +MAN_JUDGE_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2696\ufe0f" +WOMAN_JUDGE = "\U0001f469\u200d\u2696\ufe0f" +WOMAN_JUDGE_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2696\ufe0f" +WOMAN_JUDGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2696\ufe0f" +WOMAN_JUDGE_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2696\ufe0f" +WOMAN_JUDGE_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2696\ufe0f" +WOMAN_JUDGE_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2696\ufe0f" +FARMER = "\U0001f9d1\u200d\U0001f33e" +FARMER_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f33e" +FARMER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f33e" +FARMER_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f33e" +FARMER_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f33e" +FARMER_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f33e" +MAN_FARMER = "\U0001f468\u200d\U0001f33e" +MAN_FARMER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f33e" +MAN_FARMER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f33e" +MAN_FARMER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f33e" +MAN_FARMER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f33e" +MAN_FARMER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f33e" +WOMAN_FARMER = "\U0001f469\u200d\U0001f33e" +WOMAN_FARMER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f33e" +WOMAN_FARMER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f33e" +WOMAN_FARMER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f33e" +WOMAN_FARMER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f33e" +WOMAN_FARMER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f33e" +COOK = "\U0001f9d1\u200d\U0001f373" +COOK_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f373" +COOK_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f373" +COOK_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f373" +COOK_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f373" +COOK_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f373" +MAN_COOK = "\U0001f468\u200d\U0001f373" +MAN_COOK_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f373" +MAN_COOK_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f373" +MAN_COOK_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f373" +MAN_COOK_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f373" +MAN_COOK_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f373" +WOMAN_COOK = "\U0001f469\u200d\U0001f373" +WOMAN_COOK_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f373" +WOMAN_COOK_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f373" +WOMAN_COOK_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f373" +WOMAN_COOK_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f373" +WOMAN_COOK_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f373" +MECHANIC = "\U0001f9d1\u200d\U0001f527" +MECHANIC_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f527" +MECHANIC_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f527" +MECHANIC_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f527" +MECHANIC_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f527" +MECHANIC_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f527" +MAN_MECHANIC = "\U0001f468\u200d\U0001f527" +MAN_MECHANIC_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f527" +MAN_MECHANIC_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f527" +MAN_MECHANIC_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f527" +MAN_MECHANIC_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f527" +MAN_MECHANIC_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f527" +WOMAN_MECHANIC = "\U0001f469\u200d\U0001f527" +WOMAN_MECHANIC_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f527" +WOMAN_MECHANIC_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f527" +WOMAN_MECHANIC_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f527" +WOMAN_MECHANIC_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f527" +WOMAN_MECHANIC_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f527" +FACTORY_WORKER = "\U0001f9d1\u200d\U0001f3ed" +FACTORY_WORKER_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f3ed" +FACTORY_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f3ed" +FACTORY_WORKER_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f3ed" +FACTORY_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f3ed" +FACTORY_WORKER_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f3ed" +MAN_FACTORY_WORKER = "\U0001f468\u200d\U0001f3ed" +MAN_FACTORY_WORKER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f3ed" +MAN_FACTORY_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f3ed" +MAN_FACTORY_WORKER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f3ed" +MAN_FACTORY_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f3ed" +MAN_FACTORY_WORKER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f3ed" +WOMAN_FACTORY_WORKER = "\U0001f469\u200d\U0001f3ed" +WOMAN_FACTORY_WORKER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f3ed" +WOMAN_FACTORY_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f3ed" +WOMAN_FACTORY_WORKER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f3ed" +WOMAN_FACTORY_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f3ed" +WOMAN_FACTORY_WORKER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f3ed" +OFFICE_WORKER = "\U0001f9d1\u200d\U0001f4bc" +OFFICE_WORKER_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f4bc" +OFFICE_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f4bc" +OFFICE_WORKER_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f4bc" +OFFICE_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f4bc" +OFFICE_WORKER_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f4bc" +MAN_OFFICE_WORKER = "\U0001f468\u200d\U0001f4bc" +MAN_OFFICE_WORKER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f4bc" +MAN_OFFICE_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f4bc" +MAN_OFFICE_WORKER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f4bc" +MAN_OFFICE_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f4bc" +MAN_OFFICE_WORKER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f4bc" +WOMAN_OFFICE_WORKER = "\U0001f469\u200d\U0001f4bc" +WOMAN_OFFICE_WORKER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f4bc" +WOMAN_OFFICE_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f4bc" +WOMAN_OFFICE_WORKER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f4bc" +WOMAN_OFFICE_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f4bc" +WOMAN_OFFICE_WORKER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f4bc" +SCIENTIST = "\U0001f9d1\u200d\U0001f52c" +SCIENTIST_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f52c" +SCIENTIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f52c" +SCIENTIST_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f52c" +SCIENTIST_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f52c" +SCIENTIST_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f52c" +MAN_SCIENTIST = "\U0001f468\u200d\U0001f52c" +MAN_SCIENTIST_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f52c" +MAN_SCIENTIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f52c" +MAN_SCIENTIST_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f52c" +MAN_SCIENTIST_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f52c" +MAN_SCIENTIST_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f52c" +WOMAN_SCIENTIST = "\U0001f469\u200d\U0001f52c" +WOMAN_SCIENTIST_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f52c" +WOMAN_SCIENTIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f52c" +WOMAN_SCIENTIST_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f52c" +WOMAN_SCIENTIST_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f52c" +WOMAN_SCIENTIST_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f52c" +TECHNOLOGIST = "\U0001f9d1\u200d\U0001f4bb" +TECHNOLOGIST_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f4bb" +TECHNOLOGIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f4bb" +TECHNOLOGIST_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f4bb" +TECHNOLOGIST_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f4bb" +TECHNOLOGIST_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f4bb" +MAN_TECHNOLOGIST = "\U0001f468\u200d\U0001f4bb" +MAN_TECHNOLOGIST_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f4bb" +MAN_TECHNOLOGIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f4bb" +MAN_TECHNOLOGIST_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f4bb" +MAN_TECHNOLOGIST_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f4bb" +MAN_TECHNOLOGIST_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f4bb" +WOMAN_TECHNOLOGIST = "\U0001f469\u200d\U0001f4bb" +WOMAN_TECHNOLOGIST_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f4bb" +WOMAN_TECHNOLOGIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f4bb" +WOMAN_TECHNOLOGIST_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f4bb" +WOMAN_TECHNOLOGIST_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f4bb" +WOMAN_TECHNOLOGIST_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f4bb" +SINGER = "\U0001f9d1\u200d\U0001f3a4" +SINGER_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f3a4" +SINGER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f3a4" +SINGER_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f3a4" +SINGER_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f3a4" +SINGER_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f3a4" +MAN_SINGER = "\U0001f468\u200d\U0001f3a4" +MAN_SINGER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f3a4" +MAN_SINGER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f3a4" +MAN_SINGER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f3a4" +MAN_SINGER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f3a4" +MAN_SINGER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f3a4" +WOMAN_SINGER = "\U0001f469\u200d\U0001f3a4" +WOMAN_SINGER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f3a4" +WOMAN_SINGER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f3a4" +WOMAN_SINGER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f3a4" +WOMAN_SINGER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f3a4" +WOMAN_SINGER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f3a4" +ARTIST = "\U0001f9d1\u200d\U0001f3a8" +ARTIST_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f3a8" +ARTIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f3a8" +ARTIST_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f3a8" +ARTIST_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f3a8" +ARTIST_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f3a8" +MAN_ARTIST = "\U0001f468\u200d\U0001f3a8" +MAN_ARTIST_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f3a8" +MAN_ARTIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f3a8" +MAN_ARTIST_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f3a8" +MAN_ARTIST_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f3a8" +MAN_ARTIST_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f3a8" +WOMAN_ARTIST = "\U0001f469\u200d\U0001f3a8" +WOMAN_ARTIST_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f3a8" +WOMAN_ARTIST_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f3a8" +WOMAN_ARTIST_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f3a8" +WOMAN_ARTIST_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f3a8" +WOMAN_ARTIST_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f3a8" +PILOT = "\U0001f9d1\u200d\u2708\ufe0f" +PILOT_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\u2708\ufe0f" +PILOT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\u2708\ufe0f" +PILOT_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\u2708\ufe0f" +PILOT_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\u2708\ufe0f" +PILOT_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\u2708\ufe0f" +MAN_PILOT = "\U0001f468\u200d\u2708\ufe0f" +MAN_PILOT_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\u2708\ufe0f" +MAN_PILOT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\u2708\ufe0f" +MAN_PILOT_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\u2708\ufe0f" +MAN_PILOT_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\u2708\ufe0f" +MAN_PILOT_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\u2708\ufe0f" +WOMAN_PILOT = "\U0001f469\u200d\u2708\ufe0f" +WOMAN_PILOT_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\u2708\ufe0f" +WOMAN_PILOT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\u2708\ufe0f" +WOMAN_PILOT_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\u2708\ufe0f" +WOMAN_PILOT_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\u2708\ufe0f" +WOMAN_PILOT_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\u2708\ufe0f" +ASTRONAUT = "\U0001f9d1\u200d\U0001f680" +ASTRONAUT_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f680" +ASTRONAUT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f680" +ASTRONAUT_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f680" +ASTRONAUT_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f680" +ASTRONAUT_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f680" +MAN_ASTRONAUT = "\U0001f468\u200d\U0001f680" +MAN_ASTRONAUT_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f680" +MAN_ASTRONAUT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f680" +MAN_ASTRONAUT_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f680" +MAN_ASTRONAUT_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f680" +MAN_ASTRONAUT_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f680" +WOMAN_ASTRONAUT = "\U0001f469\u200d\U0001f680" +WOMAN_ASTRONAUT_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f680" +WOMAN_ASTRONAUT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f680" +WOMAN_ASTRONAUT_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f680" +WOMAN_ASTRONAUT_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f680" +WOMAN_ASTRONAUT_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f680" +FIREFIGHTER = "\U0001f9d1\u200d\U0001f692" +FIREFIGHTER_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f692" +FIREFIGHTER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f692" +FIREFIGHTER_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f692" +FIREFIGHTER_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f692" +FIREFIGHTER_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f692" +MAN_FIREFIGHTER = "\U0001f468\u200d\U0001f692" +MAN_FIREFIGHTER_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f692" +MAN_FIREFIGHTER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f692" +MAN_FIREFIGHTER_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f692" +MAN_FIREFIGHTER_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f692" +MAN_FIREFIGHTER_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f692" +WOMAN_FIREFIGHTER = "\U0001f469\u200d\U0001f692" +WOMAN_FIREFIGHTER_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f692" +WOMAN_FIREFIGHTER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f692" +WOMAN_FIREFIGHTER_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f692" +WOMAN_FIREFIGHTER_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f692" +WOMAN_FIREFIGHTER_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f692" +POLICE_OFFICER = "\U0001f46e" +POLICE_OFFICER_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fb" +POLICE_OFFICER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fc" +POLICE_OFFICER_MEDIUM_SKIN_TONE = "\U0001f46e\U0001f3fd" +POLICE_OFFICER_MEDIUM_DARK_SKIN_TONE = "\U0001f46e\U0001f3fe" +POLICE_OFFICER_DARK_SKIN_TONE = "\U0001f46e\U0001f3ff" +MAN_POLICE_OFFICER = "\U0001f46e\u200d\u2642\ufe0f" +MAN_POLICE_OFFICER_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fb\u200d\u2642\ufe0f" +MAN_POLICE_OFFICER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fc\u200d\u2642\ufe0f" +MAN_POLICE_OFFICER_MEDIUM_SKIN_TONE = "\U0001f46e\U0001f3fd\u200d\u2642\ufe0f" +MAN_POLICE_OFFICER_MEDIUM_DARK_SKIN_TONE = "\U0001f46e\U0001f3fe\u200d\u2642\ufe0f" +MAN_POLICE_OFFICER_DARK_SKIN_TONE = "\U0001f46e\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_POLICE_OFFICER = "\U0001f46e\u200d\u2640\ufe0f" +WOMAN_POLICE_OFFICER_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_POLICE_OFFICER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f46e\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_POLICE_OFFICER_MEDIUM_SKIN_TONE = "\U0001f46e\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_POLICE_OFFICER_MEDIUM_DARK_SKIN_TONE = "\U0001f46e\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_POLICE_OFFICER_DARK_SKIN_TONE = "\U0001f46e\U0001f3ff\u200d\u2640\ufe0f" +DETECTIVE = "\U0001f575\ufe0f" +DETECTIVE_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fb" +DETECTIVE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fc" +DETECTIVE_MEDIUM_SKIN_TONE = "\U0001f575\U0001f3fd" +DETECTIVE_MEDIUM_DARK_SKIN_TONE = "\U0001f575\U0001f3fe" +DETECTIVE_DARK_SKIN_TONE = "\U0001f575\U0001f3ff" +MAN_DETECTIVE = "\U0001f575\ufe0f\u200d\u2642\ufe0f" +MAN_DETECTIVE_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fb\u200d\u2642\ufe0f" +MAN_DETECTIVE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fc\u200d\u2642\ufe0f" +MAN_DETECTIVE_MEDIUM_SKIN_TONE = "\U0001f575\U0001f3fd\u200d\u2642\ufe0f" +MAN_DETECTIVE_MEDIUM_DARK_SKIN_TONE = "\U0001f575\U0001f3fe\u200d\u2642\ufe0f" +MAN_DETECTIVE_DARK_SKIN_TONE = "\U0001f575\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_DETECTIVE = "\U0001f575\ufe0f\u200d\u2640\ufe0f" +WOMAN_DETECTIVE_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_DETECTIVE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f575\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_DETECTIVE_MEDIUM_SKIN_TONE = "\U0001f575\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_DETECTIVE_MEDIUM_DARK_SKIN_TONE = "\U0001f575\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_DETECTIVE_DARK_SKIN_TONE = "\U0001f575\U0001f3ff\u200d\u2640\ufe0f" +GUARD = "\U0001f482" +GUARD_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fb" +GUARD_MEDIUM_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fc" +GUARD_MEDIUM_SKIN_TONE = "\U0001f482\U0001f3fd" +GUARD_MEDIUM_DARK_SKIN_TONE = "\U0001f482\U0001f3fe" +GUARD_DARK_SKIN_TONE = "\U0001f482\U0001f3ff" +MAN_GUARD = "\U0001f482\u200d\u2642\ufe0f" +MAN_GUARD_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fb\u200d\u2642\ufe0f" +MAN_GUARD_MEDIUM_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fc\u200d\u2642\ufe0f" +MAN_GUARD_MEDIUM_SKIN_TONE = "\U0001f482\U0001f3fd\u200d\u2642\ufe0f" +MAN_GUARD_MEDIUM_DARK_SKIN_TONE = "\U0001f482\U0001f3fe\u200d\u2642\ufe0f" +MAN_GUARD_DARK_SKIN_TONE = "\U0001f482\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_GUARD = "\U0001f482\u200d\u2640\ufe0f" +WOMAN_GUARD_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_GUARD_MEDIUM_LIGHT_SKIN_TONE = "\U0001f482\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_GUARD_MEDIUM_SKIN_TONE = "\U0001f482\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_GUARD_MEDIUM_DARK_SKIN_TONE = "\U0001f482\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_GUARD_DARK_SKIN_TONE = "\U0001f482\U0001f3ff\u200d\u2640\ufe0f" +NINJA = "\U0001f977" +NINJA_LIGHT_SKIN_TONE = "\U0001f977\U0001f3fb" +NINJA_MEDIUM_LIGHT_SKIN_TONE = "\U0001f977\U0001f3fc" +NINJA_MEDIUM_SKIN_TONE = "\U0001f977\U0001f3fd" +NINJA_MEDIUM_DARK_SKIN_TONE = "\U0001f977\U0001f3fe" +NINJA_DARK_SKIN_TONE = "\U0001f977\U0001f3ff" +CONSTRUCTION_WORKER = "\U0001f477" +CONSTRUCTION_WORKER_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fb" +CONSTRUCTION_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fc" +CONSTRUCTION_WORKER_MEDIUM_SKIN_TONE = "\U0001f477\U0001f3fd" +CONSTRUCTION_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f477\U0001f3fe" +CONSTRUCTION_WORKER_DARK_SKIN_TONE = "\U0001f477\U0001f3ff" +MAN_CONSTRUCTION_WORKER = "\U0001f477\u200d\u2642\ufe0f" +MAN_CONSTRUCTION_WORKER_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fb\u200d\u2642\ufe0f" +MAN_CONSTRUCTION_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fc\u200d\u2642\ufe0f" +MAN_CONSTRUCTION_WORKER_MEDIUM_SKIN_TONE = "\U0001f477\U0001f3fd\u200d\u2642\ufe0f" +MAN_CONSTRUCTION_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f477\U0001f3fe\u200d\u2642\ufe0f" +MAN_CONSTRUCTION_WORKER_DARK_SKIN_TONE = "\U0001f477\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_CONSTRUCTION_WORKER = "\U0001f477\u200d\u2640\ufe0f" +WOMAN_CONSTRUCTION_WORKER_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_CONSTRUCTION_WORKER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f477\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_CONSTRUCTION_WORKER_MEDIUM_SKIN_TONE = "\U0001f477\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_CONSTRUCTION_WORKER_MEDIUM_DARK_SKIN_TONE = "\U0001f477\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_CONSTRUCTION_WORKER_DARK_SKIN_TONE = "\U0001f477\U0001f3ff\u200d\u2640\ufe0f" +PRINCE = "\U0001f934" +PRINCE_LIGHT_SKIN_TONE = "\U0001f934\U0001f3fb" +PRINCE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f934\U0001f3fc" +PRINCE_MEDIUM_SKIN_TONE = "\U0001f934\U0001f3fd" +PRINCE_MEDIUM_DARK_SKIN_TONE = "\U0001f934\U0001f3fe" +PRINCE_DARK_SKIN_TONE = "\U0001f934\U0001f3ff" +PRINCESS = "\U0001f478" +PRINCESS_LIGHT_SKIN_TONE = "\U0001f478\U0001f3fb" +PRINCESS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f478\U0001f3fc" +PRINCESS_MEDIUM_SKIN_TONE = "\U0001f478\U0001f3fd" +PRINCESS_MEDIUM_DARK_SKIN_TONE = "\U0001f478\U0001f3fe" +PRINCESS_DARK_SKIN_TONE = "\U0001f478\U0001f3ff" +PERSON_WEARING_TURBAN = "\U0001f473" +PERSON_WEARING_TURBAN_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fb" +PERSON_WEARING_TURBAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fc" +PERSON_WEARING_TURBAN_MEDIUM_SKIN_TONE = "\U0001f473\U0001f3fd" +PERSON_WEARING_TURBAN_MEDIUM_DARK_SKIN_TONE = "\U0001f473\U0001f3fe" +PERSON_WEARING_TURBAN_DARK_SKIN_TONE = "\U0001f473\U0001f3ff" +MAN_WEARING_TURBAN = "\U0001f473\u200d\u2642\ufe0f" +MAN_WEARING_TURBAN_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fb\u200d\u2642\ufe0f" +MAN_WEARING_TURBAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fc\u200d\u2642\ufe0f" +MAN_WEARING_TURBAN_MEDIUM_SKIN_TONE = "\U0001f473\U0001f3fd\u200d\u2642\ufe0f" +MAN_WEARING_TURBAN_MEDIUM_DARK_SKIN_TONE = "\U0001f473\U0001f3fe\u200d\u2642\ufe0f" +MAN_WEARING_TURBAN_DARK_SKIN_TONE = "\U0001f473\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_WEARING_TURBAN = "\U0001f473\u200d\u2640\ufe0f" +WOMAN_WEARING_TURBAN_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_WEARING_TURBAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f473\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_WEARING_TURBAN_MEDIUM_SKIN_TONE = "\U0001f473\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_WEARING_TURBAN_MEDIUM_DARK_SKIN_TONE = "\U0001f473\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_WEARING_TURBAN_DARK_SKIN_TONE = "\U0001f473\U0001f3ff\u200d\u2640\ufe0f" +PERSON_WITH_SKULLCAP = "\U0001f472" +PERSON_WITH_SKULLCAP_LIGHT_SKIN_TONE = "\U0001f472\U0001f3fb" +PERSON_WITH_SKULLCAP_MEDIUM_LIGHT_SKIN_TONE = "\U0001f472\U0001f3fc" +PERSON_WITH_SKULLCAP_MEDIUM_SKIN_TONE = "\U0001f472\U0001f3fd" +PERSON_WITH_SKULLCAP_MEDIUM_DARK_SKIN_TONE = "\U0001f472\U0001f3fe" +PERSON_WITH_SKULLCAP_DARK_SKIN_TONE = "\U0001f472\U0001f3ff" +WOMAN_WITH_HEADSCARF = "\U0001f9d5" +WOMAN_WITH_HEADSCARF_LIGHT_SKIN_TONE = "\U0001f9d5\U0001f3fb" +WOMAN_WITH_HEADSCARF_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d5\U0001f3fc" +WOMAN_WITH_HEADSCARF_MEDIUM_SKIN_TONE = "\U0001f9d5\U0001f3fd" +WOMAN_WITH_HEADSCARF_MEDIUM_DARK_SKIN_TONE = "\U0001f9d5\U0001f3fe" +WOMAN_WITH_HEADSCARF_DARK_SKIN_TONE = "\U0001f9d5\U0001f3ff" +PERSON_IN_TUXEDO = "\U0001f935" +PERSON_IN_TUXEDO_LIGHT_SKIN_TONE = "\U0001f935\U0001f3fb" +PERSON_IN_TUXEDO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f935\U0001f3fc" +PERSON_IN_TUXEDO_MEDIUM_SKIN_TONE = "\U0001f935\U0001f3fd" +PERSON_IN_TUXEDO_MEDIUM_DARK_SKIN_TONE = "\U0001f935\U0001f3fe" +PERSON_IN_TUXEDO_DARK_SKIN_TONE = "\U0001f935\U0001f3ff" +MAN_IN_TUXEDO = "\U0001f935\u200d\u2642\ufe0f" +MAN_IN_TUXEDO_LIGHT_SKIN_TONE = "\U0001f935\U0001f3fb\u200d\u2642\ufe0f" +MAN_IN_TUXEDO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f935\U0001f3fc\u200d\u2642\ufe0f" +MAN_IN_TUXEDO_MEDIUM_SKIN_TONE = "\U0001f935\U0001f3fd\u200d\u2642\ufe0f" +MAN_IN_TUXEDO_MEDIUM_DARK_SKIN_TONE = "\U0001f935\U0001f3fe\u200d\u2642\ufe0f" +MAN_IN_TUXEDO_DARK_SKIN_TONE = "\U0001f935\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_IN_TUXEDO = "\U0001f935\u200d\u2640\ufe0f" +WOMAN_IN_TUXEDO_LIGHT_SKIN_TONE = "\U0001f935\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_IN_TUXEDO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f935\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_IN_TUXEDO_MEDIUM_SKIN_TONE = "\U0001f935\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_IN_TUXEDO_MEDIUM_DARK_SKIN_TONE = "\U0001f935\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_IN_TUXEDO_DARK_SKIN_TONE = "\U0001f935\U0001f3ff\u200d\u2640\ufe0f" +PERSON_WITH_VEIL = "\U0001f470" +PERSON_WITH_VEIL_LIGHT_SKIN_TONE = "\U0001f470\U0001f3fb" +PERSON_WITH_VEIL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f470\U0001f3fc" +PERSON_WITH_VEIL_MEDIUM_SKIN_TONE = "\U0001f470\U0001f3fd" +PERSON_WITH_VEIL_MEDIUM_DARK_SKIN_TONE = "\U0001f470\U0001f3fe" +PERSON_WITH_VEIL_DARK_SKIN_TONE = "\U0001f470\U0001f3ff" +MAN_WITH_VEIL = "\U0001f470\u200d\u2642\ufe0f" +MAN_WITH_VEIL_LIGHT_SKIN_TONE = "\U0001f470\U0001f3fb\u200d\u2642\ufe0f" +MAN_WITH_VEIL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f470\U0001f3fc\u200d\u2642\ufe0f" +MAN_WITH_VEIL_MEDIUM_SKIN_TONE = "\U0001f470\U0001f3fd\u200d\u2642\ufe0f" +MAN_WITH_VEIL_MEDIUM_DARK_SKIN_TONE = "\U0001f470\U0001f3fe\u200d\u2642\ufe0f" +MAN_WITH_VEIL_DARK_SKIN_TONE = "\U0001f470\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_WITH_VEIL = "\U0001f470\u200d\u2640\ufe0f" +WOMAN_WITH_VEIL_LIGHT_SKIN_TONE = "\U0001f470\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_WITH_VEIL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f470\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_WITH_VEIL_MEDIUM_SKIN_TONE = "\U0001f470\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_WITH_VEIL_MEDIUM_DARK_SKIN_TONE = "\U0001f470\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_WITH_VEIL_DARK_SKIN_TONE = "\U0001f470\U0001f3ff\u200d\u2640\ufe0f" +PREGNANT_WOMAN = "\U0001f930" +PREGNANT_WOMAN_LIGHT_SKIN_TONE = "\U0001f930\U0001f3fb" +PREGNANT_WOMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f930\U0001f3fc" +PREGNANT_WOMAN_MEDIUM_SKIN_TONE = "\U0001f930\U0001f3fd" +PREGNANT_WOMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f930\U0001f3fe" +PREGNANT_WOMAN_DARK_SKIN_TONE = "\U0001f930\U0001f3ff" +BREAST_FEEDING = "\U0001f931" +BREAST_FEEDING_LIGHT_SKIN_TONE = "\U0001f931\U0001f3fb" +BREAST_FEEDING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f931\U0001f3fc" +BREAST_FEEDING_MEDIUM_SKIN_TONE = "\U0001f931\U0001f3fd" +BREAST_FEEDING_MEDIUM_DARK_SKIN_TONE = "\U0001f931\U0001f3fe" +BREAST_FEEDING_DARK_SKIN_TONE = "\U0001f931\U0001f3ff" +WOMAN_FEEDING_BABY = "\U0001f469\u200d\U0001f37c" +WOMAN_FEEDING_BABY_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f37c" +WOMAN_FEEDING_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f37c" +WOMAN_FEEDING_BABY_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f37c" +WOMAN_FEEDING_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f37c" +WOMAN_FEEDING_BABY_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f37c" +MAN_FEEDING_BABY = "\U0001f468\u200d\U0001f37c" +MAN_FEEDING_BABY_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f37c" +MAN_FEEDING_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f37c" +MAN_FEEDING_BABY_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f37c" +MAN_FEEDING_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f37c" +MAN_FEEDING_BABY_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f37c" +PERSON_FEEDING_BABY = "\U0001f9d1\u200d\U0001f37c" +PERSON_FEEDING_BABY_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f37c" +PERSON_FEEDING_BABY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f37c" +PERSON_FEEDING_BABY_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f37c" +PERSON_FEEDING_BABY_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f37c" +PERSON_FEEDING_BABY_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f37c" +BABY_ANGEL = "\U0001f47c" +BABY_ANGEL_LIGHT_SKIN_TONE = "\U0001f47c\U0001f3fb" +BABY_ANGEL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f47c\U0001f3fc" +BABY_ANGEL_MEDIUM_SKIN_TONE = "\U0001f47c\U0001f3fd" +BABY_ANGEL_MEDIUM_DARK_SKIN_TONE = "\U0001f47c\U0001f3fe" +BABY_ANGEL_DARK_SKIN_TONE = "\U0001f47c\U0001f3ff" +SANTA_CLAUS = "\U0001f385" +SANTA_CLAUS_LIGHT_SKIN_TONE = "\U0001f385\U0001f3fb" +SANTA_CLAUS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f385\U0001f3fc" +SANTA_CLAUS_MEDIUM_SKIN_TONE = "\U0001f385\U0001f3fd" +SANTA_CLAUS_MEDIUM_DARK_SKIN_TONE = "\U0001f385\U0001f3fe" +SANTA_CLAUS_DARK_SKIN_TONE = "\U0001f385\U0001f3ff" +MRS_CLAUS = "\U0001f936" +MRS_CLAUS_LIGHT_SKIN_TONE = "\U0001f936\U0001f3fb" +MRS_CLAUS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f936\U0001f3fc" +MRS_CLAUS_MEDIUM_SKIN_TONE = "\U0001f936\U0001f3fd" +MRS_CLAUS_MEDIUM_DARK_SKIN_TONE = "\U0001f936\U0001f3fe" +MRS_CLAUS_DARK_SKIN_TONE = "\U0001f936\U0001f3ff" +MX_CLAUS = "\U0001f9d1\u200d\U0001f384" +MX_CLAUS_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f384" +MX_CLAUS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f384" +MX_CLAUS_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f384" +MX_CLAUS_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f384" +MX_CLAUS_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f384" +SUPERHERO = "\U0001f9b8" +SUPERHERO_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fb" +SUPERHERO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fc" +SUPERHERO_MEDIUM_SKIN_TONE = "\U0001f9b8\U0001f3fd" +SUPERHERO_MEDIUM_DARK_SKIN_TONE = "\U0001f9b8\U0001f3fe" +SUPERHERO_DARK_SKIN_TONE = "\U0001f9b8\U0001f3ff" +MAN_SUPERHERO = "\U0001f9b8\u200d\u2642\ufe0f" +MAN_SUPERHERO_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fb\u200d\u2642\ufe0f" +MAN_SUPERHERO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fc\u200d\u2642\ufe0f" +MAN_SUPERHERO_MEDIUM_SKIN_TONE = "\U0001f9b8\U0001f3fd\u200d\u2642\ufe0f" +MAN_SUPERHERO_MEDIUM_DARK_SKIN_TONE = "\U0001f9b8\U0001f3fe\u200d\u2642\ufe0f" +MAN_SUPERHERO_DARK_SKIN_TONE = "\U0001f9b8\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_SUPERHERO = "\U0001f9b8\u200d\u2640\ufe0f" +WOMAN_SUPERHERO_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_SUPERHERO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b8\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_SUPERHERO_MEDIUM_SKIN_TONE = "\U0001f9b8\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_SUPERHERO_MEDIUM_DARK_SKIN_TONE = "\U0001f9b8\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_SUPERHERO_DARK_SKIN_TONE = "\U0001f9b8\U0001f3ff\u200d\u2640\ufe0f" +SUPERVILLAIN = "\U0001f9b9" +SUPERVILLAIN_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fb" +SUPERVILLAIN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fc" +SUPERVILLAIN_MEDIUM_SKIN_TONE = "\U0001f9b9\U0001f3fd" +SUPERVILLAIN_MEDIUM_DARK_SKIN_TONE = "\U0001f9b9\U0001f3fe" +SUPERVILLAIN_DARK_SKIN_TONE = "\U0001f9b9\U0001f3ff" +MAN_SUPERVILLAIN = "\U0001f9b9\u200d\u2642\ufe0f" +MAN_SUPERVILLAIN_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fb\u200d\u2642\ufe0f" +MAN_SUPERVILLAIN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fc\u200d\u2642\ufe0f" +MAN_SUPERVILLAIN_MEDIUM_SKIN_TONE = "\U0001f9b9\U0001f3fd\u200d\u2642\ufe0f" +MAN_SUPERVILLAIN_MEDIUM_DARK_SKIN_TONE = "\U0001f9b9\U0001f3fe\u200d\u2642\ufe0f" +MAN_SUPERVILLAIN_DARK_SKIN_TONE = "\U0001f9b9\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_SUPERVILLAIN = "\U0001f9b9\u200d\u2640\ufe0f" +WOMAN_SUPERVILLAIN_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_SUPERVILLAIN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9b9\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_SUPERVILLAIN_MEDIUM_SKIN_TONE = "\U0001f9b9\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_SUPERVILLAIN_MEDIUM_DARK_SKIN_TONE = "\U0001f9b9\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_SUPERVILLAIN_DARK_SKIN_TONE = "\U0001f9b9\U0001f3ff\u200d\u2640\ufe0f" +MAGE = "\U0001f9d9" +MAGE_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fb" +MAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fc" +MAGE_MEDIUM_SKIN_TONE = "\U0001f9d9\U0001f3fd" +MAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f9d9\U0001f3fe" +MAGE_DARK_SKIN_TONE = "\U0001f9d9\U0001f3ff" +MAN_MAGE = "\U0001f9d9\u200d\u2642\ufe0f" +MAN_MAGE_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fb\u200d\u2642\ufe0f" +MAN_MAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fc\u200d\u2642\ufe0f" +MAN_MAGE_MEDIUM_SKIN_TONE = "\U0001f9d9\U0001f3fd\u200d\u2642\ufe0f" +MAN_MAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f9d9\U0001f3fe\u200d\u2642\ufe0f" +MAN_MAGE_DARK_SKIN_TONE = "\U0001f9d9\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_MAGE = "\U0001f9d9\u200d\u2640\ufe0f" +WOMAN_MAGE_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_MAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d9\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_MAGE_MEDIUM_SKIN_TONE = "\U0001f9d9\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_MAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f9d9\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_MAGE_DARK_SKIN_TONE = "\U0001f9d9\U0001f3ff\u200d\u2640\ufe0f" +FAIRY = "\U0001f9da" +FAIRY_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fb" +FAIRY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fc" +FAIRY_MEDIUM_SKIN_TONE = "\U0001f9da\U0001f3fd" +FAIRY_MEDIUM_DARK_SKIN_TONE = "\U0001f9da\U0001f3fe" +FAIRY_DARK_SKIN_TONE = "\U0001f9da\U0001f3ff" +MAN_FAIRY = "\U0001f9da\u200d\u2642\ufe0f" +MAN_FAIRY_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fb\u200d\u2642\ufe0f" +MAN_FAIRY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fc\u200d\u2642\ufe0f" +MAN_FAIRY_MEDIUM_SKIN_TONE = "\U0001f9da\U0001f3fd\u200d\u2642\ufe0f" +MAN_FAIRY_MEDIUM_DARK_SKIN_TONE = "\U0001f9da\U0001f3fe\u200d\u2642\ufe0f" +MAN_FAIRY_DARK_SKIN_TONE = "\U0001f9da\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_FAIRY = "\U0001f9da\u200d\u2640\ufe0f" +WOMAN_FAIRY_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_FAIRY_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9da\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_FAIRY_MEDIUM_SKIN_TONE = "\U0001f9da\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_FAIRY_MEDIUM_DARK_SKIN_TONE = "\U0001f9da\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_FAIRY_DARK_SKIN_TONE = "\U0001f9da\U0001f3ff\u200d\u2640\ufe0f" +VAMPIRE = "\U0001f9db" +VAMPIRE_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fb" +VAMPIRE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fc" +VAMPIRE_MEDIUM_SKIN_TONE = "\U0001f9db\U0001f3fd" +VAMPIRE_MEDIUM_DARK_SKIN_TONE = "\U0001f9db\U0001f3fe" +VAMPIRE_DARK_SKIN_TONE = "\U0001f9db\U0001f3ff" +MAN_VAMPIRE = "\U0001f9db\u200d\u2642\ufe0f" +MAN_VAMPIRE_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fb\u200d\u2642\ufe0f" +MAN_VAMPIRE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fc\u200d\u2642\ufe0f" +MAN_VAMPIRE_MEDIUM_SKIN_TONE = "\U0001f9db\U0001f3fd\u200d\u2642\ufe0f" +MAN_VAMPIRE_MEDIUM_DARK_SKIN_TONE = "\U0001f9db\U0001f3fe\u200d\u2642\ufe0f" +MAN_VAMPIRE_DARK_SKIN_TONE = "\U0001f9db\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_VAMPIRE = "\U0001f9db\u200d\u2640\ufe0f" +WOMAN_VAMPIRE_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_VAMPIRE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9db\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_VAMPIRE_MEDIUM_SKIN_TONE = "\U0001f9db\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_VAMPIRE_MEDIUM_DARK_SKIN_TONE = "\U0001f9db\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_VAMPIRE_DARK_SKIN_TONE = "\U0001f9db\U0001f3ff\u200d\u2640\ufe0f" +MERPERSON = "\U0001f9dc" +MERPERSON_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fb" +MERPERSON_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fc" +MERPERSON_MEDIUM_SKIN_TONE = "\U0001f9dc\U0001f3fd" +MERPERSON_MEDIUM_DARK_SKIN_TONE = "\U0001f9dc\U0001f3fe" +MERPERSON_DARK_SKIN_TONE = "\U0001f9dc\U0001f3ff" +MERMAN = "\U0001f9dc\u200d\u2642\ufe0f" +MERMAN_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fb\u200d\u2642\ufe0f" +MERMAN_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fc\u200d\u2642\ufe0f" +MERMAN_MEDIUM_SKIN_TONE = "\U0001f9dc\U0001f3fd\u200d\u2642\ufe0f" +MERMAN_MEDIUM_DARK_SKIN_TONE = "\U0001f9dc\U0001f3fe\u200d\u2642\ufe0f" +MERMAN_DARK_SKIN_TONE = "\U0001f9dc\U0001f3ff\u200d\u2642\ufe0f" +MERMAID = "\U0001f9dc\u200d\u2640\ufe0f" +MERMAID_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fb\u200d\u2640\ufe0f" +MERMAID_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dc\U0001f3fc\u200d\u2640\ufe0f" +MERMAID_MEDIUM_SKIN_TONE = "\U0001f9dc\U0001f3fd\u200d\u2640\ufe0f" +MERMAID_MEDIUM_DARK_SKIN_TONE = "\U0001f9dc\U0001f3fe\u200d\u2640\ufe0f" +MERMAID_DARK_SKIN_TONE = "\U0001f9dc\U0001f3ff\u200d\u2640\ufe0f" +ELF = "\U0001f9dd" +ELF_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fb" +ELF_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fc" +ELF_MEDIUM_SKIN_TONE = "\U0001f9dd\U0001f3fd" +ELF_MEDIUM_DARK_SKIN_TONE = "\U0001f9dd\U0001f3fe" +ELF_DARK_SKIN_TONE = "\U0001f9dd\U0001f3ff" +MAN_ELF = "\U0001f9dd\u200d\u2642\ufe0f" +MAN_ELF_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fb\u200d\u2642\ufe0f" +MAN_ELF_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fc\u200d\u2642\ufe0f" +MAN_ELF_MEDIUM_SKIN_TONE = "\U0001f9dd\U0001f3fd\u200d\u2642\ufe0f" +MAN_ELF_MEDIUM_DARK_SKIN_TONE = "\U0001f9dd\U0001f3fe\u200d\u2642\ufe0f" +MAN_ELF_DARK_SKIN_TONE = "\U0001f9dd\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_ELF = "\U0001f9dd\u200d\u2640\ufe0f" +WOMAN_ELF_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_ELF_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9dd\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_ELF_MEDIUM_SKIN_TONE = "\U0001f9dd\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_ELF_MEDIUM_DARK_SKIN_TONE = "\U0001f9dd\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_ELF_DARK_SKIN_TONE = "\U0001f9dd\U0001f3ff\u200d\u2640\ufe0f" +GENIE = "\U0001f9de" +MAN_GENIE = "\U0001f9de\u200d\u2642\ufe0f" +WOMAN_GENIE = "\U0001f9de\u200d\u2640\ufe0f" +ZOMBIE = "\U0001f9df" +MAN_ZOMBIE = "\U0001f9df\u200d\u2642\ufe0f" +WOMAN_ZOMBIE = "\U0001f9df\u200d\u2640\ufe0f" +PERSON_GETTING_MASSAGE = "\U0001f486" +PERSON_GETTING_MASSAGE_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fb" +PERSON_GETTING_MASSAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fc" +PERSON_GETTING_MASSAGE_MEDIUM_SKIN_TONE = "\U0001f486\U0001f3fd" +PERSON_GETTING_MASSAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f486\U0001f3fe" +PERSON_GETTING_MASSAGE_DARK_SKIN_TONE = "\U0001f486\U0001f3ff" +MAN_GETTING_MASSAGE = "\U0001f486\u200d\u2642\ufe0f" +MAN_GETTING_MASSAGE_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fb\u200d\u2642\ufe0f" +MAN_GETTING_MASSAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fc\u200d\u2642\ufe0f" +MAN_GETTING_MASSAGE_MEDIUM_SKIN_TONE = "\U0001f486\U0001f3fd\u200d\u2642\ufe0f" +MAN_GETTING_MASSAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f486\U0001f3fe\u200d\u2642\ufe0f" +MAN_GETTING_MASSAGE_DARK_SKIN_TONE = "\U0001f486\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_GETTING_MASSAGE = "\U0001f486\u200d\u2640\ufe0f" +WOMAN_GETTING_MASSAGE_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_GETTING_MASSAGE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f486\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_GETTING_MASSAGE_MEDIUM_SKIN_TONE = "\U0001f486\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_GETTING_MASSAGE_MEDIUM_DARK_SKIN_TONE = "\U0001f486\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_GETTING_MASSAGE_DARK_SKIN_TONE = "\U0001f486\U0001f3ff\u200d\u2640\ufe0f" +PERSON_GETTING_HAIRCUT = "\U0001f487" +PERSON_GETTING_HAIRCUT_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fb" +PERSON_GETTING_HAIRCUT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fc" +PERSON_GETTING_HAIRCUT_MEDIUM_SKIN_TONE = "\U0001f487\U0001f3fd" +PERSON_GETTING_HAIRCUT_MEDIUM_DARK_SKIN_TONE = "\U0001f487\U0001f3fe" +PERSON_GETTING_HAIRCUT_DARK_SKIN_TONE = "\U0001f487\U0001f3ff" +MAN_GETTING_HAIRCUT = "\U0001f487\u200d\u2642\ufe0f" +MAN_GETTING_HAIRCUT_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fb\u200d\u2642\ufe0f" +MAN_GETTING_HAIRCUT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fc\u200d\u2642\ufe0f" +MAN_GETTING_HAIRCUT_MEDIUM_SKIN_TONE = "\U0001f487\U0001f3fd\u200d\u2642\ufe0f" +MAN_GETTING_HAIRCUT_MEDIUM_DARK_SKIN_TONE = "\U0001f487\U0001f3fe\u200d\u2642\ufe0f" +MAN_GETTING_HAIRCUT_DARK_SKIN_TONE = "\U0001f487\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_GETTING_HAIRCUT = "\U0001f487\u200d\u2640\ufe0f" +WOMAN_GETTING_HAIRCUT_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_GETTING_HAIRCUT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f487\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_GETTING_HAIRCUT_MEDIUM_SKIN_TONE = "\U0001f487\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_GETTING_HAIRCUT_MEDIUM_DARK_SKIN_TONE = "\U0001f487\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_GETTING_HAIRCUT_DARK_SKIN_TONE = "\U0001f487\U0001f3ff\u200d\u2640\ufe0f" +PERSON_WALKING = "\U0001f6b6" +PERSON_WALKING_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fb" +PERSON_WALKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fc" +PERSON_WALKING_MEDIUM_SKIN_TONE = "\U0001f6b6\U0001f3fd" +PERSON_WALKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b6\U0001f3fe" +PERSON_WALKING_DARK_SKIN_TONE = "\U0001f6b6\U0001f3ff" +MAN_WALKING = "\U0001f6b6\u200d\u2642\ufe0f" +MAN_WALKING_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fb\u200d\u2642\ufe0f" +MAN_WALKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fc\u200d\u2642\ufe0f" +MAN_WALKING_MEDIUM_SKIN_TONE = "\U0001f6b6\U0001f3fd\u200d\u2642\ufe0f" +MAN_WALKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b6\U0001f3fe\u200d\u2642\ufe0f" +MAN_WALKING_DARK_SKIN_TONE = "\U0001f6b6\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_WALKING = "\U0001f6b6\u200d\u2640\ufe0f" +WOMAN_WALKING_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_WALKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b6\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_WALKING_MEDIUM_SKIN_TONE = "\U0001f6b6\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_WALKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b6\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_WALKING_DARK_SKIN_TONE = "\U0001f6b6\U0001f3ff\u200d\u2640\ufe0f" +PERSON_STANDING = "\U0001f9cd" +PERSON_STANDING_LIGHT_SKIN_TONE = "\U0001f9cd\U0001f3fb" +PERSON_STANDING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9cd\U0001f3fc" +PERSON_STANDING_MEDIUM_SKIN_TONE = "\U0001f9cd\U0001f3fd" +PERSON_STANDING_MEDIUM_DARK_SKIN_TONE = "\U0001f9cd\U0001f3fe" +PERSON_STANDING_DARK_SKIN_TONE = "\U0001f9cd\U0001f3ff" +MAN_STANDING = "\U0001f9cd\u200d\u2642\ufe0f" +MAN_STANDING_LIGHT_SKIN_TONE = "\U0001f9cd\U0001f3fb\u200d\u2642\ufe0f" +MAN_STANDING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9cd\U0001f3fc\u200d\u2642\ufe0f" +MAN_STANDING_MEDIUM_SKIN_TONE = "\U0001f9cd\U0001f3fd\u200d\u2642\ufe0f" +MAN_STANDING_MEDIUM_DARK_SKIN_TONE = "\U0001f9cd\U0001f3fe\u200d\u2642\ufe0f" +MAN_STANDING_DARK_SKIN_TONE = "\U0001f9cd\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_STANDING = "\U0001f9cd\u200d\u2640\ufe0f" +WOMAN_STANDING_LIGHT_SKIN_TONE = "\U0001f9cd\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_STANDING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9cd\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_STANDING_MEDIUM_SKIN_TONE = "\U0001f9cd\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_STANDING_MEDIUM_DARK_SKIN_TONE = "\U0001f9cd\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_STANDING_DARK_SKIN_TONE = "\U0001f9cd\U0001f3ff\u200d\u2640\ufe0f" +PERSON_KNEELING = "\U0001f9ce" +PERSON_KNEELING_LIGHT_SKIN_TONE = "\U0001f9ce\U0001f3fb" +PERSON_KNEELING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9ce\U0001f3fc" +PERSON_KNEELING_MEDIUM_SKIN_TONE = "\U0001f9ce\U0001f3fd" +PERSON_KNEELING_MEDIUM_DARK_SKIN_TONE = "\U0001f9ce\U0001f3fe" +PERSON_KNEELING_DARK_SKIN_TONE = "\U0001f9ce\U0001f3ff" +MAN_KNEELING = "\U0001f9ce\u200d\u2642\ufe0f" +MAN_KNEELING_LIGHT_SKIN_TONE = "\U0001f9ce\U0001f3fb\u200d\u2642\ufe0f" +MAN_KNEELING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9ce\U0001f3fc\u200d\u2642\ufe0f" +MAN_KNEELING_MEDIUM_SKIN_TONE = "\U0001f9ce\U0001f3fd\u200d\u2642\ufe0f" +MAN_KNEELING_MEDIUM_DARK_SKIN_TONE = "\U0001f9ce\U0001f3fe\u200d\u2642\ufe0f" +MAN_KNEELING_DARK_SKIN_TONE = "\U0001f9ce\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_KNEELING = "\U0001f9ce\u200d\u2640\ufe0f" +WOMAN_KNEELING_LIGHT_SKIN_TONE = "\U0001f9ce\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_KNEELING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9ce\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_KNEELING_MEDIUM_SKIN_TONE = "\U0001f9ce\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_KNEELING_MEDIUM_DARK_SKIN_TONE = "\U0001f9ce\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_KNEELING_DARK_SKIN_TONE = "\U0001f9ce\U0001f3ff\u200d\u2640\ufe0f" +PERSON_WITH_WHITE_CANE = "\U0001f9d1\u200d\U0001f9af" +PERSON_WITH_WHITE_CANE_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f9af" +PERSON_WITH_WHITE_CANE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f9af" +PERSON_WITH_WHITE_CANE_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f9af" +PERSON_WITH_WHITE_CANE_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f9af" +PERSON_WITH_WHITE_CANE_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f9af" +MAN_WITH_WHITE_CANE = "\U0001f468\u200d\U0001f9af" +MAN_WITH_WHITE_CANE_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f9af" +MAN_WITH_WHITE_CANE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f9af" +MAN_WITH_WHITE_CANE_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f9af" +MAN_WITH_WHITE_CANE_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f9af" +MAN_WITH_WHITE_CANE_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f9af" +WOMAN_WITH_WHITE_CANE = "\U0001f469\u200d\U0001f9af" +WOMAN_WITH_WHITE_CANE_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f9af" +WOMAN_WITH_WHITE_CANE_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f9af" +WOMAN_WITH_WHITE_CANE_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f9af" +WOMAN_WITH_WHITE_CANE_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f9af" +WOMAN_WITH_WHITE_CANE_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f9af" +PERSON_IN_MOTORIZED_WHEELCHAIR = "\U0001f9d1\u200d\U0001f9bc" +PERSON_IN_MOTORIZED_WHEELCHAIR_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f9bc" +PERSON_IN_MOTORIZED_WHEELCHAIR_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f9bc" +PERSON_IN_MOTORIZED_WHEELCHAIR_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f9bc" +PERSON_IN_MOTORIZED_WHEELCHAIR_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f9bc" +PERSON_IN_MOTORIZED_WHEELCHAIR_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f9bc" +MAN_IN_MOTORIZED_WHEELCHAIR = "\U0001f468\u200d\U0001f9bc" +MAN_IN_MOTORIZED_WHEELCHAIR_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f9bc" +MAN_IN_MOTORIZED_WHEELCHAIR_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f9bc" +MAN_IN_MOTORIZED_WHEELCHAIR_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f9bc" +MAN_IN_MOTORIZED_WHEELCHAIR_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f9bc" +MAN_IN_MOTORIZED_WHEELCHAIR_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f9bc" +WOMAN_IN_MOTORIZED_WHEELCHAIR = "\U0001f469\u200d\U0001f9bc" +WOMAN_IN_MOTORIZED_WHEELCHAIR_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f9bc" +WOMAN_IN_MOTORIZED_WHEELCHAIR_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f9bc" +WOMAN_IN_MOTORIZED_WHEELCHAIR_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f9bc" +WOMAN_IN_MOTORIZED_WHEELCHAIR_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f9bc" +WOMAN_IN_MOTORIZED_WHEELCHAIR_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f9bc" +PERSON_IN_MANUAL_WHEELCHAIR = "\U0001f9d1\u200d\U0001f9bd" +PERSON_IN_MANUAL_WHEELCHAIR_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f9bd" +PERSON_IN_MANUAL_WHEELCHAIR_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f9bd" +PERSON_IN_MANUAL_WHEELCHAIR_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f9bd" +PERSON_IN_MANUAL_WHEELCHAIR_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f9bd" +PERSON_IN_MANUAL_WHEELCHAIR_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f9bd" +MAN_IN_MANUAL_WHEELCHAIR = "\U0001f468\u200d\U0001f9bd" +MAN_IN_MANUAL_WHEELCHAIR_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f9bd" +MAN_IN_MANUAL_WHEELCHAIR_MEDIUM_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fc\u200d\U0001f9bd" +MAN_IN_MANUAL_WHEELCHAIR_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f9bd" +MAN_IN_MANUAL_WHEELCHAIR_MEDIUM_DARK_SKIN_TONE = "\U0001f468\U0001f3fe\u200d\U0001f9bd" +MAN_IN_MANUAL_WHEELCHAIR_DARK_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f9bd" +WOMAN_IN_MANUAL_WHEELCHAIR = "\U0001f469\u200d\U0001f9bd" +WOMAN_IN_MANUAL_WHEELCHAIR_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f9bd" +WOMAN_IN_MANUAL_WHEELCHAIR_MEDIUM_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fc\u200d\U0001f9bd" +WOMAN_IN_MANUAL_WHEELCHAIR_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f9bd" +WOMAN_IN_MANUAL_WHEELCHAIR_MEDIUM_DARK_SKIN_TONE = "\U0001f469\U0001f3fe\u200d\U0001f9bd" +WOMAN_IN_MANUAL_WHEELCHAIR_DARK_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f9bd" +PERSON_RUNNING = "\U0001f3c3" +PERSON_RUNNING_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fb" +PERSON_RUNNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fc" +PERSON_RUNNING_MEDIUM_SKIN_TONE = "\U0001f3c3\U0001f3fd" +PERSON_RUNNING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c3\U0001f3fe" +PERSON_RUNNING_DARK_SKIN_TONE = "\U0001f3c3\U0001f3ff" +MAN_RUNNING = "\U0001f3c3\u200d\u2642\ufe0f" +MAN_RUNNING_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fb\u200d\u2642\ufe0f" +MAN_RUNNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fc\u200d\u2642\ufe0f" +MAN_RUNNING_MEDIUM_SKIN_TONE = "\U0001f3c3\U0001f3fd\u200d\u2642\ufe0f" +MAN_RUNNING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c3\U0001f3fe\u200d\u2642\ufe0f" +MAN_RUNNING_DARK_SKIN_TONE = "\U0001f3c3\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_RUNNING = "\U0001f3c3\u200d\u2640\ufe0f" +WOMAN_RUNNING_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_RUNNING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c3\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_RUNNING_MEDIUM_SKIN_TONE = "\U0001f3c3\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_RUNNING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c3\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_RUNNING_DARK_SKIN_TONE = "\U0001f3c3\U0001f3ff\u200d\u2640\ufe0f" +WOMAN_DANCING = "\U0001f483" +WOMAN_DANCING_LIGHT_SKIN_TONE = "\U0001f483\U0001f3fb" +WOMAN_DANCING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f483\U0001f3fc" +WOMAN_DANCING_MEDIUM_SKIN_TONE = "\U0001f483\U0001f3fd" +WOMAN_DANCING_MEDIUM_DARK_SKIN_TONE = "\U0001f483\U0001f3fe" +WOMAN_DANCING_DARK_SKIN_TONE = "\U0001f483\U0001f3ff" +MAN_DANCING = "\U0001f57a" +MAN_DANCING_LIGHT_SKIN_TONE = "\U0001f57a\U0001f3fb" +MAN_DANCING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f57a\U0001f3fc" +MAN_DANCING_MEDIUM_SKIN_TONE = "\U0001f57a\U0001f3fd" +MAN_DANCING_MEDIUM_DARK_SKIN_TONE = "\U0001f57a\U0001f3fe" +MAN_DANCING_DARK_SKIN_TONE = "\U0001f57a\U0001f3ff" +PERSON_IN_SUIT_LEVITATING = "\U0001f574\ufe0f" +PERSON_IN_SUIT_LEVITATING_LIGHT_SKIN_TONE = "\U0001f574\U0001f3fb" +PERSON_IN_SUIT_LEVITATING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f574\U0001f3fc" +PERSON_IN_SUIT_LEVITATING_MEDIUM_SKIN_TONE = "\U0001f574\U0001f3fd" +PERSON_IN_SUIT_LEVITATING_MEDIUM_DARK_SKIN_TONE = "\U0001f574\U0001f3fe" +PERSON_IN_SUIT_LEVITATING_DARK_SKIN_TONE = "\U0001f574\U0001f3ff" +PEOPLE_WITH_BUNNY_EARS = "\U0001f46f" +MEN_WITH_BUNNY_EARS = "\U0001f46f\u200d\u2642\ufe0f" +WOMEN_WITH_BUNNY_EARS = "\U0001f46f\u200d\u2640\ufe0f" +PERSON_IN_STEAMY_ROOM = "\U0001f9d6" +PERSON_IN_STEAMY_ROOM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fb" +PERSON_IN_STEAMY_ROOM_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fc" +PERSON_IN_STEAMY_ROOM_MEDIUM_SKIN_TONE = "\U0001f9d6\U0001f3fd" +PERSON_IN_STEAMY_ROOM_MEDIUM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3fe" +PERSON_IN_STEAMY_ROOM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3ff" +MAN_IN_STEAMY_ROOM = "\U0001f9d6\u200d\u2642\ufe0f" +MAN_IN_STEAMY_ROOM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fb\u200d\u2642\ufe0f" +MAN_IN_STEAMY_ROOM_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fc\u200d\u2642\ufe0f" +MAN_IN_STEAMY_ROOM_MEDIUM_SKIN_TONE = "\U0001f9d6\U0001f3fd\u200d\u2642\ufe0f" +MAN_IN_STEAMY_ROOM_MEDIUM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3fe\u200d\u2642\ufe0f" +MAN_IN_STEAMY_ROOM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_IN_STEAMY_ROOM = "\U0001f9d6\u200d\u2640\ufe0f" +WOMAN_IN_STEAMY_ROOM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_IN_STEAMY_ROOM_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d6\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_IN_STEAMY_ROOM_MEDIUM_SKIN_TONE = "\U0001f9d6\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_IN_STEAMY_ROOM_MEDIUM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_IN_STEAMY_ROOM_DARK_SKIN_TONE = "\U0001f9d6\U0001f3ff\u200d\u2640\ufe0f" +PERSON_CLIMBING = "\U0001f9d7" +PERSON_CLIMBING_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fb" +PERSON_CLIMBING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fc" +PERSON_CLIMBING_MEDIUM_SKIN_TONE = "\U0001f9d7\U0001f3fd" +PERSON_CLIMBING_MEDIUM_DARK_SKIN_TONE = "\U0001f9d7\U0001f3fe" +PERSON_CLIMBING_DARK_SKIN_TONE = "\U0001f9d7\U0001f3ff" +MAN_CLIMBING = "\U0001f9d7\u200d\u2642\ufe0f" +MAN_CLIMBING_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fb\u200d\u2642\ufe0f" +MAN_CLIMBING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fc\u200d\u2642\ufe0f" +MAN_CLIMBING_MEDIUM_SKIN_TONE = "\U0001f9d7\U0001f3fd\u200d\u2642\ufe0f" +MAN_CLIMBING_MEDIUM_DARK_SKIN_TONE = "\U0001f9d7\U0001f3fe\u200d\u2642\ufe0f" +MAN_CLIMBING_DARK_SKIN_TONE = "\U0001f9d7\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_CLIMBING = "\U0001f9d7\u200d\u2640\ufe0f" +WOMAN_CLIMBING_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_CLIMBING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d7\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_CLIMBING_MEDIUM_SKIN_TONE = "\U0001f9d7\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_CLIMBING_MEDIUM_DARK_SKIN_TONE = "\U0001f9d7\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_CLIMBING_DARK_SKIN_TONE = "\U0001f9d7\U0001f3ff\u200d\u2640\ufe0f" +PERSON_FENCING = "\U0001f93a" +HORSE_RACING = "\U0001f3c7" +HORSE_RACING_LIGHT_SKIN_TONE = "\U0001f3c7\U0001f3fb" +HORSE_RACING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c7\U0001f3fc" +HORSE_RACING_MEDIUM_SKIN_TONE = "\U0001f3c7\U0001f3fd" +HORSE_RACING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c7\U0001f3fe" +HORSE_RACING_DARK_SKIN_TONE = "\U0001f3c7\U0001f3ff" +SKIER = "\u26f7\ufe0f" +SNOWBOARDER = "\U0001f3c2" +SNOWBOARDER_LIGHT_SKIN_TONE = "\U0001f3c2\U0001f3fb" +SNOWBOARDER_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c2\U0001f3fc" +SNOWBOARDER_MEDIUM_SKIN_TONE = "\U0001f3c2\U0001f3fd" +SNOWBOARDER_MEDIUM_DARK_SKIN_TONE = "\U0001f3c2\U0001f3fe" +SNOWBOARDER_DARK_SKIN_TONE = "\U0001f3c2\U0001f3ff" +PERSON_GOLFING = "\U0001f3cc\ufe0f" +PERSON_GOLFING_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fb" +PERSON_GOLFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fc" +PERSON_GOLFING_MEDIUM_SKIN_TONE = "\U0001f3cc\U0001f3fd" +PERSON_GOLFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3cc\U0001f3fe" +PERSON_GOLFING_DARK_SKIN_TONE = "\U0001f3cc\U0001f3ff" +MAN_GOLFING = "\U0001f3cc\ufe0f\u200d\u2642\ufe0f" +MAN_GOLFING_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fb\u200d\u2642\ufe0f" +MAN_GOLFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fc\u200d\u2642\ufe0f" +MAN_GOLFING_MEDIUM_SKIN_TONE = "\U0001f3cc\U0001f3fd\u200d\u2642\ufe0f" +MAN_GOLFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3cc\U0001f3fe\u200d\u2642\ufe0f" +MAN_GOLFING_DARK_SKIN_TONE = "\U0001f3cc\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_GOLFING = "\U0001f3cc\ufe0f\u200d\u2640\ufe0f" +WOMAN_GOLFING_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_GOLFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cc\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_GOLFING_MEDIUM_SKIN_TONE = "\U0001f3cc\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_GOLFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3cc\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_GOLFING_DARK_SKIN_TONE = "\U0001f3cc\U0001f3ff\u200d\u2640\ufe0f" +PERSON_SURFING = "\U0001f3c4" +PERSON_SURFING_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fb" +PERSON_SURFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fc" +PERSON_SURFING_MEDIUM_SKIN_TONE = "\U0001f3c4\U0001f3fd" +PERSON_SURFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c4\U0001f3fe" +PERSON_SURFING_DARK_SKIN_TONE = "\U0001f3c4\U0001f3ff" +MAN_SURFING = "\U0001f3c4\u200d\u2642\ufe0f" +MAN_SURFING_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fb\u200d\u2642\ufe0f" +MAN_SURFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fc\u200d\u2642\ufe0f" +MAN_SURFING_MEDIUM_SKIN_TONE = "\U0001f3c4\U0001f3fd\u200d\u2642\ufe0f" +MAN_SURFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c4\U0001f3fe\u200d\u2642\ufe0f" +MAN_SURFING_DARK_SKIN_TONE = "\U0001f3c4\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_SURFING = "\U0001f3c4\u200d\u2640\ufe0f" +WOMAN_SURFING_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_SURFING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3c4\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_SURFING_MEDIUM_SKIN_TONE = "\U0001f3c4\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_SURFING_MEDIUM_DARK_SKIN_TONE = "\U0001f3c4\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_SURFING_DARK_SKIN_TONE = "\U0001f3c4\U0001f3ff\u200d\u2640\ufe0f" +PERSON_ROWING_BOAT = "\U0001f6a3" +PERSON_ROWING_BOAT_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fb" +PERSON_ROWING_BOAT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fc" +PERSON_ROWING_BOAT_MEDIUM_SKIN_TONE = "\U0001f6a3\U0001f3fd" +PERSON_ROWING_BOAT_MEDIUM_DARK_SKIN_TONE = "\U0001f6a3\U0001f3fe" +PERSON_ROWING_BOAT_DARK_SKIN_TONE = "\U0001f6a3\U0001f3ff" +MAN_ROWING_BOAT = "\U0001f6a3\u200d\u2642\ufe0f" +MAN_ROWING_BOAT_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fb\u200d\u2642\ufe0f" +MAN_ROWING_BOAT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fc\u200d\u2642\ufe0f" +MAN_ROWING_BOAT_MEDIUM_SKIN_TONE = "\U0001f6a3\U0001f3fd\u200d\u2642\ufe0f" +MAN_ROWING_BOAT_MEDIUM_DARK_SKIN_TONE = "\U0001f6a3\U0001f3fe\u200d\u2642\ufe0f" +MAN_ROWING_BOAT_DARK_SKIN_TONE = "\U0001f6a3\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_ROWING_BOAT = "\U0001f6a3\u200d\u2640\ufe0f" +WOMAN_ROWING_BOAT_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_ROWING_BOAT_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6a3\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_ROWING_BOAT_MEDIUM_SKIN_TONE = "\U0001f6a3\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_ROWING_BOAT_MEDIUM_DARK_SKIN_TONE = "\U0001f6a3\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_ROWING_BOAT_DARK_SKIN_TONE = "\U0001f6a3\U0001f3ff\u200d\u2640\ufe0f" +PERSON_SWIMMING = "\U0001f3ca" +PERSON_SWIMMING_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fb" +PERSON_SWIMMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fc" +PERSON_SWIMMING_MEDIUM_SKIN_TONE = "\U0001f3ca\U0001f3fd" +PERSON_SWIMMING_MEDIUM_DARK_SKIN_TONE = "\U0001f3ca\U0001f3fe" +PERSON_SWIMMING_DARK_SKIN_TONE = "\U0001f3ca\U0001f3ff" +MAN_SWIMMING = "\U0001f3ca\u200d\u2642\ufe0f" +MAN_SWIMMING_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fb\u200d\u2642\ufe0f" +MAN_SWIMMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fc\u200d\u2642\ufe0f" +MAN_SWIMMING_MEDIUM_SKIN_TONE = "\U0001f3ca\U0001f3fd\u200d\u2642\ufe0f" +MAN_SWIMMING_MEDIUM_DARK_SKIN_TONE = "\U0001f3ca\U0001f3fe\u200d\u2642\ufe0f" +MAN_SWIMMING_DARK_SKIN_TONE = "\U0001f3ca\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_SWIMMING = "\U0001f3ca\u200d\u2640\ufe0f" +WOMAN_SWIMMING_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_SWIMMING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3ca\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_SWIMMING_MEDIUM_SKIN_TONE = "\U0001f3ca\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_SWIMMING_MEDIUM_DARK_SKIN_TONE = "\U0001f3ca\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_SWIMMING_DARK_SKIN_TONE = "\U0001f3ca\U0001f3ff\u200d\u2640\ufe0f" +PERSON_BOUNCING_BALL = "\u26f9\ufe0f" +PERSON_BOUNCING_BALL_LIGHT_SKIN_TONE = "\u26f9\U0001f3fb" +PERSON_BOUNCING_BALL_MEDIUM_LIGHT_SKIN_TONE = "\u26f9\U0001f3fc" +PERSON_BOUNCING_BALL_MEDIUM_SKIN_TONE = "\u26f9\U0001f3fd" +PERSON_BOUNCING_BALL_MEDIUM_DARK_SKIN_TONE = "\u26f9\U0001f3fe" +PERSON_BOUNCING_BALL_DARK_SKIN_TONE = "\u26f9\U0001f3ff" +MAN_BOUNCING_BALL = "\u26f9\ufe0f\u200d\u2642\ufe0f" +MAN_BOUNCING_BALL_LIGHT_SKIN_TONE = "\u26f9\U0001f3fb\u200d\u2642\ufe0f" +MAN_BOUNCING_BALL_MEDIUM_LIGHT_SKIN_TONE = "\u26f9\U0001f3fc\u200d\u2642\ufe0f" +MAN_BOUNCING_BALL_MEDIUM_SKIN_TONE = "\u26f9\U0001f3fd\u200d\u2642\ufe0f" +MAN_BOUNCING_BALL_MEDIUM_DARK_SKIN_TONE = "\u26f9\U0001f3fe\u200d\u2642\ufe0f" +MAN_BOUNCING_BALL_DARK_SKIN_TONE = "\u26f9\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_BOUNCING_BALL = "\u26f9\ufe0f\u200d\u2640\ufe0f" +WOMAN_BOUNCING_BALL_LIGHT_SKIN_TONE = "\u26f9\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_BOUNCING_BALL_MEDIUM_LIGHT_SKIN_TONE = "\u26f9\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_BOUNCING_BALL_MEDIUM_SKIN_TONE = "\u26f9\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_BOUNCING_BALL_MEDIUM_DARK_SKIN_TONE = "\u26f9\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_BOUNCING_BALL_DARK_SKIN_TONE = "\u26f9\U0001f3ff\u200d\u2640\ufe0f" +PERSON_LIFTING_WEIGHTS = "\U0001f3cb\ufe0f" +PERSON_LIFTING_WEIGHTS_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fb" +PERSON_LIFTING_WEIGHTS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fc" +PERSON_LIFTING_WEIGHTS_MEDIUM_SKIN_TONE = "\U0001f3cb\U0001f3fd" +PERSON_LIFTING_WEIGHTS_MEDIUM_DARK_SKIN_TONE = "\U0001f3cb\U0001f3fe" +PERSON_LIFTING_WEIGHTS_DARK_SKIN_TONE = "\U0001f3cb\U0001f3ff" +MAN_LIFTING_WEIGHTS = "\U0001f3cb\ufe0f\u200d\u2642\ufe0f" +MAN_LIFTING_WEIGHTS_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fb\u200d\u2642\ufe0f" +MAN_LIFTING_WEIGHTS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fc\u200d\u2642\ufe0f" +MAN_LIFTING_WEIGHTS_MEDIUM_SKIN_TONE = "\U0001f3cb\U0001f3fd\u200d\u2642\ufe0f" +MAN_LIFTING_WEIGHTS_MEDIUM_DARK_SKIN_TONE = "\U0001f3cb\U0001f3fe\u200d\u2642\ufe0f" +MAN_LIFTING_WEIGHTS_DARK_SKIN_TONE = "\U0001f3cb\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_LIFTING_WEIGHTS = "\U0001f3cb\ufe0f\u200d\u2640\ufe0f" +WOMAN_LIFTING_WEIGHTS_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_LIFTING_WEIGHTS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f3cb\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_LIFTING_WEIGHTS_MEDIUM_SKIN_TONE = "\U0001f3cb\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_LIFTING_WEIGHTS_MEDIUM_DARK_SKIN_TONE = "\U0001f3cb\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_LIFTING_WEIGHTS_DARK_SKIN_TONE = "\U0001f3cb\U0001f3ff\u200d\u2640\ufe0f" +PERSON_BIKING = "\U0001f6b4" +PERSON_BIKING_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fb" +PERSON_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fc" +PERSON_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b4\U0001f3fd" +PERSON_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b4\U0001f3fe" +PERSON_BIKING_DARK_SKIN_TONE = "\U0001f6b4\U0001f3ff" +MAN_BIKING = "\U0001f6b4\u200d\u2642\ufe0f" +MAN_BIKING_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fb\u200d\u2642\ufe0f" +MAN_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fc\u200d\u2642\ufe0f" +MAN_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b4\U0001f3fd\u200d\u2642\ufe0f" +MAN_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b4\U0001f3fe\u200d\u2642\ufe0f" +MAN_BIKING_DARK_SKIN_TONE = "\U0001f6b4\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_BIKING = "\U0001f6b4\u200d\u2640\ufe0f" +WOMAN_BIKING_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b4\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b4\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b4\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_BIKING_DARK_SKIN_TONE = "\U0001f6b4\U0001f3ff\u200d\u2640\ufe0f" +PERSON_MOUNTAIN_BIKING = "\U0001f6b5" +PERSON_MOUNTAIN_BIKING_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fb" +PERSON_MOUNTAIN_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fc" +PERSON_MOUNTAIN_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b5\U0001f3fd" +PERSON_MOUNTAIN_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b5\U0001f3fe" +PERSON_MOUNTAIN_BIKING_DARK_SKIN_TONE = "\U0001f6b5\U0001f3ff" +MAN_MOUNTAIN_BIKING = "\U0001f6b5\u200d\u2642\ufe0f" +MAN_MOUNTAIN_BIKING_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fb\u200d\u2642\ufe0f" +MAN_MOUNTAIN_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fc\u200d\u2642\ufe0f" +MAN_MOUNTAIN_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b5\U0001f3fd\u200d\u2642\ufe0f" +MAN_MOUNTAIN_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b5\U0001f3fe\u200d\u2642\ufe0f" +MAN_MOUNTAIN_BIKING_DARK_SKIN_TONE = "\U0001f6b5\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_MOUNTAIN_BIKING = "\U0001f6b5\u200d\u2640\ufe0f" +WOMAN_MOUNTAIN_BIKING_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_MOUNTAIN_BIKING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6b5\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_MOUNTAIN_BIKING_MEDIUM_SKIN_TONE = "\U0001f6b5\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_MOUNTAIN_BIKING_MEDIUM_DARK_SKIN_TONE = "\U0001f6b5\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_MOUNTAIN_BIKING_DARK_SKIN_TONE = "\U0001f6b5\U0001f3ff\u200d\u2640\ufe0f" +PERSON_CARTWHEELING = "\U0001f938" +PERSON_CARTWHEELING_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fb" +PERSON_CARTWHEELING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fc" +PERSON_CARTWHEELING_MEDIUM_SKIN_TONE = "\U0001f938\U0001f3fd" +PERSON_CARTWHEELING_MEDIUM_DARK_SKIN_TONE = "\U0001f938\U0001f3fe" +PERSON_CARTWHEELING_DARK_SKIN_TONE = "\U0001f938\U0001f3ff" +MAN_CARTWHEELING = "\U0001f938\u200d\u2642\ufe0f" +MAN_CARTWHEELING_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fb\u200d\u2642\ufe0f" +MAN_CARTWHEELING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fc\u200d\u2642\ufe0f" +MAN_CARTWHEELING_MEDIUM_SKIN_TONE = "\U0001f938\U0001f3fd\u200d\u2642\ufe0f" +MAN_CARTWHEELING_MEDIUM_DARK_SKIN_TONE = "\U0001f938\U0001f3fe\u200d\u2642\ufe0f" +MAN_CARTWHEELING_DARK_SKIN_TONE = "\U0001f938\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_CARTWHEELING = "\U0001f938\u200d\u2640\ufe0f" +WOMAN_CARTWHEELING_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_CARTWHEELING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f938\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_CARTWHEELING_MEDIUM_SKIN_TONE = "\U0001f938\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_CARTWHEELING_MEDIUM_DARK_SKIN_TONE = "\U0001f938\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_CARTWHEELING_DARK_SKIN_TONE = "\U0001f938\U0001f3ff\u200d\u2640\ufe0f" +PEOPLE_WRESTLING = "\U0001f93c" +PERSON_PLAYING_WATER_POLO = "\U0001f93d" +PERSON_PLAYING_WATER_POLO_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fb" +PERSON_PLAYING_WATER_POLO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fc" +PERSON_PLAYING_WATER_POLO_MEDIUM_SKIN_TONE = "\U0001f93d\U0001f3fd" +PERSON_PLAYING_WATER_POLO_MEDIUM_DARK_SKIN_TONE = "\U0001f93d\U0001f3fe" +PERSON_PLAYING_WATER_POLO_DARK_SKIN_TONE = "\U0001f93d\U0001f3ff" +MAN_PLAYING_WATER_POLO = "\U0001f93d\u200d\u2642\ufe0f" +MAN_PLAYING_WATER_POLO_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fb\u200d\u2642\ufe0f" +MAN_PLAYING_WATER_POLO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fc\u200d\u2642\ufe0f" +MAN_PLAYING_WATER_POLO_MEDIUM_SKIN_TONE = "\U0001f93d\U0001f3fd\u200d\u2642\ufe0f" +MAN_PLAYING_WATER_POLO_MEDIUM_DARK_SKIN_TONE = "\U0001f93d\U0001f3fe\u200d\u2642\ufe0f" +MAN_PLAYING_WATER_POLO_DARK_SKIN_TONE = "\U0001f93d\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_PLAYING_WATER_POLO = "\U0001f93d\u200d\u2640\ufe0f" +WOMAN_PLAYING_WATER_POLO_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_PLAYING_WATER_POLO_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93d\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_PLAYING_WATER_POLO_MEDIUM_SKIN_TONE = "\U0001f93d\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_PLAYING_WATER_POLO_MEDIUM_DARK_SKIN_TONE = "\U0001f93d\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_PLAYING_WATER_POLO_DARK_SKIN_TONE = "\U0001f93d\U0001f3ff\u200d\u2640\ufe0f" +PERSON_PLAYING_HANDBALL = "\U0001f93e" +PERSON_PLAYING_HANDBALL_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fb" +PERSON_PLAYING_HANDBALL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fc" +PERSON_PLAYING_HANDBALL_MEDIUM_SKIN_TONE = "\U0001f93e\U0001f3fd" +PERSON_PLAYING_HANDBALL_MEDIUM_DARK_SKIN_TONE = "\U0001f93e\U0001f3fe" +PERSON_PLAYING_HANDBALL_DARK_SKIN_TONE = "\U0001f93e\U0001f3ff" +MAN_PLAYING_HANDBALL = "\U0001f93e\u200d\u2642\ufe0f" +MAN_PLAYING_HANDBALL_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fb\u200d\u2642\ufe0f" +MAN_PLAYING_HANDBALL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fc\u200d\u2642\ufe0f" +MAN_PLAYING_HANDBALL_MEDIUM_SKIN_TONE = "\U0001f93e\U0001f3fd\u200d\u2642\ufe0f" +MAN_PLAYING_HANDBALL_MEDIUM_DARK_SKIN_TONE = "\U0001f93e\U0001f3fe\u200d\u2642\ufe0f" +MAN_PLAYING_HANDBALL_DARK_SKIN_TONE = "\U0001f93e\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_PLAYING_HANDBALL = "\U0001f93e\u200d\u2640\ufe0f" +WOMAN_PLAYING_HANDBALL_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_PLAYING_HANDBALL_MEDIUM_LIGHT_SKIN_TONE = "\U0001f93e\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_PLAYING_HANDBALL_MEDIUM_SKIN_TONE = "\U0001f93e\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_PLAYING_HANDBALL_MEDIUM_DARK_SKIN_TONE = "\U0001f93e\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_PLAYING_HANDBALL_DARK_SKIN_TONE = "\U0001f93e\U0001f3ff\u200d\u2640\ufe0f" +PERSON_JUGGLING = "\U0001f939" +PERSON_JUGGLING_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fb" +PERSON_JUGGLING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fc" +PERSON_JUGGLING_MEDIUM_SKIN_TONE = "\U0001f939\U0001f3fd" +PERSON_JUGGLING_MEDIUM_DARK_SKIN_TONE = "\U0001f939\U0001f3fe" +PERSON_JUGGLING_DARK_SKIN_TONE = "\U0001f939\U0001f3ff" +MAN_JUGGLING = "\U0001f939\u200d\u2642\ufe0f" +MAN_JUGGLING_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fb\u200d\u2642\ufe0f" +MAN_JUGGLING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fc\u200d\u2642\ufe0f" +MAN_JUGGLING_MEDIUM_SKIN_TONE = "\U0001f939\U0001f3fd\u200d\u2642\ufe0f" +MAN_JUGGLING_MEDIUM_DARK_SKIN_TONE = "\U0001f939\U0001f3fe\u200d\u2642\ufe0f" +MAN_JUGGLING_DARK_SKIN_TONE = "\U0001f939\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_JUGGLING = "\U0001f939\u200d\u2640\ufe0f" +WOMAN_JUGGLING_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_JUGGLING_MEDIUM_LIGHT_SKIN_TONE = "\U0001f939\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_JUGGLING_MEDIUM_SKIN_TONE = "\U0001f939\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_JUGGLING_MEDIUM_DARK_SKIN_TONE = "\U0001f939\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_JUGGLING_DARK_SKIN_TONE = "\U0001f939\U0001f3ff\u200d\u2640\ufe0f" +PERSON_IN_LOTUS_POSITION = "\U0001f9d8" +PERSON_IN_LOTUS_POSITION_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fb" +PERSON_IN_LOTUS_POSITION_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fc" +PERSON_IN_LOTUS_POSITION_MEDIUM_SKIN_TONE = "\U0001f9d8\U0001f3fd" +PERSON_IN_LOTUS_POSITION_MEDIUM_DARK_SKIN_TONE = "\U0001f9d8\U0001f3fe" +PERSON_IN_LOTUS_POSITION_DARK_SKIN_TONE = "\U0001f9d8\U0001f3ff" +MAN_IN_LOTUS_POSITION = "\U0001f9d8\u200d\u2642\ufe0f" +MAN_IN_LOTUS_POSITION_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fb\u200d\u2642\ufe0f" +MAN_IN_LOTUS_POSITION_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fc\u200d\u2642\ufe0f" +MAN_IN_LOTUS_POSITION_MEDIUM_SKIN_TONE = "\U0001f9d8\U0001f3fd\u200d\u2642\ufe0f" +MAN_IN_LOTUS_POSITION_MEDIUM_DARK_SKIN_TONE = "\U0001f9d8\U0001f3fe\u200d\u2642\ufe0f" +MAN_IN_LOTUS_POSITION_DARK_SKIN_TONE = "\U0001f9d8\U0001f3ff\u200d\u2642\ufe0f" +WOMAN_IN_LOTUS_POSITION = "\U0001f9d8\u200d\u2640\ufe0f" +WOMAN_IN_LOTUS_POSITION_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fb\u200d\u2640\ufe0f" +WOMAN_IN_LOTUS_POSITION_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d8\U0001f3fc\u200d\u2640\ufe0f" +WOMAN_IN_LOTUS_POSITION_MEDIUM_SKIN_TONE = "\U0001f9d8\U0001f3fd\u200d\u2640\ufe0f" +WOMAN_IN_LOTUS_POSITION_MEDIUM_DARK_SKIN_TONE = "\U0001f9d8\U0001f3fe\u200d\u2640\ufe0f" +WOMAN_IN_LOTUS_POSITION_DARK_SKIN_TONE = "\U0001f9d8\U0001f3ff\u200d\u2640\ufe0f" +PERSON_TAKING_BATH = "\U0001f6c0" +PERSON_TAKING_BATH_LIGHT_SKIN_TONE = "\U0001f6c0\U0001f3fb" +PERSON_TAKING_BATH_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6c0\U0001f3fc" +PERSON_TAKING_BATH_MEDIUM_SKIN_TONE = "\U0001f6c0\U0001f3fd" +PERSON_TAKING_BATH_MEDIUM_DARK_SKIN_TONE = "\U0001f6c0\U0001f3fe" +PERSON_TAKING_BATH_DARK_SKIN_TONE = "\U0001f6c0\U0001f3ff" +PERSON_IN_BED = "\U0001f6cc" +PERSON_IN_BED_LIGHT_SKIN_TONE = "\U0001f6cc\U0001f3fb" +PERSON_IN_BED_MEDIUM_LIGHT_SKIN_TONE = "\U0001f6cc\U0001f3fc" +PERSON_IN_BED_MEDIUM_SKIN_TONE = "\U0001f6cc\U0001f3fd" +PERSON_IN_BED_MEDIUM_DARK_SKIN_TONE = "\U0001f6cc\U0001f3fe" +PERSON_IN_BED_DARK_SKIN_TONE = "\U0001f6cc\U0001f3ff" +PEOPLE_HOLDING_HANDS = "\U0001f9d1\u200d\U0001f91d\u200d\U0001f9d1" +PEOPLE_HOLDING_HANDS_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fb" +PEOPLE_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f9d1\U0001f3fb\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fc" +PEOPLE_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_SKIN_TONE = \ + "\U0001f9d1\U0001f3fb\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fd" +PEOPLE_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f9d1\U0001f3fb\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fe" +PEOPLE_HOLDING_HANDS_LIGHT_SKIN_TONE_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fb\u200d\U0001f91d\u200d\U0001f9d1\U0001f3ff" +PEOPLE_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_LIGHT_SKIN_TONE = \ + "\U0001f9d1\U0001f3fc\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fb" +PEOPLE_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3fc\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fc" +PEOPLE_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_MEDIUM_SKIN_TONE = \ + "\U0001f9d1\U0001f3fc\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fd" +PEOPLE_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f9d1\U0001f3fc\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fe" +PEOPLE_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_DARK_SKIN_TONE = \ + "\U0001f9d1\U0001f3fc\u200d\U0001f91d\u200d\U0001f9d1\U0001f3ff" +PEOPLE_HOLDING_HANDS_MEDIUM_SKIN_TONE_LIGHT_SKIN_TONE = \ + "\U0001f9d1\U0001f3fd\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fb" +PEOPLE_HOLDING_HANDS_MEDIUM_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f9d1\U0001f3fd\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fc" +PEOPLE_HOLDING_HANDS_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fd" +PEOPLE_HOLDING_HANDS_MEDIUM_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f9d1\U0001f3fd\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fe" +PEOPLE_HOLDING_HANDS_MEDIUM_SKIN_TONE_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fd\u200d\U0001f91d\u200d\U0001f9d1\U0001f3ff" +PEOPLE_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_LIGHT_SKIN_TONE = \ + "\U0001f9d1\U0001f3fe\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fb" +PEOPLE_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f9d1\U0001f3fe\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fc" +PEOPLE_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_MEDIUM_SKIN_TONE = \ + "\U0001f9d1\U0001f3fe\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fd" +PEOPLE_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f9d1\U0001f3fe\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fe" +PEOPLE_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_DARK_SKIN_TONE = \ + "\U0001f9d1\U0001f3fe\u200d\U0001f91d\u200d\U0001f9d1\U0001f3ff" +PEOPLE_HOLDING_HANDS_DARK_SKIN_TONE_LIGHT_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fb" +PEOPLE_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f9d1\U0001f3ff\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fc" +PEOPLE_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fd" +PEOPLE_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f9d1\U0001f3ff\u200d\U0001f91d\u200d\U0001f9d1\U0001f3fe" +PEOPLE_HOLDING_HANDS_DARK_SKIN_TONE = "\U0001f9d1\U0001f3ff\u200d\U0001f91d\u200d\U0001f9d1\U0001f3ff" +WOMEN_HOLDING_HANDS = "\U0001f46d" +WOMEN_HOLDING_HANDS_LIGHT_SKIN_TONE = "\U0001f46d\U0001f3fb" +WOMEN_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3fb\u200d\U0001f91d\u200d\U0001f469\U0001f3fc" +WOMEN_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f91d\u200d\U0001f469\U0001f3fd" +WOMEN_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fb\u200d\U0001f91d\u200d\U0001f469\U0001f3fe" +WOMEN_HOLDING_HANDS_LIGHT_SKIN_TONE_DARK_SKIN_TONE = "\U0001f469\U0001f3fb\u200d\U0001f91d\u200d\U0001f469\U0001f3ff" +WOMEN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3fc\u200d\U0001f91d\u200d\U0001f469\U0001f3fb" +WOMEN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f46d\U0001f3fc" +WOMEN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_MEDIUM_SKIN_TONE = \ + "\U0001f469\U0001f3fc\u200d\U0001f91d\u200d\U0001f469\U0001f3fd" +WOMEN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fc\u200d\U0001f91d\u200d\U0001f469\U0001f3fe" +WOMEN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fc\u200d\U0001f91d\u200d\U0001f469\U0001f3ff" +WOMEN_HOLDING_HANDS_MEDIUM_SKIN_TONE_LIGHT_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f91d\u200d\U0001f469\U0001f3fb" +WOMEN_HOLDING_HANDS_MEDIUM_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3fd\u200d\U0001f91d\u200d\U0001f469\U0001f3fc" +WOMEN_HOLDING_HANDS_MEDIUM_SKIN_TONE = "\U0001f46d\U0001f3fd" +WOMEN_HOLDING_HANDS_MEDIUM_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fd\u200d\U0001f91d\u200d\U0001f469\U0001f3fe" +WOMEN_HOLDING_HANDS_MEDIUM_SKIN_TONE_DARK_SKIN_TONE = "\U0001f469\U0001f3fd\u200d\U0001f91d\u200d\U0001f469\U0001f3ff" +WOMEN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3fe\u200d\U0001f91d\u200d\U0001f469\U0001f3fb" +WOMEN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3fe\u200d\U0001f91d\u200d\U0001f469\U0001f3fc" +WOMEN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_MEDIUM_SKIN_TONE = \ + "\U0001f469\U0001f3fe\u200d\U0001f91d\u200d\U0001f469\U0001f3fd" +WOMEN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f46d\U0001f3fe" +WOMEN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fe\u200d\U0001f91d\u200d\U0001f469\U0001f3ff" +WOMEN_HOLDING_HANDS_DARK_SKIN_TONE_LIGHT_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f91d\u200d\U0001f469\U0001f3fb" +WOMEN_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3ff\u200d\U0001f91d\u200d\U0001f469\U0001f3fc" +WOMEN_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_SKIN_TONE = "\U0001f469\U0001f3ff\u200d\U0001f91d\u200d\U0001f469\U0001f3fd" +WOMEN_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3ff\u200d\U0001f91d\u200d\U0001f469\U0001f3fe" +WOMEN_HOLDING_HANDS_DARK_SKIN_TONE = "\U0001f46d\U0001f3ff" +WOMAN_AND_MAN_HOLDING_HANDS = "\U0001f46b" +WOMAN_AND_MAN_HOLDING_HANDS_LIGHT_SKIN_TONE = "\U0001f46b\U0001f3fb" +WOMAN_AND_MAN_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3fb\u200d\U0001f91d\u200d\U0001f468\U0001f3fc" +WOMAN_AND_MAN_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_SKIN_TONE = \ + "\U0001f469\U0001f3fb\u200d\U0001f91d\u200d\U0001f468\U0001f3fd" +WOMAN_AND_MAN_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fb\u200d\U0001f91d\u200d\U0001f468\U0001f3fe" +WOMAN_AND_MAN_HOLDING_HANDS_LIGHT_SKIN_TONE_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fb\u200d\U0001f91d\u200d\U0001f468\U0001f3ff" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3fc\u200d\U0001f91d\u200d\U0001f468\U0001f3fb" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f46b\U0001f3fc" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_MEDIUM_SKIN_TONE = \ + "\U0001f469\U0001f3fc\u200d\U0001f91d\u200d\U0001f468\U0001f3fd" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fc\u200d\U0001f91d\u200d\U0001f468\U0001f3fe" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fc\u200d\U0001f91d\u200d\U0001f468\U0001f3ff" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_SKIN_TONE_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3fd\u200d\U0001f91d\u200d\U0001f468\U0001f3fb" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3fd\u200d\U0001f91d\u200d\U0001f468\U0001f3fc" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_SKIN_TONE = "\U0001f46b\U0001f3fd" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fd\u200d\U0001f91d\u200d\U0001f468\U0001f3fe" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_SKIN_TONE_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fd\u200d\U0001f91d\u200d\U0001f468\U0001f3ff" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3fe\u200d\U0001f91d\u200d\U0001f468\U0001f3fb" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3fe\u200d\U0001f91d\u200d\U0001f468\U0001f3fc" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_MEDIUM_SKIN_TONE = \ + "\U0001f469\U0001f3fe\u200d\U0001f91d\u200d\U0001f468\U0001f3fd" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f46b\U0001f3fe" +WOMAN_AND_MAN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3fe\u200d\U0001f91d\u200d\U0001f468\U0001f3ff" +WOMAN_AND_MAN_HOLDING_HANDS_DARK_SKIN_TONE_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3ff\u200d\U0001f91d\u200d\U0001f468\U0001f3fb" +WOMAN_AND_MAN_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f469\U0001f3ff\u200d\U0001f91d\u200d\U0001f468\U0001f3fc" +WOMAN_AND_MAN_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_SKIN_TONE = \ + "\U0001f469\U0001f3ff\u200d\U0001f91d\u200d\U0001f468\U0001f3fd" +WOMAN_AND_MAN_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f469\U0001f3ff\u200d\U0001f91d\u200d\U0001f468\U0001f3fe" +WOMAN_AND_MAN_HOLDING_HANDS_DARK_SKIN_TONE = "\U0001f46b\U0001f3ff" +MEN_HOLDING_HANDS = "\U0001f46c" +MEN_HOLDING_HANDS_LIGHT_SKIN_TONE = "\U0001f46c\U0001f3fb" +MEN_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f468\U0001f3fb\u200d\U0001f91d\u200d\U0001f468\U0001f3fc" +MEN_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f91d\u200d\U0001f468\U0001f3fd" +MEN_HOLDING_HANDS_LIGHT_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f468\U0001f3fb\u200d\U0001f91d\u200d\U0001f468\U0001f3fe" +MEN_HOLDING_HANDS_LIGHT_SKIN_TONE_DARK_SKIN_TONE = "\U0001f468\U0001f3fb\u200d\U0001f91d\u200d\U0001f468\U0001f3ff" +MEN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_LIGHT_SKIN_TONE = \ + "\U0001f468\U0001f3fc\u200d\U0001f91d\u200d\U0001f468\U0001f3fb" +MEN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE = "\U0001f46c\U0001f3fc" +MEN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_MEDIUM_SKIN_TONE = \ + "\U0001f468\U0001f3fc\u200d\U0001f91d\u200d\U0001f468\U0001f3fd" +MEN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f468\U0001f3fc\u200d\U0001f91d\u200d\U0001f468\U0001f3fe" +MEN_HOLDING_HANDS_MEDIUM_LIGHT_SKIN_TONE_DARK_SKIN_TONE = \ + "\U0001f468\U0001f3fc\u200d\U0001f91d\u200d\U0001f468\U0001f3ff" +MEN_HOLDING_HANDS_MEDIUM_SKIN_TONE_LIGHT_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f91d\u200d\U0001f468\U0001f3fb" +MEN_HOLDING_HANDS_MEDIUM_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f468\U0001f3fd\u200d\U0001f91d\u200d\U0001f468\U0001f3fc" +MEN_HOLDING_HANDS_MEDIUM_SKIN_TONE = "\U0001f46c\U0001f3fd" +MEN_HOLDING_HANDS_MEDIUM_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f468\U0001f3fd\u200d\U0001f91d\u200d\U0001f468\U0001f3fe" +MEN_HOLDING_HANDS_MEDIUM_SKIN_TONE_DARK_SKIN_TONE = "\U0001f468\U0001f3fd\u200d\U0001f91d\u200d\U0001f468\U0001f3ff" +MEN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_LIGHT_SKIN_TONE = \ + "\U0001f468\U0001f3fe\u200d\U0001f91d\u200d\U0001f468\U0001f3fb" +MEN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f468\U0001f3fe\u200d\U0001f91d\u200d\U0001f468\U0001f3fc" +MEN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_MEDIUM_SKIN_TONE = \ + "\U0001f468\U0001f3fe\u200d\U0001f91d\u200d\U0001f468\U0001f3fd" +MEN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE = "\U0001f46c\U0001f3fe" +MEN_HOLDING_HANDS_MEDIUM_DARK_SKIN_TONE_DARK_SKIN_TONE = \ + "\U0001f468\U0001f3fe\u200d\U0001f91d\u200d\U0001f468\U0001f3ff" +MEN_HOLDING_HANDS_DARK_SKIN_TONE_LIGHT_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f91d\u200d\U0001f468\U0001f3fb" +MEN_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_LIGHT_SKIN_TONE = \ + "\U0001f468\U0001f3ff\u200d\U0001f91d\u200d\U0001f468\U0001f3fc" +MEN_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_SKIN_TONE = "\U0001f468\U0001f3ff\u200d\U0001f91d\u200d\U0001f468\U0001f3fd" +MEN_HOLDING_HANDS_DARK_SKIN_TONE_MEDIUM_DARK_SKIN_TONE = \ + "\U0001f468\U0001f3ff\u200d\U0001f91d\u200d\U0001f468\U0001f3fe" +MEN_HOLDING_HANDS_DARK_SKIN_TONE = "\U0001f46c\U0001f3ff" +KISS = "\U0001f48f" +KISS_WOMAN_MAN = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" +KISS_MAN_MAN = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f468" +KISS_WOMAN_WOMAN = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f48b\u200d\U0001f469" +COUPLE_WITH_HEART = "\U0001f491" +COUPLE_WITH_HEART_WOMAN_MAN = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f468" +COUPLE_WITH_HEART_MAN_MAN = "\U0001f468\u200d\u2764\ufe0f\u200d\U0001f468" +COUPLE_WITH_HEART_WOMAN_WOMAN = "\U0001f469\u200d\u2764\ufe0f\u200d\U0001f469" +FAMILY = "\U0001f46a" +FAMILY_MAN_WOMAN_BOY = "\U0001f468\u200d\U0001f469\u200d\U0001f466" +FAMILY_MAN_WOMAN_GIRL = "\U0001f468\u200d\U0001f469\u200d\U0001f467" +FAMILY_MAN_WOMAN_GIRL_BOY = "\U0001f468\u200d\U0001f469\u200d\U0001f467\u200d\U0001f466" +FAMILY_MAN_WOMAN_BOY_BOY = "\U0001f468\u200d\U0001f469\u200d\U0001f466\u200d\U0001f466" +FAMILY_MAN_WOMAN_GIRL_GIRL = "\U0001f468\u200d\U0001f469\u200d\U0001f467\u200d\U0001f467" +FAMILY_MAN_MAN_BOY = "\U0001f468\u200d\U0001f468\u200d\U0001f466" +FAMILY_MAN_MAN_GIRL = "\U0001f468\u200d\U0001f468\u200d\U0001f467" +FAMILY_MAN_MAN_GIRL_BOY = "\U0001f468\u200d\U0001f468\u200d\U0001f467\u200d\U0001f466" +FAMILY_MAN_MAN_BOY_BOY = "\U0001f468\u200d\U0001f468\u200d\U0001f466\u200d\U0001f466" +FAMILY_MAN_MAN_GIRL_GIRL = "\U0001f468\u200d\U0001f468\u200d\U0001f467\u200d\U0001f467" +FAMILY_WOMAN_WOMAN_BOY = "\U0001f469\u200d\U0001f469\u200d\U0001f466" +FAMILY_WOMAN_WOMAN_GIRL = "\U0001f469\u200d\U0001f469\u200d\U0001f467" +FAMILY_WOMAN_WOMAN_GIRL_BOY = "\U0001f469\u200d\U0001f469\u200d\U0001f467\u200d\U0001f466" +FAMILY_WOMAN_WOMAN_BOY_BOY = "\U0001f469\u200d\U0001f469\u200d\U0001f466\u200d\U0001f466" +FAMILY_WOMAN_WOMAN_GIRL_GIRL = "\U0001f469\u200d\U0001f469\u200d\U0001f467\u200d\U0001f467" +FAMILY_MAN_BOY = "\U0001f468\u200d\U0001f466" +FAMILY_MAN_BOY_BOY = "\U0001f468\u200d\U0001f466\u200d\U0001f466" +FAMILY_MAN_GIRL = "\U0001f468\u200d\U0001f467" +FAMILY_MAN_GIRL_BOY = "\U0001f468\u200d\U0001f467\u200d\U0001f466" +FAMILY_MAN_GIRL_GIRL = "\U0001f468\u200d\U0001f467\u200d\U0001f467" +FAMILY_WOMAN_BOY = "\U0001f469\u200d\U0001f466" +FAMILY_WOMAN_BOY_BOY = "\U0001f469\u200d\U0001f466\u200d\U0001f466" +FAMILY_WOMAN_GIRL = "\U0001f469\u200d\U0001f467" +FAMILY_WOMAN_GIRL_BOY = "\U0001f469\u200d\U0001f467\u200d\U0001f466" +FAMILY_WOMAN_GIRL_GIRL = "\U0001f469\u200d\U0001f467\u200d\U0001f467" +SPEAKING_HEAD = "\U0001f5e3\ufe0f" +BUST_IN_SILHOUETTE = "\U0001f464" +BUSTS_IN_SILHOUETTE = "\U0001f465" +PEOPLE_HUGGING = "\U0001fac2" +FOOTPRINTS = "\U0001f463" +LIGHT_SKIN_TONE = "\U0001f3fb" +MEDIUM_LIGHT_SKIN_TONE = "\U0001f3fc" +MEDIUM_SKIN_TONE = "\U0001f3fd" +MEDIUM_DARK_SKIN_TONE = "\U0001f3fe" +DARK_SKIN_TONE = "\U0001f3ff" +RED_HAIR = "\U0001f9b0" +CURLY_HAIR = "\U0001f9b1" +WHITE_HAIR = "\U0001f9b3" +BALD = "\U0001f9b2" +MONKEY_FACE = "\U0001f435" +MONKEY = "\U0001f412" +GORILLA = "\U0001f98d" +ORANGUTAN = "\U0001f9a7" +DOG_FACE = "\U0001f436" +DOG = "\U0001f415" +GUIDE_DOG = "\U0001f9ae" +SERVICE_DOG = "\U0001f415\u200d\U0001f9ba" +POODLE = "\U0001f429" +WOLF = "\U0001f43a" +FOX = "\U0001f98a" +RACCOON = "\U0001f99d" +CAT_FACE = "\U0001f431" +CAT = "\U0001f408" +BLACK_CAT = "\U0001f408\u200d\u2b1b" +LION = "\U0001f981" +TIGER_FACE = "\U0001f42f" +TIGER = "\U0001f405" +LEOPARD = "\U0001f406" +HORSE_FACE = "\U0001f434" +HORSE = "\U0001f40e" +UNICORN = "\U0001f984" +ZEBRA = "\U0001f993" +DEER = "\U0001f98c" +BISON = "\U0001f9ac" +COW_FACE = "\U0001f42e" +OX = "\U0001f402" +WATER_BUFFALO = "\U0001f403" +COW = "\U0001f404" +PIG_FACE = "\U0001f437" +PIG = "\U0001f416" +BOAR = "\U0001f417" +PIG_NOSE = "\U0001f43d" +RAM = "\U0001f40f" +EWE = "\U0001f411" +GOAT = "\U0001f410" +CAMEL = "\U0001f42a" +TWO_HUMP_CAMEL = "\U0001f42b" +LLAMA = "\U0001f999" +GIRAFFE = "\U0001f992" +ELEPHANT = "\U0001f418" +MAMMOTH = "\U0001f9a3" +RHINOCEROS = "\U0001f98f" +HIPPOPOTAMUS = "\U0001f99b" +MOUSE_FACE = "\U0001f42d" +MOUSE = "\U0001f401" +RAT = "\U0001f400" +HAMSTER = "\U0001f439" +RABBIT_FACE = "\U0001f430" +RABBIT = "\U0001f407" +CHIPMUNK = "\U0001f43f\ufe0f" +BEAVER = "\U0001f9ab" +HEDGEHOG = "\U0001f994" +BAT = "\U0001f987" +BEAR = "\U0001f43b" +POLAR_BEAR = "\U0001f43b\u200d\u2744\ufe0f" +KOALA = "\U0001f428" +PANDA = "\U0001f43c" +SLOTH = "\U0001f9a5" +OTTER = "\U0001f9a6" +SKUNK = "\U0001f9a8" +KANGAROO = "\U0001f998" +BADGER = "\U0001f9a1" +PAW_PRINTS = "\U0001f43e" +TURKEY = "\U0001f983" +CHICKEN = "\U0001f414" +ROOSTER = "\U0001f413" +HATCHING_CHICK = "\U0001f423" +BABY_CHICK = "\U0001f424" +FRONT_FACING_BABY_CHICK = "\U0001f425" +BIRD = "\U0001f426" +PENGUIN = "\U0001f427" +DOVE = "\U0001f54a\ufe0f" +EAGLE = "\U0001f985" +DUCK = "\U0001f986" +SWAN = "\U0001f9a2" +OWL = "\U0001f989" +DODO = "\U0001f9a4" +FEATHER = "\U0001fab6" +FLAMINGO = "\U0001f9a9" +PEACOCK = "\U0001f99a" +PARROT = "\U0001f99c" +FROG = "\U0001f438" +CROCODILE = "\U0001f40a" +TURTLE = "\U0001f422" +LIZARD = "\U0001f98e" +SNAKE = "\U0001f40d" +DRAGON_FACE = "\U0001f432" +DRAGON = "\U0001f409" +SAUROPOD = "\U0001f995" +T_REX = "\U0001f996" +SPOUTING_WHALE = "\U0001f433" +WHALE = "\U0001f40b" +DOLPHIN = "\U0001f42c" +SEAL = "\U0001f9ad" +FISH = "\U0001f41f" +TROPICAL_FISH = "\U0001f420" +BLOWFISH = "\U0001f421" +SHARK = "\U0001f988" +OCTOPUS = "\U0001f419" +SPIRAL_SHELL = "\U0001f41a" +SNAIL = "\U0001f40c" +BUTTERFLY = "\U0001f98b" +BUG = "\U0001f41b" +ANT = "\U0001f41c" +HONEYBEE = "\U0001f41d" +BEETLE = "\U0001fab2" +LADY_BEETLE = "\U0001f41e" +CRICKET = "\U0001f997" +COCKROACH = "\U0001fab3" +SPIDER = "\U0001f577\ufe0f" +SPIDER_WEB = "\U0001f578\ufe0f" +SCORPION = "\U0001f982" +MOSQUITO = "\U0001f99f" +FLY = "\U0001fab0" +WORM = "\U0001fab1" +MICROBE = "\U0001f9a0" +BOUQUET = "\U0001f490" +CHERRY_BLOSSOM = "\U0001f338" +WHITE_FLOWER = "\U0001f4ae" +ROSETTE = "\U0001f3f5\ufe0f" +ROSE = "\U0001f339" +WILTED_FLOWER = "\U0001f940" +HIBISCUS = "\U0001f33a" +SUNFLOWER = "\U0001f33b" +BLOSSOM = "\U0001f33c" +TULIP = "\U0001f337" +SEEDLING = "\U0001f331" +POTTED_PLANT = "\U0001fab4" +EVERGREEN_TREE = "\U0001f332" +DECIDUOUS_TREE = "\U0001f333" +PALM_TREE = "\U0001f334" +CACTUS = "\U0001f335" +SHEAF_OF_RICE = "\U0001f33e" +HERB = "\U0001f33f" +SHAMROCK = "\u2618\ufe0f" +FOUR_LEAF_CLOVER = "\U0001f340" +MAPLE_LEAF = "\U0001f341" +FALLEN_LEAF = "\U0001f342" +LEAF_FLUTTERING_IN_WIND = "\U0001f343" +GRAPES = "\U0001f347" +MELON = "\U0001f348" +WATERMELON = "\U0001f349" +TANGERINE = "\U0001f34a" +LEMON = "\U0001f34b" +BANANA = "\U0001f34c" +PINEAPPLE = "\U0001f34d" +MANGO = "\U0001f96d" +RED_APPLE = "\U0001f34e" +GREEN_APPLE = "\U0001f34f" +PEAR = "\U0001f350" +PEACH = "\U0001f351" +CHERRIES = "\U0001f352" +STRAWBERRY = "\U0001f353" +BLUEBERRIES = "\U0001fad0" +KIWI_FRUIT = "\U0001f95d" +TOMATO = "\U0001f345" +OLIVE = "\U0001fad2" +COCONUT = "\U0001f965" +AVOCADO = "\U0001f951" +EGGPLANT = "\U0001f346" +POTATO = "\U0001f954" +CARROT = "\U0001f955" +EAR_OF_CORN = "\U0001f33d" +HOT_PEPPER = "\U0001f336\ufe0f" +BELL_PEPPER = "\U0001fad1" +CUCUMBER = "\U0001f952" +LEAFY_GREEN = "\U0001f96c" +BROCCOLI = "\U0001f966" +GARLIC = "\U0001f9c4" +ONION = "\U0001f9c5" +MUSHROOM = "\U0001f344" +PEANUTS = "\U0001f95c" +CHESTNUT = "\U0001f330" +BREAD = "\U0001f35e" +CROISSANT = "\U0001f950" +BAGUETTE_BREAD = "\U0001f956" +FLATBREAD = "\U0001fad3" +PRETZEL = "\U0001f968" +BAGEL = "\U0001f96f" +PANCAKES = "\U0001f95e" +WAFFLE = "\U0001f9c7" +CHEESE_WEDGE = "\U0001f9c0" +MEAT_ON_BONE = "\U0001f356" +POULTRY_LEG = "\U0001f357" +CUT_OF_MEAT = "\U0001f969" +BACON = "\U0001f953" +HAMBURGER = "\U0001f354" +FRENCH_FRIES = "\U0001f35f" +PIZZA = "\U0001f355" +HOT_DOG = "\U0001f32d" +SANDWICH = "\U0001f96a" +TACO = "\U0001f32e" +BURRITO = "\U0001f32f" +TAMALE = "\U0001fad4" +STUFFED_FLATBREAD = "\U0001f959" +FALAFEL = "\U0001f9c6" +EGG = "\U0001f95a" +COOKING = "\U0001f373" +SHALLOW_PAN_OF_FOOD = "\U0001f958" +POT_OF_FOOD = "\U0001f372" +FONDUE = "\U0001fad5" +BOWL_WITH_SPOON = "\U0001f963" +GREEN_SALAD = "\U0001f957" +POPCORN = "\U0001f37f" +BUTTER = "\U0001f9c8" +SALT = "\U0001f9c2" +CANNED_FOOD = "\U0001f96b" +BENTO_BOX = "\U0001f371" +RICE_CRACKER = "\U0001f358" +RICE_BALL = "\U0001f359" +COOKED_RICE = "\U0001f35a" +CURRY_RICE = "\U0001f35b" +STEAMING_BOWL = "\U0001f35c" +SPAGHETTI = "\U0001f35d" +ROASTED_SWEET_POTATO = "\U0001f360" +ODEN = "\U0001f362" +SUSHI = "\U0001f363" +FRIED_SHRIMP = "\U0001f364" +FISH_CAKE_WITH_SWIRL = "\U0001f365" +MOON_CAKE = "\U0001f96e" +DANGO = "\U0001f361" +DUMPLING = "\U0001f95f" +FORTUNE_COOKIE = "\U0001f960" +TAKEOUT_BOX = "\U0001f961" +CRAB = "\U0001f980" +LOBSTER = "\U0001f99e" +SHRIMP = "\U0001f990" +SQUID = "\U0001f991" +OYSTER = "\U0001f9aa" +SOFT_ICE_CREAM = "\U0001f366" +SHAVED_ICE = "\U0001f367" +ICE_CREAM = "\U0001f368" +DOUGHNUT = "\U0001f369" +COOKIE = "\U0001f36a" +BIRTHDAY_CAKE = "\U0001f382" +SHORTCAKE = "\U0001f370" +CUPCAKE = "\U0001f9c1" +PIE = "\U0001f967" +CHOCOLATE_BAR = "\U0001f36b" +CANDY = "\U0001f36c" +LOLLIPOP = "\U0001f36d" +CUSTARD = "\U0001f36e" +HONEY_POT = "\U0001f36f" +BABY_BOTTLE = "\U0001f37c" +GLASS_OF_MILK = "\U0001f95b" +HOT_BEVERAGE = "\u2615" +TEAPOT = "\U0001fad6" +TEACUP_WITHOUT_HANDLE = "\U0001f375" +SAKE = "\U0001f376" +BOTTLE_WITH_POPPING_CORK = "\U0001f37e" +WINE_GLASS = "\U0001f377" +COCKTAIL_GLASS = "\U0001f378" +TROPICAL_DRINK = "\U0001f379" +BEER_MUG = "\U0001f37a" +CLINKING_BEER_MUGS = "\U0001f37b" +CLINKING_GLASSES = "\U0001f942" +TUMBLER_GLASS = "\U0001f943" +CUP_WITH_STRAW = "\U0001f964" +BUBBLE_TEA = "\U0001f9cb" +BEVERAGE_BOX = "\U0001f9c3" +MATE = "\U0001f9c9" +ICE = "\U0001f9ca" +CHOPSTICKS = "\U0001f962" +FORK_AND_KNIFE_WITH_PLATE = "\U0001f37d\ufe0f" +FORK_AND_KNIFE = "\U0001f374" +SPOON = "\U0001f944" +KITCHEN_KNIFE = "\U0001f52a" +AMPHORA = "\U0001f3fa" +GLOBE_SHOWING_EUROPE_AFRICA = "\U0001f30d" +GLOBE_SHOWING_AMERICAS = "\U0001f30e" +GLOBE_SHOWING_ASIA_AUSTRALIA = "\U0001f30f" +GLOBE_WITH_MERIDIANS = "\U0001f310" +WORLD_MAP = "\U0001f5fa\ufe0f" +MAP_OF_JAPAN = "\U0001f5fe" +COMPASS = "\U0001f9ed" +SNOW_CAPPED_MOUNTAIN = "\U0001f3d4\ufe0f" +MOUNTAIN = "\u26f0\ufe0f" +VOLCANO = "\U0001f30b" +MOUNT_FUJI = "\U0001f5fb" +CAMPING = "\U0001f3d5\ufe0f" +BEACH_WITH_UMBRELLA = "\U0001f3d6\ufe0f" +DESERT = "\U0001f3dc\ufe0f" +DESERT_ISLAND = "\U0001f3dd\ufe0f" +NATIONAL_PARK = "\U0001f3de\ufe0f" +STADIUM = "\U0001f3df\ufe0f" +CLASSICAL_BUILDING = "\U0001f3db\ufe0f" +BUILDING_CONSTRUCTION = "\U0001f3d7\ufe0f" +BRICK = "\U0001f9f1" +ROCK = "\U0001faa8" +WOOD = "\U0001fab5" +HUT = "\U0001f6d6" +HOUSES = "\U0001f3d8\ufe0f" +DERELICT_HOUSE = "\U0001f3da\ufe0f" +HOUSE = "\U0001f3e0" +HOUSE_WITH_GARDEN = "\U0001f3e1" +OFFICE_BUILDING = "\U0001f3e2" +JAPANESE_POST_OFFICE = "\U0001f3e3" +POST_OFFICE = "\U0001f3e4" +HOSPITAL = "\U0001f3e5" +BANK = "\U0001f3e6" +HOTEL = "\U0001f3e8" +LOVE_HOTEL = "\U0001f3e9" +CONVENIENCE_STORE = "\U0001f3ea" +SCHOOL = "\U0001f3eb" +DEPARTMENT_STORE = "\U0001f3ec" +FACTORY = "\U0001f3ed" +JAPANESE_CASTLE = "\U0001f3ef" +CASTLE = "\U0001f3f0" +WEDDING = "\U0001f492" +TOKYO_TOWER = "\U0001f5fc" +STATUE_OF_LIBERTY = "\U0001f5fd" +CHURCH = "\u26ea" +MOSQUE = "\U0001f54c" +HINDU_TEMPLE = "\U0001f6d5" +SYNAGOGUE = "\U0001f54d" +SHINTO_SHRINE = "\u26e9\ufe0f" +KAABA = "\U0001f54b" +FOUNTAIN = "\u26f2" +TENT = "\u26fa" +FOGGY = "\U0001f301" +NIGHT_WITH_STARS = "\U0001f303" +CITYSCAPE = "\U0001f3d9\ufe0f" +SUNRISE_OVER_MOUNTAINS = "\U0001f304" +SUNRISE = "\U0001f305" +CITYSCAPE_AT_DUSK = "\U0001f306" +SUNSET = "\U0001f307" +BRIDGE_AT_NIGHT = "\U0001f309" +HOT_SPRINGS = "\u2668\ufe0f" +CAROUSEL_HORSE = "\U0001f3a0" +FERRIS_WHEEL = "\U0001f3a1" +ROLLER_COASTER = "\U0001f3a2" +BARBER_POLE = "\U0001f488" +CIRCUS_TENT = "\U0001f3aa" +LOCOMOTIVE = "\U0001f682" +RAILWAY_CAR = "\U0001f683" +HIGH_SPEED_TRAIN = "\U0001f684" +BULLET_TRAIN = "\U0001f685" +TRAIN = "\U0001f686" +METRO = "\U0001f687" +LIGHT_RAIL = "\U0001f688" +STATION = "\U0001f689" +TRAM = "\U0001f68a" +MONORAIL = "\U0001f69d" +MOUNTAIN_RAILWAY = "\U0001f69e" +TRAM_CAR = "\U0001f68b" +BUS = "\U0001f68c" +ONCOMING_BUS = "\U0001f68d" +TROLLEYBUS = "\U0001f68e" +MINIBUS = "\U0001f690" +AMBULANCE = "\U0001f691" +FIRE_ENGINE = "\U0001f692" +POLICE_CAR = "\U0001f693" +ONCOMING_POLICE_CAR = "\U0001f694" +TAXI = "\U0001f695" +ONCOMING_TAXI = "\U0001f696" +AUTOMOBILE = "\U0001f697" +ONCOMING_AUTOMOBILE = "\U0001f698" +SPORT_UTILITY_VEHICLE = "\U0001f699" +PICKUP_TRUCK = "\U0001f6fb" +DELIVERY_TRUCK = "\U0001f69a" +ARTICULATED_LORRY = "\U0001f69b" +TRACTOR = "\U0001f69c" +RACING_CAR = "\U0001f3ce\ufe0f" +MOTORCYCLE = "\U0001f3cd\ufe0f" +MOTOR_SCOOTER = "\U0001f6f5" +MANUAL_WHEELCHAIR = "\U0001f9bd" +MOTORIZED_WHEELCHAIR = "\U0001f9bc" +AUTO_RICKSHAW = "\U0001f6fa" +BICYCLE = "\U0001f6b2" +KICK_SCOOTER = "\U0001f6f4" +SKATEBOARD = "\U0001f6f9" +ROLLER_SKATE = "\U0001f6fc" +BUS_STOP = "\U0001f68f" +MOTORWAY = "\U0001f6e3\ufe0f" +RAILWAY_TRACK = "\U0001f6e4\ufe0f" +OIL_DRUM = "\U0001f6e2\ufe0f" +FUEL_PUMP = "\u26fd" +POLICE_CAR_LIGHT = "\U0001f6a8" +HORIZONTAL_TRAFFIC_LIGHT = "\U0001f6a5" +VERTICAL_TRAFFIC_LIGHT = "\U0001f6a6" +STOP_SIGN = "\U0001f6d1" +CONSTRUCTION = "\U0001f6a7" +ANCHOR = "\u2693" +SAILBOAT = "\u26f5" +CANOE = "\U0001f6f6" +SPEEDBOAT = "\U0001f6a4" +PASSENGER_SHIP = "\U0001f6f3\ufe0f" +FERRY = "\u26f4\ufe0f" +MOTOR_BOAT = "\U0001f6e5\ufe0f" +SHIP = "\U0001f6a2" +AIRPLANE = "\u2708\ufe0f" +SMALL_AIRPLANE = "\U0001f6e9\ufe0f" +AIRPLANE_DEPARTURE = "\U0001f6eb" +AIRPLANE_ARRIVAL = "\U0001f6ec" +PARACHUTE = "\U0001fa82" +SEAT = "\U0001f4ba" +HELICOPTER = "\U0001f681" +SUSPENSION_RAILWAY = "\U0001f69f" +MOUNTAIN_CABLEWAY = "\U0001f6a0" +AERIAL_TRAMWAY = "\U0001f6a1" +SATELLITE = "\U0001f6f0\ufe0f" +ROCKET = "\U0001f680" +FLYING_SAUCER = "\U0001f6f8" +BELLHOP_BELL = "\U0001f6ce\ufe0f" +LUGGAGE = "\U0001f9f3" +HOURGLASS_DONE = "\u231b" +HOURGLASS_NOT_DONE = "\u23f3" +WATCH = "\u231a" +ALARM_CLOCK = "\u23f0" +STOPWATCH = "\u23f1\ufe0f" +TIMER_CLOCK = "\u23f2\ufe0f" +MANTELPIECE_CLOCK = "\U0001f570\ufe0f" +TWELVE_O_CLOCK = "\U0001f55b" +TWELVE_THIRTY = "\U0001f567" +ONE_O_CLOCK = "\U0001f550" +ONE_THIRTY = "\U0001f55c" +TWO_O_CLOCK = "\U0001f551" +TWO_THIRTY = "\U0001f55d" +THREE_O_CLOCK = "\U0001f552" +THREE_THIRTY = "\U0001f55e" +FOUR_O_CLOCK = "\U0001f553" +FOUR_THIRTY = "\U0001f55f" +FIVE_O_CLOCK = "\U0001f554" +FIVE_THIRTY = "\U0001f560" +SIX_O_CLOCK = "\U0001f555" +SIX_THIRTY = "\U0001f561" +SEVEN_O_CLOCK = "\U0001f556" +SEVEN_THIRTY = "\U0001f562" +EIGHT_O_CLOCK = "\U0001f557" +EIGHT_THIRTY = "\U0001f563" +NINE_O_CLOCK = "\U0001f558" +NINE_THIRTY = "\U0001f564" +TEN_O_CLOCK = "\U0001f559" +TEN_THIRTY = "\U0001f565" +ELEVEN_O_CLOCK = "\U0001f55a" +ELEVEN_THIRTY = "\U0001f566" +NEW_MOON = "\U0001f311" +WAXING_CRESCENT_MOON = "\U0001f312" +FIRST_QUARTER_MOON = "\U0001f313" +WAXING_GIBBOUS_MOON = "\U0001f314" +FULL_MOON = "\U0001f315" +WANING_GIBBOUS_MOON = "\U0001f316" +LAST_QUARTER_MOON = "\U0001f317" +WANING_CRESCENT_MOON = "\U0001f318" +CRESCENT_MOON = "\U0001f319" +NEW_MOON_FACE = "\U0001f31a" +FIRST_QUARTER_MOON_FACE = "\U0001f31b" +LAST_QUARTER_MOON_FACE = "\U0001f31c" +THERMOMETER = "\U0001f321\ufe0f" +SUN = "\u2600\ufe0f" +FULL_MOON_FACE = "\U0001f31d" +SUN_WITH_FACE = "\U0001f31e" +RINGED_PLANET = "\U0001fa90" +STAR = "\u2b50" +GLOWING_STAR = "\U0001f31f" +SHOOTING_STAR = "\U0001f320" +MILKY_WAY = "\U0001f30c" +CLOUD = "\u2601\ufe0f" +SUN_BEHIND_CLOUD = "\u26c5" +CLOUD_WITH_LIGHTNING_AND_RAIN = "\u26c8\ufe0f" +SUN_BEHIND_SMALL_CLOUD = "\U0001f324\ufe0f" +SUN_BEHIND_LARGE_CLOUD = "\U0001f325\ufe0f" +SUN_BEHIND_RAIN_CLOUD = "\U0001f326\ufe0f" +CLOUD_WITH_RAIN = "\U0001f327\ufe0f" +CLOUD_WITH_SNOW = "\U0001f328\ufe0f" +CLOUD_WITH_LIGHTNING = "\U0001f329\ufe0f" +TORNADO = "\U0001f32a\ufe0f" +FOG = "\U0001f32b\ufe0f" +WIND_FACE = "\U0001f32c\ufe0f" +CYCLONE = "\U0001f300" +RAINBOW = "\U0001f308" +CLOSED_UMBRELLA = "\U0001f302" +UMBRELLA = "\u2602\ufe0f" +UMBRELLA_WITH_RAIN_DROPS = "\u2614" +UMBRELLA_ON_GROUND = "\u26f1\ufe0f" +HIGH_VOLTAGE = "\u26a1" +SNOWFLAKE = "\u2744\ufe0f" +SNOWMAN = "\u2603\ufe0f" +SNOWMAN_WITHOUT_SNOW = "\u26c4" +COMET = "\u2604\ufe0f" +FIRE = "\U0001f525" +DROPLET = "\U0001f4a7" +WATER_WAVE = "\U0001f30a" +JACK_O_LANTERN = "\U0001f383" +CHRISTMAS_TREE = "\U0001f384" +FIREWORKS = "\U0001f386" +SPARKLER = "\U0001f387" +FIRECRACKER = "\U0001f9e8" +SPARKLES = "\u2728" +BALLOON = "\U0001f388" +PARTY_POPPER = "\U0001f389" +CONFETTI_BALL = "\U0001f38a" +TANABATA_TREE = "\U0001f38b" +PINE_DECORATION = "\U0001f38d" +JAPANESE_DOLLS = "\U0001f38e" +CARP_STREAMER = "\U0001f38f" +WIND_CHIME = "\U0001f390" +MOON_VIEWING_CEREMONY = "\U0001f391" +RED_ENVELOPE = "\U0001f9e7" +RIBBON = "\U0001f380" +WRAPPED_GIFT = "\U0001f381" +REMINDER_RIBBON = "\U0001f397\ufe0f" +ADMISSION_TICKETS = "\U0001f39f\ufe0f" +TICKET = "\U0001f3ab" +MILITARY_MEDAL = "\U0001f396\ufe0f" +TROPHY = "\U0001f3c6" +SPORTS_MEDAL = "\U0001f3c5" +FIRST_PLACE_MEDAL = "\U0001f947" +SECOND_PLACE_MEDAL = "\U0001f948" +THIRD_PLACE_MEDAL = "\U0001f949" +SOCCER_BALL = "\u26bd" +BASEBALL = "\u26be" +SOFTBALL = "\U0001f94e" +BASKETBALL = "\U0001f3c0" +VOLLEYBALL = "\U0001f3d0" +AMERICAN_FOOTBALL = "\U0001f3c8" +RUGBY_FOOTBALL = "\U0001f3c9" +TENNIS = "\U0001f3be" +FLYING_DISC = "\U0001f94f" +BOWLING = "\U0001f3b3" +CRICKET_GAME = "\U0001f3cf" +FIELD_HOCKEY = "\U0001f3d1" +ICE_HOCKEY = "\U0001f3d2" +LACROSSE = "\U0001f94d" +PING_PONG = "\U0001f3d3" +BADMINTON = "\U0001f3f8" +BOXING_GLOVE = "\U0001f94a" +MARTIAL_ARTS_UNIFORM = "\U0001f94b" +GOAL_NET = "\U0001f945" +FLAG_IN_HOLE = "\u26f3" +ICE_SKATE = "\u26f8\ufe0f" +FISHING_POLE = "\U0001f3a3" +DIVING_MASK = "\U0001f93f" +RUNNING_SHIRT = "\U0001f3bd" +SKIS = "\U0001f3bf" +SLED = "\U0001f6f7" +CURLING_STONE = "\U0001f94c" +DIRECT_HIT = "\U0001f3af" +YO_YO = "\U0001fa80" +KITE = "\U0001fa81" +POOL_8_BALL = "\U0001f3b1" +CRYSTAL_BALL = "\U0001f52e" +MAGIC_WAND = "\U0001fa84" +NAZAR_AMULET = "\U0001f9ff" +VIDEO_GAME = "\U0001f3ae" +JOYSTICK = "\U0001f579\ufe0f" +SLOT_MACHINE = "\U0001f3b0" +GAME_DIE = "\U0001f3b2" +PUZZLE_PIECE = "\U0001f9e9" +TEDDY_BEAR = "\U0001f9f8" +PINATA = "\U0001fa85" +NESTING_DOLLS = "\U0001fa86" +SPADE_SUIT = "\u2660\ufe0f" +HEART_SUIT = "\u2665\ufe0f" +DIAMOND_SUIT = "\u2666\ufe0f" +CLUB_SUIT = "\u2663\ufe0f" +CHESS_PAWN = "\u265f\ufe0f" +JOKER = "\U0001f0cf" +MAHJONG_RED_DRAGON = "\U0001f004" +FLOWER_PLAYING_CARDS = "\U0001f3b4" +PERFORMING_ARTS = "\U0001f3ad" +FRAMED_PICTURE = "\U0001f5bc\ufe0f" +ARTIST_PALETTE = "\U0001f3a8" +THREAD = "\U0001f9f5" +SEWING_NEEDLE = "\U0001faa1" +YARN = "\U0001f9f6" +KNOT = "\U0001faa2" +GLASSES = "\U0001f453" +SUNGLASSES = "\U0001f576\ufe0f" +GOGGLES = "\U0001f97d" +LAB_COAT = "\U0001f97c" +SAFETY_VEST = "\U0001f9ba" +NECKTIE = "\U0001f454" +T_SHIRT = "\U0001f455" +JEANS = "\U0001f456" +SCARF = "\U0001f9e3" +GLOVES = "\U0001f9e4" +COAT = "\U0001f9e5" +SOCKS = "\U0001f9e6" +DRESS = "\U0001f457" +KIMONO = "\U0001f458" +SARI = "\U0001f97b" +ONE_PIECE_SWIMSUIT = "\U0001fa71" +BRIEFS = "\U0001fa72" +SHORTS = "\U0001fa73" +BIKINI = "\U0001f459" +WOMAN_S_CLOTHES = "\U0001f45a" +PURSE = "\U0001f45b" +HANDBAG = "\U0001f45c" +CLUTCH_BAG = "\U0001f45d" +SHOPPING_BAGS = "\U0001f6cd\ufe0f" +BACKPACK = "\U0001f392" +THONG_SANDAL = "\U0001fa74" +MAN_S_SHOE = "\U0001f45e" +RUNNING_SHOE = "\U0001f45f" +HIKING_BOOT = "\U0001f97e" +FLAT_SHOE = "\U0001f97f" +HIGH_HEELED_SHOE = "\U0001f460" +WOMAN_S_SANDAL = "\U0001f461" +BALLET_SHOES = "\U0001fa70" +WOMAN_S_BOOT = "\U0001f462" +CROWN = "\U0001f451" +WOMAN_S_HAT = "\U0001f452" +TOP_HAT = "\U0001f3a9" +GRADUATION_CAP = "\U0001f393" +BILLED_CAP = "\U0001f9e2" +MILITARY_HELMET = "\U0001fa96" +RESCUE_WORKER_S_HELMET = "\u26d1\ufe0f" +PRAYER_BEADS = "\U0001f4ff" +LIPSTICK = "\U0001f484" +RING = "\U0001f48d" +GEM_STONE = "\U0001f48e" +MUTED_SPEAKER = "\U0001f507" +SPEAKER_LOW_VOLUME = "\U0001f508" +SPEAKER_MEDIUM_VOLUME = "\U0001f509" +SPEAKER_HIGH_VOLUME = "\U0001f50a" +LOUDSPEAKER = "\U0001f4e2" +MEGAPHONE = "\U0001f4e3" +POSTAL_HORN = "\U0001f4ef" +BELL = "\U0001f514" +BELL_WITH_SLASH = "\U0001f515" +MUSICAL_SCORE = "\U0001f3bc" +MUSICAL_NOTE = "\U0001f3b5" +MUSICAL_NOTES = "\U0001f3b6" +STUDIO_MICROPHONE = "\U0001f399\ufe0f" +LEVEL_SLIDER = "\U0001f39a\ufe0f" +CONTROL_KNOBS = "\U0001f39b\ufe0f" +MICROPHONE = "\U0001f3a4" +HEADPHONE = "\U0001f3a7" +RADIO = "\U0001f4fb" +SAXOPHONE = "\U0001f3b7" +ACCORDION = "\U0001fa97" +GUITAR = "\U0001f3b8" +MUSICAL_KEYBOARD = "\U0001f3b9" +TRUMPET = "\U0001f3ba" +VIOLIN = "\U0001f3bb" +BANJO = "\U0001fa95" +DRUM = "\U0001f941" +LONG_DRUM = "\U0001fa98" +MOBILE_PHONE = "\U0001f4f1" +MOBILE_PHONE_WITH_ARROW = "\U0001f4f2" +TELEPHONE = "\u260e\ufe0f" +TELEPHONE_RECEIVER = "\U0001f4de" +PAGER = "\U0001f4df" +FAX_MACHINE = "\U0001f4e0" +BATTERY = "\U0001f50b" +ELECTRIC_PLUG = "\U0001f50c" +LAPTOP = "\U0001f4bb" +DESKTOP_COMPUTER = "\U0001f5a5\ufe0f" +PRINTER = "\U0001f5a8\ufe0f" +KEYBOARD = "\u2328\ufe0f" +COMPUTER_MOUSE = "\U0001f5b1\ufe0f" +TRACKBALL = "\U0001f5b2\ufe0f" +COMPUTER_DISK = "\U0001f4bd" +FLOPPY_DISK = "\U0001f4be" +OPTICAL_DISK = "\U0001f4bf" +DVD = "\U0001f4c0" +ABACUS = "\U0001f9ee" +MOVIE_CAMERA = "\U0001f3a5" +FILM_FRAMES = "\U0001f39e\ufe0f" +FILM_PROJECTOR = "\U0001f4fd\ufe0f" +CLAPPER_BOARD = "\U0001f3ac" +TELEVISION = "\U0001f4fa" +CAMERA = "\U0001f4f7" +CAMERA_WITH_FLASH = "\U0001f4f8" +VIDEO_CAMERA = "\U0001f4f9" +VIDEOCASSETTE = "\U0001f4fc" +MAGNIFYING_GLASS_TILTED_LEFT = "\U0001f50d" +MAGNIFYING_GLASS_TILTED_RIGHT = "\U0001f50e" +CANDLE = "\U0001f56f\ufe0f" +LIGHT_BULB = "\U0001f4a1" +FLASHLIGHT = "\U0001f526" +RED_PAPER_LANTERN = "\U0001f3ee" +DIYA_LAMP = "\U0001fa94" +NOTEBOOK_WITH_DECORATIVE_COVER = "\U0001f4d4" +CLOSED_BOOK = "\U0001f4d5" +OPEN_BOOK = "\U0001f4d6" +GREEN_BOOK = "\U0001f4d7" +BLUE_BOOK = "\U0001f4d8" +ORANGE_BOOK = "\U0001f4d9" +BOOKS = "\U0001f4da" +NOTEBOOK = "\U0001f4d3" +LEDGER = "\U0001f4d2" +PAGE_WITH_CURL = "\U0001f4c3" +SCROLL = "\U0001f4dc" +PAGE_FACING_UP = "\U0001f4c4" +NEWSPAPER = "\U0001f4f0" +ROLLED_UP_NEWSPAPER = "\U0001f5de\ufe0f" +BOOKMARK_TABS = "\U0001f4d1" +BOOKMARK = "\U0001f516" +LABEL = "\U0001f3f7\ufe0f" +MONEY_BAG = "\U0001f4b0" +COIN = "\U0001fa99" +YEN_BANKNOTE = "\U0001f4b4" +DOLLAR_BANKNOTE = "\U0001f4b5" +EURO_BANKNOTE = "\U0001f4b6" +POUND_BANKNOTE = "\U0001f4b7" +MONEY_WITH_WINGS = "\U0001f4b8" +CREDIT_CARD = "\U0001f4b3" +RECEIPT = "\U0001f9fe" +CHART_INCREASING_WITH_YEN = "\U0001f4b9" +ENVELOPE = "\u2709\ufe0f" +E_MAIL = "\U0001f4e7" +INCOMING_ENVELOPE = "\U0001f4e8" +ENVELOPE_WITH_ARROW = "\U0001f4e9" +OUTBOX_TRAY = "\U0001f4e4" +INBOX_TRAY = "\U0001f4e5" +PACKAGE = "\U0001f4e6" +CLOSED_MAILBOX_WITH_RAISED_FLAG = "\U0001f4eb" +CLOSED_MAILBOX_WITH_LOWERED_FLAG = "\U0001f4ea" +OPEN_MAILBOX_WITH_RAISED_FLAG = "\U0001f4ec" +OPEN_MAILBOX_WITH_LOWERED_FLAG = "\U0001f4ed" +POSTBOX = "\U0001f4ee" +BALLOT_BOX_WITH_BALLOT = "\U0001f5f3\ufe0f" +PENCIL = "\u270f\ufe0f" +BLACK_NIB = "\u2712\ufe0f" +FOUNTAIN_PEN = "\U0001f58b\ufe0f" +PEN = "\U0001f58a\ufe0f" +PAINTBRUSH = "\U0001f58c\ufe0f" +CRAYON = "\U0001f58d\ufe0f" +MEMO = "\U0001f4dd" +BRIEFCASE = "\U0001f4bc" +FILE_FOLDER = "\U0001f4c1" +OPEN_FILE_FOLDER = "\U0001f4c2" +CARD_INDEX_DIVIDERS = "\U0001f5c2\ufe0f" +CALENDAR = "\U0001f4c5" +TEAR_OFF_CALENDAR = "\U0001f4c6" +SPIRAL_NOTEPAD = "\U0001f5d2\ufe0f" +SPIRAL_CALENDAR = "\U0001f5d3\ufe0f" +CARD_INDEX = "\U0001f4c7" +CHART_INCREASING = "\U0001f4c8" +CHART_DECREASING = "\U0001f4c9" +BAR_CHART = "\U0001f4ca" +CLIPBOARD = "\U0001f4cb" +PUSHPIN = "\U0001f4cc" +ROUND_PUSHPIN = "\U0001f4cd" +PAPERCLIP = "\U0001f4ce" +LINKED_PAPERCLIPS = "\U0001f587\ufe0f" +STRAIGHT_RULER = "\U0001f4cf" +TRIANGULAR_RULER = "\U0001f4d0" +SCISSORS = "\u2702\ufe0f" +CARD_FILE_BOX = "\U0001f5c3\ufe0f" +FILE_CABINET = "\U0001f5c4\ufe0f" +WASTEBASKET = "\U0001f5d1\ufe0f" +LOCKED = "\U0001f512" +UNLOCKED = "\U0001f513" +LOCKED_WITH_PEN = "\U0001f50f" +LOCKED_WITH_KEY = "\U0001f510" +KEY = "\U0001f511" +OLD_KEY = "\U0001f5dd\ufe0f" +HAMMER = "\U0001f528" +AXE = "\U0001fa93" +PICK = "\u26cf\ufe0f" +HAMMER_AND_PICK = "\u2692\ufe0f" +HAMMER_AND_WRENCH = "\U0001f6e0\ufe0f" +DAGGER = "\U0001f5e1\ufe0f" +CROSSED_SWORDS = "\u2694\ufe0f" +PISTOL = "\U0001f52b" +BOOMERANG = "\U0001fa83" +BOW_AND_ARROW = "\U0001f3f9" +SHIELD = "\U0001f6e1\ufe0f" +CARPENTRY_SAW = "\U0001fa9a" +WRENCH = "\U0001f527" +SCREWDRIVER = "\U0001fa9b" +NUT_AND_BOLT = "\U0001f529" +GEAR = "\u2699\ufe0f" +CLAMP = "\U0001f5dc\ufe0f" +BALANCE_SCALE = "\u2696\ufe0f" +WHITE_CANE = "\U0001f9af" +LINK = "\U0001f517" +CHAINS = "\u26d3\ufe0f" +HOOK = "\U0001fa9d" +TOOLBOX = "\U0001f9f0" +MAGNET = "\U0001f9f2" +LADDER = "\U0001fa9c" +ALEMBIC = "\u2697\ufe0f" +TEST_TUBE = "\U0001f9ea" +PETRI_DISH = "\U0001f9eb" +DNA = "\U0001f9ec" +MICROSCOPE = "\U0001f52c" +TELESCOPE = "\U0001f52d" +SATELLITE_ANTENNA = "\U0001f4e1" +SYRINGE = "\U0001f489" +DROP_OF_BLOOD = "\U0001fa78" +PILL = "\U0001f48a" +ADHESIVE_BANDAGE = "\U0001fa79" +STETHOSCOPE = "\U0001fa7a" +DOOR = "\U0001f6aa" +ELEVATOR = "\U0001f6d7" +MIRROR = "\U0001fa9e" +WINDOW = "\U0001fa9f" +BED = "\U0001f6cf\ufe0f" +COUCH_AND_LAMP = "\U0001f6cb\ufe0f" +CHAIR = "\U0001fa91" +TOILET = "\U0001f6bd" +PLUNGER = "\U0001faa0" +SHOWER = "\U0001f6bf" +BATHTUB = "\U0001f6c1" +MOUSE_TRAP = "\U0001faa4" +RAZOR = "\U0001fa92" +LOTION_BOTTLE = "\U0001f9f4" +SAFETY_PIN = "\U0001f9f7" +BROOM = "\U0001f9f9" +BASKET = "\U0001f9fa" +ROLL_OF_PAPER = "\U0001f9fb" +BUCKET = "\U0001faa3" +SOAP = "\U0001f9fc" +TOOTHBRUSH = "\U0001faa5" +SPONGE = "\U0001f9fd" +FIRE_EXTINGUISHER = "\U0001f9ef" +SHOPPING_CART = "\U0001f6d2" +CIGARETTE = "\U0001f6ac" +COFFIN = "\u26b0\ufe0f" +HEADSTONE = "\U0001faa6" +FUNERAL_URN = "\u26b1\ufe0f" +MOAI = "\U0001f5ff" +PLACARD = "\U0001faa7" +ATM_SIGN = "\U0001f3e7" +LITTER_IN_BIN_SIGN = "\U0001f6ae" +POTABLE_WATER = "\U0001f6b0" +WHEELCHAIR_SYMBOL = "\u267f" +MEN_S_ROOM = "\U0001f6b9" +WOMEN_S_ROOM = "\U0001f6ba" +RESTROOM = "\U0001f6bb" +BABY_SYMBOL = "\U0001f6bc" +WATER_CLOSET = "\U0001f6be" +PASSPORT_CONTROL = "\U0001f6c2" +CUSTOMS = "\U0001f6c3" +BAGGAGE_CLAIM = "\U0001f6c4" +LEFT_LUGGAGE = "\U0001f6c5" +WARNING = "\u26a0\ufe0f" +CHILDREN_CROSSING = "\U0001f6b8" +NO_ENTRY = "\u26d4" +PROHIBITED = "\U0001f6ab" +NO_BICYCLES = "\U0001f6b3" +NO_SMOKING = "\U0001f6ad" +NO_LITTERING = "\U0001f6af" +NON_POTABLE_WATER = "\U0001f6b1" +NO_PEDESTRIANS = "\U0001f6b7" +NO_MOBILE_PHONES = "\U0001f4f5" +NO_ONE_UNDER_EIGHTEEN = "\U0001f51e" +RADIOACTIVE = "\u2622\ufe0f" +BIOHAZARD = "\u2623\ufe0f" +UP_ARROW = "\u2b06\ufe0f" +UP_RIGHT_ARROW = "\u2197\ufe0f" +RIGHT_ARROW = "\u27a1\ufe0f" +DOWN_RIGHT_ARROW = "\u2198\ufe0f" +DOWN_ARROW = "\u2b07\ufe0f" +DOWN_LEFT_ARROW = "\u2199\ufe0f" +LEFT_ARROW = "\u2b05\ufe0f" +UP_LEFT_ARROW = "\u2196\ufe0f" +UP_DOWN_ARROW = "\u2195\ufe0f" +LEFT_RIGHT_ARROW = "\u2194\ufe0f" +RIGHT_ARROW_CURVING_LEFT = "\u21a9\ufe0f" +LEFT_ARROW_CURVING_RIGHT = "\u21aa\ufe0f" +RIGHT_ARROW_CURVING_UP = "\u2934\ufe0f" +RIGHT_ARROW_CURVING_DOWN = "\u2935\ufe0f" +CLOCKWISE_VERTICAL_ARROWS = "\U0001f503" +COUNTERCLOCKWISE_ARROWS_BUTTON = "\U0001f504" +BACK_ARROW = "\U0001f519" +END_ARROW = "\U0001f51a" +ON_ARROW = "\U0001f51b" +SOON_ARROW = "\U0001f51c" +TOP_ARROW = "\U0001f51d" +PLACE_OF_WORSHIP = "\U0001f6d0" +ATOM_SYMBOL = "\u269b\ufe0f" +OM = "\U0001f549\ufe0f" +STAR_OF_DAVID = "\u2721\ufe0f" +WHEEL_OF_DHARMA = "\u2638\ufe0f" +YIN_YANG = "\u262f\ufe0f" +LATIN_CROSS = "\u271d\ufe0f" +ORTHODOX_CROSS = "\u2626\ufe0f" +STAR_AND_CRESCENT = "\u262a\ufe0f" +PEACE_SYMBOL = "\u262e\ufe0f" +MENORAH = "\U0001f54e" +DOTTED_SIX_POINTED_STAR = "\U0001f52f" +ARIES = "\u2648" +TAURUS = "\u2649" +GEMINI = "\u264a" +CANCER = "\u264b" +LEO = "\u264c" +VIRGO = "\u264d" +LIBRA = "\u264e" +SCORPIO = "\u264f" +SAGITTARIUS = "\u2650" +CAPRICORN = "\u2651" +AQUARIUS = "\u2652" +PISCES = "\u2653" +OPHIUCHUS = "\u26ce" +SHUFFLE_TRACKS_BUTTON = "\U0001f500" +REPEAT_BUTTON = "\U0001f501" +REPEAT_SINGLE_BUTTON = "\U0001f502" +PLAY_BUTTON = "\u25b6\ufe0f" +FAST_FORWARD_BUTTON = "\u23e9" +NEXT_TRACK_BUTTON = "\u23ed\ufe0f" +PLAY_OR_PAUSE_BUTTON = "\u23ef\ufe0f" +REVERSE_BUTTON = "\u25c0\ufe0f" +FAST_REVERSE_BUTTON = "\u23ea" +LAST_TRACK_BUTTON = "\u23ee\ufe0f" +UPWARDS_BUTTON = "\U0001f53c" +FAST_UP_BUTTON = "\u23eb" +DOWNWARDS_BUTTON = "\U0001f53d" +FAST_DOWN_BUTTON = "\u23ec" +PAUSE_BUTTON = "\u23f8\ufe0f" +STOP_BUTTON = "\u23f9\ufe0f" +RECORD_BUTTON = "\u23fa\ufe0f" +EJECT_BUTTON = "\u23cf\ufe0f" +CINEMA = "\U0001f3a6" +DIM_BUTTON = "\U0001f505" +BRIGHT_BUTTON = "\U0001f506" +ANTENNA_BARS = "\U0001f4f6" +VIBRATION_MODE = "\U0001f4f3" +MOBILE_PHONE_OFF = "\U0001f4f4" +FEMALE_SIGN = "\u2640\ufe0f" +MALE_SIGN = "\u2642\ufe0f" +TRANSGENDER_SYMBOL = "\u26a7\ufe0f" +MULTIPLY = "\u2716\ufe0f" +PLUS = "\u2795" +MINUS = "\u2796" +DIVIDE = "\u2797" +INFINITY = "\u267e\ufe0f" +DOUBLE_EXCLAMATION_MARK = "\u203c\ufe0f" +EXCLAMATION_QUESTION_MARK = "\u2049\ufe0f" +QUESTION_MARK = "\u2753" +WHITE_QUESTION_MARK = "\u2754" +WHITE_EXCLAMATION_MARK = "\u2755" +EXCLAMATION_MARK = "\u2757" +WAVY_DASH = "\u3030\ufe0f" +CURRENCY_EXCHANGE = "\U0001f4b1" +HEAVY_DOLLAR_SIGN = "\U0001f4b2" +MEDICAL_SYMBOL = "\u2695\ufe0f" +RECYCLING_SYMBOL = "\u267b\ufe0f" +FLEUR_DE_LIS = "\u269c\ufe0f" +TRIDENT_EMBLEM = "\U0001f531" +NAME_BADGE = "\U0001f4db" +JAPANESE_SYMBOL_FOR_BEGINNER = "\U0001f530" +HOLLOW_RED_CIRCLE = "\u2b55" +CHECK_MARK_BUTTON = "\u2705" +CHECK_BOX_WITH_CHECK = "\u2611\ufe0f" +CHECK_MARK = "\u2714\ufe0f" +CROSS_MARK = "\u274c" +CROSS_MARK_BUTTON = "\u274e" +CURLY_LOOP = "\u27b0" +DOUBLE_CURLY_LOOP = "\u27bf" +PART_ALTERNATION_MARK = "\u303d\ufe0f" +EIGHT_SPOKED_ASTERISK = "\u2733\ufe0f" +EIGHT_POINTED_STAR = "\u2734\ufe0f" +SPARKLE = "\u2747\ufe0f" +COPYRIGHT = "\xa9\ufe0f" +REGISTERED = "\xae\ufe0f" +TRADE_MARK = "\u2122\ufe0f" +KEYCAP_NUMBER_SIGN = "#\ufe0f\u20e3" +KEYCAP_ASTERISK = "*\ufe0f\u20e3" +KEYCAP_DIGIT_ZERO = "0\ufe0f\u20e3" +KEYCAP_DIGIT_ONE = "1\ufe0f\u20e3" +KEYCAP_DIGIT_TWO = "2\ufe0f\u20e3" +KEYCAP_DIGIT_THREE = "3\ufe0f\u20e3" +KEYCAP_DIGIT_FOUR = "4\ufe0f\u20e3" +KEYCAP_DIGIT_FIVE = "5\ufe0f\u20e3" +KEYCAP_DIGIT_SIX = "6\ufe0f\u20e3" +KEYCAP_DIGIT_SEVEN = "7\ufe0f\u20e3" +KEYCAP_DIGIT_EIGHT = "8\ufe0f\u20e3" +KEYCAP_DIGIT_NINE = "9\ufe0f\u20e3" +KEYCAP_10 = "\U0001f51f" +INPUT_LATIN_UPPERCASE = "\U0001f520" +INPUT_LATIN_LOWERCASE = "\U0001f521" +INPUT_NUMBERS = "\U0001f522" +INPUT_SYMBOLS = "\U0001f523" +INPUT_LATIN_LETTERS = "\U0001f524" +A_BUTTON_BLOOD_TYPE = "\U0001f170\ufe0f" +AB_BUTTON_BLOOD_TYPE = "\U0001f18e" +B_BUTTON_BLOOD_TYPE = "\U0001f171\ufe0f" +CL_BUTTON = "\U0001f191" +COOL_BUTTON = "\U0001f192" +FREE_BUTTON = "\U0001f193" +INFORMATION = "\u2139\ufe0f" +ID_BUTTON = "\U0001f194" +CIRCLED_M = "\u24c2\ufe0f" +NEW_BUTTON = "\U0001f195" +NG_BUTTON = "\U0001f196" +O_BUTTON_BLOOD_TYPE = "\U0001f17e\ufe0f" +OK_BUTTON = "\U0001f197" +P_BUTTON = "\U0001f17f\ufe0f" +SOS_BUTTON = "\U0001f198" +UP_BUTTON = "\U0001f199" +VS_BUTTON = "\U0001f19a" +JAPANESE_HERE_BUTTON = "\U0001f201" +JAPANESE_SERVICE_CHARGE_BUTTON = "\U0001f202\ufe0f" +JAPANESE_MONTHLY_AMOUNT_BUTTON = "\U0001f237\ufe0f" +JAPANESE_NOT_FREE_OF_CHARGE_BUTTON = "\U0001f236" +JAPANESE_RESERVED_BUTTON = "\U0001f22f" +JAPANESE_BARGAIN_BUTTON = "\U0001f250" +JAPANESE_DISCOUNT_BUTTON = "\U0001f239" +JAPANESE_FREE_OF_CHARGE_BUTTON = "\U0001f21a" +JAPANESE_PROHIBITED_BUTTON = "\U0001f232" +JAPANESE_ACCEPTABLE_BUTTON = "\U0001f251" +JAPANESE_APPLICATION_BUTTON = "\U0001f238" +JAPANESE_PASSING_GRADE_BUTTON = "\U0001f234" +JAPANESE_VACANCY_BUTTON = "\U0001f233" +JAPANESE_CONGRATULATIONS_BUTTON = "\u3297\ufe0f" +JAPANESE_SECRET_BUTTON = "\u3299\ufe0f" +JAPANESE_OPEN_FOR_BUSINESS_BUTTON = "\U0001f23a" +JAPANESE_NO_VACANCY_BUTTON = "\U0001f235" +RED_CIRCLE = "\U0001f534" +ORANGE_CIRCLE = "\U0001f7e0" +YELLOW_CIRCLE = "\U0001f7e1" +GREEN_CIRCLE = "\U0001f7e2" +BLUE_CIRCLE = "\U0001f535" +PURPLE_CIRCLE = "\U0001f7e3" +BROWN_CIRCLE = "\U0001f7e4" +BLACK_CIRCLE = "\u26ab" +WHITE_CIRCLE = "\u26aa" +RED_SQUARE = "\U0001f7e5" +ORANGE_SQUARE = "\U0001f7e7" +YELLOW_SQUARE = "\U0001f7e8" +GREEN_SQUARE = "\U0001f7e9" +BLUE_SQUARE = "\U0001f7e6" +PURPLE_SQUARE = "\U0001f7ea" +BROWN_SQUARE = "\U0001f7eb" +BLACK_LARGE_SQUARE = "\u2b1b" +WHITE_LARGE_SQUARE = "\u2b1c" +BLACK_MEDIUM_SQUARE = "\u25fc\ufe0f" +WHITE_MEDIUM_SQUARE = "\u25fb\ufe0f" +BLACK_MEDIUM_SMALL_SQUARE = "\u25fe" +WHITE_MEDIUM_SMALL_SQUARE = "\u25fd" +BLACK_SMALL_SQUARE = "\u25aa\ufe0f" +WHITE_SMALL_SQUARE = "\u25ab\ufe0f" +LARGE_ORANGE_DIAMOND = "\U0001f536" +LARGE_BLUE_DIAMOND = "\U0001f537" +SMALL_ORANGE_DIAMOND = "\U0001f538" +SMALL_BLUE_DIAMOND = "\U0001f539" +RED_TRIANGLE_POINTED_UP = "\U0001f53a" +RED_TRIANGLE_POINTED_DOWN = "\U0001f53b" +DIAMOND_WITH_A_DOT = "\U0001f4a0" +RADIO_BUTTON = "\U0001f518" +WHITE_SQUARE_BUTTON = "\U0001f533" +BLACK_SQUARE_BUTTON = "\U0001f532" +CHEQUERED_FLAG = "\U0001f3c1" +TRIANGULAR_FLAG = "\U0001f6a9" +CROSSED_FLAGS = "\U0001f38c" +BLACK_FLAG = "\U0001f3f4" +WHITE_FLAG = "\U0001f3f3\ufe0f" +RAINBOW_FLAG = "\U0001f3f3\ufe0f\u200d\U0001f308" +TRANSGENDER_FLAG = "\U0001f3f3\ufe0f\u200d\u26a7\ufe0f" +PIRATE_FLAG = "\U0001f3f4\u200d\u2620\ufe0f" +FLAG_ASCENSION_ISLAND = "\U0001f1e6\U0001f1e8" +FLAG_ANDORRA = "\U0001f1e6\U0001f1e9" +FLAG_UNITED_ARAB_EMIRATES = "\U0001f1e6\U0001f1ea" +FLAG_AFGHANISTAN = "\U0001f1e6\U0001f1eb" +FLAG_ANTIGUA_ANDAMP_BARBUDA = "\U0001f1e6\U0001f1ec" +FLAG_ANGUILLA = "\U0001f1e6\U0001f1ee" +FLAG_ALBANIA = "\U0001f1e6\U0001f1f1" +FLAG_ARMENIA = "\U0001f1e6\U0001f1f2" +FLAG_ANGOLA = "\U0001f1e6\U0001f1f4" +FLAG_ANTARCTICA = "\U0001f1e6\U0001f1f6" +FLAG_ARGENTINA = "\U0001f1e6\U0001f1f7" +FLAG_AMERICAN_SAMOA = "\U0001f1e6\U0001f1f8" +FLAG_AUSTRIA = "\U0001f1e6\U0001f1f9" +FLAG_AUSTRALIA = "\U0001f1e6\U0001f1fa" +FLAG_ARUBA = "\U0001f1e6\U0001f1fc" +FLAG_ALAND_ISLANDS = "\U0001f1e6\U0001f1fd" +FLAG_AZERBAIJAN = "\U0001f1e6\U0001f1ff" +FLAG_BOSNIA_ANDAMP_HERZEGOVINA = "\U0001f1e7\U0001f1e6" +FLAG_BARBADOS = "\U0001f1e7\U0001f1e7" +FLAG_BANGLADESH = "\U0001f1e7\U0001f1e9" +FLAG_BELGIUM = "\U0001f1e7\U0001f1ea" +FLAG_BURKINA_FASO = "\U0001f1e7\U0001f1eb" +FLAG_BULGARIA = "\U0001f1e7\U0001f1ec" +FLAG_BAHRAIN = "\U0001f1e7\U0001f1ed" +FLAG_BURUNDI = "\U0001f1e7\U0001f1ee" +FLAG_BENIN = "\U0001f1e7\U0001f1ef" +FLAG_ST_BARTHELEMY = "\U0001f1e7\U0001f1f1" +FLAG_BERMUDA = "\U0001f1e7\U0001f1f2" +FLAG_BRUNEI = "\U0001f1e7\U0001f1f3" +FLAG_BOLIVIA = "\U0001f1e7\U0001f1f4" +FLAG_CARIBBEAN_NETHERLANDS = "\U0001f1e7\U0001f1f6" +FLAG_BRAZIL = "\U0001f1e7\U0001f1f7" +FLAG_BAHAMAS = "\U0001f1e7\U0001f1f8" +FLAG_BHUTAN = "\U0001f1e7\U0001f1f9" +FLAG_BOUVET_ISLAND = "\U0001f1e7\U0001f1fb" +FLAG_BOTSWANA = "\U0001f1e7\U0001f1fc" +FLAG_BELARUS = "\U0001f1e7\U0001f1fe" +FLAG_BELIZE = "\U0001f1e7\U0001f1ff" +FLAG_CANADA = "\U0001f1e8\U0001f1e6" +FLAG_COCOS_KEELING_ISLANDS = "\U0001f1e8\U0001f1e8" +FLAG_CONGO_KINSHASA = "\U0001f1e8\U0001f1e9" +FLAG_CENTRAL_AFRICAN_REPUBLIC = "\U0001f1e8\U0001f1eb" +FLAG_CONGO_BRAZZAVILLE = "\U0001f1e8\U0001f1ec" +FLAG_SWITZERLAND = "\U0001f1e8\U0001f1ed" +FLAG_COTE_D_IVOIRE = "\U0001f1e8\U0001f1ee" +FLAG_COOK_ISLANDS = "\U0001f1e8\U0001f1f0" +FLAG_CHILE = "\U0001f1e8\U0001f1f1" +FLAG_CAMEROON = "\U0001f1e8\U0001f1f2" +FLAG_CHINA = "\U0001f1e8\U0001f1f3" +FLAG_COLOMBIA = "\U0001f1e8\U0001f1f4" +FLAG_CLIPPERTON_ISLAND = "\U0001f1e8\U0001f1f5" +FLAG_COSTA_RICA = "\U0001f1e8\U0001f1f7" +FLAG_CUBA = "\U0001f1e8\U0001f1fa" +FLAG_CAPE_VERDE = "\U0001f1e8\U0001f1fb" +FLAG_CURACAO = "\U0001f1e8\U0001f1fc" +FLAG_CHRISTMAS_ISLAND = "\U0001f1e8\U0001f1fd" +FLAG_CYPRUS = "\U0001f1e8\U0001f1fe" +FLAG_CZECHIA = "\U0001f1e8\U0001f1ff" +FLAG_GERMANY = "\U0001f1e9\U0001f1ea" +FLAG_DIEGO_GARCIA = "\U0001f1e9\U0001f1ec" +FLAG_DJIBOUTI = "\U0001f1e9\U0001f1ef" +FLAG_DENMARK = "\U0001f1e9\U0001f1f0" +FLAG_DOMINICA = "\U0001f1e9\U0001f1f2" +FLAG_DOMINICAN_REPUBLIC = "\U0001f1e9\U0001f1f4" +FLAG_ALGERIA = "\U0001f1e9\U0001f1ff" +FLAG_CEUTA_ANDAMP_MELILLA = "\U0001f1ea\U0001f1e6" +FLAG_ECUADOR = "\U0001f1ea\U0001f1e8" +FLAG_ESTONIA = "\U0001f1ea\U0001f1ea" +FLAG_EGYPT = "\U0001f1ea\U0001f1ec" +FLAG_WESTERN_SAHARA = "\U0001f1ea\U0001f1ed" +FLAG_ERITREA = "\U0001f1ea\U0001f1f7" +FLAG_SPAIN = "\U0001f1ea\U0001f1f8" +FLAG_ETHIOPIA = "\U0001f1ea\U0001f1f9" +FLAG_EUROPEAN_UNION = "\U0001f1ea\U0001f1fa" +FLAG_FINLAND = "\U0001f1eb\U0001f1ee" +FLAG_FIJI = "\U0001f1eb\U0001f1ef" +FLAG_FALKLAND_ISLANDS = "\U0001f1eb\U0001f1f0" +FLAG_MICRONESIA = "\U0001f1eb\U0001f1f2" +FLAG_FAROE_ISLANDS = "\U0001f1eb\U0001f1f4" +FLAG_FRANCE = "\U0001f1eb\U0001f1f7" +FLAG_GABON = "\U0001f1ec\U0001f1e6" +FLAG_UNITED_KINGDOM = "\U0001f1ec\U0001f1e7" +FLAG_GRENADA = "\U0001f1ec\U0001f1e9" +FLAG_GEORGIA = "\U0001f1ec\U0001f1ea" +FLAG_FRENCH_GUIANA = "\U0001f1ec\U0001f1eb" +FLAG_GUERNSEY = "\U0001f1ec\U0001f1ec" +FLAG_GHANA = "\U0001f1ec\U0001f1ed" +FLAG_GIBRALTAR = "\U0001f1ec\U0001f1ee" +FLAG_GREENLAND = "\U0001f1ec\U0001f1f1" +FLAG_GAMBIA = "\U0001f1ec\U0001f1f2" +FLAG_GUINEA = "\U0001f1ec\U0001f1f3" +FLAG_GUADELOUPE = "\U0001f1ec\U0001f1f5" +FLAG_EQUATORIAL_GUINEA = "\U0001f1ec\U0001f1f6" +FLAG_GREECE = "\U0001f1ec\U0001f1f7" +FLAG_SOUTH_GEORGIA_ANDAMP_SOUTH_SANDWICH_ISLANDS = "\U0001f1ec\U0001f1f8" +FLAG_GUATEMALA = "\U0001f1ec\U0001f1f9" +FLAG_GUAM = "\U0001f1ec\U0001f1fa" +FLAG_GUINEA_BISSAU = "\U0001f1ec\U0001f1fc" +FLAG_GUYANA = "\U0001f1ec\U0001f1fe" +FLAG_HONG_KONG_SAR_CHINA = "\U0001f1ed\U0001f1f0" +FLAG_HEARD_ANDAMP_MCDONALD_ISLANDS = "\U0001f1ed\U0001f1f2" +FLAG_HONDURAS = "\U0001f1ed\U0001f1f3" +FLAG_CROATIA = "\U0001f1ed\U0001f1f7" +FLAG_HAITI = "\U0001f1ed\U0001f1f9" +FLAG_HUNGARY = "\U0001f1ed\U0001f1fa" +FLAG_CANARY_ISLANDS = "\U0001f1ee\U0001f1e8" +FLAG_INDONESIA = "\U0001f1ee\U0001f1e9" +FLAG_IRELAND = "\U0001f1ee\U0001f1ea" +FLAG_ISRAEL = "\U0001f1ee\U0001f1f1" +FLAG_ISLE_OF_MAN = "\U0001f1ee\U0001f1f2" +FLAG_INDIA = "\U0001f1ee\U0001f1f3" +FLAG_BRITISH_INDIAN_OCEAN_TERRITORY = "\U0001f1ee\U0001f1f4" +FLAG_IRAQ = "\U0001f1ee\U0001f1f6" +FLAG_IRAN = "\U0001f1ee\U0001f1f7" +FLAG_ICELAND = "\U0001f1ee\U0001f1f8" +FLAG_ITALY = "\U0001f1ee\U0001f1f9" +FLAG_JERSEY = "\U0001f1ef\U0001f1ea" +FLAG_JAMAICA = "\U0001f1ef\U0001f1f2" +FLAG_JORDAN = "\U0001f1ef\U0001f1f4" +FLAG_JAPAN = "\U0001f1ef\U0001f1f5" +FLAG_KENYA = "\U0001f1f0\U0001f1ea" +FLAG_KYRGYZSTAN = "\U0001f1f0\U0001f1ec" +FLAG_CAMBODIA = "\U0001f1f0\U0001f1ed" +FLAG_KIRIBATI = "\U0001f1f0\U0001f1ee" +FLAG_COMOROS = "\U0001f1f0\U0001f1f2" +FLAG_ST_KITTS_ANDAMP_NEVIS = "\U0001f1f0\U0001f1f3" +FLAG_NORTH_KOREA = "\U0001f1f0\U0001f1f5" +FLAG_SOUTH_KOREA = "\U0001f1f0\U0001f1f7" +FLAG_KUWAIT = "\U0001f1f0\U0001f1fc" +FLAG_CAYMAN_ISLANDS = "\U0001f1f0\U0001f1fe" +FLAG_KAZAKHSTAN = "\U0001f1f0\U0001f1ff" +FLAG_LAOS = "\U0001f1f1\U0001f1e6" +FLAG_LEBANON = "\U0001f1f1\U0001f1e7" +FLAG_ST_LUCIA = "\U0001f1f1\U0001f1e8" +FLAG_LIECHTENSTEIN = "\U0001f1f1\U0001f1ee" +FLAG_SRI_LANKA = "\U0001f1f1\U0001f1f0" +FLAG_LIBERIA = "\U0001f1f1\U0001f1f7" +FLAG_LESOTHO = "\U0001f1f1\U0001f1f8" +FLAG_LITHUANIA = "\U0001f1f1\U0001f1f9" +FLAG_LUXEMBOURG = "\U0001f1f1\U0001f1fa" +FLAG_LATVIA = "\U0001f1f1\U0001f1fb" +FLAG_LIBYA = "\U0001f1f1\U0001f1fe" +FLAG_MOROCCO = "\U0001f1f2\U0001f1e6" +FLAG_MONACO = "\U0001f1f2\U0001f1e8" +FLAG_MOLDOVA = "\U0001f1f2\U0001f1e9" +FLAG_MONTENEGRO = "\U0001f1f2\U0001f1ea" +FLAG_ST_MARTIN = "\U0001f1f2\U0001f1eb" +FLAG_MADAGASCAR = "\U0001f1f2\U0001f1ec" +FLAG_MARSHALL_ISLANDS = "\U0001f1f2\U0001f1ed" +FLAG_NORTH_MACEDONIA = "\U0001f1f2\U0001f1f0" +FLAG_MALI = "\U0001f1f2\U0001f1f1" +FLAG_MYANMAR_BURMA = "\U0001f1f2\U0001f1f2" +FLAG_MONGOLIA = "\U0001f1f2\U0001f1f3" +FLAG_MACAO_SAR_CHINA = "\U0001f1f2\U0001f1f4" +FLAG_NORTHERN_MARIANA_ISLANDS = "\U0001f1f2\U0001f1f5" +FLAG_MARTINIQUE = "\U0001f1f2\U0001f1f6" +FLAG_MAURITANIA = "\U0001f1f2\U0001f1f7" +FLAG_MONTSERRAT = "\U0001f1f2\U0001f1f8" +FLAG_MALTA = "\U0001f1f2\U0001f1f9" +FLAG_MAURITIUS = "\U0001f1f2\U0001f1fa" +FLAG_MALDIVES = "\U0001f1f2\U0001f1fb" +FLAG_MALAWI = "\U0001f1f2\U0001f1fc" +FLAG_MEXICO = "\U0001f1f2\U0001f1fd" +FLAG_MALAYSIA = "\U0001f1f2\U0001f1fe" +FLAG_MOZAMBIQUE = "\U0001f1f2\U0001f1ff" +FLAG_NAMIBIA = "\U0001f1f3\U0001f1e6" +FLAG_NEW_CALEDONIA = "\U0001f1f3\U0001f1e8" +FLAG_NIGER = "\U0001f1f3\U0001f1ea" +FLAG_NORFOLK_ISLAND = "\U0001f1f3\U0001f1eb" +FLAG_NIGERIA = "\U0001f1f3\U0001f1ec" +FLAG_NICARAGUA = "\U0001f1f3\U0001f1ee" +FLAG_NETHERLANDS = "\U0001f1f3\U0001f1f1" +FLAG_NORWAY = "\U0001f1f3\U0001f1f4" +FLAG_NEPAL = "\U0001f1f3\U0001f1f5" +FLAG_NAURU = "\U0001f1f3\U0001f1f7" +FLAG_NIUE = "\U0001f1f3\U0001f1fa" +FLAG_NEW_ZEALAND = "\U0001f1f3\U0001f1ff" +FLAG_OMAN = "\U0001f1f4\U0001f1f2" +FLAG_PANAMA = "\U0001f1f5\U0001f1e6" +FLAG_PERU = "\U0001f1f5\U0001f1ea" +FLAG_FRENCH_POLYNESIA = "\U0001f1f5\U0001f1eb" +FLAG_PAPUA_NEW_GUINEA = "\U0001f1f5\U0001f1ec" +FLAG_PHILIPPINES = "\U0001f1f5\U0001f1ed" +FLAG_PAKISTAN = "\U0001f1f5\U0001f1f0" +FLAG_POLAND = "\U0001f1f5\U0001f1f1" +FLAG_ST_PIERRE_ANDAMP_MIQUELON = "\U0001f1f5\U0001f1f2" +FLAG_PITCAIRN_ISLANDS = "\U0001f1f5\U0001f1f3" +FLAG_PUERTO_RICO = "\U0001f1f5\U0001f1f7" +FLAG_PALESTINIAN_TERRITORIES = "\U0001f1f5\U0001f1f8" +FLAG_PORTUGAL = "\U0001f1f5\U0001f1f9" +FLAG_PALAU = "\U0001f1f5\U0001f1fc" +FLAG_PARAGUAY = "\U0001f1f5\U0001f1fe" +FLAG_QATAR = "\U0001f1f6\U0001f1e6" +FLAG_REUNION = "\U0001f1f7\U0001f1ea" +FLAG_ROMANIA = "\U0001f1f7\U0001f1f4" +FLAG_SERBIA = "\U0001f1f7\U0001f1f8" +FLAG_RUSSIA = "\U0001f1f7\U0001f1fa" +FLAG_RWANDA = "\U0001f1f7\U0001f1fc" +FLAG_SAUDI_ARABIA = "\U0001f1f8\U0001f1e6" +FLAG_SOLOMON_ISLANDS = "\U0001f1f8\U0001f1e7" +FLAG_SEYCHELLES = "\U0001f1f8\U0001f1e8" +FLAG_SUDAN = "\U0001f1f8\U0001f1e9" +FLAG_SWEDEN = "\U0001f1f8\U0001f1ea" +FLAG_SINGAPORE = "\U0001f1f8\U0001f1ec" +FLAG_ST_HELENA = "\U0001f1f8\U0001f1ed" +FLAG_SLOVENIA = "\U0001f1f8\U0001f1ee" +FLAG_SVALBARD_ANDAMP_JAN_MAYEN = "\U0001f1f8\U0001f1ef" +FLAG_SLOVAKIA = "\U0001f1f8\U0001f1f0" +FLAG_SIERRA_LEONE = "\U0001f1f8\U0001f1f1" +FLAG_SAN_MARINO = "\U0001f1f8\U0001f1f2" +FLAG_SENEGAL = "\U0001f1f8\U0001f1f3" +FLAG_SOMALIA = "\U0001f1f8\U0001f1f4" +FLAG_SURINAME = "\U0001f1f8\U0001f1f7" +FLAG_SOUTH_SUDAN = "\U0001f1f8\U0001f1f8" +FLAG_SAO_TOME_ANDAMP_PRINCIPE = "\U0001f1f8\U0001f1f9" +FLAG_EL_SALVADOR = "\U0001f1f8\U0001f1fb" +FLAG_SINT_MAARTEN = "\U0001f1f8\U0001f1fd" +FLAG_SYRIA = "\U0001f1f8\U0001f1fe" +FLAG_ESWATINI = "\U0001f1f8\U0001f1ff" +FLAG_TRISTAN_DA_CUNHA = "\U0001f1f9\U0001f1e6" +FLAG_TURKS_ANDAMP_CAICOS_ISLANDS = "\U0001f1f9\U0001f1e8" +FLAG_CHAD = "\U0001f1f9\U0001f1e9" +FLAG_FRENCH_SOUTHERN_TERRITORIES = "\U0001f1f9\U0001f1eb" +FLAG_TOGO = "\U0001f1f9\U0001f1ec" +FLAG_THAILAND = "\U0001f1f9\U0001f1ed" +FLAG_TAJIKISTAN = "\U0001f1f9\U0001f1ef" +FLAG_TOKELAU = "\U0001f1f9\U0001f1f0" +FLAG_TIMOR_LESTE = "\U0001f1f9\U0001f1f1" +FLAG_TURKMENISTAN = "\U0001f1f9\U0001f1f2" +FLAG_TUNISIA = "\U0001f1f9\U0001f1f3" +FLAG_TONGA = "\U0001f1f9\U0001f1f4" +FLAG_TURKEY = "\U0001f1f9\U0001f1f7" +FLAG_TRINIDAD_ANDAMP_TOBAGO = "\U0001f1f9\U0001f1f9" +FLAG_TUVALU = "\U0001f1f9\U0001f1fb" +FLAG_TAIWAN = "\U0001f1f9\U0001f1fc" +FLAG_TANZANIA = "\U0001f1f9\U0001f1ff" +FLAG_UKRAINE = "\U0001f1fa\U0001f1e6" +FLAG_UGANDA = "\U0001f1fa\U0001f1ec" +FLAG_U_S_OUTLYING_ISLANDS = "\U0001f1fa\U0001f1f2" +FLAG_UNITED_NATIONS = "\U0001f1fa\U0001f1f3" +FLAG_UNITED_STATES = "\U0001f1fa\U0001f1f8" +FLAG_URUGUAY = "\U0001f1fa\U0001f1fe" +FLAG_UZBEKISTAN = "\U0001f1fa\U0001f1ff" +FLAG_VATICAN_CITY = "\U0001f1fb\U0001f1e6" +FLAG_ST_VINCENT_ANDAMP_GRENADINES = "\U0001f1fb\U0001f1e8" +FLAG_VENEZUELA = "\U0001f1fb\U0001f1ea" +FLAG_BRITISH_VIRGIN_ISLANDS = "\U0001f1fb\U0001f1ec" +FLAG_U_S_VIRGIN_ISLANDS = "\U0001f1fb\U0001f1ee" +FLAG_VIETNAM = "\U0001f1fb\U0001f1f3" +FLAG_VANUATU = "\U0001f1fb\U0001f1fa" +FLAG_WALLIS_ANDAMP_FUTUNA = "\U0001f1fc\U0001f1eb" +FLAG_SAMOA = "\U0001f1fc\U0001f1f8" +FLAG_KOSOVO = "\U0001f1fd\U0001f1f0" +FLAG_YEMEN = "\U0001f1fe\U0001f1ea" +FLAG_MAYOTTE = "\U0001f1fe\U0001f1f9" +FLAG_SOUTH_AFRICA = "\U0001f1ff\U0001f1e6" +FLAG_ZAMBIA = "\U0001f1ff\U0001f1f2" +FLAG_ZIMBABWE = "\U0001f1ff\U0001f1fc" +FLAG_ENGLAND = "\U0001f3f4\U000e0067\U000e0062\U000e0065\U000e006e\U000e0067\U000e007f" +FLAG_SCOTLAND = "\U0001f3f4\U000e0067\U000e0062\U000e0073\U000e0063\U000e0074\U000e007f" +FLAG_WALES = "\U0001f3f4\U000e0067\U000e0062\U000e0077\U000e006c\U000e0073\U000e007f" +REGIONAL_INDICATOR_SYMBOL_LETTER_A = "\U0001f1e6" +REGIONAL_INDICATOR_SYMBOL_LETTER_B = "\U0001f1e7" +REGIONAL_INDICATOR_SYMBOL_LETTER_C = "\U0001f1e8" +REGIONAL_INDICATOR_SYMBOL_LETTER_D = "\U0001f1e9" +REGIONAL_INDICATOR_SYMBOL_LETTER_E = "\U0001f1ea" +REGIONAL_INDICATOR_SYMBOL_LETTER_F = "\U0001f1eb" +REGIONAL_INDICATOR_SYMBOL_LETTER_G = "\U0001f1ec" +REGIONAL_INDICATOR_SYMBOL_LETTER_H = "\U0001f1ed" +REGIONAL_INDICATOR_SYMBOL_LETTER_I = "\U0001f1ee" +REGIONAL_INDICATOR_SYMBOL_LETTER_J = "\U0001f1ef" +REGIONAL_INDICATOR_SYMBOL_LETTER_K = "\U0001f1f0" +REGIONAL_INDICATOR_SYMBOL_LETTER_L = "\U0001f1f1" +REGIONAL_INDICATOR_SYMBOL_LETTER_M = "\U0001f1f2" +REGIONAL_INDICATOR_SYMBOL_LETTER_N = "\U0001f1f3" +REGIONAL_INDICATOR_SYMBOL_LETTER_O = "\U0001f1f4" +REGIONAL_INDICATOR_SYMBOL_LETTER_P = "\U0001f1f5" +REGIONAL_INDICATOR_SYMBOL_LETTER_Q = "\U0001f1f6" +REGIONAL_INDICATOR_SYMBOL_LETTER_R = "\U0001f1f7" +REGIONAL_INDICATOR_SYMBOL_LETTER_S = "\U0001f1f8" +REGIONAL_INDICATOR_SYMBOL_LETTER_T = "\U0001f1f9" +REGIONAL_INDICATOR_SYMBOL_LETTER_U = "\U0001f1fa" +REGIONAL_INDICATOR_SYMBOL_LETTER_V = "\U0001f1fb" +REGIONAL_INDICATOR_SYMBOL_LETTER_W = "\U0001f1fc" +REGIONAL_INDICATOR_SYMBOL_LETTER_X = "\U0001f1fd" +REGIONAL_INDICATOR_SYMBOL_LETTER_Y = "\U0001f1fe" +REGIONAL_INDICATOR_SYMBOL_LETTER_Z = "\U0001f1ff" +TAG_VERTICAL_LINE = "\U000e007c" +TAG_LATIN_CAPITAL_LETTER_O = "\U000e004f" +TAG_LOW_LINE = "\U000e005f" +TAG_LATIN_SMALL_LETTER_E = "\U000e0065" +TAG_PERCENT_SIGN = "\U000e0025" +TAG_DIGIT_SEVEN = "\U000e0037" +TAG_LATIN_SMALL_LETTER_W = "\U000e0077" +TAG_DIGIT_ONE = "\U000e0031" +TAG_LATIN_CAPITAL_LETTER_A = "\U000e0041" +TAG_LATIN_CAPITAL_LETTER_Z = "\U000e005a" +TAG_LATIN_CAPITAL_LETTER_M = "\U000e004d" +TAG_QUESTION_MARK = "\U000e003f" +TAG_LATIN_CAPITAL_LETTER_W = "\U000e0057" +TAG_LATIN_SMALL_LETTER_D = "\U000e0064" +TAG_LATIN_SMALL_LETTER_K = "\U000e006b" +TAG_LATIN_SMALL_LETTER_V = "\U000e0076" +DIGIT_ZERO = "0\ufe0f" +TAG_DIGIT_SIX = "\U000e0036" +TAG_LATIN_SMALL_LETTER_C = "\U000e0063" +TAG_LATIN_SMALL_LETTER_X = "\U000e0078" +TAG_LATIN_SMALL_LETTER_U = "\U000e0075" +TAG_DIGIT_NINE = "\U000e0039" +DIGIT_FOUR = "4\ufe0f" +DIGIT_EIGHT = "8\ufe0f" +TAG_RIGHT_CURLY_BRACKET = "\U000e007d" +TAG_LATIN_CAPITAL_LETTER_S = "\U000e0053" +TAG_DIGIT_FIVE = "\U000e0035" +TAG_LATIN_CAPITAL_LETTER_V = "\U000e0056" +TAG_LATIN_SMALL_LETTER_L = "\U000e006c" +TAG_SOLIDUS = "\U000e002f" +TAG_LATIN_SMALL_LETTER_B = "\U000e0062" +TAG_SEMICOLON = "\U000e003b" +TAG_LESS_THAN_SIGN = "\U000e003c" +TAG_DIGIT_TWO = "\U000e0032" +TAG_LATIN_SMALL_LETTER_M = "\U000e006d" +TAG_LATIN_CAPITAL_LETTER_N = "\U000e004e" +TAG_LATIN_SMALL_LETTER_P = "\U000e0070" +TAG_LATIN_SMALL_LETTER_I = "\U000e0069" +TAG_LATIN_SMALL_LETTER_A = "\U000e0061" +TAG_NUMBER_SIGN = "\U000e0023" +TAG_LATIN_CAPITAL_LETTER_K = "\U000e004b" +TAG_LATIN_CAPITAL_LETTER_J = "\U000e004a" +TAG_LATIN_CAPITAL_LETTER_T = "\U000e0054" +TAG_LATIN_SMALL_LETTER_Y = "\U000e0079" +TAG_QUOTATION_MARK = "\U000e0022" +TAG_TILDE = "\U000e007e" +TAG_FULL_STOP = "\U000e002e" +TAG_LATIN_SMALL_LETTER_S = "\U000e0073" +TAG_LATIN_SMALL_LETTER_F = "\U000e0066" +TAG_LATIN_SMALL_LETTER_O = "\U000e006f" +TAG_DIGIT_ZERO = "\U000e0030" +DIGIT_FIVE = "5\ufe0f" +DIGIT_ONE = "1\ufe0f" +TAG_LATIN_CAPITAL_LETTER_B = "\U000e0042" +DIGIT_NINE = "9\ufe0f" +TAG_LATIN_CAPITAL_LETTER_F = "\U000e0046" +TAG_LATIN_CAPITAL_LETTER_Y = "\U000e0059" +TAG_GREATER_THAN_SIGN = "\U000e003e" +TAG_HYPHEN_MINUS = "\U000e002d" +TAG_LEFT_CURLY_BRACKET = "\U000e007b" +TAG_DIGIT_THREE = "\U000e0033" +TAG_EQUALS_SIGN = "\U000e003d" +TAG_DIGIT_FOUR = "\U000e0034" +TAG_LATIN_SMALL_LETTER_N = "\U000e006e" +TAG_DOLLAR_SIGN = "\U000e0024" +TAG_RIGHT_PARENTHESIS = "\U000e0029" +TAG_LATIN_CAPITAL_LETTER_Q = "\U000e0051" +TAG_CIRCUMFLEX_ACCENT = "\U000e005e" +DIGIT_SEVEN = "7\ufe0f" +VARIATION_SELECTOR_16 = "\ufe0f" +NUMBER_SIGN = "#\ufe0f" +DIGIT_TWO = "2\ufe0f" +TAG_GRAVE_ACCENT = "\U000e0060" +TAG_COLON = "\U000e003a" +TAG_REVERSE_SOLIDUS = "\U000e005c" +TAG_COMMERCIAL_AT = "\U000e0040" +TAG_EXCLAMATION_MARK = "\U000e0021" +TAG_APOSTROPHE = "\U000e0027" +TAG_LATIN_SMALL_LETTER_Z = "\U000e007a" +TAG_LATIN_CAPITAL_LETTER_X = "\U000e0058" +TAG_LATIN_CAPITAL_LETTER_R = "\U000e0052" +COMBINING_ENCLOSING_KEYCAP = "\u20e3" +ZERO_WIDTH_JOINER = "\u200d" +TAG_LATIN_SMALL_LETTER_G = "\U000e0067" +TAG_LATIN_CAPITAL_LETTER_U = "\U000e0055" +TAG_LATIN_CAPITAL_LETTER_D = "\U000e0044" +TAG_LATIN_SMALL_LETTER_R = "\U000e0072" +TAG_LATIN_CAPITAL_LETTER_P = "\U000e0050" +TAG_LATIN_SMALL_LETTER_H = "\U000e0068" +CANCEL_TAG = "\U000e007f" +TAG_AMPERSAND = "\U000e0026" +TAG_LEFT_PARENTHESIS = "\U000e0028" +TAG_LATIN_SMALL_LETTER_Q = "\U000e0071" +TAG_LATIN_CAPITAL_LETTER_C = "\U000e0043" +TAG_ASTERISK = "\U000e002a" +TAG_LATIN_SMALL_LETTER_T = "\U000e0074" +TAG_LATIN_CAPITAL_LETTER_L = "\U000e004c" +TAG_COMMA = "\U000e002c" +TAG_RIGHT_SQUARE_BRACKET = "\U000e005d" +DIGIT_THREE = "3\ufe0f" +TAG_LATIN_CAPITAL_LETTER_H = "\U000e0048" +TAG_LATIN_SMALL_LETTER_J = "\U000e006a" +TAG_SPACE = "\U000e0020" +TAG_PLUS_SIGN = "\U000e002b" +TAG_LEFT_SQUARE_BRACKET = "\U000e005b" +ASTERISK = "*\ufe0f" +DIGIT_SIX = "6\ufe0f" +TAG_DIGIT_EIGHT = "\U000e0038" +TAG_LATIN_CAPITAL_LETTER_E = "\U000e0045" +TAG_LATIN_CAPITAL_LETTER_G = "\U000e0047" +TAG_LATIN_CAPITAL_LETTER_I = "\U000e0049" diff --git a/pyrogram/errors/rpc_error.py b/pyrogram/errors/rpc_error.py index 2586d873..d1146794 100644 --- a/pyrogram/errors/rpc_error.py +++ b/pyrogram/errors/rpc_error.py @@ -21,9 +21,8 @@ from datetime import datetime from importlib import import_module from typing import Type -from pyrogram.api.types import RpcError as RawRPCError - -from pyrogram.api.core import TLObject +from pyrogram import raw +from pyrogram.raw.core import TLObject from .exceptions.all import exceptions @@ -33,12 +32,12 @@ class RPCError(Exception): NAME = None MESSAGE = "{x}" - def __init__(self, x: int or RawRPCError = None, rpc_name: str = None, is_unknown: bool = False): + def __init__(self, x: int or raw.types.RpcError = None, rpc_name: str = None, is_unknown: bool = False): super().__init__("[{} {}]: {} {}".format( self.CODE, self.ID or self.NAME, self.MESSAGE.format(x=x), - '(caused by "{}")'.format(rpc_name) if rpc_name else "" + f'(caused by "{rpc_name}")' if rpc_name else "" )) try: @@ -48,17 +47,17 @@ class RPCError(Exception): if is_unknown: with open("unknown_errors.txt", "a", encoding="utf-8") as f: - f.write("{}\t{}\t{}\n".format(datetime.now(), x, rpc_name)) + f.write(f"{datetime.now()}\t{x}\t{rpc_name}\n") @staticmethod - def raise_it(rpc_error: RawRPCError, rpc_type: Type[TLObject]): + def raise_it(rpc_error: "raw.types.RpcError", rpc_type: Type[TLObject]): error_code = rpc_error.error_code error_message = rpc_error.error_message rpc_name = ".".join(rpc_type.QUALNAME.split(".")[1:]) if error_code not in exceptions: raise UnknownError( - x="[{} {}]".format(error_code, error_message), + x=f"[{error_code} {error_message}]", rpc_name=rpc_name, is_unknown=True ) @@ -69,7 +68,7 @@ class RPCError(Exception): raise getattr( import_module("pyrogram.errors"), exceptions[error_code]["_"] - )(x="[{} {}]".format(error_code, error_message), + )(x=f"[{error_code} {error_message}]", rpc_name=rpc_name, is_unknown=True) diff --git a/pyrogram/filters.py b/pyrogram/filters.py new file mode 100644 index 00000000..45762aee --- /dev/null +++ b/pyrogram/filters.py @@ -0,0 +1,877 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import inspect +import re +from typing import Callable, Union, List, Pattern + +import pyrogram +from pyrogram.types import Message, CallbackQuery, InlineQuery, InlineKeyboardMarkup, ReplyKeyboardMarkup, Update + + +class Filter: + async def __call__(self, client: "pyrogram.Client", update: Update): + raise NotImplementedError + + def __invert__(self): + return InvertFilter(self) + + def __and__(self, other): + return AndFilter(self, other) + + def __or__(self, other): + return OrFilter(self, other) + + +class InvertFilter(Filter): + def __init__(self, base): + self.base = base + + async def __call__(self, client: "pyrogram.Client", update: Update): + if inspect.iscoroutinefunction(self.base.__call__): + x = await self.base(client, update) + else: + x = await client.loop.run_in_executor( + client.executor, + self.base, + client, update + ) + + return not x + + +class AndFilter(Filter): + def __init__(self, base, other): + self.base = base + self.other = other + + async def __call__(self, client: "pyrogram.Client", update: Update): + if inspect.iscoroutinefunction(self.base.__call__): + x = await self.base(client, update) + else: + x = await client.loop.run_in_executor( + client.executor, + self.base, + client, update + ) + + if inspect.iscoroutinefunction(self.other.__call__): + y = await self.other(client, update) + else: + y = await client.loop.run_in_executor( + client.executor, + self.other, + client, update + ) + + return x and y + + +class OrFilter(Filter): + def __init__(self, base, other): + self.base = base + self.other = other + + async def __call__(self, client: "pyrogram.Client", update: Update): + if inspect.iscoroutinefunction(self.base.__call__): + x = await self.base(client, update) + else: + x = await client.loop.run_in_executor( + client.executor, + self.base, + client, update + ) + + if inspect.iscoroutinefunction(self.other.__call__): + y = await self.other(client, update) + else: + y = await client.loop.run_in_executor( + client.executor, + self.other, + client, update + ) + + return x or y + + +CUSTOM_FILTER_NAME = "CustomFilter" + + +def create(func: Callable, name: str = None, **kwargs) -> Filter: + """Easily create a custom filter. + + Custom filters give you extra control over which updates are allowed or not to be processed by your handlers. + + Parameters: + func (``callable``): + A function that accepts two positional arguments *(filter, update)* and returns a boolean: True if the + update should be handled, False otherwise. The *filter* argument refers to the filter itself and can be used + to access keyword arguments (read below). The *update* argument type will vary depending on which + `Handler `_ is coming from. For example, in a :obj:`~pyrogram.handlers.MessageHandler` the + *update* argument will be a :obj:`~pyrogram.types.Message`; in a + :obj:`~pyrogram.handlers.CallbackQueryHandler` the *update* will be a :obj:`~pyrogram.types.CallbackQuery`. + Your function body can then access the incoming update attributes and decide whether to allow it or not. + + name (``str``, *optional*): + Your filter's name. Can be anything you like. + Defaults to "CustomFilter". + + **kwargs (``any``, *optional*): + Any keyword argument you would like to pass. Useful when creating parameterized custom filters, such as + :meth:`~Filters.command` or :meth:`~Filters.regex`. + """ + return type( + name or func.__name__ or CUSTOM_FILTER_NAME, + (Filter,), + {"__call__": func, **kwargs} + )() + + +# region all_filter +async def all_filter(_, __, ___): + return True + + +all = create(all_filter) +"""Filter all messages.""" + + +# endregion + +# region me_filter +async def me_filter(_, __, m: Message): + return bool(m.from_user and m.from_user.is_self) + + +me = create(me_filter) +"""Filter messages generated by you yourself.""" + + +# endregion + +# region bot_filter +async def bot_filter(_, __, m: Message): + return bool(m.from_user and m.from_user.is_bot) + + +bot = create(bot_filter) +"""Filter messages coming from bots.""" + + +# endregion + +# region incoming_filter +async def incoming_filter(_, __, m: Message): + return not m.outgoing + + +incoming = create(incoming_filter) +"""Filter incoming messages. Messages sent to your own chat (Saved Messages) are also recognised as incoming.""" + + +# endregion + +# region outgoing_filter +async def outgoing_filter(_, __, m: Message): + return m.outgoing + + +outgoing = create(outgoing_filter) +"""Filter outgoing messages. Messages sent to your own chat (Saved Messages) are not recognized as outgoing.""" + + +# endregion + +# region text_filter +async def text_filter(_, __, m: Message): + return bool(m.text) + + +text = create(text_filter) +"""Filter text messages.""" + + +# endregion + +# region reply_filter +async def reply_filter(_, __, m: Message): + return bool(m.reply_to_message) + + +reply = create(reply_filter) +"""Filter messages that are replies to other messages.""" + + +# endregion + +# region forwarded_filter +async def forwarded_filter(_, __, m: Message): + return bool(m.forward_date) + + +forwarded = create(forwarded_filter) +"""Filter messages that are forwarded.""" + + +# endregion + +# region caption_filter +async def caption_filter(_, __, m: Message): + return bool(m.caption) + + +caption = create(caption_filter) +"""Filter media messages that contain captions.""" + + +# endregion + +# region edited_filter +async def edited_filter(_, __, m: Message): + return bool(m.edit_date) + + +edited = create(edited_filter) +"""Filter edited messages.""" + + +# endregion + +# region audio_filter +async def audio_filter(_, __, m: Message): + return bool(m.audio) + + +audio = create(audio_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Audio` objects.""" + + +# endregion + +# region document_filter +async def document_filter(_, __, m: Message): + return bool(m.document) + + +document = create(document_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Document` objects.""" + + +# endregion + +# region photo_filter +async def photo_filter(_, __, m: Message): + return bool(m.photo) + + +photo = create(photo_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Photo` objects.""" + + +# endregion + +# region sticker_filter +async def sticker_filter(_, __, m: Message): + return bool(m.sticker) + + +sticker = create(sticker_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Sticker` objects.""" + + +# endregion + +# region animation_filter +async def animation_filter(_, __, m: Message): + return bool(m.animation) + + +animation = create(animation_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Animation` objects.""" + + +# endregion + +# region game_filter +async def game_filter(_, __, m: Message): + return bool(m.game) + + +game = create(game_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Game` objects.""" + + +# endregion + +# region video_filter +async def video_filter(_, __, m: Message): + return bool(m.video) + + +video = create(video_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Video` objects.""" + + +# endregion + +# region media_group_filter +async def media_group_filter(_, __, m: Message): + return bool(m.media_group_id) + + +media_group = create(media_group_filter) +"""Filter messages containing photos or videos being part of an album.""" + + +# endregion + +# region voice_filter +async def voice_filter(_, __, m: Message): + return bool(m.voice) + + +voice = create(voice_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Voice` note objects.""" + + +# endregion + +# region video_note_filter +async def video_note_filter(_, __, m: Message): + return bool(m.video_note) + + +video_note = create(video_note_filter) +"""Filter messages that contain :obj:`~pyrogram.types.VideoNote` objects.""" + + +# endregion + +# region contact_filter +async def contact_filter(_, __, m: Message): + return bool(m.contact) + + +contact = create(contact_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Contact` objects.""" + + +# endregion + +# region location_filter +async def location_filter(_, __, m: Message): + return bool(m.location) + + +location = create(location_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Location` objects.""" + + +# endregion + +# region venue_filter +async def venue_filter(_, __, m: Message): + return bool(m.venue) + + +venue = create(venue_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Venue` objects.""" + + +# endregion + +# region web_page_filter +async def web_page_filter(_, __, m: Message): + return m.web_page + + +web_page = create(web_page_filter) +"""Filter messages sent with a webpage preview.""" + + +# endregion + +# region poll_filter +async def poll_filter(_, __, m: Message): + return m.poll + + +poll = create(poll_filter) +"""Filter messages that contain :obj:`~pyrogram.types.Poll` objects.""" + + +# endregion + +# region private_filter +async def private_filter(_, __, m: Message): + return bool(m.chat and m.chat.type in {"private", "bot"}) + + +private = create(private_filter) +"""Filter messages sent in private chats.""" + + +# endregion + +# region group_filter +async def group_filter(_, __, m: Message): + return bool(m.chat and m.chat.type in {"group", "supergroup"}) + + +group = create(group_filter) +"""Filter messages sent in group or supergroup chats.""" + + +# endregion + +# region channel_filter +async def channel_filter(_, __, m: Message): + return bool(m.chat and m.chat.type == "channel") + + +channel = create(channel_filter) +"""Filter messages sent in channels.""" + + +# endregion + +# region new_chat_members_filter +async def new_chat_members_filter(_, __, m: Message): + return bool(m.new_chat_members) + + +new_chat_members = create(new_chat_members_filter) +"""Filter service messages for new chat members.""" + + +# endregion + +# region left_chat_member_filter +async def left_chat_member_filter(_, __, m: Message): + return bool(m.left_chat_member) + + +left_chat_member = create(left_chat_member_filter) +"""Filter service messages for members that left the chat.""" + + +# endregion + +# region new_chat_title_filter +async def new_chat_title_filter(_, __, m: Message): + return bool(m.new_chat_title) + + +new_chat_title = create(new_chat_title_filter) +"""Filter service messages for new chat titles.""" + + +# endregion + +# region new_chat_photo_filter +async def new_chat_photo_filter(_, __, m: Message): + return bool(m.new_chat_photo) + + +new_chat_photo = create(new_chat_photo_filter) +"""Filter service messages for new chat photos.""" + + +# endregion + +# region delete_chat_photo_filter +async def delete_chat_photo_filter(_, __, m: Message): + return bool(m.delete_chat_photo) + + +delete_chat_photo = create(delete_chat_photo_filter) +"""Filter service messages for deleted photos.""" + + +# endregion + +# region group_chat_created_filter +async def group_chat_created_filter(_, __, m: Message): + return bool(m.group_chat_created) + + +group_chat_created = create(group_chat_created_filter) +"""Filter service messages for group chat creations.""" + + +# endregion + +# region supergroup_chat_created_filter +async def supergroup_chat_created_filter(_, __, m: Message): + return bool(m.supergroup_chat_created) + + +supergroup_chat_created = create(supergroup_chat_created_filter) +"""Filter service messages for supergroup chat creations.""" + + +# endregion + +# region channel_chat_created_filter +async def channel_chat_created_filter(_, __, m: Message): + return bool(m.channel_chat_created) + + +channel_chat_created = create(channel_chat_created_filter) +"""Filter service messages for channel chat creations.""" + + +# endregion + +# region migrate_to_chat_id_filter +async def migrate_to_chat_id_filter(_, __, m: Message): + return bool(m.migrate_to_chat_id) + + +migrate_to_chat_id = create(migrate_to_chat_id_filter) +"""Filter service messages that contain migrate_to_chat_id.""" + + +# endregion + +# region migrate_from_chat_id_filter +async def migrate_from_chat_id_filter(_, __, m: Message): + return bool(m.migrate_from_chat_id) + + +migrate_from_chat_id = create(migrate_from_chat_id_filter) +"""Filter service messages that contain migrate_from_chat_id.""" + + +# endregion + +# region pinned_message_filter +async def pinned_message_filter(_, __, m: Message): + return bool(m.pinned_message) + + +pinned_message = create(pinned_message_filter) +"""Filter service messages for pinned messages.""" + + +# endregion + +# region game_high_score_filter +async def game_high_score_filter(_, __, m: Message): + return bool(m.game_high_score) + + +game_high_score = create(game_high_score_filter) +"""Filter service messages for game high scores.""" + + +# endregion + +# region reply_keyboard_filter +async def reply_keyboard_filter(_, __, m: Message): + return isinstance(m.reply_markup, ReplyKeyboardMarkup) + + +reply_keyboard = create(reply_keyboard_filter) +"""Filter messages containing reply keyboard markups""" + + +# endregion + +# region inline_keyboard_filter +async def inline_keyboard_filter(_, __, m: Message): + return isinstance(m.reply_markup, InlineKeyboardMarkup) + + +inline_keyboard = create(inline_keyboard_filter) +"""Filter messages containing inline keyboard markups""" + + +# endregion + +# region mentioned_filter +async def mentioned_filter(_, __, m: Message): + return bool(m.mentioned) + + +mentioned = create(mentioned_filter) +"""Filter messages containing mentions""" + + +# endregion + +# region via_bot_filter +async def via_bot_filter(_, __, m: Message): + return bool(m.via_bot) + + +via_bot = create(via_bot_filter) +"""Filter messages sent via inline bots""" + + +# endregion + +# region service_filter +async def service_filter(_, __, m: Message): + return bool(m.service) + + +service = create(service_filter) +"""Filter service messages. + +A service message contains any of the following fields set: *left_chat_member*, +*new_chat_title*, *new_chat_photo*, *delete_chat_photo*, *group_chat_created*, *supergroup_chat_created*, +*channel_chat_created*, *migrate_to_chat_id*, *migrate_from_chat_id*, *pinned_message*, *game_score*. +""" + + +# endregion + +# region media_filter +async def media_filter(_, __, m: Message): + return bool(m.media) + + +media = create(media_filter) +"""Filter media messages. + +A media message contains any of the following fields set: *audio*, *document*, *photo*, *sticker*, *video*, +*animation*, *voice*, *video_note*, *contact*, *location*, *venue*, *poll*. +""" + + +# endregion + +# region scheduled_filter +async def scheduled_filter(_, __, m: Message): + return bool(m.scheduled) + + +scheduled = create(scheduled_filter) +"""Filter messages that have been scheduled (not yet sent).""" + + +# endregion + +# region from_scheduled_filter +async def from_scheduled_filter(_, __, m: Message): + return bool(m.from_scheduled) + + +from_scheduled = create(from_scheduled_filter) +"""Filter new automatically sent messages that were previously scheduled.""" + + +# endregion + +# region linked_channel_filter +async def linked_channel_filter(_, __, m: Message): + return bool(m.forward_from_chat and not m.from_user) + + +linked_channel = create(linked_channel_filter) +"""Filter messages that are automatically forwarded from the linked channel to the group chat.""" + + +# endregion + + +def command(commands: str or List[str], prefixes: str or List[str] = "/", case_sensitive: bool = False): + """Filter commands, i.e.: text messages starting with "/" or any other custom prefix. + + Parameters: + commands (``str`` | ``list``): + The command or list of commands as string the filter should look for. + Examples: "start", ["start", "help", "settings"]. When a message text containing + a command arrives, the command itself and its arguments will be stored in the *command* + field of the :obj:`~pyrogram.types.Message`. + + prefixes (``str`` | ``list``, *optional*): + A prefix or a list of prefixes as string the filter should look for. + Defaults to "/" (slash). Examples: ".", "!", ["/", "!", "."], list(".:!"). + Pass None or "" (empty string) to allow commands with no prefix at all. + + case_sensitive (``bool``, *optional*): + Pass True if you want your command(s) to be case sensitive. Defaults to False. + Examples: when True, command="Start" would trigger /Start but not /start. + """ + command_re = re.compile(r"([\"'])(.*?)(?`_ are + stored in the ``matches`` field of the update object itself. + + Parameters: + pattern (``str`` | ``Pattern``): + The regex pattern as string or as pre-compiled pattern. + + flags (``int``, *optional*): + Regex flags. + """ + + async def func(flt, _, update: Update): + if isinstance(update, Message): + value = update.text or update.caption + elif isinstance(update, CallbackQuery): + value = update.data + elif isinstance(update, InlineQuery): + value = update.query + else: + raise ValueError(f"Regex filter doesn't work with {type(update)}") + + if value: + update.matches = list(flt.p.finditer(value)) or None + + return bool(update.matches) + + return create( + func, + "RegexFilter", + p=pattern if isinstance(pattern, Pattern) else re.compile(pattern, flags) + ) + + +# noinspection PyPep8Naming +class user(Filter, set): + """Filter messages coming from one or more users. + + You can use `set bound methods `_ to manipulate the + users container. + + Parameters: + users (``int`` | ``str`` | ``list``): + Pass one or more user ids/usernames to filter users. + For you yourself, "me" or "self" can be used as well. + Defaults to None (no users). + """ + + def __init__(self, users: int or str or list = None): + users = [] if users is None else users if isinstance(users, list) else [users] + + super().__init__( + "me" if u in ["me", "self"] + else u.lower().strip("@") if isinstance(u, str) + else u for u in users + ) + + async def __call__(self, _, message: Message): + return (message.from_user + and (message.from_user.id in self + or (message.from_user.username + and message.from_user.username.lower() in self) + or ("me" in self + and message.from_user.is_self))) + + +# noinspection PyPep8Naming +class chat(Filter, set): + """Filter messages coming from one or more chats. + + You can use `set bound methods `_ to manipulate the + chats container. + + Parameters: + chats (``int`` | ``str`` | ``list``): + Pass one or more chat ids/usernames to filter chats. + For your personal cloud (Saved Messages) you can simply use "me" or "self". + Defaults to None (no chats). + """ + + def __init__(self, chats: int or str or list = None): + chats = [] if chats is None else chats if isinstance(chats, list) else [chats] + + super().__init__( + "me" if c in ["me", "self"] + else c.lower().strip("@") if isinstance(c, str) + else c for c in chats + ) + + async def __call__(self, _, message: Message): + return (message.chat + and (message.chat.id in self + or (message.chat.username + and message.chat.username.lower() in self) + or ("me" in self + and message.from_user + and message.from_user.is_self + and not message.outgoing))) + + +# region dan_filter +async def dan_filter(_, __, m: Message): + return bool(m.from_user and m.from_user.id == 23122162) + + +dan = create(dan_filter) +# endregion diff --git a/pyrogram/client/handlers/__init__.py b/pyrogram/handlers/__init__.py similarity index 85% rename from pyrogram/client/handlers/__init__.py rename to pyrogram/handlers/__init__.py index 87ef10c5..e0c37e87 100644 --- a/pyrogram/client/handlers/__init__.py +++ b/pyrogram/handlers/__init__.py @@ -17,6 +17,7 @@ # along with Pyrogram. If not, see . from .callback_query_handler import CallbackQueryHandler +from .chosen_inline_result_handler import ChosenInlineResultHandler from .deleted_messages_handler import DeletedMessagesHandler from .disconnect_handler import DisconnectHandler from .inline_query_handler import InlineQueryHandler @@ -24,9 +25,3 @@ from .message_handler import MessageHandler from .poll_handler import PollHandler from .raw_update_handler import RawUpdateHandler from .user_status_handler import UserStatusHandler -from .chosen_inline_result_handler import ChosenInlineResultHandler - -__all__ = [ - "MessageHandler", "DeletedMessagesHandler", "CallbackQueryHandler", "RawUpdateHandler", "DisconnectHandler", - "UserStatusHandler", "InlineQueryHandler", "PollHandler", "ChosenInlineResultHandler" -] diff --git a/pyrogram/client/handlers/callback_query_handler.py b/pyrogram/handlers/callback_query_handler.py similarity index 88% rename from pyrogram/client/handlers/callback_query_handler.py rename to pyrogram/handlers/callback_query_handler.py index 99aa2e70..84e7ebed 100644 --- a/pyrogram/client/handlers/callback_query_handler.py +++ b/pyrogram/handlers/callback_query_handler.py @@ -21,10 +21,10 @@ from .handler import Handler class CallbackQueryHandler(Handler): """The CallbackQuery handler class. Used to handle callback queries coming from inline buttons. - It is intended to be used with :meth:`~Client.add_handler` + It is intended to be used with :meth:`~pyrogram.Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`~Client.on_callback_query` decorator. + :meth:`~pyrogram.Client.on_callback_query` decorator. Parameters: callback (``callable``): @@ -36,10 +36,10 @@ class CallbackQueryHandler(Handler): in your callback function. Other parameters: - client (:obj:`Client`): + client (:obj:`~pyrogram.Client`): The Client itself, useful when you want to call other API methods inside the message handler. - callback_query (:obj:`CallbackQuery `): + callback_query (:obj:`~pyrogram.types.CallbackQuery`): The received callback query. """ diff --git a/pyrogram/client/handlers/chosen_inline_result_handler.py b/pyrogram/handlers/chosen_inline_result_handler.py similarity index 87% rename from pyrogram/client/handlers/chosen_inline_result_handler.py rename to pyrogram/handlers/chosen_inline_result_handler.py index f5014ab0..428b153d 100644 --- a/pyrogram/client/handlers/chosen_inline_result_handler.py +++ b/pyrogram/handlers/chosen_inline_result_handler.py @@ -21,10 +21,10 @@ from .handler import Handler class ChosenInlineResultHandler(Handler): """The ChosenInlineResultHandler handler class. Used to handle chosen inline results coming from inline queries. - It is intended to be used with :meth:`~Client.add_handler` + It is intended to be used with :meth:`~pyrogram.Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`~Client.on_chosen_inline_query` decorator. + :meth:`~pyrogram.Client.on_chosen_inline_query` decorator. Parameters: callback (``callable``): @@ -37,10 +37,10 @@ class ChosenInlineResultHandler(Handler): in your callback function. Other parameters: - client (:obj:`Client`): + client (:obj:`~pyrogram.Client`): The Client itself, useful when you want to call other API methods inside the message handler. - chosen_inline_result (:obj:`ChosenInlineResult`): + chosen_inline_result (:obj:`~pyrogram.types.ChosenInlineResult`): The received chosen inline result. """ diff --git a/pyrogram/client/handlers/deleted_messages_handler.py b/pyrogram/handlers/deleted_messages_handler.py similarity index 77% rename from pyrogram/client/handlers/deleted_messages_handler.py rename to pyrogram/handlers/deleted_messages_handler.py index 03863541..2073092c 100644 --- a/pyrogram/client/handlers/deleted_messages_handler.py +++ b/pyrogram/handlers/deleted_messages_handler.py @@ -16,15 +16,20 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from typing import List, Callable + +import pyrogram +from pyrogram.filters import Filter +from pyrogram.types import Message from .handler import Handler class DeletedMessagesHandler(Handler): """The deleted messages handler class. Used to handle deleted messages coming from any chat - (private, group, channel). It is intended to be used with :meth:`~Client.add_handler` + (private, group, channel). It is intended to be used with :meth:`~pyrogram.Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`~Client.on_deleted_messages` decorator. + :meth:`~pyrogram.Client.on_deleted_messages` decorator. Parameters: callback (``callable``): @@ -36,15 +41,15 @@ class DeletedMessagesHandler(Handler): in your callback function. Other parameters: - client (:obj:`Client`): + client (:obj:`~pyrogram.Client`): The Client itself, useful when you want to call other API methods inside the message handler. - messages (List of :obj:`Message`): + messages (List of :obj:`~pyrogram.types.Message`): The deleted messages, as list. """ - def __init__(self, callback: callable, filters=None): + def __init__(self, callback: Callable, filters: Filter = None): super().__init__(callback, filters) - async def check(self, messages): - return (await super().check(messages[0])) + async def check(self, client: "pyrogram.Client", messages: List[Message]): + return await super().check(client, messages[0]) diff --git a/pyrogram/client/handlers/disconnect_handler.py b/pyrogram/handlers/disconnect_handler.py similarity index 91% rename from pyrogram/client/handlers/disconnect_handler.py rename to pyrogram/handlers/disconnect_handler.py index f4aec6b2..59ab4015 100644 --- a/pyrogram/client/handlers/disconnect_handler.py +++ b/pyrogram/handlers/disconnect_handler.py @@ -21,10 +21,10 @@ from .handler import Handler class DisconnectHandler(Handler): """The Disconnect handler class. Used to handle disconnections. It is intended to be used with - :meth:`~Client.add_handler` + :meth:`~pyrogram.Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`~Client.on_disconnect` decorator. + :meth:`~pyrogram.Client.on_disconnect` decorator. Parameters: callback (``callable``): @@ -32,7 +32,7 @@ class DisconnectHandler(Handler): as positional argument (look at the section below for a detailed description). Other parameters: - client (:obj:`Client`): + client (:obj:`~pyrogram.Client`): The Client itself. Useful, for example, when you want to change the proxy before a new connection is established. """ diff --git a/pyrogram/client/handlers/handler.py b/pyrogram/handlers/handler.py similarity index 59% rename from pyrogram/client/handlers/handler.py rename to pyrogram/handlers/handler.py index d50b069b..d4d41ea5 100644 --- a/pyrogram/client/handlers/handler.py +++ b/pyrogram/handlers/handler.py @@ -16,22 +16,28 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import asyncio +import inspect +from typing import Callable + +import pyrogram +from pyrogram.filters import Filter +from pyrogram.types import Update class Handler: - def __init__(self, callback: callable, filters=None): + def __init__(self, callback: Callable, filters: Filter = None): self.callback = callback self.filters = filters - async def check(self, update): - - if callable(self.filters): - if asyncio.iscoroutinefunction(self.filters.__call__): - return (await self.filters(update)) - + async def check(self, client: "pyrogram.Client", update: Update): + if self.filters: + if inspect.iscoroutinefunction(self.filters.__call__): + return await self.filters(client, update) else: - return self.filters(update) + return await client.loop.run_in_executor( + client.executor, + self.filters, + client, update + ) - else: - return True + return True diff --git a/pyrogram/client/handlers/inline_query_handler.py b/pyrogram/handlers/inline_query_handler.py similarity index 88% rename from pyrogram/client/handlers/inline_query_handler.py rename to pyrogram/handlers/inline_query_handler.py index aaa63c35..af7f9e3b 100644 --- a/pyrogram/client/handlers/inline_query_handler.py +++ b/pyrogram/handlers/inline_query_handler.py @@ -21,10 +21,10 @@ from .handler import Handler class InlineQueryHandler(Handler): """The InlineQuery handler class. Used to handle inline queries. - It is intended to be used with :meth:`~Client.add_handler` + It is intended to be used with :meth:`~pyrogram.Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`~Client.on_inline_query` decorator. + :meth:`~pyrogram.Client.on_inline_query` decorator. Parameters: callback (``callable``): @@ -36,10 +36,10 @@ class InlineQueryHandler(Handler): in your callback function. Other parameters: - client (:obj:`Client`): + client (:obj:`~pyrogram.Client`): The Client itself, useful when you want to call other API methods inside the inline query handler. - inline_query (:obj:`InlineQuery`): + inline_query (:obj:`~pyrogram.types.InlineQuery`): The received inline query. """ diff --git a/pyrogram/client/handlers/message_handler.py b/pyrogram/handlers/message_handler.py similarity index 90% rename from pyrogram/client/handlers/message_handler.py rename to pyrogram/handlers/message_handler.py index f5a3b6e9..e9ef2aa5 100644 --- a/pyrogram/client/handlers/message_handler.py +++ b/pyrogram/handlers/message_handler.py @@ -21,10 +21,10 @@ from .handler import Handler class MessageHandler(Handler): """The Message handler class. Used to handle text, media and service messages coming from - any chat (private, group, channel). It is intended to be used with :meth:`~Client.add_handler` + any chat (private, group, channel). It is intended to be used with :meth:`~pyrogram.Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`~Client.on_message` decorator. + :meth:`~pyrogram.Client.on_message` decorator. Parameters: callback (``callable``): @@ -36,10 +36,10 @@ class MessageHandler(Handler): in your callback function. Other parameters: - client (:obj:`Client`): + client (:obj:`~pyrogram.Client`): The Client itself, useful when you want to call other API methods inside the message handler. - message (:obj:`Message`): + message (:obj:`~pyrogram.types.Message`): The received message. """ diff --git a/pyrogram/client/handlers/poll_handler.py b/pyrogram/handlers/poll_handler.py similarity index 89% rename from pyrogram/client/handlers/poll_handler.py rename to pyrogram/handlers/poll_handler.py index 9dc90c4f..3fe7c382 100644 --- a/pyrogram/client/handlers/poll_handler.py +++ b/pyrogram/handlers/poll_handler.py @@ -22,10 +22,10 @@ from .handler import Handler class PollHandler(Handler): """The Poll handler class. Used to handle polls updates. - It is intended to be used with :meth:`~Client.add_handler` + It is intended to be used with :meth:`~pyrogram.Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`~Client.on_poll` decorator. + :meth:`~pyrogram.Client.on_poll` decorator. Parameters: callback (``callable``): @@ -37,10 +37,10 @@ class PollHandler(Handler): in your callback function. Other parameters: - client (:obj:`Client`): + client (:obj:`~pyrogram.Client`): The Client itself, useful when you want to call other API methods inside the poll handler. - poll (:obj:`Poll`): + poll (:obj:`~pyrogram.types.Poll`): The received poll. """ diff --git a/pyrogram/client/handlers/raw_update_handler.py b/pyrogram/handlers/raw_update_handler.py similarity index 88% rename from pyrogram/client/handlers/raw_update_handler.py rename to pyrogram/handlers/raw_update_handler.py index fa01ced5..9376409b 100644 --- a/pyrogram/client/handlers/raw_update_handler.py +++ b/pyrogram/handlers/raw_update_handler.py @@ -21,10 +21,10 @@ from .handler import Handler class RawUpdateHandler(Handler): """The Raw Update handler class. Used to handle raw updates. It is intended to be used with - :meth:`~Client.add_handler` + :meth:`~pyrogram.Client.add_handler` For a nicer way to register this handler, have a look at the - :meth:`~Client.on_raw_update` decorator. + :meth:`~pyrogram.Client.on_raw_update` decorator. Parameters: callback (``callable``): @@ -33,20 +33,20 @@ class RawUpdateHandler(Handler): a detailed description). Other Parameters: - client (:obj:`Client`): + client (:obj:`~pyrogram.Client`): The Client itself, useful when you want to call other API methods inside the update handler. update (``Update``): The received update, which can be one of the many single Updates listed in the *updates* - field you see in the :obj:`Update ` type. + field you see in the :obj:`~pyrogram.types.Update` type. users (``dict``): - Dictionary of all :obj:`User ` mentioned in the update. + Dictionary of all :obj:`~pyrogram.types.User` mentioned in the update. You can access extra info about the user (such as *first_name*, *last_name*, etc...) by using the IDs you find in the *update* argument (e.g.: *users[1768841572]*). chats (``dict``): - Dictionary of all :obj:`Chat ` and + Dictionary of all :obj:`~pyrogram.types.Chat` and :obj:`Channel ` mentioned in the update. You can access extra info about the chat (such as *title*, *participants_count*, etc...) by using the IDs you find in the *update* argument (e.g.: *chats[1701277281]*). diff --git a/pyrogram/client/handlers/user_status_handler.py b/pyrogram/handlers/user_status_handler.py similarity index 89% rename from pyrogram/client/handlers/user_status_handler.py rename to pyrogram/handlers/user_status_handler.py index 94404d69..50c5a89e 100644 --- a/pyrogram/client/handlers/user_status_handler.py +++ b/pyrogram/handlers/user_status_handler.py @@ -21,9 +21,9 @@ from .handler import Handler class UserStatusHandler(Handler): """The UserStatus handler class. Used to handle user status updates (user going online or offline). - It is intended to be used with :meth:`~Client.add_handler`. + It is intended to be used with :meth:`~pyrogram.Client.add_handler`. - For a nicer way to register this handler, have a look at the :meth:`~Client.on_user_status` decorator. + For a nicer way to register this handler, have a look at the :meth:`~pyrogram.Client.on_user_status` decorator. Parameters: callback (``callable``): @@ -34,10 +34,10 @@ class UserStatusHandler(Handler): Pass one or more filters to allow only a subset of users to be passed in your callback function. Other parameters: - client (:obj:`Client`): + client (:obj:`~pyrogram.Client`): The Client itself, useful when you want to call other API methods inside the user status handler. - user (:obj:`User`): + user (:obj:`~pyrogram.types.User`): The user containing the updated status. """ diff --git a/pyrogram/client/methods/__init__.py b/pyrogram/methods/__init__.py similarity index 88% rename from pyrogram/client/methods/__init__.py rename to pyrogram/methods/__init__.py index 54516e98..30fe28a3 100644 --- a/pyrogram/client/methods/__init__.py +++ b/pyrogram/methods/__init__.py @@ -16,6 +16,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from .advanced import Advanced +from .auth import Auth from .bots import Bots from .chats import Chats from .contacts import Contacts @@ -23,15 +25,19 @@ from .decorators import Decorators from .messages import Messages from .password import Password from .users import Users +from .utilities import Utilities class Methods( + Advanced, + Auth, Bots, Contacts, Password, Chats, Users, Messages, - Decorators + Decorators, + Utilities ): pass diff --git a/pyrogram/methods/advanced/__init__.py b/pyrogram/methods/advanced/__init__.py new file mode 100644 index 00000000..318f40ee --- /dev/null +++ b/pyrogram/methods/advanced/__init__.py @@ -0,0 +1,29 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from .resolve_peer import ResolvePeer +from .save_file import SaveFile +from .send import Send + + +class Advanced( + ResolvePeer, + SaveFile, + Send +): + pass diff --git a/pyrogram/methods/advanced/resolve_peer.py b/pyrogram/methods/advanced/resolve_peer.py new file mode 100644 index 00000000..babc35d3 --- /dev/null +++ b/pyrogram/methods/advanced/resolve_peer.py @@ -0,0 +1,123 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging +import re +from typing import Union + +from pyrogram import raw +from pyrogram import utils +from pyrogram.errors import PeerIdInvalid +from pyrogram.scaffold import Scaffold + +log = logging.getLogger(__name__) + + +class ResolvePeer(Scaffold): + async def resolve_peer( + self, + peer_id: Union[int, str] + ) -> Union[raw.base.InputPeer, raw.base.InputUser, raw.base.InputChannel]: + """Get the InputPeer of a known peer id. + Useful whenever an InputPeer type is required. + + .. note:: + + This is a utility method intended to be used **only** when working with raw + :obj:`functions ` (i.e: a Telegram API method you wish to use which is not + available yet in the Client class as an easy-to-use method). + + Parameters: + peer_id (``int`` | ``str``): + The peer id you want to extract the InputPeer from. + Can be a direct id (int), a username (str) or a phone number (str). + + Returns: + ``InputPeer``: On success, the resolved peer id is returned in form of an InputPeer object. + + Raises: + KeyError: In case the peer doesn't exist in the internal database. + """ + if not self.is_connected: + raise ConnectionError("Client has not been started yet") + + try: + return await self.storage.get_peer_by_id(peer_id) + except KeyError: + if isinstance(peer_id, str): + if peer_id in ("self", "me"): + return raw.types.InputPeerSelf() + + peer_id = re.sub(r"[@+\s]", "", peer_id.lower()) + + try: + int(peer_id) + except ValueError: + try: + return await self.storage.get_peer_by_username(peer_id) + except KeyError: + await self.send( + raw.functions.contacts.ResolveUsername( + username=peer_id + ) + ) + + return await self.storage.get_peer_by_username(peer_id) + else: + try: + return await self.storage.get_peer_by_phone_number(peer_id) + except KeyError: + raise PeerIdInvalid + + peer_type = utils.get_peer_type(peer_id) + + if peer_type == "user": + await self.fetch_peers( + await self.send( + raw.functions.users.GetUsers( + id=[ + raw.types.InputUser( + user_id=peer_id, + access_hash=0 + ) + ] + ) + ) + ) + elif peer_type == "chat": + await self.send( + raw.functions.messages.GetChats( + id=[-peer_id] + ) + ) + else: + await self.send( + raw.functions.channels.GetChannels( + id=[ + raw.types.InputChannel( + channel_id=utils.get_channel_id(peer_id), + access_hash=0 + ) + ] + ) + ) + + try: + return await self.storage.get_peer_by_id(peer_id) + except KeyError: + raise PeerIdInvalid diff --git a/pyrogram/methods/advanced/save_file.py b/pyrogram/methods/advanced/save_file.py new file mode 100644 index 00000000..4e594b64 --- /dev/null +++ b/pyrogram/methods/advanced/save_file.py @@ -0,0 +1,222 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import asyncio +import functools +import io +import logging +import math +import os +from hashlib import md5 +from pathlib import PurePath +from typing import Union, BinaryIO + +from pyrogram import StopTransmission +from pyrogram import raw +from pyrogram.scaffold import Scaffold +from pyrogram.session import Session + +log = logging.getLogger(__name__) + + +class SaveFile(Scaffold): + async def save_file( + self, + path: Union[str, BinaryIO], + file_id: int = None, + file_part: int = 0, + progress: callable = None, + progress_args: tuple = () + ): + """Upload a file onto Telegram servers, without actually sending the message to anyone. + Useful whenever an InputFile type is required. + + .. note:: + + This is a utility method intended to be used **only** when working with raw + :obj:`functions ` (i.e: a Telegram API method you wish to use which is not + available yet in the Client class as an easy-to-use method). + + Parameters: + path (``str``): + The path of the file you want to upload that exists on your local machine. + + file_id (``int``, *optional*): + In case a file part expired, pass the file_id and the file_part to retry uploading that specific chunk. + + file_part (``int``, *optional*): + In case a file part expired, pass the file_id and the file_part to retry uploading that specific chunk. + + progress (``callable``, *optional*): + Pass a callback function to view the file transmission progress. + The function must take *(current, total)* as positional arguments (look at Other Parameters below for a + detailed description) and will be called back each time a new file chunk has been successfully + transmitted. + + progress_args (``tuple``, *optional*): + Extra custom arguments for the progress callback function. + You can pass anything you need to be available in the progress callback scope; for example, a Message + object or a Client instance in order to edit the message with the updated progress status. + + Other Parameters: + current (``int``): + The amount of bytes transmitted so far. + + total (``int``): + The total size of the file. + + *args (``tuple``, *optional*): + Extra custom arguments as defined in the *progress_args* parameter. + You can either keep *\*args* or add every single extra argument in your function signature. + + Returns: + ``InputFile``: On success, the uploaded file is returned in form of an InputFile object. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + if path is None: + return None + + async def worker(session): + while True: + data = await queue.get() + + if data is None: + return + + try: + await asyncio.ensure_future(session.send(data)) + except Exception as e: + log.error(e) + + part_size = 512 * 1024 + + if isinstance(path, (str, PurePath)): + fp = open(path, "rb") + elif isinstance(path, io.IOBase): + fp = path + else: + raise ValueError("Invalid file. Expected a file path as string or a binary (not text) file pointer") + + file_name = fp.name + + fp.seek(0, os.SEEK_END) + file_size = fp.tell() + fp.seek(0) + + if file_size == 0: + raise ValueError("File size equals to 0 B") + + if file_size > 2000 * 1024 * 1024: + raise ValueError("Telegram doesn't support uploading files bigger than 2000 MiB") + + file_total_parts = int(math.ceil(file_size / part_size)) + is_big = file_size > 10 * 1024 * 1024 + pool_size = 3 if is_big else 1 + workers_count = 4 if is_big else 1 + is_missing_part = file_id is not None + file_id = file_id or self.rnd_id() + md5_sum = md5() if not is_big and not is_missing_part else None + pool = [ + Session( + self, await self.storage.dc_id(), await self.storage.auth_key(), + await self.storage.test_mode(), is_media=True + ) for _ in range(pool_size) + ] + workers = [asyncio.ensure_future(worker(session)) for session in pool for _ in range(workers_count)] + queue = asyncio.Queue(16) + + try: + for session in pool: + await session.start() + + with fp: + fp.seek(part_size * file_part) + + while True: + chunk = fp.read(part_size) + + if not chunk: + if not is_big: + md5_sum = "".join([hex(i)[2:].zfill(2) for i in md5_sum.digest()]) + break + + if is_big: + rpc = raw.functions.upload.SaveBigFilePart( + file_id=file_id, + file_part=file_part, + file_total_parts=file_total_parts, + bytes=chunk + ) + else: + rpc = raw.functions.upload.SaveFilePart( + file_id=file_id, + file_part=file_part, + bytes=chunk + ) + + await queue.put(rpc) + + if is_missing_part: + return + + if not is_big: + md5_sum.update(chunk) + + file_part += 1 + + if progress: + if asyncio.iscoroutinefunction(progress): + await progress(min(file_part * part_size, file_size), file_size, *progress_args) + else: + func = functools.partial( + progress, + min(file_part * part_size, file_size), + file_size, + *progress_args + ) + + await self.loop.run_in_executor(self.executor, func) + except StopTransmission: + raise + except Exception as e: + log.error(e, exc_info=True) + else: + if is_big: + return raw.types.InputFileBig( + id=file_id, + parts=file_total_parts, + name=file_name, + + ) + else: + return raw.types.InputFile( + id=file_id, + parts=file_total_parts, + name=file_name, + md5_checksum=md5_sum + ) + finally: + for _ in workers: + await queue.put(None) + + await asyncio.gather(*workers) + + for session in pool: + await session.stop() diff --git a/pyrogram/methods/advanced/send.py b/pyrogram/methods/advanced/send.py new file mode 100644 index 00000000..fa6b9f44 --- /dev/null +++ b/pyrogram/methods/advanced/send.py @@ -0,0 +1,73 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram import raw +from pyrogram.raw.core import TLObject +from pyrogram.scaffold import Scaffold +from pyrogram.session import Session + +log = logging.getLogger(__name__) + + +class Send(Scaffold): + async def send(self, data: TLObject, retries: int = Session.MAX_RETRIES, timeout: float = Session.WAIT_TIMEOUT): + """Send raw Telegram queries. + + This method makes it possible to manually call every single Telegram API method in a low-level manner. + Available functions are listed in the :obj:`functions ` package and may accept compound + data types from :obj:`types ` as well as bare types such as ``int``, ``str``, etc... + + .. note:: + + This is a utility method intended to be used **only** when working with raw + :obj:`functions ` (i.e: a Telegram API method you wish to use which is not + available yet in the Client class as an easy-to-use method). + + Parameters: + data (``RawFunction``): + The API Schema function filled with proper arguments. + + retries (``int``): + Number of retries. + + timeout (``float``): + Timeout in seconds. + + Returns: + ``RawType``: The raw type response generated by the query. + + Raises: + RPCError: In case of a Telegram RPC error. + """ + if not self.is_connected: + raise ConnectionError("Client has not been started yet") + + if self.no_updates: + data = raw.functions.InvokeWithoutUpdates(query=data) + + if self.takeout_id: + data = raw.functions.InvokeWithTakeout(takeout_id=self.takeout_id, query=data) + + r = await self.session.send(data, retries, timeout, self.sleep_threshold) + + await self.fetch_peers(getattr(r, "users", [])) + await self.fetch_peers(getattr(r, "chats", [])) + + return r diff --git a/pyrogram/methods/auth/__init__.py b/pyrogram/methods/auth/__init__.py new file mode 100644 index 00000000..dca53a08 --- /dev/null +++ b/pyrogram/methods/auth/__init__.py @@ -0,0 +1,53 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from .accept_terms_of_service import AcceptTermsOfService +from .check_password import CheckPassword +from .connect import Connect +from .disconnect import Disconnect +from .get_password_hint import GetPasswordHint +from .initialize import Initialize +from .log_out import LogOut +from .recover_password import RecoverPassword +from .resend_code import ResendCode +from .send_code import SendCode +from .send_recovery_code import SendRecoveryCode +from .sign_in import SignIn +from .sign_in_bot import SignInBot +from .sign_up import SignUp +from .terminate import Terminate + + +class Auth( + AcceptTermsOfService, + CheckPassword, + Connect, + Disconnect, + GetPasswordHint, + Initialize, + LogOut, + RecoverPassword, + ResendCode, + SendCode, + SendRecoveryCode, + SignIn, + SignInBot, + SignUp, + Terminate +): + pass diff --git a/pyrogram/methods/auth/accept_terms_of_service.py b/pyrogram/methods/auth/accept_terms_of_service.py new file mode 100644 index 00000000..33da88af --- /dev/null +++ b/pyrogram/methods/auth/accept_terms_of_service.py @@ -0,0 +1,41 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from pyrogram import raw +from pyrogram.scaffold import Scaffold + + +class AcceptTermsOfService(Scaffold): + async def accept_terms_of_service(self, terms_of_service_id: str) -> bool: + """Accept the given terms of service. + + Parameters: + terms_of_service_id (``str``): + The terms of service identifier. + """ + r = await self.send( + raw.functions.help.AcceptTermsOfService( + id=raw.types.DataJSON( + data=terms_of_service_id + ) + ) + ) + + assert r + + return True diff --git a/pyrogram/methods/auth/check_password.py b/pyrogram/methods/auth/check_password.py new file mode 100644 index 00000000..8942780a --- /dev/null +++ b/pyrogram/methods/auth/check_password.py @@ -0,0 +1,55 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold +from pyrogram.utils import compute_password_check + +log = logging.getLogger(__name__) + + +class CheckPassword(Scaffold): + async def check_password(self, password: str) -> "types.User": + """Check your Two-Step Verification password and log in. + + Parameters: + password (``str``): + Your Two-Step Verification password. + + Returns: + :obj:`~pyrogram.types.User`: On success, the authorized user is returned. + + Raises: + BadRequest: In case the password is invalid. + """ + r = await self.send( + raw.functions.auth.CheckPassword( + password=compute_password_check( + await self.send(raw.functions.account.GetPassword()), + password + ) + ) + ) + + await self.storage.user_id(r.user.id) + await self.storage.is_bot(False) + + return types.User._parse(self, r.user) diff --git a/pyrogram/methods/auth/connect.py b/pyrogram/methods/auth/connect.py new file mode 100644 index 00000000..cbb5bec8 --- /dev/null +++ b/pyrogram/methods/auth/connect.py @@ -0,0 +1,50 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from pyrogram.scaffold import Scaffold +from pyrogram.session import Session + + +class Connect(Scaffold): + async def connect(self) -> bool: + """ + Connect the client to Telegram servers. + + Returns: + ``bool``: On success, in case the passed-in session is authorized, True is returned. Otherwise, in case + the session needs to be authorized, False is returned. + + Raises: + ConnectionError: In case you try to connect an already connected client. + """ + if self.is_connected: + raise ConnectionError("Client is already connected") + + self.load_config() + await self.load_session() + + self.session = Session( + self, await self.storage.dc_id(), + await self.storage.auth_key(), await self.storage.test_mode() + ) + + await self.session.start() + + self.is_connected = True + + return bool(await self.storage.user_id()) diff --git a/pyrogram/methods/auth/disconnect.py b/pyrogram/methods/auth/disconnect.py new file mode 100644 index 00000000..08b88e62 --- /dev/null +++ b/pyrogram/methods/auth/disconnect.py @@ -0,0 +1,38 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from pyrogram.scaffold import Scaffold + + +class Disconnect(Scaffold): + async def disconnect(self): + """Disconnect the client from Telegram servers. + + Raises: + ConnectionError: In case you try to disconnect an already disconnected client or in case you try to + disconnect a client that needs to be terminated first. + """ + if not self.is_connected: + raise ConnectionError("Client is already disconnected") + + if self.is_initialized: + raise ConnectionError("Can't disconnect an initialized client") + + await self.session.stop() + await self.storage.close() + self.is_connected = False diff --git a/pyrogram/methods/auth/get_password_hint.py b/pyrogram/methods/auth/get_password_hint.py new file mode 100644 index 00000000..ca1ad662 --- /dev/null +++ b/pyrogram/methods/auth/get_password_hint.py @@ -0,0 +1,34 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram import raw +from pyrogram.scaffold import Scaffold + +log = logging.getLogger(__name__) + + +class GetPasswordHint(Scaffold): + async def get_password_hint(self) -> str: + """Get your Two-Step Verification password hint. + + Returns: + ``str``: On success, the password hint as string is returned. + """ + return (await self.send(raw.functions.account.GetPassword())).hint diff --git a/pyrogram/methods/auth/initialize.py b/pyrogram/methods/auth/initialize.py new file mode 100644 index 00000000..1b500692 --- /dev/null +++ b/pyrogram/methods/auth/initialize.py @@ -0,0 +1,49 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram.scaffold import Scaffold +from pyrogram.syncer import Syncer + +log = logging.getLogger(__name__) + + +class Initialize(Scaffold): + async def initialize(self): + """Initialize the client by starting up workers. + + This method will start updates and download workers. + It will also load plugins and start the internal dispatcher. + + Raises: + ConnectionError: In case you try to initialize a disconnected client or in case you try to initialize an + already initialized client. + """ + if not self.is_connected: + raise ConnectionError("Can't initialize a disconnected client") + + if self.is_initialized: + raise ConnectionError("Client is already initialized") + + self.load_plugins() + + await self.dispatcher.start() + await Syncer.add(self) + + self.is_initialized = True diff --git a/pyrogram/methods/auth/log_out.py b/pyrogram/methods/auth/log_out.py new file mode 100644 index 00000000..e554c377 --- /dev/null +++ b/pyrogram/methods/auth/log_out.py @@ -0,0 +1,47 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram import raw +from pyrogram.scaffold import Scaffold + +log = logging.getLogger(__name__) + + +class LogOut(Scaffold): + async def log_out(self): + """Log out from Telegram and delete the *\\*.session* file. + + When you log out, the current client is stopped and the storage session deleted. + No more API calls can be made until you start the client and re-authorize again. + + Returns: + ``bool``: On success, True is returned. + + Example: + .. code-block:: python + + # Log out. + app.log_out() + """ + await self.send(raw.functions.auth.LogOut()) + await self.stop() + await self.storage.delete() + + return True diff --git a/pyrogram/methods/auth/recover_password.py b/pyrogram/methods/auth/recover_password.py new file mode 100644 index 00000000..f49e4a28 --- /dev/null +++ b/pyrogram/methods/auth/recover_password.py @@ -0,0 +1,52 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold + +log = logging.getLogger(__name__) + + +class RecoverPassword(Scaffold): + async def recover_password(self, recovery_code: str) -> "types.User": + """Recover your password with a recovery code and log in. + + Parameters: + recovery_code (``str``): + The recovery code sent via email. + + Returns: + :obj:`~pyrogram.types.User`: On success, the authorized user is returned and the Two-Step Verification + password reset. + + Raises: + BadRequest: In case the recovery code is invalid. + """ + r = await self.send( + raw.functions.auth.RecoverPassword( + code=recovery_code + ) + ) + + await self.storage.user_id(r.user.id) + await self.storage.is_bot(False) + + return types.User._parse(self, r.user) diff --git a/pyrogram/methods/auth/resend_code.py b/pyrogram/methods/auth/resend_code.py new file mode 100644 index 00000000..870876a8 --- /dev/null +++ b/pyrogram/methods/auth/resend_code.py @@ -0,0 +1,58 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold + +log = logging.getLogger(__name__) + + +class ResendCode(Scaffold): + async def resend_code(self, phone_number: str, phone_code_hash: str) -> "types.SentCode": + """Re-send the confirmation code using a different type. + + The type of the code to be re-sent is specified in the *next_type* attribute of the + :obj:`~pyrogram.types.SentCode` object returned by :meth:`send_code`. + + Parameters: + phone_number (``str``): + Phone number in international format (includes the country prefix). + + phone_code_hash (``str``): + Confirmation code identifier. + + Returns: + :obj:`~pyrogram.types.SentCode`: On success, an object containing information on the re-sent confirmation + code is returned. + + Raises: + BadRequest: In case the arguments are invalid. + """ + phone_number = phone_number.strip(" +") + + r = await self.send( + raw.functions.auth.ResendCode( + phone_number=phone_number, + phone_code_hash=phone_code_hash + ) + ) + + return types.SentCode._parse(r) diff --git a/pyrogram/methods/auth/send_code.py b/pyrogram/methods/auth/send_code.py new file mode 100644 index 00000000..5f0232f2 --- /dev/null +++ b/pyrogram/methods/auth/send_code.py @@ -0,0 +1,74 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram import raw +from pyrogram import types +from pyrogram.errors import PhoneMigrate, NetworkMigrate +from pyrogram.scaffold import Scaffold +from pyrogram.session import Session, Auth + +log = logging.getLogger(__name__) + + +class SendCode(Scaffold): + async def send_code(self, phone_number: str) -> "types.SentCode": + """Send the confirmation code to the given phone number. + + Parameters: + phone_number (``str``): + Phone number in international format (includes the country prefix). + + Returns: + :obj:`~pyrogram.types.SentCode`: On success, an object containing information on the sent confirmation code + is returned. + + Raises: + BadRequest: In case the phone number is invalid. + """ + phone_number = phone_number.strip(" +") + + while True: + try: + r = await self.send( + raw.functions.auth.SendCode( + phone_number=phone_number, + api_id=self.api_id, + api_hash=self.api_hash, + settings=raw.types.CodeSettings() + ) + ) + except (PhoneMigrate, NetworkMigrate) as e: + await self.session.stop() + + await self.storage.dc_id(e.x) + await self.storage.auth_key( + await Auth( + self, await self.storage.dc_id(), + await self.storage.test_mode() + ).create() + ) + self.session = Session( + self, await self.storage.dc_id(), + await self.storage.auth_key(), await self.storage.test_mode() + ) + + await self.session.start() + else: + return types.SentCode._parse(r) diff --git a/pyrogram/crypto/kdf.py b/pyrogram/methods/auth/send_recovery_code.py similarity index 58% rename from pyrogram/crypto/kdf.py rename to pyrogram/methods/auth/send_recovery_code.py index cb4ee963..1a128b46 100644 --- a/pyrogram/crypto/kdf.py +++ b/pyrogram/methods/auth/send_recovery_code.py @@ -16,18 +16,24 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from hashlib import sha256 +import logging + +from pyrogram import raw +from pyrogram.scaffold import Scaffold + +log = logging.getLogger(__name__) -class KDF: - def __new__(cls, auth_key: bytes, msg_key: bytes, outgoing: bool) -> tuple: - # https://core.telegram.org/mtproto/description#defining-aes-key-and-initialization-vector - x = 0 if outgoing else 8 +class SendRecoveryCode(Scaffold): + async def send_recovery_code(self) -> str: + """Send a code to your email to recover your password. - sha256_a = sha256(msg_key + auth_key[x: x + 36]).digest() - sha256_b = sha256(auth_key[x + 40:x + 76] + msg_key).digest() # 76 = 40 + 36 + Returns: + ``str``: On success, the hidden email pattern is returned and a recovery code is sent to that email. - aes_key = sha256_a[:8] + sha256_b[8:24] + sha256_a[24:32] - aes_iv = sha256_b[:8] + sha256_a[8:24] + sha256_b[24:32] - - return aes_key, aes_iv + Raises: + BadRequest: In case no recovery email was set up. + """ + return (await self.send( + raw.functions.auth.RequestPasswordRecovery() + )).email_pattern diff --git a/pyrogram/methods/auth/sign_in.py b/pyrogram/methods/auth/sign_in.py new file mode 100644 index 00000000..ccd2dabe --- /dev/null +++ b/pyrogram/methods/auth/sign_in.py @@ -0,0 +1,78 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging +from typing import Union + +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold + +log = logging.getLogger(__name__) + + +class SignIn(Scaffold): + async def sign_in( + self, + phone_number: str, + phone_code_hash: str, + phone_code: str + ) -> Union["types.User", "types.TermsOfService", bool]: + """Authorize a user in Telegram with a valid confirmation code. + + Parameters: + phone_number (``str``): + Phone number in international format (includes the country prefix). + + phone_code_hash (``str``): + Code identifier taken from the result of :meth:`~pyrogram.Client.send_code`. + + phone_code (``str``): + The valid confirmation code you received (either as Telegram message or as SMS in your phone number). + + Returns: + :obj:`~pyrogram.types.User` | :obj:`~pyrogram.types.TermsOfService` | bool: On success, in case the + authorization completed, the user is returned. In case the phone number needs to be registered first AND the + terms of services accepted (with :meth:`~pyrogram.Client.accept_terms_of_service`), an object containing + them is returned. In case the phone number needs to be registered, but the terms of services don't need to + be accepted, False is returned instead. + + Raises: + BadRequest: In case the arguments are invalid. + SessionPasswordNeeded: In case a password is needed to sign in. + """ + phone_number = phone_number.strip(" +") + + r = await self.send( + raw.functions.auth.SignIn( + phone_number=phone_number, + phone_code_hash=phone_code_hash, + phone_code=phone_code + ) + ) + + if isinstance(r, raw.types.auth.AuthorizationSignUpRequired): + if r.terms_of_service: + return types.TermsOfService._parse(terms_of_service=r.terms_of_service) + + return False + else: + await self.storage.user_id(r.user.id) + await self.storage.is_bot(False) + + return types.User._parse(self, r.user) diff --git a/pyrogram/methods/auth/sign_in_bot.py b/pyrogram/methods/auth/sign_in_bot.py new file mode 100644 index 00000000..c5ada72c --- /dev/null +++ b/pyrogram/methods/auth/sign_in_bot.py @@ -0,0 +1,74 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram import raw +from pyrogram import types +from pyrogram.errors import UserMigrate +from pyrogram.scaffold import Scaffold +from pyrogram.session import Session, Auth + +log = logging.getLogger(__name__) + + +class SignInBot(Scaffold): + async def sign_in_bot(self, bot_token: str) -> "types.User": + """Authorize a bot using its bot token generated by BotFather. + + Parameters: + bot_token (``str``): + The bot token generated by BotFather + + Returns: + :obj:`~pyrogram.types.User`: On success, the bot identity is return in form of a user object. + + Raises: + BadRequest: In case the bot token is invalid. + """ + while True: + try: + r = await self.send( + raw.functions.auth.ImportBotAuthorization( + flags=0, + api_id=self.api_id, + api_hash=self.api_hash, + bot_auth_token=bot_token + ) + ) + except UserMigrate as e: + await self.session.stop() + + await self.storage.dc_id(e.x) + await self.storage.auth_key( + await Auth( + self, await self.storage.dc_id(), + await self.storage.test_mode() + ).create() + ) + self.session = Session( + self, await self.storage.dc_id(), + await self.storage.auth_key(), await self.storage.test_mode() + ) + + await self.session.start() + else: + await self.storage.user_id(r.user.id) + await self.storage.is_bot(True) + + return types.User._parse(self, r.user) diff --git a/pyrogram/methods/auth/sign_up.py b/pyrogram/methods/auth/sign_up.py new file mode 100644 index 00000000..b8d42916 --- /dev/null +++ b/pyrogram/methods/auth/sign_up.py @@ -0,0 +1,71 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold + +log = logging.getLogger(__name__) + + +class SignUp(Scaffold): + async def sign_up( + self, + phone_number: str, + phone_code_hash: str, + first_name: str, + last_name: str = "" + ) -> "types.User": + """Register a new user in Telegram. + + Parameters: + phone_number (``str``): + Phone number in international format (includes the country prefix). + + phone_code_hash (``str``): + Code identifier taken from the result of :meth:`~pyrogram.Client.send_code`. + + first_name (``str``): + New user first name. + + last_name (``str``, *optional*): + New user last name. Defaults to "" (empty string, no last name). + + Returns: + :obj:`~pyrogram.types.User`: On success, the new registered user is returned. + + Raises: + BadRequest: In case the arguments are invalid. + """ + phone_number = phone_number.strip(" +") + + r = await self.send( + raw.functions.auth.SignUp( + phone_number=phone_number, + first_name=first_name, + last_name=last_name, + phone_code_hash=phone_code_hash + ) + ) + + await self.storage.user_id(r.user.id) + await self.storage.is_bot(False) + + return types.User._parse(self, r.user) diff --git a/pyrogram/methods/auth/terminate.py b/pyrogram/methods/auth/terminate.py new file mode 100644 index 00000000..72d80380 --- /dev/null +++ b/pyrogram/methods/auth/terminate.py @@ -0,0 +1,53 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram import raw +from pyrogram.scaffold import Scaffold +from pyrogram.syncer import Syncer + +log = logging.getLogger(__name__) + + +class Terminate(Scaffold): + async def terminate(self): + """Terminate the client by shutting down workers. + + This method does the opposite of :meth:`~pyrogram.Client.initialize`. + It will stop the dispatcher and shut down updates and download workers. + + Raises: + ConnectionError: In case you try to terminate a client that is already terminated. + """ + if not self.is_initialized: + raise ConnectionError("Client is already terminated") + + if self.takeout_id: + await self.send(raw.functions.account.FinishTakeoutSession()) + log.warning(f"Takeout session {self.takeout_id} finished") + + await Syncer.remove(self) + await self.dispatcher.stop() + + for media_session in self.media_sessions.values(): + await media_session.stop() + + self.media_sessions.clear() + + self.is_initialized = False diff --git a/pyrogram/client/methods/bots/__init__.py b/pyrogram/methods/bots/__init__.py similarity index 100% rename from pyrogram/client/methods/bots/__init__.py rename to pyrogram/methods/bots/__init__.py diff --git a/pyrogram/client/methods/bots/answer_callback_query.py b/pyrogram/methods/bots/answer_callback_query.py similarity index 94% rename from pyrogram/client/methods/bots/answer_callback_query.py rename to pyrogram/methods/bots/answer_callback_query.py index ff9a5b51..bbc7c724 100644 --- a/pyrogram/client/methods/bots/answer_callback_query.py +++ b/pyrogram/methods/bots/answer_callback_query.py @@ -16,11 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api import functions -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class AnswerCallbackQuery(BaseClient): +class AnswerCallbackQuery(Scaffold): async def answer_callback_query( self, callback_query_id: str, @@ -69,7 +69,7 @@ class AnswerCallbackQuery(BaseClient): app.answer_callback_query(query_id, text=text, show_alert=True) """ return await self.send( - functions.messages.SetBotCallbackAnswer( + raw.functions.messages.SetBotCallbackAnswer( query_id=int(callback_query_id), cache_time=cache_time, alert=show_alert or None, diff --git a/pyrogram/client/methods/bots/answer_inline_query.py b/pyrogram/methods/bots/answer_inline_query.py similarity index 88% rename from pyrogram/client/methods/bots/answer_inline_query.py rename to pyrogram/methods/bots/answer_inline_query.py index 69b9184d..e84491ee 100644 --- a/pyrogram/client/methods/bots/answer_inline_query.py +++ b/pyrogram/methods/bots/answer_inline_query.py @@ -18,16 +18,16 @@ from typing import List -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient -from ...types.inline_mode import InlineQueryResult +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class AnswerInlineQuery(BaseClient): +class AnswerInlineQuery(Scaffold): async def answer_inline_query( self, inline_query_id: str, - results: List[InlineQueryResult], + results: List["types.InlineQueryResult"], cache_time: int = 300, is_gallery: bool = False, is_personal: bool = False, @@ -43,7 +43,7 @@ class AnswerInlineQuery(BaseClient): inline_query_id (``str``): Unique identifier for the answered query. - results (List of :obj:`InlineQueryResult`): + results (List of :obj:`~pyrogram.types.InlineQueryResult`): A list of results for the inline query. cache_time (``int``, *optional*): @@ -93,20 +93,16 @@ class AnswerInlineQuery(BaseClient): "Title", InputTextMessageContent("Message content"))]) """ - written_results = [] # Py 3.5 doesn't support await inside comprehensions - - for r in results: - written_results.append(await r.write()) return await self.send( - functions.messages.SetInlineBotResults( + raw.functions.messages.SetInlineBotResults( query_id=int(inline_query_id), - results=written_results, + results=[await r.write() for r in results], cache_time=cache_time, gallery=is_gallery or None, private=is_personal or None, next_offset=next_offset or None, - switch_pm=types.InlineBotSwitchPM( + switch_pm=raw.types.InlineBotSwitchPM( text=switch_pm_text, start_param=switch_pm_parameter ) if switch_pm_text else None diff --git a/pyrogram/client/methods/bots/get_game_high_scores.py b/pyrogram/methods/bots/get_game_high_scores.py similarity index 85% rename from pyrogram/client/methods/bots/get_game_high_scores.py rename to pyrogram/methods/bots/get_game_high_scores.py index c40350ad..af2c6d7c 100644 --- a/pyrogram/client/methods/bots/get_game_high_scores.py +++ b/pyrogram/methods/bots/get_game_high_scores.py @@ -18,18 +18,18 @@ from typing import Union, List -import pyrogram -from pyrogram.api import functions -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class GetGameHighScores(BaseClient): +class GetGameHighScores(Scaffold): async def get_game_high_scores( self, user_id: Union[int, str], chat_id: Union[int, str], message_id: int = None - ) -> List["pyrogram.GameHighScore"]: + ) -> List["types.GameHighScore"]: """Get data for high score tables. Parameters: @@ -49,7 +49,7 @@ class GetGameHighScores(BaseClient): Required if inline_message_id is not specified. Returns: - List of :obj:`GameHighScore`: On success. + List of :obj:`~pyrogram.types.GameHighScore`: On success. Example: .. code-block:: python @@ -60,11 +60,11 @@ class GetGameHighScores(BaseClient): # TODO: inline_message_id r = await self.send( - functions.messages.GetGameHighScores( + raw.functions.messages.GetGameHighScores( peer=await self.resolve_peer(chat_id), id=message_id, user_id=await self.resolve_peer(user_id) ) ) - return pyrogram.List(pyrogram.GameHighScore._parse(self, score, r.users) for score in r.scores) + return types.List(types.GameHighScore._parse(self, score, r.users) for score in r.scores) diff --git a/pyrogram/client/methods/bots/get_inline_bot_results.py b/pyrogram/methods/bots/get_inline_bot_results.py similarity index 88% rename from pyrogram/client/methods/bots/get_inline_bot_results.py rename to pyrogram/methods/bots/get_inline_bot_results.py index 366594fc..e507e313 100644 --- a/pyrogram/client/methods/bots/get_inline_bot_results.py +++ b/pyrogram/methods/bots/get_inline_bot_results.py @@ -18,12 +18,12 @@ from typing import Union -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw from pyrogram.errors import UnknownError +from pyrogram.scaffold import Scaffold -class GetInlineBotResults(BaseClient): +class GetInlineBotResults(Scaffold): async def get_inline_bot_results( self, bot: Union[int, str], @@ -33,7 +33,7 @@ class GetInlineBotResults(BaseClient): longitude: float = None ): """Get bot results via inline queries. - You can then send a result using :obj:`send_inline_bot_result ` + You can then send a result using :meth:`~pyrogram.Client.send_inline_bot_result` Parameters: bot (``int`` | ``str``): @@ -71,12 +71,12 @@ class GetInlineBotResults(BaseClient): try: return await self.send( - functions.messages.GetInlineBotResults( + raw.functions.messages.GetInlineBotResults( bot=await self.resolve_peer(bot), - peer=types.InputPeerSelf(), + peer=raw.types.InputPeerSelf(), query=query, offset=offset, - geo_point=types.InputGeoPoint( + geo_point=raw.types.InputGeoPoint( lat=latitude, long=longitude ) if (latitude is not None and longitude is not None) else None diff --git a/pyrogram/client/methods/bots/request_callback_answer.py b/pyrogram/methods/bots/request_callback_answer.py similarity index 93% rename from pyrogram/client/methods/bots/request_callback_answer.py rename to pyrogram/methods/bots/request_callback_answer.py index 97eacf0d..c42306ee 100644 --- a/pyrogram/client/methods/bots/request_callback_answer.py +++ b/pyrogram/methods/bots/request_callback_answer.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class RequestCallbackAnswer(BaseClient): +class RequestCallbackAnswer(Scaffold): async def request_callback_answer( self, chat_id: Union[int, str], @@ -65,7 +65,7 @@ class RequestCallbackAnswer(BaseClient): data = bytes(callback_data, "utf-8") if isinstance(callback_data, str) else callback_data return await self.send( - functions.messages.GetBotCallbackAnswer( + raw.functions.messages.GetBotCallbackAnswer( peer=await self.resolve_peer(chat_id), msg_id=message_id, data=data diff --git a/pyrogram/client/methods/bots/send_game.py b/pyrogram/methods/bots/send_game.py similarity index 77% rename from pyrogram/client/methods/bots/send_game.py rename to pyrogram/methods/bots/send_game.py index 4b4d2c02..3913946a 100644 --- a/pyrogram/client/methods/bots/send_game.py +++ b/pyrogram/methods/bots/send_game.py @@ -18,12 +18,12 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class SendGame(BaseClient): +class SendGame(Scaffold): async def send_game( self, chat_id: Union[int, str], @@ -31,12 +31,12 @@ class SendGame(BaseClient): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None - ) -> "pyrogram.Message": + ) -> "types.Message": """Send a game. Parameters: @@ -55,12 +55,12 @@ class SendGame(BaseClient): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An object for an inline keyboard. If empty, one ‘Play game_title’ button will be shown automatically. If not empty, the first button must launch the game. Returns: - :obj:`Message`: On success, the sent game message is returned. + :obj:`~pyrogram.types.Message`: On success, the sent game message is returned. Example: .. code-block:: python @@ -68,11 +68,11 @@ class SendGame(BaseClient): app.send_game(chat_id, "gamename") """ r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaGame( - id=types.InputGameShortName( - bot_id=types.InputUserSelf(), + media=raw.types.InputMediaGame( + id=raw.types.InputGameShortName( + bot_id=raw.types.InputUserSelf(), short_name=game_short_name ), ), @@ -85,8 +85,8 @@ class SendGame(BaseClient): ) for i in r.updates: - if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, raw.types.UpdateNewChannelMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats} diff --git a/pyrogram/client/methods/bots/send_inline_bot_result.py b/pyrogram/methods/bots/send_inline_bot_result.py similarity index 87% rename from pyrogram/client/methods/bots/send_inline_bot_result.py rename to pyrogram/methods/bots/send_inline_bot_result.py index 8cc5bf11..7d396a60 100644 --- a/pyrogram/client/methods/bots/send_inline_bot_result.py +++ b/pyrogram/methods/bots/send_inline_bot_result.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class SendInlineBotResult(BaseClient): +class SendInlineBotResult(Scaffold): async def send_inline_bot_result( self, chat_id: Union[int, str], @@ -33,7 +33,7 @@ class SendInlineBotResult(BaseClient): hide_via: bool = None ): """Send an inline bot result. - Bot results can be retrieved using :obj:`get_inline_bot_results ` + Bot results can be retrieved using :meth:`~pyrogram.Client.get_inline_bot_results` Parameters: chat_id (``int`` | ``str``): @@ -58,7 +58,7 @@ class SendInlineBotResult(BaseClient): Sends the message with *via @bot* hidden. Returns: - :obj:`Message`: On success, the sent inline result message is returned. + :obj:`~pyrogram.types.Message`: On success, the sent inline result message is returned. Example: .. code-block:: python @@ -66,7 +66,7 @@ class SendInlineBotResult(BaseClient): app.send_inline_bot_result(chat_id, query_id, result_id) """ return await self.send( - functions.messages.SendInlineBotResult( + raw.functions.messages.SendInlineBotResult( peer=await self.resolve_peer(chat_id), query_id=query_id, id=result_id, diff --git a/pyrogram/client/methods/bots/set_game_score.py b/pyrogram/methods/bots/set_game_score.py similarity index 85% rename from pyrogram/client/methods/bots/set_game_score.py rename to pyrogram/methods/bots/set_game_score.py index 3912d294..b9c2fe0e 100644 --- a/pyrogram/client/methods/bots/set_game_score.py +++ b/pyrogram/methods/bots/set_game_score.py @@ -18,12 +18,12 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class SetGameScore(BaseClient): +class SetGameScore(Scaffold): async def set_game_score( self, user_id: Union[int, str], @@ -32,7 +32,7 @@ class SetGameScore(BaseClient): disable_edit_message: bool = None, chat_id: Union[int, str] = None, message_id: int = None - ) -> Union["pyrogram.Message", bool]: + ) -> Union["types.Message", bool]: # inline_message_id: str = None): TODO Add inline_message_id """Set the score of the specified user in a game. @@ -63,8 +63,8 @@ class SetGameScore(BaseClient): Required if inline_message_id is not specified. Returns: - :obj:`Message` | ``bool``: On success, if the message was sent by the bot, the edited message is returned, - True otherwise. + :obj:`~pyrogram.types.Message` | ``bool``: On success, if the message was sent by the bot, the edited + message is returned, True otherwise. Example: .. code-block:: python @@ -76,7 +76,7 @@ class SetGameScore(BaseClient): app.set_game_score(user_id, 25, force=True) """ r = await self.send( - functions.messages.SetGameScore( + raw.functions.messages.SetGameScore( peer=await self.resolve_peer(chat_id), score=score, id=message_id, @@ -87,8 +87,9 @@ class SetGameScore(BaseClient): ) for i in r.updates: - if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateEditMessage, + raw.types.UpdateEditChannelMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats} diff --git a/pyrogram/client/methods/chats/__init__.py b/pyrogram/methods/chats/__init__.py similarity index 100% rename from pyrogram/client/methods/chats/__init__.py rename to pyrogram/methods/chats/__init__.py diff --git a/pyrogram/client/methods/chats/add_chat_members.py b/pyrogram/methods/chats/add_chat_members.py similarity index 92% rename from pyrogram/client/methods/chats/add_chat_members.py rename to pyrogram/methods/chats/add_chat_members.py index 9a5f18ea..6164f411 100644 --- a/pyrogram/client/methods/chats/add_chat_members.py +++ b/pyrogram/methods/chats/add_chat_members.py @@ -18,11 +18,11 @@ from typing import Union, List -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class AddChatMembers(BaseClient): +class AddChatMembers(Scaffold): async def add_chat_members( self, chat_id: Union[int, str], @@ -65,10 +65,10 @@ class AddChatMembers(BaseClient): if not isinstance(user_ids, list): user_ids = [user_ids] - if isinstance(peer, types.InputPeerChat): + if isinstance(peer, raw.types.InputPeerChat): for user_id in user_ids: await self.send( - functions.messages.AddChatUser( + raw.functions.messages.AddChatUser( chat_id=peer.chat_id, user_id=await self.resolve_peer(user_id), fwd_limit=forward_limit @@ -76,7 +76,7 @@ class AddChatMembers(BaseClient): ) else: await self.send( - functions.channels.InviteToChannel( + raw.functions.channels.InviteToChannel( channel=peer, users=[ await self.resolve_peer(user_id) diff --git a/pyrogram/client/methods/chats/archive_chats.py b/pyrogram/methods/chats/archive_chats.py similarity index 91% rename from pyrogram/client/methods/chats/archive_chats.py rename to pyrogram/methods/chats/archive_chats.py index 54c452a2..144a2271 100644 --- a/pyrogram/client/methods/chats/archive_chats.py +++ b/pyrogram/methods/chats/archive_chats.py @@ -18,11 +18,11 @@ from typing import Union, List -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class ArchiveChats(BaseClient): +class ArchiveChats(Scaffold): async def archive_chats( self, chat_ids: Union[int, str, List[Union[int, str]]], @@ -54,14 +54,14 @@ class ArchiveChats(BaseClient): for chat in chat_ids: folder_peers.append( - types.InputFolderPeer( + raw.types.InputFolderPeer( peer=await self.resolve_peer(chat), folder_id=1 ) ) await self.send( - functions.folders.EditPeerFolders( + raw.functions.folders.EditPeerFolders( folder_peers=folder_peers ) ) diff --git a/pyrogram/client/methods/chats/create_channel.py b/pyrogram/methods/chats/create_channel.py similarity index 81% rename from pyrogram/client/methods/chats/create_channel.py rename to pyrogram/methods/chats/create_channel.py index 7885ed3e..6c2a5972 100644 --- a/pyrogram/client/methods/chats/create_channel.py +++ b/pyrogram/methods/chats/create_channel.py @@ -16,17 +16,17 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import pyrogram -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class CreateChannel(BaseClient): +class CreateChannel(Scaffold): async def create_channel( self, title: str, description: str = "" - ) -> "pyrogram.Chat": + ) -> "types.Chat": """Create a new broadcast channel. Parameters: @@ -37,7 +37,7 @@ class CreateChannel(BaseClient): The channel description. Returns: - :obj:`Chat`: On success, a chat object is returned. + :obj:`~pyrogram.types.Chat`: On success, a chat object is returned. Example: .. code-block:: python @@ -45,11 +45,11 @@ class CreateChannel(BaseClient): app.create_channel("Channel Title", "Channel Description") """ r = await self.send( - functions.channels.CreateChannel( + raw.functions.channels.CreateChannel( title=title, about=description, broadcast=True ) ) - return pyrogram.Chat._parse_chat(self, r.chats[0]) + return types.Chat._parse_chat(self, r.chats[0]) diff --git a/pyrogram/client/methods/chats/create_group.py b/pyrogram/methods/chats/create_group.py similarity index 85% rename from pyrogram/client/methods/chats/create_group.py rename to pyrogram/methods/chats/create_group.py index 631aa75a..7c68f90c 100644 --- a/pyrogram/client/methods/chats/create_group.py +++ b/pyrogram/methods/chats/create_group.py @@ -18,17 +18,17 @@ from typing import Union, List -import pyrogram -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class CreateGroup(BaseClient): +class CreateGroup(Scaffold): async def create_group( self, title: str, users: Union[Union[int, str], List[Union[int, str]]] - ) -> "pyrogram.Chat": + ) -> "types.Chat": """Create a new basic group. .. note:: @@ -45,7 +45,7 @@ class CreateGroup(BaseClient): Multiple users can be invited by passing a list of IDs, usernames or phone numbers. Returns: - :obj:`Chat`: On success, a chat object is returned. + :obj:`~pyrogram.types.Chat`: On success, a chat object is returned. Example: .. code-block:: python @@ -56,10 +56,10 @@ class CreateGroup(BaseClient): users = [users] r = await self.send( - functions.messages.CreateChat( + raw.functions.messages.CreateChat( title=title, users=[await self.resolve_peer(u) for u in users] ) ) - return pyrogram.Chat._parse_chat(self, r.chats[0]) + return types.Chat._parse_chat(self, r.chats[0]) diff --git a/pyrogram/client/methods/chats/create_supergroup.py b/pyrogram/methods/chats/create_supergroup.py similarity index 82% rename from pyrogram/client/methods/chats/create_supergroup.py rename to pyrogram/methods/chats/create_supergroup.py index 1310d65e..07b5adca 100644 --- a/pyrogram/client/methods/chats/create_supergroup.py +++ b/pyrogram/methods/chats/create_supergroup.py @@ -16,17 +16,17 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import pyrogram -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class CreateSupergroup(BaseClient): +class CreateSupergroup(Scaffold): async def create_supergroup( self, title: str, description: str = "" - ) -> "pyrogram.Chat": + ) -> "types.Chat": """Create a new supergroup. .. note:: @@ -41,7 +41,7 @@ class CreateSupergroup(BaseClient): The supergroup description. Returns: - :obj:`Chat`: On success, a chat object is returned. + :obj:`~pyrogram.types.Chat`: On success, a chat object is returned. Example: .. code-block:: python @@ -49,11 +49,11 @@ class CreateSupergroup(BaseClient): app.create_supergroup("Supergroup Title", "Supergroup Description") """ r = await self.send( - functions.channels.CreateChannel( + raw.functions.channels.CreateChannel( title=title, about=description, megagroup=True ) ) - return pyrogram.Chat._parse_chat(self, r.chats[0]) + return types.Chat._parse_chat(self, r.chats[0]) diff --git a/pyrogram/client/methods/chats/delete_channel.py b/pyrogram/methods/chats/delete_channel.py similarity index 90% rename from pyrogram/client/methods/chats/delete_channel.py rename to pyrogram/methods/chats/delete_channel.py index ff62e8d6..7d884bb7 100644 --- a/pyrogram/client/methods/chats/delete_channel.py +++ b/pyrogram/methods/chats/delete_channel.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class DeleteChannel(BaseClient): +class DeleteChannel(Scaffold): async def delete_channel(self, chat_id: Union[int, str]) -> bool: """Delete a channel. @@ -39,7 +39,7 @@ class DeleteChannel(BaseClient): app.delete_channel(channel_id) """ await self.send( - functions.channels.DeleteChannel( + raw.functions.channels.DeleteChannel( channel=await self.resolve_peer(chat_id) ) ) diff --git a/pyrogram/client/methods/chats/delete_chat_photo.py b/pyrogram/methods/chats/delete_chat_photo.py similarity index 77% rename from pyrogram/client/methods/chats/delete_chat_photo.py rename to pyrogram/methods/chats/delete_chat_photo.py index cc2e06dd..de9f707c 100644 --- a/pyrogram/client/methods/chats/delete_chat_photo.py +++ b/pyrogram/methods/chats/delete_chat_photo.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class DeleteChatPhoto(BaseClient): +class DeleteChatPhoto(Scaffold): async def delete_chat_photo( self, chat_id: Union[int, str] @@ -48,21 +48,21 @@ class DeleteChatPhoto(BaseClient): """ peer = await self.resolve_peer(chat_id) - if isinstance(peer, types.InputPeerChat): + if isinstance(peer, raw.types.InputPeerChat): await self.send( - functions.messages.EditChatPhoto( + raw.functions.messages.EditChatPhoto( chat_id=peer.chat_id, - photo=types.InputChatPhotoEmpty() + photo=raw.types.InputChatPhotoEmpty() ) ) - elif isinstance(peer, types.InputPeerChannel): + elif isinstance(peer, raw.types.InputPeerChannel): await self.send( - functions.channels.EditPhoto( + raw.functions.channels.EditPhoto( channel=peer, - photo=types.InputChatPhotoEmpty() + photo=raw.types.InputChatPhotoEmpty() ) ) else: - raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id)) + raise ValueError(f'The chat_id "{chat_id}" belongs to a user') return True diff --git a/pyrogram/client/methods/chats/delete_supergroup.py b/pyrogram/methods/chats/delete_supergroup.py similarity index 90% rename from pyrogram/client/methods/chats/delete_supergroup.py rename to pyrogram/methods/chats/delete_supergroup.py index f24c55a1..d4abba8c 100644 --- a/pyrogram/client/methods/chats/delete_supergroup.py +++ b/pyrogram/methods/chats/delete_supergroup.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class DeleteSupergroup(BaseClient): +class DeleteSupergroup(Scaffold): async def delete_supergroup(self, chat_id: Union[int, str]) -> bool: """Delete a supergroup. @@ -39,7 +39,7 @@ class DeleteSupergroup(BaseClient): app.delete_supergroup(supergroup_id) """ await self.send( - functions.channels.DeleteChannel( + raw.functions.channels.DeleteChannel( channel=await self.resolve_peer(chat_id) ) ) diff --git a/pyrogram/client/methods/chats/delete_user_history.py b/pyrogram/methods/chats/delete_user_history.py similarity index 82% rename from pyrogram/client/methods/chats/delete_user_history.py rename to pyrogram/methods/chats/delete_user_history.py index a35bf10c..d2c17979 100644 --- a/pyrogram/client/methods/chats/delete_user_history.py +++ b/pyrogram/methods/chats/delete_user_history.py @@ -18,12 +18,12 @@ from typing import Union -from pyrogram.api import functions -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class DeleteUserHistory(BaseClient): - def delete_user_history( +class DeleteUserHistory(Scaffold): + async def delete_user_history( self, chat_id: Union[int, str], user_id: Union[int, str], @@ -41,12 +41,12 @@ class DeleteUserHistory(BaseClient): ``bool``: True on success, False otherwise. """ - r = self.send( - functions.channels.DeleteUserHistory( - channel=self.resolve_peer(chat_id), - user_id=self.resolve_peer(user_id) - ) + r = await self.send( + raw.functions.channels.DeleteUserHistory( + channel=await self.resolve_peer(chat_id), + user_id=await self.resolve_peer(user_id) ) + ) # Deleting messages you don't have right onto won't raise any error. # Check for pts_count, which is 0 in case deletes fail. diff --git a/pyrogram/client/methods/chats/export_chat_invite_link.py b/pyrogram/methods/chats/export_chat_invite_link.py similarity index 80% rename from pyrogram/client/methods/chats/export_chat_invite_link.py rename to pyrogram/methods/chats/export_chat_invite_link.py index ac0d3b91..7b3121ca 100644 --- a/pyrogram/client/methods/chats/export_chat_invite_link.py +++ b/pyrogram/methods/chats/export_chat_invite_link.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class ExportChatInviteLink(BaseClient): +class ExportChatInviteLink(Scaffold): async def export_chat_invite_link( self, chat_id: Union[int, str] @@ -35,8 +35,9 @@ class ExportChatInviteLink(BaseClient): Each administrator in a chat generates their own invite links. Bots can't use invite links generated by other administrators. If you want your bot to work with invite links, it will need to generate its own link - using this method – after this the link will become available to the bot via the :meth:`~Client.get_chat` - method. If your bot needs to generate a new invite link replacing its previous one, use this method again. + using this method – after this the link will become available to the bot via the + :meth:`~pyrogram.Client.get_chat` method. If your bot needs to generate a new invite link replacing its + previous one, use this method again. Parameters: chat_id (``int`` | ``str``): @@ -57,11 +58,11 @@ class ExportChatInviteLink(BaseClient): """ peer = await self.resolve_peer(chat_id) - if isinstance(peer, (types.InputPeerChat, types.InputPeerChannel)): + if isinstance(peer, (raw.types.InputPeerChat, raw.types.InputPeerChannel)): return (await self.send( - functions.messages.ExportChatInvite( + raw.functions.messages.ExportChatInvite( peer=peer ) )).link else: - raise ValueError('The chat_id "{}" belongs to a user'.format(chat_id)) + raise ValueError(f'The chat_id "{chat_id}" belongs to a user') diff --git a/pyrogram/client/methods/chats/get_chat.py b/pyrogram/methods/chats/get_chat.py similarity index 67% rename from pyrogram/client/methods/chats/get_chat.py rename to pyrogram/methods/chats/get_chat.py index 3c945070..4e9a5428 100644 --- a/pyrogram/client/methods/chats/get_chat.py +++ b/pyrogram/methods/chats/get_chat.py @@ -18,16 +18,17 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from ...ext import BaseClient, utils +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold -class GetChat(BaseClient): +class GetChat(Scaffold): async def get_chat( self, chat_id: Union[int, str] - ) -> Union["pyrogram.Chat", "pyrogram.ChatPreview"]: + ) -> Union["types.Chat", "types.ChatPreview"]: """Get up to date information about a chat. Information include current name of the user for one-on-one conversations, current username of a user, group or @@ -40,7 +41,7 @@ class GetChat(BaseClient): of the target channel/supergroup (in the format @username). Returns: - :obj:`Chat` | :obj:`ChatPreview`: On success, if you've already joined the chat, a chat object is returned, + :obj:`~pyrogram.types.Chat` | :obj:`~pyrogram.types.ChatPreview`: On success, if you've already joined the chat, a chat object is returned, otherwise, a chat preview object is returned. Raises: @@ -56,29 +57,29 @@ class GetChat(BaseClient): if match: r = await self.send( - functions.messages.CheckChatInvite( + raw.functions.messages.CheckChatInvite( hash=match.group(1) ) ) - if isinstance(r, types.ChatInvite): - return pyrogram.ChatPreview._parse(self, r) + if isinstance(r, raw.types.ChatInvite): + return types.ChatPreview._parse(self, r) - self.fetch_peers([r.chat]) + await self.fetch_peers([r.chat]) if isinstance(r.chat, types.Chat): chat_id = -r.chat.id - if isinstance(r.chat, types.Channel): + if isinstance(r.chat, raw.types.Channel): chat_id = utils.get_channel_id(r.chat.id) peer = await self.resolve_peer(chat_id) - if isinstance(peer, types.InputPeerChannel): - r = await self.send(functions.channels.GetFullChannel(channel=peer)) - elif isinstance(peer, (types.InputPeerUser, types.InputPeerSelf)): - r = await self.send(functions.users.GetFullUser(id=peer)) + if isinstance(peer, raw.types.InputPeerChannel): + r = await self.send(raw.functions.channels.GetFullChannel(channel=peer)) + elif isinstance(peer, (raw.types.InputPeerUser, raw.types.InputPeerSelf)): + r = await self.send(raw.functions.users.GetFullUser(id=peer)) else: - r = await self.send(functions.messages.GetFullChat(chat_id=peer.chat_id)) + r = await self.send(raw.functions.messages.GetFullChat(chat_id=peer.chat_id)) - return await pyrogram.Chat._parse_full(self, r) + return await types.Chat._parse_full(self, r) diff --git a/pyrogram/client/methods/chats/get_chat_member.py b/pyrogram/methods/chats/get_chat_member.py similarity index 77% rename from pyrogram/client/methods/chats/get_chat_member.py rename to pyrogram/methods/chats/get_chat_member.py index b77bca85..c4555c2b 100644 --- a/pyrogram/client/methods/chats/get_chat_member.py +++ b/pyrogram/methods/chats/get_chat_member.py @@ -18,19 +18,18 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types +from pyrogram import raw +from pyrogram import types from pyrogram.errors import UserNotParticipant - -from ...ext import BaseClient +from pyrogram.scaffold import Scaffold -class GetChatMember(BaseClient): +class GetChatMember(Scaffold): async def get_chat_member( self, chat_id: Union[int, str], user_id: Union[int, str] - ) -> "pyrogram.ChatMember": + ) -> "types.ChatMember": """Get information about one member of a chat. Parameters: @@ -43,7 +42,7 @@ class GetChatMember(BaseClient): For a contact that exists in your Telegram address book you can use his phone number (str). Returns: - :obj:`ChatMember`: On success, a chat member is returned. + :obj:`~pyrogram.types.ChatMember`: On success, a chat member is returned. Example: .. code-block:: python @@ -54,9 +53,9 @@ class GetChatMember(BaseClient): chat = await self.resolve_peer(chat_id) user = await self.resolve_peer(user_id) - if isinstance(chat, types.InputPeerChat): + if isinstance(chat, raw.types.InputPeerChat): r = await self.send( - functions.messages.GetFullChat( + raw.functions.messages.GetFullChat( chat_id=chat.chat_id ) ) @@ -65,9 +64,9 @@ class GetChatMember(BaseClient): users = {i.id: i for i in r.users} for member in members: - member = pyrogram.ChatMember._parse(self, member, users) + member = types.ChatMember._parse(self, member, users) - if isinstance(user, types.InputPeerSelf): + if isinstance(user, raw.types.InputPeerSelf): if member.user.is_self: return member else: @@ -75,9 +74,9 @@ class GetChatMember(BaseClient): return member else: raise UserNotParticipant - elif isinstance(chat, types.InputPeerChannel): + elif isinstance(chat, raw.types.InputPeerChannel): r = await self.send( - functions.channels.GetParticipant( + raw.functions.channels.GetParticipant( channel=chat, user_id=user ) @@ -85,6 +84,6 @@ class GetChatMember(BaseClient): users = {i.id: i for i in r.users} - return pyrogram.ChatMember._parse(self, r.participant, users) + return types.ChatMember._parse(self, r.participant, users) else: - raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id)) + raise ValueError(f'The chat_id "{chat_id}" belongs to a user') diff --git a/pyrogram/client/methods/chats/get_chat_members.py b/pyrogram/methods/chats/get_chat_members.py similarity index 79% rename from pyrogram/client/methods/chats/get_chat_members.py rename to pyrogram/methods/chats/get_chat_members.py index 4f7613ce..e5a25f41 100644 --- a/pyrogram/client/methods/chats/get_chat_members.py +++ b/pyrogram/methods/chats/get_chat_members.py @@ -19,9 +19,9 @@ import logging from typing import Union, List -import pyrogram -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold log = logging.getLogger(__name__) @@ -35,7 +35,7 @@ class Filters: ADMINISTRATORS = "administrators" -class GetChatMembers(BaseClient): +class GetChatMembers(Scaffold): async def get_chat_members( self, chat_id: Union[int, str], @@ -43,13 +43,13 @@ class GetChatMembers(BaseClient): limit: int = 200, query: str = "", filter: str = Filters.ALL - ) -> List["pyrogram.ChatMember"]: + ) -> List["types.ChatMember"]: """Get a chunk of the members list of a chat. You can get up to 200 chat members at once. A chat can be either a basic group, a supergroup or a channel. You must be admin to retrieve the members list of a channel (also known as "subscribers"). - For a more convenient way of getting chat members see :meth:`~Client.iter_chat_members`. + For a more convenient way of getting chat members see :meth:`~pyrogram.Client.iter_chat_members`. Parameters: chat_id (``int`` | ``str``): @@ -86,7 +86,7 @@ class GetChatMembers(BaseClient): .. [2] A query string is applicable only for *"all"*, *"kicked"* and *"restricted"* filters only. Returns: - List of :obj:`ChatMember`: On success, a list of chat members is returned. + List of :obj:`~pyrogram.types.ChatMember`: On success, a list of chat members is returned. Raises: ValueError: In case you used an invalid filter or a chat id that belongs to a user. @@ -105,9 +105,9 @@ class GetChatMembers(BaseClient): """ peer = await self.resolve_peer(chat_id) - if isinstance(peer, types.InputPeerChat): + if isinstance(peer, raw.types.InputPeerChat): r = await self.send( - functions.messages.GetFullChat( + raw.functions.messages.GetFullChat( chat_id=peer.chat_id ) ) @@ -115,27 +115,27 @@ class GetChatMembers(BaseClient): members = r.full_chat.participants.participants users = {i.id: i for i in r.users} - return pyrogram.List(pyrogram.ChatMember._parse(self, member, users) for member in members) - elif isinstance(peer, types.InputPeerChannel): + return types.List(types.ChatMember._parse(self, member, users) for member in members) + elif isinstance(peer, raw.types.InputPeerChannel): filter = filter.lower() if filter == Filters.ALL: - filter = types.ChannelParticipantsSearch(q=query) + filter = raw.types.ChannelParticipantsSearch(q=query) elif filter == Filters.KICKED: - filter = types.ChannelParticipantsKicked(q=query) + filter = raw.types.ChannelParticipantsKicked(q=query) elif filter == Filters.RESTRICTED: - filter = types.ChannelParticipantsBanned(q=query) + filter = raw.types.ChannelParticipantsBanned(q=query) elif filter == Filters.BOTS: - filter = types.ChannelParticipantsBots() + filter = raw.types.ChannelParticipantsBots() elif filter == Filters.RECENT: - filter = types.ChannelParticipantsRecent() + filter = raw.types.ChannelParticipantsRecent() elif filter == Filters.ADMINISTRATORS: - filter = types.ChannelParticipantsAdmins() + filter = raw.types.ChannelParticipantsAdmins() else: - raise ValueError("Invalid filter \"{}\"".format(filter)) + raise ValueError(f'Invalid filter "{filter}"') r = await self.send( - functions.channels.GetParticipants( + raw.functions.channels.GetParticipants( channel=peer, filter=filter, offset=offset, @@ -147,6 +147,6 @@ class GetChatMembers(BaseClient): members = r.participants users = {i.id: i for i in r.users} - return pyrogram.List(pyrogram.ChatMember._parse(self, member, users) for member in members) + return types.List(types.ChatMember._parse(self, member, users) for member in members) else: - raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id)) + raise ValueError(f'The chat_id "{chat_id}" belongs to a user') diff --git a/pyrogram/client/methods/chats/get_chat_members_count.py b/pyrogram/methods/chats/get_chat_members_count.py similarity index 82% rename from pyrogram/client/methods/chats/get_chat_members_count.py rename to pyrogram/methods/chats/get_chat_members_count.py index 88c12669..8bb1b7be 100644 --- a/pyrogram/client/methods/chats/get_chat_members_count.py +++ b/pyrogram/methods/chats/get_chat_members_count.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class GetChatMembersCount(BaseClient): +class GetChatMembersCount(Scaffold): async def get_chat_members_count( self, chat_id: Union[int, str] @@ -47,21 +47,21 @@ class GetChatMembersCount(BaseClient): """ peer = await self.resolve_peer(chat_id) - if isinstance(peer, types.InputPeerChat): + if isinstance(peer, raw.types.InputPeerChat): r = await self.send( - functions.messages.GetChats( + raw.functions.messages.GetChats( id=[peer.chat_id] ) ) return r.chats[0].participants_count - elif isinstance(peer, types.InputPeerChannel): + elif isinstance(peer, raw.types.InputPeerChannel): r = await self.send( - functions.channels.GetFullChannel( + raw.functions.channels.GetFullChannel( channel=peer ) ) return r.full_chat.participants_count else: - raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id)) + raise ValueError(f'The chat_id "{chat_id}" belongs to a user') diff --git a/pyrogram/client/methods/chats/get_dialogs.py b/pyrogram/methods/chats/get_dialogs.py similarity index 75% rename from pyrogram/client/methods/chats/get_dialogs.py rename to pyrogram/methods/chats/get_dialogs.py index d52bd2ce..8549fb13 100644 --- a/pyrogram/client/methods/chats/get_dialogs.py +++ b/pyrogram/methods/chats/get_dialogs.py @@ -19,28 +19,29 @@ import logging from typing import List -import pyrogram -from pyrogram.api import functions, types -from ...ext import BaseClient, utils +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold log = logging.getLogger(__name__) -class GetDialogs(BaseClient): +class GetDialogs(Scaffold): async def get_dialogs( self, offset_date: int = 0, limit: int = 100, pinned_only: bool = False - ) -> List["pyrogram.Dialog"]: + ) -> List["types.Dialog"]: """Get a chunk of the user's dialogs. You can get up to 100 dialogs at once. - For a more convenient way of getting a user's dialogs see :meth:`~Client.iter_dialogs`. + For a more convenient way of getting a user's dialogs see :meth:`~pyrogram.Client.iter_dialogs`. Parameters: offset_date (``int``): - The offset date in Unix time taken from the top message of a :obj:`Dialog`. + The offset date in Unix time taken from the top message of a :obj:`~pyrogram.types.Dialog`. Defaults to 0. Valid for non-pinned dialogs only. limit (``str``, *optional*): @@ -52,7 +53,7 @@ class GetDialogs(BaseClient): Defaults to False. Returns: - List of :obj:`Dialog`: On success, a list of dialogs is returned. + List of :obj:`~pyrogram.types.Dialog`: On success, a list of dialogs is returned. Example: .. code-block:: python @@ -65,13 +66,13 @@ class GetDialogs(BaseClient): """ if pinned_only: - r = await self.send(functions.messages.GetPinnedDialogs(folder_id=0)) + r = await self.send(raw.functions.messages.GetPinnedDialogs(folder_id=0)) else: r = await self.send( - functions.messages.GetDialogs( + raw.functions.messages.GetDialogs( offset_date=offset_date, offset_id=0, - offset_peer=types.InputPeerEmpty(), + offset_peer=raw.types.InputPeerEmpty(), limit=limit, hash=0, exclude_pinned=True @@ -86,7 +87,7 @@ class GetDialogs(BaseClient): for message in r.messages: to_id = message.to_id - if isinstance(to_id, types.PeerUser): + if isinstance(to_id, raw.types.PeerUser): if message.out: chat_id = to_id.user_id else: @@ -94,14 +95,14 @@ class GetDialogs(BaseClient): else: chat_id = utils.get_peer_id(to_id) - messages[chat_id] = await pyrogram.Message._parse(self, message, users, chats) + messages[chat_id] = await types.Message._parse(self, message, users, chats) parsed_dialogs = [] for dialog in r.dialogs: - if not isinstance(dialog, types.Dialog): + if not isinstance(dialog, raw.types.Dialog): continue - parsed_dialogs.append(pyrogram.Dialog._parse(self, dialog, messages, users, chats)) + parsed_dialogs.append(types.Dialog._parse(self, dialog, messages, users, chats)) - return pyrogram.List(parsed_dialogs) + return types.List(parsed_dialogs) diff --git a/pyrogram/client/methods/chats/get_dialogs_count.py b/pyrogram/methods/chats/get_dialogs_count.py similarity index 81% rename from pyrogram/client/methods/chats/get_dialogs_count.py rename to pyrogram/methods/chats/get_dialogs_count.py index da4c60ce..4eef96ad 100644 --- a/pyrogram/client/methods/chats/get_dialogs_count.py +++ b/pyrogram/methods/chats/get_dialogs_count.py @@ -16,11 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class GetDialogsCount(BaseClient): +class GetDialogsCount(Scaffold): async def get_dialogs_count(self, pinned_only: bool = False) -> int: """Get the total count of your dialogs. @@ -39,19 +39,19 @@ class GetDialogsCount(BaseClient): """ if pinned_only: - return len((await self.send(functions.messages.GetPinnedDialogs(folder_id=0))).dialogs) + return len((await self.send(raw.functions.messages.GetPinnedDialogs(folder_id=0))).dialogs) else: r = await self.send( - functions.messages.GetDialogs( + raw.functions.messages.GetDialogs( offset_date=0, offset_id=0, - offset_peer=types.InputPeerEmpty(), + offset_peer=raw.types.InputPeerEmpty(), limit=1, hash=0 ) ) - if isinstance(r, types.messages.Dialogs): + if isinstance(r, raw.types.messages.Dialogs): return len(r.dialogs) else: return r.count diff --git a/pyrogram/client/methods/chats/get_nearby_chats.py b/pyrogram/methods/chats/get_nearby_chats.py similarity index 77% rename from pyrogram/client/methods/chats/get_nearby_chats.py rename to pyrogram/methods/chats/get_nearby_chats.py index 4e76b7e6..69746503 100644 --- a/pyrogram/client/methods/chats/get_nearby_chats.py +++ b/pyrogram/methods/chats/get_nearby_chats.py @@ -18,17 +18,18 @@ from typing import List -import pyrogram -from pyrogram.api import functions, types -from ...ext import BaseClient, utils +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold -class GetNearbyChats(BaseClient): +class GetNearbyChats(Scaffold): async def get_nearby_chats( self, latitude: float, longitude: float - ) -> List["pyrogram.Chat"]: + ) -> List["types.Chat"]: """Get nearby chats. Parameters: @@ -39,7 +40,7 @@ class GetNearbyChats(BaseClient): Longitude of the location. Returns: - List of :obj:`Chat`: On success, a list of nearby chats is returned. + List of :obj:`~pyrogram.types.Chat`: On success, a list of nearby chats is returned. Example: .. code-block:: python @@ -49,8 +50,8 @@ class GetNearbyChats(BaseClient): """ r = await self.send( - functions.contacts.GetLocated( - geo_point=types.InputGeoPoint( + raw.functions.contacts.GetLocated( + geo_point=raw.types.InputGeoPoint( lat=latitude, long=longitude ) @@ -60,11 +61,11 @@ class GetNearbyChats(BaseClient): if not r.updates: return [] - chats = pyrogram.List([pyrogram.Chat._parse_chat(self, chat) for chat in r.chats]) + chats = types.List([types.Chat._parse_chat(self, chat) for chat in r.chats]) peers = r.updates[0].peers for peer in peers: - if isinstance(peer.peer, types.PeerChannel): + if isinstance(peer.peer, raw.types.PeerChannel): chat_id = utils.get_channel_id(peer.peer.channel_id) for chat in chats: diff --git a/pyrogram/client/methods/chats/iter_chat_members.py b/pyrogram/methods/chats/iter_chat_members.py similarity index 85% rename from pyrogram/client/methods/chats/iter_chat_members.py rename to pyrogram/methods/chats/iter_chat_members.py index b5ded4dc..2954bcdb 100644 --- a/pyrogram/client/methods/chats/iter_chat_members.py +++ b/pyrogram/methods/chats/iter_chat_members.py @@ -17,13 +17,11 @@ # along with Pyrogram. If not, see . from string import ascii_lowercase -from typing import Union, Generator, Optional +from typing import Union, AsyncGenerator, Optional -import pyrogram -from async_generator import async_generator, yield_ -from pyrogram.api import types - -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold class Filters: @@ -39,20 +37,19 @@ QUERIES = [""] + [str(i) for i in range(10)] + list(ascii_lowercase) QUERYABLE_FILTERS = (Filters.ALL, Filters.KICKED, Filters.RESTRICTED) -class IterChatMembers(BaseClient): - @async_generator +class IterChatMembers(Scaffold): async def iter_chat_members( self, chat_id: Union[int, str], limit: int = 0, query: str = "", filter: str = Filters.ALL - ) -> Optional[Generator["pyrogram.ChatMember", None, None]]: + ) -> Optional[AsyncGenerator["types.ChatMember", None]]: """Iterate through the members of a chat sequentially. - This convenience method does the same as repeatedly calling :meth:`~Client.get_chat_members` in a loop, thus saving you - from the hassle of setting up boilerplate code. It is useful for getting the whole members list of a chat with - a single call. + This convenience method does the same as repeatedly calling :meth:`~pyrogram.Client.get_chat_members` in a loop, + thus saving you from the hassle of setting up boilerplate code. It is useful for getting the whole members list + of a chat with a single call. Parameters: chat_id (``int`` | ``str``): @@ -78,7 +75,7 @@ class IterChatMembers(BaseClient): Defaults to *"all"*. Returns: - ``Generator``: A generator yielding :obj:`ChatMember` objects. + ``Generator``: A generator yielding :obj:`~pyrogram.types.ChatMember` objects. Example: .. code-block:: python @@ -120,7 +117,7 @@ class IterChatMembers(BaseClient): if not chat_members: break - if isinstance(resolved_chat_id, types.InputPeerChat): + if isinstance(resolved_chat_id, raw.types.InputPeerChat): total = len(chat_members) offset += len(chat_members) @@ -131,7 +128,7 @@ class IterChatMembers(BaseClient): if user_id in yielded: continue - await yield_(chat_member) + yield chat_member yielded.add(chat_member.user.id) diff --git a/pyrogram/client/methods/chats/iter_dialogs.py b/pyrogram/methods/chats/iter_dialogs.py similarity index 79% rename from pyrogram/client/methods/chats/iter_dialogs.py rename to pyrogram/methods/chats/iter_dialogs.py index a1933a7e..0c878f0e 100644 --- a/pyrogram/client/methods/chats/iter_dialogs.py +++ b/pyrogram/methods/chats/iter_dialogs.py @@ -16,26 +16,23 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import Generator, Optional +from typing import AsyncGenerator, Optional -from async_generator import async_generator, yield_ - -import pyrogram -from ...ext import BaseClient +from pyrogram import types +from pyrogram.scaffold import Scaffold -class IterDialogs(BaseClient): - @async_generator +class IterDialogs(Scaffold): async def iter_dialogs( self, limit: int = 0, offset_date: int = 0 - ) -> Optional[Generator["pyrogram.Dialog", None, None]]: + ) -> Optional[AsyncGenerator["types.Dialog", None]]: """Iterate through a user's dialogs sequentially. - This convenience method does the same as repeatedly calling :meth:`~Client.get_dialogs` in a loop, thus saving - you from the hassle of setting up boilerplate code. It is useful for getting the whole dialogs list with a - single call. + This convenience method does the same as repeatedly calling :meth:`~pyrogram.Client.get_dialogs` in a loop, + thus saving you from the hassle of setting up boilerplate code. It is useful for getting the whole dialogs list + with a single call. Parameters: limit (``int``, *optional*): @@ -43,11 +40,11 @@ class IterDialogs(BaseClient): By default, no limit is applied and all dialogs are returned. offset_date (``int``): - The offset date in Unix time taken from the top message of a :obj:`Dialog`. + The offset date in Unix time taken from the top message of a :obj:`~pyrogram.types.Dialog`. Defaults to 0 (most recent dialog). Returns: - ``Generator``: A generator yielding :obj:`Dialog` objects. + ``Generator``: A generator yielding :obj:`~pyrogram.types.Dialog` objects. Example: .. code-block:: python @@ -65,7 +62,7 @@ class IterDialogs(BaseClient): ) for dialog in pinned_dialogs: - await yield_(dialog) + yield dialog current += 1 @@ -84,7 +81,7 @@ class IterDialogs(BaseClient): offset_date = dialogs[-1].top_message.date for dialog in dialogs: - await yield_(dialog) + yield dialog current += 1 diff --git a/pyrogram/client/methods/chats/join_chat.py b/pyrogram/methods/chats/join_chat.py similarity index 75% rename from pyrogram/client/methods/chats/join_chat.py rename to pyrogram/methods/chats/join_chat.py index 05bde186..88adc4ed 100644 --- a/pyrogram/client/methods/chats/join_chat.py +++ b/pyrogram/methods/chats/join_chat.py @@ -18,12 +18,12 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class JoinChat(BaseClient): +class JoinChat(Scaffold): async def join_chat( self, chat_id: Union[int, str] @@ -36,7 +36,7 @@ class JoinChat(BaseClient): channel/supergroup (in the format @username) or a chat id of a linked chat (channel or supergroup). Returns: - :obj:`Chat`: On success, a chat object is returned. + :obj:`~pyrogram.types.Chat`: On success, a chat object is returned. Example: .. code-block:: python @@ -54,19 +54,19 @@ class JoinChat(BaseClient): if match: chat = await self.send( - functions.messages.ImportChatInvite( + raw.functions.messages.ImportChatInvite( hash=match.group(1) ) ) - if isinstance(chat.chats[0], types.Chat): - return pyrogram.Chat._parse_chat_chat(self, chat.chats[0]) - elif isinstance(chat.chats[0], types.Channel): - return pyrogram.Chat._parse_channel_chat(self, chat.chats[0]) + if isinstance(chat.chats[0], raw.types.Chat): + return types.Chat._parse_chat_chat(self, chat.chats[0]) + elif isinstance(chat.chats[0], raw.types.Channel): + return types.Chat._parse_channel_chat(self, chat.chats[0]) else: chat = await self.send( - functions.channels.JoinChannel( + raw.functions.channels.JoinChannel( channel=await self.resolve_peer(chat_id) ) ) - return pyrogram.Chat._parse_channel_chat(self, chat.chats[0]) + return types.Chat._parse_channel_chat(self, chat.chats[0]) diff --git a/pyrogram/client/methods/chats/kick_chat_member.py b/pyrogram/methods/chats/kick_chat_member.py similarity index 83% rename from pyrogram/client/methods/chats/kick_chat_member.py rename to pyrogram/methods/chats/kick_chat_member.py index d72da5ab..ce814f25 100644 --- a/pyrogram/client/methods/chats/kick_chat_member.py +++ b/pyrogram/methods/chats/kick_chat_member.py @@ -18,18 +18,18 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class KickChatMember(BaseClient): +class KickChatMember(Scaffold): async def kick_chat_member( self, chat_id: Union[int, str], user_id: Union[int, str], until_date: int = 0 - ) -> Union["pyrogram.Message", bool]: + ) -> Union["types.Message", bool]: """Kick a user from a group, a supergroup or a channel. In the case of supergroups and channels, the user will not be able to return to the group on their own using invite links, etc., unless unbanned first. You must be an administrator in the chat for this to work and must @@ -54,8 +54,8 @@ class KickChatMember(BaseClient): considered to be banned forever. Defaults to 0 (ban forever). Returns: - :obj:`Message` | ``bool``: On success, a service message will be returned (when applicable), otherwise, in - case a message object couldn't be returned, True is returned. + :obj:`~pyrogram.types.Message` | ``bool``: On success, a service message will be returned (when applicable), + otherwise, in case a message object couldn't be returned, True is returned. Example: .. code-block:: python @@ -71,12 +71,12 @@ class KickChatMember(BaseClient): chat_peer = await self.resolve_peer(chat_id) user_peer = await self.resolve_peer(user_id) - if isinstance(chat_peer, types.InputPeerChannel): + if isinstance(chat_peer, raw.types.InputPeerChannel): r = await self.send( - functions.channels.EditBanned( + raw.functions.channels.EditBanned( channel=chat_peer, user_id=user_peer, - banned_rights=types.ChatBannedRights( + banned_rights=raw.types.ChatBannedRights( until_date=until_date, view_messages=True, send_messages=True, @@ -91,15 +91,15 @@ class KickChatMember(BaseClient): ) else: r = await self.send( - functions.messages.DeleteChatUser( + raw.functions.messages.DeleteChatUser( chat_id=abs(chat_id), user_id=user_peer ) ) for i in r.updates: - if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, raw.types.UpdateNewChannelMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats} diff --git a/pyrogram/client/methods/chats/leave_chat.py b/pyrogram/methods/chats/leave_chat.py similarity index 83% rename from pyrogram/client/methods/chats/leave_chat.py rename to pyrogram/methods/chats/leave_chat.py index 31b7cc78..5c60e658 100644 --- a/pyrogram/client/methods/chats/leave_chat.py +++ b/pyrogram/methods/chats/leave_chat.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class LeaveChat(BaseClient): +class LeaveChat(Scaffold): async def leave_chat( self, chat_id: Union[int, str], @@ -50,23 +50,23 @@ class LeaveChat(BaseClient): """ peer = await self.resolve_peer(chat_id) - if isinstance(peer, types.InputPeerChannel): + if isinstance(peer, raw.types.InputPeerChannel): return await self.send( - functions.channels.LeaveChannel( + raw.functions.channels.LeaveChannel( channel=await self.resolve_peer(chat_id) ) ) - elif isinstance(peer, types.InputPeerChat): + elif isinstance(peer, raw.types.InputPeerChat): r = await self.send( - functions.messages.DeleteChatUser( + raw.functions.messages.DeleteChatUser( chat_id=peer.chat_id, - user_id=types.InputPeerSelf() + user_id=raw.types.InputUserSelf() ) ) if delete: await self.send( - functions.messages.DeleteHistory( + raw.functions.messages.DeleteHistory( peer=peer, max_id=0 ) diff --git a/pyrogram/client/methods/chats/pin_chat_message.py b/pyrogram/methods/chats/pin_chat_message.py similarity index 93% rename from pyrogram/client/methods/chats/pin_chat_message.py rename to pyrogram/methods/chats/pin_chat_message.py index 6adaa2e8..a357aab9 100644 --- a/pyrogram/client/methods/chats/pin_chat_message.py +++ b/pyrogram/methods/chats/pin_chat_message.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class PinChatMessage(BaseClient): +class PinChatMessage(Scaffold): async def pin_chat_message( self, chat_id: Union[int, str], @@ -57,7 +57,7 @@ class PinChatMessage(BaseClient): app.pin_chat_message(chat_id, message_id, disable_notification=True) """ await self.send( - functions.messages.UpdatePinnedMessage( + raw.functions.messages.UpdatePinnedMessage( peer=await self.resolve_peer(chat_id), id=message_id, silent=disable_notification or None diff --git a/pyrogram/client/methods/chats/promote_chat_member.py b/pyrogram/methods/chats/promote_chat_member.py similarity index 95% rename from pyrogram/client/methods/chats/promote_chat_member.py rename to pyrogram/methods/chats/promote_chat_member.py index c6912031..eb49bce0 100644 --- a/pyrogram/client/methods/chats/promote_chat_member.py +++ b/pyrogram/methods/chats/promote_chat_member.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class PromoteChatMember(BaseClient): +class PromoteChatMember(Scaffold): async def promote_chat_member( self, chat_id: Union[int, str], @@ -85,10 +85,10 @@ class PromoteChatMember(BaseClient): app.promote_chat_member(chat_id, user_id) """ await self.send( - functions.channels.EditAdmin( + raw.functions.channels.EditAdmin( channel=await self.resolve_peer(chat_id), user_id=await self.resolve_peer(user_id), - admin_rights=types.ChatAdminRights( + admin_rights=raw.types.ChatAdminRights( change_info=can_change_info or None, post_messages=can_post_messages or None, edit_messages=can_edit_messages or None, diff --git a/pyrogram/client/methods/chats/restrict_chat_member.py b/pyrogram/methods/chats/restrict_chat_member.py similarity index 88% rename from pyrogram/client/methods/chats/restrict_chat_member.py rename to pyrogram/methods/chats/restrict_chat_member.py index 500482a1..af760feb 100644 --- a/pyrogram/client/methods/chats/restrict_chat_member.py +++ b/pyrogram/methods/chats/restrict_chat_member.py @@ -18,19 +18,19 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient -from ...types.user_and_chats import Chat, ChatPermissions +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class RestrictChatMember(BaseClient): +class RestrictChatMember(Scaffold): async def restrict_chat_member( self, chat_id: Union[int, str], user_id: Union[int, str], - permissions: ChatPermissions, + permissions: "types.ChatPermissions", until_date: int = 0 - ) -> Chat: + ) -> "types.Chat": """Restrict a user in a supergroup. You must be an administrator in the supergroup for this to work and must have the appropriate admin rights. @@ -44,7 +44,7 @@ class RestrictChatMember(BaseClient): Unique identifier (int) or username (str) of the target user. For a contact that exists in your Telegram address book you can use his phone number (str). - permissions (:obj:`ChatPermissions`): + permissions (:obj:`~pyrogram.types.ChatPermissions`): New user permissions. until_date (``int``, *optional*): @@ -53,7 +53,7 @@ class RestrictChatMember(BaseClient): considered to be banned forever. Defaults to 0 (ban forever). Returns: - :obj:`Chat`: On success, a chat object is returned. + :obj:`~pyrogram.types.Chat`: On success, a chat object is returned. Example: .. code-block:: python @@ -72,10 +72,10 @@ class RestrictChatMember(BaseClient): app.restrict_chat_member(chat_id, user_id, ChatPermissions(can_send_messages=True)) """ r = await self.send( - functions.channels.EditBanned( + raw.functions.channels.EditBanned( channel=await self.resolve_peer(chat_id), user_id=await self.resolve_peer(user_id), - banned_rights=types.ChatBannedRights( + banned_rights=raw.types.ChatBannedRights( until_date=until_date, send_messages=True if not permissions.can_send_messages else None, send_media=True if not permissions.can_send_media_messages else None, @@ -92,4 +92,4 @@ class RestrictChatMember(BaseClient): ) ) - return Chat._parse_chat(self, r.chats[0]) + return types.Chat._parse_chat(self, r.chats[0]) diff --git a/pyrogram/client/methods/chats/set_administrator_title.py b/pyrogram/methods/chats/set_administrator_title.py similarity index 90% rename from pyrogram/client/methods/chats/set_administrator_title.py rename to pyrogram/methods/chats/set_administrator_title.py index 0cbc937a..e354fd5b 100644 --- a/pyrogram/client/methods/chats/set_administrator_title.py +++ b/pyrogram/methods/chats/set_administrator_title.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class SetAdministratorTitle(BaseClient): +class SetAdministratorTitle(Scaffold): async def set_administrator_title( self, chat_id: Union[int, str], @@ -58,14 +58,14 @@ class SetAdministratorTitle(BaseClient): user_id = await self.resolve_peer(user_id) r = (await self.send( - functions.channels.GetParticipant( + raw.functions.channels.GetParticipant( channel=chat_id, user_id=user_id ) )).participant - if isinstance(r, types.ChannelParticipantCreator): - admin_rights = types.ChatAdminRights( + if isinstance(r, raw.types.ChannelParticipantCreator): + admin_rights = raw.types.ChatAdminRights( change_info=True, post_messages=True, edit_messages=True, @@ -75,7 +75,7 @@ class SetAdministratorTitle(BaseClient): pin_messages=True, add_admins=True, ) - elif isinstance(r, types.ChannelParticipantAdmin): + elif isinstance(r, raw.types.ChannelParticipantAdmin): admin_rights = r.admin_rights else: raise ValueError("Custom titles can only be applied to owners or administrators of supergroups") @@ -105,7 +105,7 @@ class SetAdministratorTitle(BaseClient): admin_rights.add_admins = None await self.send( - functions.channels.EditAdmin( + raw.functions.channels.EditAdmin( channel=chat_id, user_id=user_id, admin_rights=admin_rights, diff --git a/pyrogram/client/methods/chats/set_chat_description.py b/pyrogram/methods/chats/set_chat_description.py similarity index 85% rename from pyrogram/client/methods/chats/set_chat_description.py rename to pyrogram/methods/chats/set_chat_description.py index e2960408..0dc87c48 100644 --- a/pyrogram/client/methods/chats/set_chat_description.py +++ b/pyrogram/methods/chats/set_chat_description.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class SetChatDescription(BaseClient): +class SetChatDescription(Scaffold): async def set_chat_description( self, chat_id: Union[int, str], @@ -51,14 +51,14 @@ class SetChatDescription(BaseClient): """ peer = await self.resolve_peer(chat_id) - if isinstance(peer, (types.InputPeerChannel, types.InputPeerChat)): + if isinstance(peer, (raw.types.InputPeerChannel, raw.types.InputPeerChat)): await self.send( - functions.messages.EditChatAbout( + raw.functions.messages.EditChatAbout( peer=peer, about=description ) ) else: - raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id)) + raise ValueError(f'The chat_id "{chat_id}" belongs to a user') return True diff --git a/pyrogram/client/methods/chats/set_chat_permissions.py b/pyrogram/methods/chats/set_chat_permissions.py similarity index 85% rename from pyrogram/client/methods/chats/set_chat_permissions.py rename to pyrogram/methods/chats/set_chat_permissions.py index 3509baf4..028f0eb1 100644 --- a/pyrogram/client/methods/chats/set_chat_permissions.py +++ b/pyrogram/methods/chats/set_chat_permissions.py @@ -18,17 +18,17 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient -from ...types.user_and_chats import Chat, ChatPermissions +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class SetChatPermissions(BaseClient): +class SetChatPermissions(Scaffold): async def set_chat_permissions( self, chat_id: Union[int, str], - permissions: ChatPermissions, - ) -> Chat: + permissions: "types.ChatPermissions", + ) -> "types.Chat": """Set default chat permissions for all members. You must be an administrator in the group or a supergroup for this to work and must have the @@ -38,11 +38,11 @@ class SetChatPermissions(BaseClient): chat_id (``int`` | ``str``): Unique identifier (int) or username (str) of the target chat. - permissions (:obj:`ChatPermissions`): + permissions (:obj:`~pyrogram.types.ChatPermissions`): New default chat permissions. Returns: - :obj:`Chat`: On success, a chat object is returned. + :obj:`~pyrogram.types.Chat`: On success, a chat object is returned. Example: .. code-block:: python @@ -64,9 +64,9 @@ class SetChatPermissions(BaseClient): ) """ r = await self.send( - functions.messages.EditChatDefaultBannedRights( + raw.functions.messages.EditChatDefaultBannedRights( peer=await self.resolve_peer(chat_id), - banned_rights=types.ChatBannedRights( + banned_rights=raw.types.ChatBannedRights( until_date=0, send_messages=True if not permissions.can_send_messages else None, send_media=True if not permissions.can_send_media_messages else None, @@ -83,4 +83,4 @@ class SetChatPermissions(BaseClient): ) ) - return Chat._parse_chat(self, r.chats[0]) + return types.Chat._parse_chat(self, r.chats[0]) diff --git a/pyrogram/client/methods/chats/set_chat_photo.py b/pyrogram/methods/chats/set_chat_photo.py similarity index 74% rename from pyrogram/client/methods/chats/set_chat_photo.py rename to pyrogram/methods/chats/set_chat_photo.py index e6d35448..8ccb123c 100644 --- a/pyrogram/client/methods/chats/set_chat_photo.py +++ b/pyrogram/methods/chats/set_chat_photo.py @@ -19,11 +19,12 @@ import os from typing import Union, BinaryIO -from pyrogram.api import functions, types -from ...ext import BaseClient, utils +from pyrogram import raw +from pyrogram import utils +from pyrogram.scaffold import Scaffold -class SetChatPhoto(BaseClient): +class SetChatPhoto(Scaffold): async def set_chat_photo( self, chat_id: Union[int, str], @@ -44,14 +45,14 @@ class SetChatPhoto(BaseClient): Unique identifier (int) or username (str) of the target chat. photo (``str`` | ``BinaryIO``, *optional*): - New chat photo. You can pass a :obj:`Photo` file_id (in pair with a valid file_ref), a file path to - upload a new photo from your local machine or a binary file-like object with its attribute ".name" - set for in-memory uploads. + New chat photo. You can pass a :obj:`~pyrogram.types.Photo` file_id (in pair with a valid file_ref), a + file path to upload a new photo from your local machine or a binary file-like object with its attribute + ".name" set for in-memory uploads. video (``str`` | ``BinaryIO``, *optional*): - New chat video. You can pass a :obj:`Video` file_id (in pair with a valid file_ref), a file path to - upload a new video from your local machine or a binary file-like object with its attribute ".name" - set for in-memory uploads. + New chat video. You can pass a :obj:`~pyrogram.types.Video` file_id (in pair with a valid file_ref), a + file path to upload a new video from your local machine or a binary file-like object with its attribute + ".name" set for in-memory uploads. file_ref (``str``, *optional*): A valid file reference obtained by a recently fetched media message. @@ -83,34 +84,34 @@ class SetChatPhoto(BaseClient): if isinstance(photo, str): if os.path.isfile(photo): - photo = types.InputChatUploadedPhoto( + photo = raw.types.InputChatUploadedPhoto( file=await self.save_file(photo), video=await self.save_file(video) ) else: photo = utils.get_input_media_from_file_id(photo, file_ref, 2) - photo = types.InputChatPhoto(id=photo.id) + photo = raw.types.InputChatPhoto(id=photo.id) else: - photo = types.InputChatUploadedPhoto( + photo = raw.types.InputChatUploadedPhoto( file=await self.save_file(photo), video=await self.save_file(video) ) - if isinstance(peer, types.InputPeerChat): + if isinstance(peer, raw.types.InputPeerChat): await self.send( - functions.messages.EditChatPhoto( + raw.functions.messages.EditChatPhoto( chat_id=peer.chat_id, photo=photo ) ) - elif isinstance(peer, types.InputPeerChannel): + elif isinstance(peer, raw.types.InputPeerChannel): await self.send( - functions.channels.EditPhoto( + raw.functions.channels.EditPhoto( channel=peer, photo=photo ) ) else: - raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id)) + raise ValueError(f'The chat_id "{chat_id}" belongs to a user') return True diff --git a/pyrogram/client/methods/chats/set_chat_title.py b/pyrogram/methods/chats/set_chat_title.py similarity index 84% rename from pyrogram/client/methods/chats/set_chat_title.py rename to pyrogram/methods/chats/set_chat_title.py index a6b9bc71..2ed7d2e8 100644 --- a/pyrogram/client/methods/chats/set_chat_title.py +++ b/pyrogram/methods/chats/set_chat_title.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class SetChatTitle(BaseClient): +class SetChatTitle(Scaffold): async def set_chat_title( self, chat_id: Union[int, str], @@ -56,21 +56,21 @@ class SetChatTitle(BaseClient): """ peer = await self.resolve_peer(chat_id) - if isinstance(peer, types.InputPeerChat): + if isinstance(peer, raw.types.InputPeerChat): await self.send( - functions.messages.EditChatTitle( + raw.functions.messages.EditChatTitle( chat_id=peer.chat_id, title=title ) ) - elif isinstance(peer, types.InputPeerChannel): + elif isinstance(peer, raw.types.InputPeerChannel): await self.send( - functions.channels.EditTitle( + raw.functions.channels.EditTitle( channel=peer, title=title ) ) else: - raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id)) + raise ValueError(f'The chat_id "{chat_id}" belongs to a user') return True diff --git a/pyrogram/client/methods/chats/set_slow_mode.py b/pyrogram/methods/chats/set_slow_mode.py similarity index 92% rename from pyrogram/client/methods/chats/set_slow_mode.py rename to pyrogram/methods/chats/set_slow_mode.py index 185a3824..e2db5a85 100644 --- a/pyrogram/client/methods/chats/set_slow_mode.py +++ b/pyrogram/methods/chats/set_slow_mode.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class SetSlowMode(BaseClient): +class SetSlowMode(Scaffold): async def set_slow_mode( self, chat_id: Union[int, str], @@ -52,7 +52,7 @@ class SetSlowMode(BaseClient): """ await self.send( - functions.channels.ToggleSlowMode( + raw.functions.channels.ToggleSlowMode( channel=await self.resolve_peer(chat_id), seconds=0 if seconds is None else seconds ) diff --git a/pyrogram/client/methods/chats/unarchive_chats.py b/pyrogram/methods/chats/unarchive_chats.py similarity index 91% rename from pyrogram/client/methods/chats/unarchive_chats.py rename to pyrogram/methods/chats/unarchive_chats.py index dfba70a7..af62d9a7 100644 --- a/pyrogram/client/methods/chats/unarchive_chats.py +++ b/pyrogram/methods/chats/unarchive_chats.py @@ -18,11 +18,11 @@ from typing import Union, List -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class UnarchiveChats(BaseClient): +class UnarchiveChats(Scaffold): async def unarchive_chats( self, chat_ids: Union[int, str, List[Union[int, str]]], @@ -54,14 +54,14 @@ class UnarchiveChats(BaseClient): for chat in chat_ids: folder_peers.append( - types.InputFolderPeer( + raw.types.InputFolderPeer( peer=await self.resolve_peer(chat), folder_id=0 ) ) await self.send( - functions.folders.EditPeerFolders( + raw.functions.folders.EditPeerFolders( folder_peers=folder_peers ) ) diff --git a/pyrogram/client/methods/chats/unban_chat_member.py b/pyrogram/methods/chats/unban_chat_member.py similarity index 90% rename from pyrogram/client/methods/chats/unban_chat_member.py rename to pyrogram/methods/chats/unban_chat_member.py index 4a7b3940..e6f0b7b0 100644 --- a/pyrogram/client/methods/chats/unban_chat_member.py +++ b/pyrogram/methods/chats/unban_chat_member.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class UnbanChatMember(BaseClient): +class UnbanChatMember(Scaffold): async def unban_chat_member( self, chat_id: Union[int, str], @@ -50,10 +50,10 @@ class UnbanChatMember(BaseClient): app.unban_chat_member(chat_id, user_id) """ await self.send( - functions.channels.EditBanned( + raw.functions.channels.EditBanned( channel=await self.resolve_peer(chat_id), user_id=await self.resolve_peer(user_id), - banned_rights=types.ChatBannedRights( + banned_rights=raw.types.ChatBannedRights( until_date=0 ) ) diff --git a/pyrogram/client/methods/chats/unpin_chat_message.py b/pyrogram/methods/chats/unpin_chat_message.py similarity index 91% rename from pyrogram/client/methods/chats/unpin_chat_message.py rename to pyrogram/methods/chats/unpin_chat_message.py index 0ca8254a..3ee7814d 100644 --- a/pyrogram/client/methods/chats/unpin_chat_message.py +++ b/pyrogram/methods/chats/unpin_chat_message.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class UnpinChatMessage(BaseClient): +class UnpinChatMessage(Scaffold): async def unpin_chat_message( self, chat_id: Union[int, str] @@ -44,7 +44,7 @@ class UnpinChatMessage(BaseClient): app.unpin_chat_message(chat_id) """ await self.send( - functions.messages.UpdatePinnedMessage( + raw.functions.messages.UpdatePinnedMessage( peer=await self.resolve_peer(chat_id), id=0 ) diff --git a/pyrogram/client/methods/chats/update_chat_username.py b/pyrogram/methods/chats/update_chat_username.py similarity index 84% rename from pyrogram/client/methods/chats/update_chat_username.py rename to pyrogram/methods/chats/update_chat_username.py index b1c57f1e..876115a4 100644 --- a/pyrogram/client/methods/chats/update_chat_username.py +++ b/pyrogram/methods/chats/update_chat_username.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class UpdateChatUsername(BaseClient): +class UpdateChatUsername(Scaffold): async def update_chat_username( self, chat_id: Union[int, str], @@ -30,7 +30,7 @@ class UpdateChatUsername(BaseClient): ) -> bool: """Update a channel or a supergroup username. - To update your own username (for users only, not bots) you can use :meth:`~Client.update_username`. + To update your own username (for users only, not bots) you can use :meth:`~pyrogram.Client.update_username`. Parameters: chat_id (``int`` | ``str``) @@ -52,14 +52,14 @@ class UpdateChatUsername(BaseClient): peer = await self.resolve_peer(chat_id) - if isinstance(peer, types.InputPeerChannel): + if isinstance(peer, raw.types.InputPeerChannel): return bool( await self.send( - functions.channels.UpdateUsername( + raw.functions.channels.UpdateUsername( channel=peer, username=username or "" ) ) ) else: - raise ValueError("The chat_id \"{}\" belongs to a user or chat".format(chat_id)) + raise ValueError(f'The chat_id "{chat_id}" belongs to a user or chat') diff --git a/pyrogram/client/methods/contacts/__init__.py b/pyrogram/methods/contacts/__init__.py similarity index 100% rename from pyrogram/client/methods/contacts/__init__.py rename to pyrogram/methods/contacts/__init__.py diff --git a/pyrogram/client/methods/contacts/add_contacts.py b/pyrogram/methods/contacts/add_contacts.py similarity index 84% rename from pyrogram/client/methods/contacts/add_contacts.py rename to pyrogram/methods/contacts/add_contacts.py index 7226d60b..b786991c 100644 --- a/pyrogram/client/methods/contacts/add_contacts.py +++ b/pyrogram/methods/contacts/add_contacts.py @@ -18,20 +18,20 @@ from typing import List -import pyrogram -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class AddContacts(BaseClient): +class AddContacts(Scaffold): async def add_contacts( self, - contacts: List["pyrogram.InputPhoneContact"] + contacts: List["types.InputPhoneContact"] ): """Add contacts to your Telegram address book. Parameters: - contacts (List of :obj:`InputPhoneContact`): + contacts (List of :obj:`~pyrogram.types.InputPhoneContact`): The contact list to be added Returns: @@ -48,7 +48,7 @@ class AddContacts(BaseClient): InputPhoneContact("01234567891", "Baz")]) """ imported_contacts = await self.send( - functions.contacts.ImportContacts( + raw.functions.contacts.ImportContacts( contacts=contacts ) ) diff --git a/pyrogram/client/methods/contacts/delete_contacts.py b/pyrogram/methods/contacts/delete_contacts.py similarity index 88% rename from pyrogram/client/methods/contacts/delete_contacts.py rename to pyrogram/methods/contacts/delete_contacts.py index 777d8b39..2f576a5e 100644 --- a/pyrogram/client/methods/contacts/delete_contacts.py +++ b/pyrogram/methods/contacts/delete_contacts.py @@ -18,12 +18,12 @@ from typing import List -from pyrogram.api import functions, types +from pyrogram import raw from pyrogram.errors import PeerIdInvalid -from ...ext import BaseClient +from pyrogram.scaffold import Scaffold -class DeleteContacts(BaseClient): +class DeleteContacts(Scaffold): async def delete_contacts( self, ids: List[int] @@ -51,11 +51,11 @@ class DeleteContacts(BaseClient): except PeerIdInvalid: continue else: - if isinstance(input_user, types.InputPeerUser): + if isinstance(input_user, raw.types.InputPeerUser): contacts.append(input_user) return await self.send( - functions.contacts.DeleteContacts( + raw.functions.contacts.DeleteContacts( id=contacts ) ) diff --git a/pyrogram/client/methods/contacts/get_contacts.py b/pyrogram/methods/contacts/get_contacts.py similarity index 72% rename from pyrogram/client/methods/contacts/get_contacts.py rename to pyrogram/methods/contacts/get_contacts.py index 8f8392d6..d4f08168 100644 --- a/pyrogram/client/methods/contacts/get_contacts.py +++ b/pyrogram/methods/contacts/get_contacts.py @@ -16,23 +16,22 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import asyncio import logging from typing import List -import pyrogram -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold log = logging.getLogger(__name__) -class GetContacts(BaseClient): - async def get_contacts(self) -> List["pyrogram.User"]: +class GetContacts(Scaffold): + async def get_contacts(self) -> List["types.User"]: """Get contacts from your Telegram address book. Returns: - List of :obj:`User`: On success, a list of users is returned. + List of :obj:`~pyrogram.types.User`: On success, a list of users is returned. Example: .. code-block:: python @@ -40,5 +39,5 @@ class GetContacts(BaseClient): contacts = app.get_contacts() print(contacts) """ - contacts = await self.send(functions.contacts.GetContacts(hash=0)) - return pyrogram.List(pyrogram.User._parse(self, user) for user in contacts.users) + contacts = await self.send(raw.functions.contacts.GetContacts(hash=0)) + return types.List(types.User._parse(self, user) for user in contacts.users) diff --git a/pyrogram/client/methods/contacts/get_contacts_count.py b/pyrogram/methods/contacts/get_contacts_count.py similarity index 86% rename from pyrogram/client/methods/contacts/get_contacts_count.py rename to pyrogram/methods/contacts/get_contacts_count.py index 8435557a..3a16c905 100644 --- a/pyrogram/client/methods/contacts/get_contacts_count.py +++ b/pyrogram/methods/contacts/get_contacts_count.py @@ -16,11 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class GetContactsCount(BaseClient): +class GetContactsCount(Scaffold): async def get_contacts_count(self) -> int: """Get the total count of contacts from your Telegram address book. @@ -34,4 +34,4 @@ class GetContactsCount(BaseClient): print(count) """ - return len((await self.send(functions.contacts.GetContacts(hash=0))).contacts) + return len((await self.send(raw.functions.contacts.GetContacts(hash=0))).contacts) diff --git a/pyrogram/client/methods/decorators/__init__.py b/pyrogram/methods/decorators/__init__.py similarity index 100% rename from pyrogram/client/methods/decorators/__init__.py rename to pyrogram/methods/decorators/__init__.py index 5a60ff9b..fbc4fac6 100644 --- a/pyrogram/client/methods/decorators/__init__.py +++ b/pyrogram/methods/decorators/__init__.py @@ -17,6 +17,7 @@ # along with Pyrogram. If not, see . from .on_callback_query import OnCallbackQuery +from .on_chosen_inline_result import OnChosenInlineResult from .on_deleted_messages import OnDeletedMessages from .on_disconnect import OnDisconnect from .on_inline_query import OnInlineQuery @@ -24,7 +25,6 @@ from .on_message import OnMessage from .on_poll import OnPoll from .on_raw_update import OnRawUpdate from .on_user_status import OnUserStatus -from .on_chosen_inline_result import OnChosenInlineResult class Decorators( diff --git a/pyrogram/client/methods/decorators/on_callback_query.py b/pyrogram/methods/decorators/on_callback_query.py similarity index 84% rename from pyrogram/client/methods/decorators/on_callback_query.py rename to pyrogram/methods/decorators/on_callback_query.py index c7bcae26..f681eee7 100644 --- a/pyrogram/client/methods/decorators/on_callback_query.py +++ b/pyrogram/methods/decorators/on_callback_query.py @@ -19,11 +19,11 @@ from typing import Callable import pyrogram -from pyrogram.client.filters.filter import Filter -from ...ext import BaseClient +from pyrogram.filters import Filter +from pyrogram.scaffold import Scaffold -class OnCallbackQuery(BaseClient): +class OnCallbackQuery(Scaffold): def on_callback_query( self=None, filters=None, @@ -32,7 +32,7 @@ class OnCallbackQuery(BaseClient): """Decorator for handling callback queries. This does the same thing as :meth:`~pyrogram.Client.add_handler` using the - :obj:`~pyrogram.CallbackQueryHandler`. + :obj:`~pyrogram.handlers.CallbackQueryHandler`. Parameters: filters (:obj:`~pyrogram.Filters`, *optional*): @@ -45,10 +45,10 @@ class OnCallbackQuery(BaseClient): def decorator(func: Callable) -> Callable: if isinstance(self, pyrogram.Client): - self.add_handler(pyrogram.CallbackQueryHandler(func, filters), group) + self.add_handler(pyrogram.handlers.CallbackQueryHandler(func, filters), group) elif isinstance(self, Filter) or self is None: func.handler = ( - pyrogram.CallbackQueryHandler(func, self), + pyrogram.handlers.CallbackQueryHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/decorators/on_chosen_inline_result.py b/pyrogram/methods/decorators/on_chosen_inline_result.py similarity index 82% rename from pyrogram/client/methods/decorators/on_chosen_inline_result.py rename to pyrogram/methods/decorators/on_chosen_inline_result.py index 40446eb2..3163ccb3 100644 --- a/pyrogram/client/methods/decorators/on_chosen_inline_result.py +++ b/pyrogram/methods/decorators/on_chosen_inline_result.py @@ -19,11 +19,11 @@ from typing import Callable import pyrogram -from pyrogram.client.filters.filter import Filter -from ...ext import BaseClient +from pyrogram.filters import Filter +from pyrogram.scaffold import Scaffold -class OnChosenInlineResult(BaseClient): +class OnChosenInlineResult(Scaffold): def on_chosen_inline_result( self=None, filters=None, @@ -31,7 +31,8 @@ class OnChosenInlineResult(BaseClient): ) -> callable: """Decorator for handling chosen inline results. - This does the same thing as :meth:`~pyrogram.Client.add_handler` using the :obj:`~pyrogram.ChosenInlineResult`. + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.ChosenInlineResult`. Parameters: filters (:obj:`~pyrogram.Filters`, *optional*): @@ -44,10 +45,10 @@ class OnChosenInlineResult(BaseClient): def decorator(func: Callable) -> Callable: if isinstance(self, pyrogram.Client): - self.add_handler(pyrogram.ChosenInlineResultHandler(func, filters), group) + self.add_handler(pyrogram.handlers.ChosenInlineResultHandler(func, filters), group) elif isinstance(self, Filter) or self is None: func.handler = ( - pyrogram.ChosenInlineResultHandler(func, self), + pyrogram.handlers.ChosenInlineResultHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/decorators/on_deleted_messages.py b/pyrogram/methods/decorators/on_deleted_messages.py similarity index 83% rename from pyrogram/client/methods/decorators/on_deleted_messages.py rename to pyrogram/methods/decorators/on_deleted_messages.py index 8a7e1e55..adb4d879 100644 --- a/pyrogram/client/methods/decorators/on_deleted_messages.py +++ b/pyrogram/methods/decorators/on_deleted_messages.py @@ -19,11 +19,11 @@ from typing import Callable import pyrogram -from pyrogram.client.filters.filter import Filter -from ...ext import BaseClient +from pyrogram.filters import Filter +from pyrogram.scaffold import Scaffold -class OnDeletedMessages(BaseClient): +class OnDeletedMessages(Scaffold): def on_deleted_messages( self=None, filters=None, @@ -32,7 +32,7 @@ class OnDeletedMessages(BaseClient): """Decorator for handling deleted messages. This does the same thing as :meth:`~pyrogram.Client.add_handler` using the - :obj:`~pyrogram.DeletedMessagesHandler`. + :obj:`~pyrogram.handlers.DeletedMessagesHandler`. Parameters: filters (:obj:`~pyrogram.Filters`, *optional*): @@ -45,10 +45,10 @@ class OnDeletedMessages(BaseClient): def decorator(func: Callable) -> Callable: if isinstance(self, pyrogram.Client): - self.add_handler(pyrogram.DeletedMessagesHandler(func, filters), group) + self.add_handler(pyrogram.handlers.DeletedMessagesHandler(func, filters), group) elif isinstance(self, Filter) or self is None: func.handler = ( - pyrogram.DeletedMessagesHandler(func, self), + pyrogram.handlers.DeletedMessagesHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/decorators/on_disconnect.py b/pyrogram/methods/decorators/on_disconnect.py similarity index 84% rename from pyrogram/client/methods/decorators/on_disconnect.py rename to pyrogram/methods/decorators/on_disconnect.py index 0df65848..6e7b1522 100644 --- a/pyrogram/client/methods/decorators/on_disconnect.py +++ b/pyrogram/methods/decorators/on_disconnect.py @@ -19,19 +19,20 @@ from typing import Callable import pyrogram -from ...ext import BaseClient +from pyrogram.scaffold import Scaffold -class OnDisconnect(BaseClient): +class OnDisconnect(Scaffold): def on_disconnect(self=None) -> callable: """Decorator for handling disconnections. - This does the same thing as :meth:`~pyrogram.Client.add_handler` using the :obj:`~pyrogram.DisconnectHandler`. + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.DisconnectHandler`. """ def decorator(func: Callable) -> Callable: if isinstance(self, pyrogram.Client): - self.add_handler(pyrogram.DisconnectHandler(func)) + self.add_handler(pyrogram.handlers.DisconnectHandler(func)) return func diff --git a/pyrogram/client/methods/decorators/on_inline_query.py b/pyrogram/methods/decorators/on_inline_query.py similarity index 83% rename from pyrogram/client/methods/decorators/on_inline_query.py rename to pyrogram/methods/decorators/on_inline_query.py index 4a9b1128..fdc287ec 100644 --- a/pyrogram/client/methods/decorators/on_inline_query.py +++ b/pyrogram/methods/decorators/on_inline_query.py @@ -19,11 +19,11 @@ from typing import Callable import pyrogram -from pyrogram.client.filters.filter import Filter -from ...ext import BaseClient +from pyrogram.filters import Filter +from pyrogram.scaffold import Scaffold -class OnInlineQuery(BaseClient): +class OnInlineQuery(Scaffold): def on_inline_query( self=None, filters=None, @@ -31,7 +31,8 @@ class OnInlineQuery(BaseClient): ) -> callable: """Decorator for handling inline queries. - This does the same thing as :meth:`~pyrogram.Client.add_handler` using the :obj:`~pyrogram.InlineQueryHandler`. + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.InlineQueryHandler`. Parameters: filters (:obj:`~pyrogram.Filters`, *optional*): @@ -44,10 +45,10 @@ class OnInlineQuery(BaseClient): def decorator(func: Callable) -> Callable: if isinstance(self, pyrogram.Client): - self.add_handler(pyrogram.InlineQueryHandler(func, filters), group) + self.add_handler(pyrogram.handlers.InlineQueryHandler(func, filters), group) elif isinstance(self, Filter) or self is None: func.handler = ( - pyrogram.InlineQueryHandler(func, self), + pyrogram.handlers.InlineQueryHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/decorators/on_message.py b/pyrogram/methods/decorators/on_message.py similarity index 83% rename from pyrogram/client/methods/decorators/on_message.py rename to pyrogram/methods/decorators/on_message.py index 9d2791c2..6316def6 100644 --- a/pyrogram/client/methods/decorators/on_message.py +++ b/pyrogram/methods/decorators/on_message.py @@ -19,11 +19,11 @@ from typing import Callable import pyrogram -from pyrogram.client.filters.filter import Filter -from ...ext import BaseClient +from pyrogram.filters import Filter +from pyrogram.scaffold import Scaffold -class OnMessage(BaseClient): +class OnMessage(Scaffold): def on_message( self=None, filters=None, @@ -31,7 +31,8 @@ class OnMessage(BaseClient): ) -> callable: """Decorator for handling messages. - This does the same thing as :meth:`~pyrogram.Client.add_handler` using the :obj:`~pyrogram.MessageHandler`. + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.MessageHandler`. Parameters: filters (:obj:`~pyrogram.Filters`, *optional*): @@ -44,10 +45,10 @@ class OnMessage(BaseClient): def decorator(func: Callable) -> Callable: if isinstance(self, pyrogram.Client): - self.add_handler(pyrogram.MessageHandler(func, filters), group) + self.add_handler(pyrogram.handlers.MessageHandler(func, filters), group) elif isinstance(self, Filter) or self is None: func.handler = ( - pyrogram.MessageHandler(func, self), + pyrogram.handlers.MessageHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/decorators/on_poll.py b/pyrogram/methods/decorators/on_poll.py similarity index 84% rename from pyrogram/client/methods/decorators/on_poll.py rename to pyrogram/methods/decorators/on_poll.py index 2326b3e5..7506c218 100644 --- a/pyrogram/client/methods/decorators/on_poll.py +++ b/pyrogram/methods/decorators/on_poll.py @@ -19,11 +19,11 @@ from typing import Callable import pyrogram -from pyrogram.client.filters.filter import Filter -from ...ext import BaseClient +from pyrogram.filters import Filter +from pyrogram.scaffold import Scaffold -class OnPoll(BaseClient): +class OnPoll(Scaffold): def on_poll( self=None, filters=None, @@ -31,7 +31,8 @@ class OnPoll(BaseClient): ) -> callable: """Decorator for handling poll updates. - This does the same thing as :meth:`~pyrogram.Client.add_handler` using the :obj:`~pyrogram.PollHandler`. + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.PollHandler`. Parameters: filters (:obj:`~pyrogram.Filters`, *optional*): @@ -44,10 +45,10 @@ class OnPoll(BaseClient): def decorator(func: Callable) -> Callable: if isinstance(self, pyrogram.Client): - self.add_handler(pyrogram.PollHandler(func, filters), group) + self.add_handler(pyrogram.handlers.PollHandler(func, filters), group) elif isinstance(self, Filter) or self is None: func.handler = ( - pyrogram.PollHandler(func, self), + pyrogram.handlers.PollHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/decorators/on_raw_update.py b/pyrogram/methods/decorators/on_raw_update.py similarity index 83% rename from pyrogram/client/methods/decorators/on_raw_update.py rename to pyrogram/methods/decorators/on_raw_update.py index 749b9b54..9e3a7cd8 100644 --- a/pyrogram/client/methods/decorators/on_raw_update.py +++ b/pyrogram/methods/decorators/on_raw_update.py @@ -19,17 +19,18 @@ from typing import Callable import pyrogram -from ...ext import BaseClient +from pyrogram.scaffold import Scaffold -class OnRawUpdate(BaseClient): +class OnRawUpdate(Scaffold): def on_raw_update( self=None, group: int = 0 ) -> callable: """Decorator for handling raw updates. - This does the same thing as :meth:`~pyrogram.Client.add_handler` using the :obj:`~pyrogram.RawUpdateHandler`. + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.RawUpdateHandler`. Parameters: group (``int``, *optional*): @@ -38,10 +39,10 @@ class OnRawUpdate(BaseClient): def decorator(func: Callable) -> Callable: if isinstance(self, pyrogram.Client): - self.add_handler(pyrogram.RawUpdateHandler(func), group) + self.add_handler(pyrogram.handlers.RawUpdateHandler(func), group) else: func.handler = ( - pyrogram.RawUpdateHandler(func), + pyrogram.handlers.RawUpdateHandler(func), group if self is None else group ) diff --git a/pyrogram/client/methods/decorators/on_user_status.py b/pyrogram/methods/decorators/on_user_status.py similarity index 83% rename from pyrogram/client/methods/decorators/on_user_status.py rename to pyrogram/methods/decorators/on_user_status.py index ea09c8a4..3063ad3d 100644 --- a/pyrogram/client/methods/decorators/on_user_status.py +++ b/pyrogram/methods/decorators/on_user_status.py @@ -19,18 +19,19 @@ from typing import Callable import pyrogram -from pyrogram.client.filters.filter import Filter -from ...ext import BaseClient +from pyrogram.filters import Filter +from pyrogram.scaffold import Scaffold -class OnUserStatus(BaseClient): +class OnUserStatus(Scaffold): def on_user_status( self=None, filters=None, group: int = 0 ) -> callable: """Decorator for handling user status updates. - This does the same thing as :meth:`~pyrogram.Client.add_handler` using the :obj:`~pyrogram.UserStatusHandler`. + This does the same thing as :meth:`~pyrogram.Client.add_handler` using the + :obj:`~pyrogram.handlers.UserStatusHandler`. Parameters: filters (:obj:`~pyrogram.Filters`, *optional*): @@ -42,10 +43,10 @@ class OnUserStatus(BaseClient): def decorator(func: Callable) -> Callable: if isinstance(self, pyrogram.Client): - self.add_handler(pyrogram.UserStatusHandler(func, filters), group) + self.add_handler(pyrogram.handlers.UserStatusHandler(func, filters), group) elif isinstance(self, Filter) or self is None: func.handler = ( - pyrogram.UserStatusHandler(func, self), + pyrogram.handlers.UserStatusHandler(func, self), group if filters is None else filters ) diff --git a/pyrogram/client/methods/messages/__init__.py b/pyrogram/methods/messages/__init__.py similarity index 100% rename from pyrogram/client/methods/messages/__init__.py rename to pyrogram/methods/messages/__init__.py diff --git a/pyrogram/client/methods/messages/delete_messages.py b/pyrogram/methods/messages/delete_messages.py similarity index 86% rename from pyrogram/client/methods/messages/delete_messages.py rename to pyrogram/methods/messages/delete_messages.py index 5deb6d5a..1855ce9b 100644 --- a/pyrogram/client/methods/messages/delete_messages.py +++ b/pyrogram/methods/messages/delete_messages.py @@ -18,15 +18,15 @@ from typing import Union, Iterable -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class DeleteMessages(BaseClient): +class DeleteMessages(Scaffold): async def delete_messages( self, chat_id: Union[int, str], - message_ids: Iterable[int], + message_ids: Union[int, Iterable[int]], revoke: bool = True ) -> bool: """Delete messages, including service messages. @@ -37,8 +37,8 @@ class DeleteMessages(BaseClient): For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). - message_ids (``iterable``): - A list of Message identifiers to delete or a single message id. + message_ids (``int`` | ``Iterable[int]``): + A list of Message identifiers to delete (integers) or a single message id. Iterators and Generators are also accepted. revoke (``bool``, *optional*): @@ -65,16 +65,16 @@ class DeleteMessages(BaseClient): peer = await self.resolve_peer(chat_id) message_ids = list(message_ids) if not isinstance(message_ids, int) else [message_ids] - if isinstance(peer, types.InputPeerChannel): + if isinstance(peer, raw.types.InputPeerChannel): r = await self.send( - functions.channels.DeleteMessages( + raw.functions.channels.DeleteMessages( channel=peer, id=message_ids ) ) else: r = await self.send( - functions.messages.DeleteMessages( + raw.functions.messages.DeleteMessages( id=message_ids, revoke=revoke or None ) diff --git a/pyrogram/client/methods/messages/download_media.py b/pyrogram/methods/messages/download_media.py similarity index 84% rename from pyrogram/client/methods/messages/download_media.py rename to pyrogram/methods/messages/download_media.py index 3c1a8cbe..24092cac 100644 --- a/pyrogram/client/methods/messages/download_media.py +++ b/pyrogram/methods/messages/download_media.py @@ -22,20 +22,45 @@ import os import struct import time from datetime import datetime -from threading import Event from typing import Union -import pyrogram -from pyrogram.client.ext import BaseClient, FileData, utils +from pyrogram import types +from pyrogram import utils from pyrogram.errors import FileIdInvalid +from pyrogram.scaffold import Scaffold DEFAULT_DOWNLOAD_DIR = "downloads/" -class DownloadMedia(BaseClient): +class FileData: + def __init__( + self, *, media_type: int = None, dc_id: int = None, document_id: int = None, access_hash: int = None, + thumb_size: str = None, peer_id: int = None, peer_type: str = None, peer_access_hash: int = None, + volume_id: int = None, local_id: int = None, is_big: bool = None, file_size: int = None, mime_type: str = None, + file_name: str = None, date: int = None, file_ref: str = None + ): + self.media_type = media_type + self.dc_id = dc_id + self.document_id = document_id + self.access_hash = access_hash + self.thumb_size = thumb_size + self.peer_id = peer_id + self.peer_type = peer_type + self.peer_access_hash = peer_access_hash + self.volume_id = volume_id + self.local_id = local_id + self.is_big = is_big + self.file_size = file_size + self.mime_type = mime_type + self.file_name = file_name + self.date = date + self.file_ref = file_ref + + +class DownloadMedia(Scaffold): async def download_media( self, - message: Union["pyrogram.Message", str], + message: Union["types.Message", str], file_ref: str = None, file_name: str = DEFAULT_DOWNLOAD_DIR, block: bool = True, @@ -45,7 +70,7 @@ class DownloadMedia(BaseClient): """Download the media from a message. Parameters: - message (:obj:`Message` | ``str``): + message (:obj:`~pyrogram.types.Message` | ``str``): Pass a Message containing the media, the media itself (message.audio, message.video, ...) or the file id as string. @@ -87,7 +112,8 @@ class DownloadMedia(BaseClient): Returns: ``str`` | ``None``: On success, the absolute path of the downloaded file is returned, otherwise, in case - the download failed or was deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. + the download failed or was deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is + returned. Raises: ValueError: if the message doesn't contain any downloadable media @@ -103,7 +129,7 @@ class DownloadMedia(BaseClient): # Keep track of the progress while downloading def progress(current, total): - print("{:.1f}%".format(current * 100 / total)) + print(f"{current * 100 / total:.1f}%") app.download_media(message, progress=progress) """ @@ -115,7 +141,7 @@ class DownloadMedia(BaseClient): mime_type = None date = None - if isinstance(message, pyrogram.Message): + if isinstance(message, types.Message): for kind in available_media: media = getattr(message, kind, None) @@ -199,13 +225,10 @@ class DownloadMedia(BaseClient): access_hash=access_hash ) else: - raise ValueError("Unknown media type: {}".format(file_id_str)) + raise ValueError(f"Unknown media type: {file_id_str}") except (AssertionError, binascii.Error, struct.error): raise FileIdInvalid from None - done = asyncio.Event() - path = [None] - directory, file_name = os.path.split(file_name) file_name = file_name or data.file_name or "" @@ -239,10 +262,9 @@ class DownloadMedia(BaseClient): extension ) - # Cast to string because Path objects aren't supported by Python 3.5 - self.download_queue.put_nowait((data, str(directory), str(file_name), done, progress, progress_args, path)) + downloader = self.handle_download((data, directory, file_name, progress, progress_args)) if block: - await done.wait() - - return path[0] + return await downloader + else: + asyncio.get_event_loop().create_task(downloader) diff --git a/pyrogram/client/methods/messages/edit_inline_caption.py b/pyrogram/methods/messages/edit_inline_caption.py similarity index 89% rename from pyrogram/client/methods/messages/edit_inline_caption.py rename to pyrogram/methods/messages/edit_inline_caption.py index 335f878e..055303b4 100644 --- a/pyrogram/client/methods/messages/edit_inline_caption.py +++ b/pyrogram/methods/messages/edit_inline_caption.py @@ -18,17 +18,17 @@ from typing import Union -import pyrogram -from pyrogram.client.ext import BaseClient +from pyrogram import types +from pyrogram.scaffold import Scaffold -class EditInlineCaption(BaseClient): +class EditInlineCaption(Scaffold): async def edit_inline_caption( self, inline_message_id: str, caption: str, parse_mode: Union[str, None] = object, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None + reply_markup: "types.InlineKeyboardMarkup" = None ) -> bool: """Edit the caption of inline media messages. @@ -46,7 +46,7 @@ class EditInlineCaption(BaseClient): Pass "html" to enable HTML-style parsing only. Pass None to completely disable style parsing. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: diff --git a/pyrogram/client/methods/messages/edit_inline_media.py b/pyrogram/methods/messages/edit_inline_media.py similarity index 76% rename from pyrogram/client/methods/messages/edit_inline_media.py rename to pyrogram/methods/messages/edit_inline_media.py index 74cb2910..76b716f1 100644 --- a/pyrogram/client/methods/messages/edit_inline_media.py +++ b/pyrogram/methods/messages/edit_inline_media.py @@ -18,22 +18,18 @@ import re -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils -from pyrogram.client.types import ( - InputMediaPhoto, InputMediaVideo, InputMediaAudio, - InputMediaAnimation, InputMediaDocument -) -from pyrogram.client.types.input_media import InputMedia +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold -class EditInlineMedia(BaseClient): +class EditInlineMedia(Scaffold): async def edit_inline_media( self, inline_message_id: str, - media: InputMedia, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None + media: "types.InputMedia", + reply_markup: "types.InlineKeyboardMarkup" = None ) -> bool: """Edit inline animation, audio, document, photo or video messages. @@ -45,10 +41,10 @@ class EditInlineMedia(BaseClient): Required if *chat_id* and *message_id* are not specified. Identifier of the inline message. - media (:obj:`InputMedia`): + media (:obj:`~pyrogram.types.InputMedia`): One of the InputMedia objects describing an animation, audio, document, photo or video. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: @@ -73,44 +69,44 @@ class EditInlineMedia(BaseClient): caption = media.caption parse_mode = media.parse_mode - if isinstance(media, InputMediaPhoto): + if isinstance(media, types.InputMediaPhoto): if re.match("^https?://", media.media): - media = types.InputMediaPhotoExternal( + media = raw.types.InputMediaPhotoExternal( url=media.media ) else: media = utils.get_input_media_from_file_id(media.media, media.file_ref, 2) - elif isinstance(media, InputMediaVideo): + elif isinstance(media, types.InputMediaVideo): if re.match("^https?://", media.media): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=media.media ) else: media = utils.get_input_media_from_file_id(media.media, media.file_ref, 4) - elif isinstance(media, InputMediaAudio): + elif isinstance(media, types.InputMediaAudio): if re.match("^https?://", media.media): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=media.media ) else: media = utils.get_input_media_from_file_id(media.media, media.file_ref, 9) - elif isinstance(media, InputMediaAnimation): + elif isinstance(media, types.InputMediaAnimation): if re.match("^https?://", media.media): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=media.media ) else: media = utils.get_input_media_from_file_id(media.media, media.file_ref, 10) - elif isinstance(media, InputMediaDocument): + elif isinstance(media, types.InputMediaDocument): if re.match("^https?://", media.media): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=media.media ) else: media = utils.get_input_media_from_file_id(media.media, media.file_ref, 5) return await self.send( - functions.messages.EditInlineBotMessage( + raw.functions.messages.EditInlineBotMessage( id=utils.unpack_inline_message_id(inline_message_id), media=media, reply_markup=reply_markup.write() if reply_markup else None, diff --git a/pyrogram/client/methods/messages/edit_inline_reply_markup.py b/pyrogram/methods/messages/edit_inline_reply_markup.py similarity index 83% rename from pyrogram/client/methods/messages/edit_inline_reply_markup.py rename to pyrogram/methods/messages/edit_inline_reply_markup.py index f5381806..5d1b2463 100644 --- a/pyrogram/client/methods/messages/edit_inline_reply_markup.py +++ b/pyrogram/methods/messages/edit_inline_reply_markup.py @@ -16,16 +16,17 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import pyrogram -from pyrogram.api import functions -from pyrogram.client.ext import BaseClient, utils +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold -class EditInlineReplyMarkup(BaseClient): +class EditInlineReplyMarkup(Scaffold): async def edit_inline_reply_markup( self, inline_message_id: str, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None + reply_markup: "types.InlineKeyboardMarkup" = None ) -> bool: """Edit only the reply markup of inline messages sent via the bot (for inline bots). @@ -33,7 +34,7 @@ class EditInlineReplyMarkup(BaseClient): inline_message_id (``str``): Identifier of the inline message. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: @@ -51,7 +52,7 @@ class EditInlineReplyMarkup(BaseClient): InlineKeyboardButton("New button", callback_data="new_data")]])) """ return await self.send( - functions.messages.EditInlineBotMessage( + raw.functions.messages.EditInlineBotMessage( id=utils.unpack_inline_message_id(inline_message_id), reply_markup=reply_markup.write() if reply_markup else None, ) diff --git a/pyrogram/client/methods/messages/edit_inline_text.py b/pyrogram/methods/messages/edit_inline_text.py similarity index 88% rename from pyrogram/client/methods/messages/edit_inline_text.py rename to pyrogram/methods/messages/edit_inline_text.py index cfdd232b..ebb2f91a 100644 --- a/pyrogram/client/methods/messages/edit_inline_text.py +++ b/pyrogram/methods/messages/edit_inline_text.py @@ -18,19 +18,20 @@ from typing import Union -import pyrogram -from pyrogram.api import functions -from pyrogram.client.ext import BaseClient, utils +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold -class EditInlineText(BaseClient): +class EditInlineText(Scaffold): async def edit_inline_text( self, inline_message_id: str, text: str, parse_mode: Union[str, None] = object, disable_web_page_preview: bool = None, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None + reply_markup: "types.InlineKeyboardMarkup" = None ) -> bool: """Edit the text of inline messages. @@ -51,7 +52,7 @@ class EditInlineText(BaseClient): disable_web_page_preview (``bool``, *optional*): Disables link previews for links in this message. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: @@ -72,7 +73,7 @@ class EditInlineText(BaseClient): """ return await self.send( - functions.messages.EditInlineBotMessage( + raw.functions.messages.EditInlineBotMessage( id=utils.unpack_inline_message_id(inline_message_id), no_webpage=disable_web_page_preview or None, reply_markup=reply_markup.write() if reply_markup else None, diff --git a/pyrogram/client/methods/messages/edit_message_caption.py b/pyrogram/methods/messages/edit_message_caption.py similarity index 87% rename from pyrogram/client/methods/messages/edit_message_caption.py rename to pyrogram/methods/messages/edit_message_caption.py index 01bd8147..76b6cc48 100644 --- a/pyrogram/client/methods/messages/edit_message_caption.py +++ b/pyrogram/methods/messages/edit_message_caption.py @@ -18,19 +18,19 @@ from typing import Union -import pyrogram -from pyrogram.client.ext import BaseClient +from pyrogram import types +from pyrogram.scaffold import Scaffold -class EditMessageCaption(BaseClient): +class EditMessageCaption(Scaffold): async def edit_message_caption( self, chat_id: Union[int, str], message_id: int, caption: str, parse_mode: Union[str, None] = object, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None - ) -> "pyrogram.Message": + reply_markup: "types.InlineKeyboardMarkup" = None + ) -> "types.Message": """Edit the caption of media messages. Parameters: @@ -52,11 +52,11 @@ class EditMessageCaption(BaseClient): Pass "html" to enable HTML-style parsing only. Pass None to completely disable style parsing. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - :obj:`Message`: On success, the edited message is returned. + :obj:`~pyrogram.types.Message`: On success, the edited message is returned. Example: .. code-block:: python diff --git a/pyrogram/client/methods/messages/edit_message_media.py b/pyrogram/methods/messages/edit_message_media.py similarity index 74% rename from pyrogram/client/methods/messages/edit_message_media.py rename to pyrogram/methods/messages/edit_message_media.py index 765c1598..5733c5bd 100644 --- a/pyrogram/client/methods/messages/edit_message_media.py +++ b/pyrogram/methods/messages/edit_message_media.py @@ -20,25 +20,21 @@ import os import re from typing import Union -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils -from pyrogram.client.types import ( - InputMediaPhoto, InputMediaVideo, InputMediaAudio, - InputMediaAnimation, InputMediaDocument -) -from pyrogram.client.types.input_media import InputMedia +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold -class EditMessageMedia(BaseClient): +class EditMessageMedia(Scaffold): async def edit_message_media( self, chat_id: Union[int, str], message_id: int, - media: InputMedia, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None, + media: "types.InputMedia", + reply_markup: "types.InlineKeyboardMarkup" = None, file_name: str = None - ) -> "pyrogram.Message": + ) -> "types.Message": """Edit animation, audio, document, photo or video messages. If a message is a part of a message album, then it can be edited only to a photo or a video. Otherwise, the @@ -53,10 +49,10 @@ class EditMessageMedia(BaseClient): message_id (``int``): Message identifier in the chat specified in chat_id. - media (:obj:`InputMedia`): + media (:obj:`~pyrogram.types.InputMedia`): One of the InputMedia objects describing an animation, audio, document, photo or video. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. file_name (``str``, *optional*): @@ -64,7 +60,7 @@ class EditMessageMedia(BaseClient): Defaults to file's path basename. Returns: - :obj:`Message`: On success, the edited message is returned. + :obj:`~pyrogram.types.Message`: On success, the edited message is returned. Example: .. code-block:: python @@ -83,47 +79,47 @@ class EditMessageMedia(BaseClient): caption = media.caption parse_mode = media.parse_mode - if isinstance(media, InputMediaPhoto): + if isinstance(media, types.InputMediaPhoto): if os.path.isfile(media.media): media = await self.send( - functions.messages.UploadMedia( + raw.functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaUploadedPhoto( + media=raw.types.InputMediaUploadedPhoto( file=await self.save_file(media.media) ) ) ) - media = types.InputMediaPhoto( - id=types.InputPhoto( + media = raw.types.InputMediaPhoto( + id=raw.types.InputPhoto( id=media.photo.id, access_hash=media.photo.access_hash, file_reference=media.photo.file_reference ) ) elif re.match("^https?://", media.media): - media = types.InputMediaPhotoExternal( + media = raw.types.InputMediaPhotoExternal( url=media.media ) else: media = utils.get_input_media_from_file_id(media.media, media.file_ref, 2) - elif isinstance(media, InputMediaVideo): + elif isinstance(media, types.InputMediaVideo): if os.path.isfile(media.media): media = await self.send( - functions.messages.UploadMedia( + raw.functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaUploadedDocument( + media=raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(media.media) or "video/mp4", thumb=await self.save_file(media.thumb), file=await self.save_file(media.media), attributes=[ - types.DocumentAttributeVideo( + raw.types.DocumentAttributeVideo( supports_streaming=media.supports_streaming or None, duration=media.duration, w=media.width, h=media.height ), - types.DocumentAttributeFilename( + raw.types.DocumentAttributeFilename( file_name=file_name or os.path.basename(media.media) ) ] @@ -131,35 +127,35 @@ class EditMessageMedia(BaseClient): ) ) - media = types.InputMediaDocument( - id=types.InputDocument( + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=media.document.file_reference ) ) elif re.match("^https?://", media.media): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=media.media ) else: media = utils.get_input_media_from_file_id(media.media, media.file_ref, 4) - elif isinstance(media, InputMediaAudio): + elif isinstance(media, types.InputMediaAudio): if os.path.isfile(media.media): media = await self.send( - functions.messages.UploadMedia( + raw.functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaUploadedDocument( + media=raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(media.media) or "audio/mpeg", thumb=await self.save_file(media.thumb), file=await self.save_file(media.media), attributes=[ - types.DocumentAttributeAudio( + raw.types.DocumentAttributeAudio( duration=media.duration, performer=media.performer, title=media.title ), - types.DocumentAttributeFilename( + raw.types.DocumentAttributeFilename( file_name=file_name or os.path.basename(media.media) ) ] @@ -167,68 +163,68 @@ class EditMessageMedia(BaseClient): ) ) - media = types.InputMediaDocument( - id=types.InputDocument( + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=media.document.file_reference ) ) elif re.match("^https?://", media.media): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=media.media ) else: media = utils.get_input_media_from_file_id(media.media, media.file_ref, 9) - elif isinstance(media, InputMediaAnimation): + elif isinstance(media, types.InputMediaAnimation): if os.path.isfile(media.media): media = await self.send( - functions.messages.UploadMedia( + raw.functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaUploadedDocument( + media=raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(media.media) or "video/mp4", - thumb=self.save_file(media.thumb), + thumb=await self.save_file(media.thumb), file=await self.save_file(media.media), attributes=[ - types.DocumentAttributeVideo( + raw.types.DocumentAttributeVideo( supports_streaming=True, duration=media.duration, w=media.width, h=media.height ), - types.DocumentAttributeFilename( + raw.types.DocumentAttributeFilename( file_name=file_name or os.path.basename(media.media) ), - types.DocumentAttributeAnimated() + raw.types.DocumentAttributeAnimated() ] ) ) ) - media = types.InputMediaDocument( - id=types.InputDocument( + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=media.document.file_reference ) ) elif re.match("^https?://", media.media): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=media.media ) else: media = utils.get_input_media_from_file_id(media.media, media.file_ref, 10) - elif isinstance(media, InputMediaDocument): + elif isinstance(media, types.InputMediaDocument): if os.path.isfile(media.media): media = await self.send( - functions.messages.UploadMedia( + raw.functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaUploadedDocument( + media=raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(media.media) or "application/zip", thumb=await self.save_file(media.thumb), file=await self.save_file(media.media), attributes=[ - types.DocumentAttributeFilename( + raw.types.DocumentAttributeFilename( file_name=file_name or os.path.basename(media.media) ) ] @@ -236,22 +232,22 @@ class EditMessageMedia(BaseClient): ) ) - media = types.InputMediaDocument( - id=types.InputDocument( + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=media.document.file_reference ) ) elif re.match("^https?://", media.media): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=media.media ) else: media = utils.get_input_media_from_file_id(media.media, media.file_ref, 5) r = await self.send( - functions.messages.EditMessage( + raw.functions.messages.EditMessage( peer=await self.resolve_peer(chat_id), id=message_id, media=media, @@ -261,8 +257,8 @@ class EditMessageMedia(BaseClient): ) for i in r.updates: - if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateEditMessage, raw.types.UpdateEditChannelMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats} diff --git a/pyrogram/client/methods/messages/edit_message_reply_markup.py b/pyrogram/methods/messages/edit_message_reply_markup.py similarity index 79% rename from pyrogram/client/methods/messages/edit_message_reply_markup.py rename to pyrogram/methods/messages/edit_message_reply_markup.py index 65fa26e2..43d870ad 100644 --- a/pyrogram/client/methods/messages/edit_message_reply_markup.py +++ b/pyrogram/methods/messages/edit_message_reply_markup.py @@ -18,18 +18,18 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class EditMessageReplyMarkup(BaseClient): +class EditMessageReplyMarkup(Scaffold): async def edit_message_reply_markup( self, chat_id: Union[int, str], message_id: int, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None, - ) -> "pyrogram.Message": + reply_markup: "types.InlineKeyboardMarkup" = None, + ) -> "types.Message": """Edit only the reply markup of messages sent by the bot. Parameters: @@ -41,11 +41,11 @@ class EditMessageReplyMarkup(BaseClient): message_id (``int``): Message identifier in the chat specified in chat_id. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - :obj:`Message`: On success, the edited message is returned. + :obj:`~pyrogram.types.Message`: On success, the edited message is returned. Example: .. code-block:: python @@ -59,7 +59,7 @@ class EditMessageReplyMarkup(BaseClient): InlineKeyboardButton("New button", callback_data="new_data")]])) """ r = await self.send( - functions.messages.EditMessage( + raw.functions.messages.EditMessage( peer=await self.resolve_peer(chat_id), id=message_id, reply_markup=reply_markup.write() if reply_markup else None, @@ -67,8 +67,8 @@ class EditMessageReplyMarkup(BaseClient): ) for i in r.updates: - if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateEditMessage, raw.types.UpdateEditChannelMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats} diff --git a/pyrogram/client/methods/messages/edit_message_text.py b/pyrogram/methods/messages/edit_message_text.py similarity index 84% rename from pyrogram/client/methods/messages/edit_message_text.py rename to pyrogram/methods/messages/edit_message_text.py index a2b43f16..b7d84830 100644 --- a/pyrogram/client/methods/messages/edit_message_text.py +++ b/pyrogram/methods/messages/edit_message_text.py @@ -18,12 +18,12 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class EditMessageText(BaseClient): +class EditMessageText(Scaffold): async def edit_message_text( self, chat_id: Union[int, str], @@ -31,8 +31,8 @@ class EditMessageText(BaseClient): text: str, parse_mode: Union[str, None] = object, disable_web_page_preview: bool = None, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None - ) -> "pyrogram.Message": + reply_markup: "types.InlineKeyboardMarkup" = None + ) -> "types.Message": """Edit the text of messages. Parameters: @@ -57,11 +57,11 @@ class EditMessageText(BaseClient): disable_web_page_preview (``bool``, *optional*): Disables link previews for links in this message. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - :obj:`Message`: On success, the edited message is returned. + :obj:`~pyrogram.types.Message`: On success, the edited message is returned. Example: .. code-block:: python @@ -76,7 +76,7 @@ class EditMessageText(BaseClient): """ r = await self.send( - functions.messages.EditMessage( + raw.functions.messages.EditMessage( peer=await self.resolve_peer(chat_id), id=message_id, no_webpage=disable_web_page_preview or None, @@ -86,8 +86,8 @@ class EditMessageText(BaseClient): ) for i in r.updates: - if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateEditMessage, raw.types.UpdateEditChannelMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats} diff --git a/pyrogram/client/methods/messages/forward_messages.py b/pyrogram/methods/messages/forward_messages.py similarity index 83% rename from pyrogram/client/methods/messages/forward_messages.py rename to pyrogram/methods/messages/forward_messages.py index c7f47a52..5287a4ce 100644 --- a/pyrogram/client/methods/messages/forward_messages.py +++ b/pyrogram/methods/messages/forward_messages.py @@ -18,13 +18,12 @@ from typing import Union, Iterable, List -import pyrogram -from pyrogram.api import functions, types - -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class ForwardMessages(BaseClient): +class ForwardMessages(Scaffold): async def forward_messages( self, chat_id: Union[int, str], @@ -34,7 +33,7 @@ class ForwardMessages(BaseClient): as_copy: bool = False, remove_caption: bool = False, schedule_date: int = None - ) -> List["pyrogram.Message"]: + ) -> List["types.Message"]: """Forward messages of any kind. Parameters: @@ -70,9 +69,9 @@ class ForwardMessages(BaseClient): Date when the message will be automatically sent. Unix time. Returns: - :obj:`Message` | List of :obj:`Message`: In case *message_ids* was an integer, the single forwarded message - is returned, otherwise, in case *message_ids* was an iterable, the returned value will be a list of - messages, even if such iterable contained just a single element. + :obj:`~pyrogram.types.Message` | List of :obj:`~pyrogram.types.Message`: In case *message_ids* was an + integer, the single forwarded message is returned, otherwise, in case *message_ids* was an iterable, + the returned value will be a list of messages, even if such iterable contained just a single element. Example: .. code-block:: python @@ -108,10 +107,10 @@ class ForwardMessages(BaseClient): ) ) - return pyrogram.List(forwarded_messages) if is_iterable else forwarded_messages[0] + return types.List(forwarded_messages) if is_iterable else forwarded_messages[0] else: r = await self.send( - functions.messages.ForwardMessages( + raw.functions.messages.ForwardMessages( to_peer=await self.resolve_peer(chat_id), from_peer=await self.resolve_peer(from_chat_id), id=message_ids, @@ -127,12 +126,14 @@ class ForwardMessages(BaseClient): chats = {i.id: i for i in r.chats} for i in r.updates: - if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): forwarded_messages.append( - await pyrogram.Message._parse( + await types.Message._parse( self, i.message, users, chats ) ) - return pyrogram.List(forwarded_messages) if is_iterable else forwarded_messages[0] + return types.List(forwarded_messages) if is_iterable else forwarded_messages[0] diff --git a/pyrogram/client/methods/messages/get_history.py b/pyrogram/methods/messages/get_history.py similarity index 90% rename from pyrogram/client/methods/messages/get_history.py rename to pyrogram/methods/messages/get_history.py index 92a84d9b..00c9f435 100644 --- a/pyrogram/client/methods/messages/get_history.py +++ b/pyrogram/methods/messages/get_history.py @@ -16,19 +16,18 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import asyncio import logging from typing import Union, List -import pyrogram -from pyrogram.api import functions -from pyrogram.client.ext import utils -from ...ext import BaseClient +from pyrogram import raw +# from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold log = logging.getLogger(__name__) -class GetHistory(BaseClient): +class GetHistory(Scaffold): async def get_history( self, chat_id: Union[int, str], @@ -37,11 +36,11 @@ class GetHistory(BaseClient): offset_id: int = 0, offset_date: int = 0, reverse: bool = False - ) -> List["pyrogram.Message"]: + ) -> List["types.Message"]: """Retrieve a chunk of the history of a chat. You can get up to 100 messages at once. - For a more convenient way of getting a chat history see :meth:`~Client.iter_history`. + For a more convenient way of getting a chat history see :meth:`~pyrogram.Client.iter_history`. Parameters: chat_id (``int`` | ``str``): @@ -67,7 +66,7 @@ class GetHistory(BaseClient): Pass True to retrieve the messages in reversed order (from older to most recent). Returns: - List of :obj:`Message` - On success, a list of the retrieved messages is returned. + List of :obj:`~pyrogram.types.Message` - On success, a list of the retrieved messages is returned. Example: .. code-block:: python @@ -87,7 +86,7 @@ class GetHistory(BaseClient): messages = await utils.parse_messages( self, await self.send( - functions.messages.GetHistory( + raw.functions.messages.GetHistory( peer=await self.resolve_peer(chat_id), offset_id=offset_id, offset_date=offset_date, diff --git a/pyrogram/client/methods/messages/get_history_count.py b/pyrogram/methods/messages/get_history_count.py similarity index 90% rename from pyrogram/client/methods/messages/get_history_count.py rename to pyrogram/methods/messages/get_history_count.py index d7476f95..e08bf027 100644 --- a/pyrogram/client/methods/messages/get_history_count.py +++ b/pyrogram/methods/messages/get_history_count.py @@ -19,13 +19,13 @@ import logging from typing import Union -from pyrogram.api import types, functions -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold log = logging.getLogger(__name__) -class GetHistoryCount(BaseClient): +class GetHistoryCount(Scaffold): async def get_history_count( self, chat_id: Union[int, str] @@ -52,7 +52,7 @@ class GetHistoryCount(BaseClient): """ r = await self.send( - functions.messages.GetHistory( + raw.functions.messages.GetHistory( peer=await self.resolve_peer(chat_id), offset_id=0, offset_date=0, @@ -64,7 +64,7 @@ class GetHistoryCount(BaseClient): ) ) - if isinstance(r, types.messages.Messages): + if isinstance(r, raw.types.messages.Messages): return len(r.messages) else: return r.count diff --git a/pyrogram/client/methods/messages/get_messages.py b/pyrogram/methods/messages/get_messages.py similarity index 81% rename from pyrogram/client/methods/messages/get_messages.py rename to pyrogram/methods/messages/get_messages.py index b4199b30..d99bcb2f 100644 --- a/pyrogram/client/methods/messages/get_messages.py +++ b/pyrogram/methods/messages/get_messages.py @@ -16,13 +16,13 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import asyncio import logging from typing import Union, Iterable, List -import pyrogram -from pyrogram.api import functions, types -from ...ext import BaseClient, utils +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold log = logging.getLogger(__name__) @@ -30,14 +30,14 @@ log = logging.getLogger(__name__) # TODO: Rewrite using a flag for replied messages and have message_ids non-optional -class GetMessages(BaseClient): +class GetMessages(Scaffold): async def get_messages( self, chat_id: Union[int, str], message_ids: Union[int, Iterable[int]] = None, reply_to_message_ids: Union[int, Iterable[int]] = None, replies: int = 1 - ) -> Union["pyrogram.Message", List["pyrogram.Message"]]: + ) -> Union["types.Message", List["types.Message"]]: """Get one or more messages from a chat by using message identifiers. You can retrieve up to 200 messages at once. @@ -63,9 +63,9 @@ class GetMessages(BaseClient): Defaults to 1. Returns: - :obj:`Message` | List of :obj:`Message`: In case *message_ids* was an integer, the single requested message is - returned, otherwise, in case *message_ids* was an iterable, the returned value will be a list of messages, - even if such iterable contained just a single element. + :obj:`~pyrogram.types.Message` | List of :obj:`~pyrogram.types.Message`: In case *message_ids* was an + integer, the single requested message is returned, otherwise, in case *message_ids* was an iterable, the + returned value will be a list of messages, even if such iterable contained just a single element. Example: .. code-block:: python @@ -89,8 +89,8 @@ class GetMessages(BaseClient): ValueError: In case of invalid arguments. """ ids, ids_type = ( - (message_ids, types.InputMessageID) if message_ids - else (reply_to_message_ids, types.InputMessageReplyTo) if reply_to_message_ids + (message_ids, raw.types.InputMessageID) if message_ids + else (reply_to_message_ids, raw.types.InputMessageReplyTo) if reply_to_message_ids else (None, None) ) @@ -106,10 +106,10 @@ class GetMessages(BaseClient): if replies < 0: replies = (1 << 31) - 1 - if isinstance(peer, types.InputPeerChannel): - rpc = functions.channels.GetMessages(channel=peer, id=ids) + if isinstance(peer, raw.types.InputPeerChannel): + rpc = raw.functions.channels.GetMessages(channel=peer, id=ids) else: - rpc = functions.messages.GetMessages(id=ids) + rpc = raw.functions.messages.GetMessages(id=ids) r = await self.send(rpc) diff --git a/pyrogram/client/methods/messages/iter_history.py b/pyrogram/methods/messages/iter_history.py similarity index 88% rename from pyrogram/client/methods/messages/iter_history.py rename to pyrogram/methods/messages/iter_history.py index 04c7dc1a..6bd3d581 100644 --- a/pyrogram/client/methods/messages/iter_history.py +++ b/pyrogram/methods/messages/iter_history.py @@ -16,16 +16,13 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import Union, Optional, Generator +from typing import Union, Optional, AsyncGenerator -import pyrogram -from async_generator import async_generator, yield_ - -from ...ext import BaseClient +from pyrogram import types +from pyrogram.scaffold import Scaffold -class IterHistory(BaseClient): - @async_generator +class IterHistory(Scaffold): async def iter_history( self, chat_id: Union[int, str], @@ -34,10 +31,10 @@ class IterHistory(BaseClient): offset_id: int = 0, offset_date: int = 0, reverse: bool = False - ) -> Optional[Generator["pyrogram.Message", None, None]]: + ) -> Optional[AsyncGenerator["types.Message", None]]: """Iterate through a chat history sequentially. - This convenience method does the same as repeatedly calling :meth:`~Client.get_history` in a loop, thus saving + This convenience method does the same as repeatedly calling :meth:`~pyrogram.Client.get_history` in a loop, thus saving you from the hassle of setting up boilerplate code. It is useful for getting the whole chat history with a single call. @@ -65,7 +62,7 @@ class IterHistory(BaseClient): Pass True to retrieve the messages in reversed order (from older to most recent). Returns: - ``Generator``: A generator yielding :obj:`Message` objects. + ``Generator``: A generator yielding :obj:`~pyrogram.types.Message` objects. Example: .. code-block:: python @@ -94,7 +91,7 @@ class IterHistory(BaseClient): offset_id = messages[-1].message_id + (1 if reverse else 0) for message in messages: - await yield_(message) + yield message current += 1 diff --git a/pyrogram/client/methods/messages/read_history.py b/pyrogram/methods/messages/read_history.py similarity index 89% rename from pyrogram/client/methods/messages/read_history.py rename to pyrogram/methods/messages/read_history.py index 5e1e265b..15f09128 100644 --- a/pyrogram/client/methods/messages/read_history.py +++ b/pyrogram/methods/messages/read_history.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class ReadHistory(BaseClient): +class ReadHistory(Scaffold): async def read_history( self, chat_id: Union[int, str], @@ -55,13 +55,13 @@ class ReadHistory(BaseClient): peer = await self.resolve_peer(chat_id) - if isinstance(peer, types.InputPeerChannel): - q = functions.channels.ReadHistory( + if isinstance(peer, raw.types.InputPeerChannel): + q = raw.functions.channels.ReadHistory( channel=peer, max_id=max_id ) else: - q = functions.messages.ReadHistory( + q = raw.functions.messages.ReadHistory( peer=peer, max_id=max_id ) diff --git a/pyrogram/client/methods/messages/retract_vote.py b/pyrogram/methods/messages/retract_vote.py similarity index 83% rename from pyrogram/client/methods/messages/retract_vote.py rename to pyrogram/methods/messages/retract_vote.py index 191c8c75..add319c7 100644 --- a/pyrogram/client/methods/messages/retract_vote.py +++ b/pyrogram/methods/messages/retract_vote.py @@ -18,17 +18,17 @@ from typing import Union -import pyrogram -from pyrogram.api import functions -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class RetractVote(BaseClient): +class RetractVote(Scaffold): async def retract_vote( self, chat_id: Union[int, str], message_id: int - ) -> "pyrogram.Poll": + ) -> "types.Poll": """Retract your vote in a poll. Parameters: @@ -41,7 +41,7 @@ class RetractVote(BaseClient): Identifier of the original message with the poll. Returns: - :obj:`Poll`: On success, the poll with the retracted vote is returned. + :obj:`~pyrogram.types.Poll`: On success, the poll with the retracted vote is returned. Example: .. code-block:: python @@ -49,11 +49,11 @@ class RetractVote(BaseClient): app.retract_vote(chat_id, message_id) """ r = await self.send( - functions.messages.SendVote( + raw.functions.messages.SendVote( peer=await self.resolve_peer(chat_id), msg_id=message_id, options=[] ) ) - return pyrogram.Poll._parse(self, r.updates[0]) + return types.Poll._parse(self, r.updates[0]) diff --git a/pyrogram/client/methods/messages/search_global.py b/pyrogram/methods/messages/search_global.py similarity index 83% rename from pyrogram/client/methods/messages/search_global.py rename to pyrogram/methods/messages/search_global.py index 2a889e31..60c0c752 100644 --- a/pyrogram/client/methods/messages/search_global.py +++ b/pyrogram/methods/messages/search_global.py @@ -16,22 +16,20 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import Generator, Optional +from typing import AsyncGenerator, Optional -from async_generator import async_generator, yield_ - -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold -class SearchGlobal(BaseClient): - @async_generator +class SearchGlobal(Scaffold): async def search_global( self, query: str, limit: int = 0, - ) -> Optional[Generator["pyrogram.Message", None, None]]: + ) -> Optional[AsyncGenerator["types.Message", None]]: """Search messages globally from all of your chats. .. note:: @@ -48,7 +46,7 @@ class SearchGlobal(BaseClient): By default, no limit is applied and all messages are returned. Returns: - ``Generator``: A generator yielding :obj:`Message` objects. + ``Generator``: A generator yielding :obj:`~pyrogram.types.Message` objects. Example: .. code-block:: python @@ -63,14 +61,14 @@ class SearchGlobal(BaseClient): limit = min(100, total) offset_date = 0 - offset_peer = types.InputPeerEmpty() + offset_peer = raw.types.InputPeerEmpty() offset_id = 0 while True: messages = await utils.parse_messages( self, await self.send( - functions.messages.SearchGlobal( + raw.functions.messages.SearchGlobal( q=query, offset_rate=offset_date, offset_peer=offset_peer, @@ -91,7 +89,7 @@ class SearchGlobal(BaseClient): offset_id = last.message_id for message in messages: - await yield_(message) + yield message current += 1 diff --git a/pyrogram/client/methods/messages/search_messages.py b/pyrogram/methods/messages/search_messages.py similarity index 80% rename from pyrogram/client/methods/messages/search_messages.py rename to pyrogram/methods/messages/search_messages.py index bfd56663..44132dce 100644 --- a/pyrogram/client/methods/messages/search_messages.py +++ b/pyrogram/methods/messages/search_messages.py @@ -16,31 +16,31 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import Union, List, Generator, Optional +from typing import Union, List, AsyncGenerator, Optional -import pyrogram -from pyrogram.client.ext import BaseClient, utils -from pyrogram.api import functions, types -from async_generator import async_generator, yield_ +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold class Filters: - EMPTY = types.InputMessagesFilterEmpty() - PHOTO = types.InputMessagesFilterPhotos() - VIDEO = types.InputMessagesFilterVideo() - PHOTO_VIDEO = types.InputMessagesFilterPhotoVideo() - DOCUMENT = types.InputMessagesFilterDocument() - URL = types.InputMessagesFilterUrl() - ANIMATION = types.InputMessagesFilterGif() - VOICE_NOTE = types.InputMessagesFilterVoice() - AUDIO = types.InputMessagesFilterMusic() - CHAT_PHOTO = types.InputMessagesFilterChatPhotos() - PHONE_CALL = types.InputMessagesFilterPhoneCalls() - AUDIO_VIDEO_NOTE = types.InputMessagesFilterRoundVideo() - VIDEO_NOTE = types.InputMessagesFilterRoundVideo() - MENTION = types.InputMessagesFilterMyMentions() - LOCATION = types.InputMessagesFilterGeo() - CONTACT = types.InputMessagesFilterContacts() + EMPTY = raw.types.InputMessagesFilterEmpty() + PHOTO = raw.types.InputMessagesFilterPhotos() + VIDEO = raw.types.InputMessagesFilterVideo() + PHOTO_VIDEO = raw.types.InputMessagesFilterPhotoVideo() + DOCUMENT = raw.types.InputMessagesFilterDocument() + URL = raw.types.InputMessagesFilterUrl() + ANIMATION = raw.types.InputMessagesFilterGif() + VOICE_NOTE = raw.types.InputMessagesFilterVoice() + AUDIO = raw.types.InputMessagesFilterMusic() + CHAT_PHOTO = raw.types.InputMessagesFilterChatPhotos() + PHONE_CALL = raw.types.InputMessagesFilterPhoneCalls() + AUDIO_VIDEO_NOTE = raw.types.InputMessagesFilterRoundVideo() + VIDEO_NOTE = raw.types.InputMessagesFilterRoundVideo() + MENTION = raw.types.InputMessagesFilterMyMentions() + LOCATION = raw.types.InputMessagesFilterGeo() + CONTACT = raw.types.InputMessagesFilterContacts() POSSIBLE_VALUES = list(map(lambda x: x.lower(), filter(lambda x: not x.startswith("__"), Filters.__dict__.keys()))) @@ -48,22 +48,22 @@ POSSIBLE_VALUES = list(map(lambda x: x.lower(), filter(lambda x: not x.startswit # noinspection PyShadowingBuiltins async def get_chunk( - client: BaseClient, + client: Scaffold, chat_id: Union[int, str], query: str = "", filter: str = "empty", offset: int = 0, limit: int = 100, from_user: Union[int, str] = None -) -> List["pyrogram.Message"]: +) -> List["types.Message"]: try: filter = Filters.__dict__[filter.upper()] except KeyError: raise ValueError('Invalid filter "{}". Possible values are: {}'.format( - filter, ", ".join('"{}"'.format(v) for v in POSSIBLE_VALUES))) from None + filter, ", ".join(f'"{v}"' for v in POSSIBLE_VALUES))) from None r = await client.send( - functions.messages.Search( + raw.functions.messages.Search( peer=await client.resolve_peer(chat_id), q=query, filter=filter, @@ -86,9 +86,8 @@ async def get_chunk( return await utils.parse_messages(client, r) -class SearchMessages(BaseClient): +class SearchMessages(Scaffold): # noinspection PyShadowingBuiltins - @async_generator async def search_messages( self, chat_id: Union[int, str], @@ -97,7 +96,7 @@ class SearchMessages(BaseClient): filter: str = "empty", limit: int = 0, from_user: Union[int, str] = None - ) -> Optional[Generator["pyrogram.Message", None, None]]: + ) -> Optional[AsyncGenerator["types.Message", None]]: """Search for text and media messages inside a specific chat. Parameters: @@ -144,7 +143,7 @@ class SearchMessages(BaseClient): Unique identifier (int) or username (str) of the target user you want to search for messages from. Returns: - ``Generator``: A generator yielding :obj:`Message` objects. + ``Generator``: A generator yielding :obj:`~pyrogram.types.Message` objects. Example: .. code-block:: python @@ -178,7 +177,7 @@ class SearchMessages(BaseClient): offset += 100 for message in messages: - await yield_(message) + yield message current += 1 diff --git a/pyrogram/client/methods/messages/send_animation.py b/pyrogram/methods/messages/send_animation.py similarity index 82% rename from pyrogram/client/methods/messages/send_animation.py rename to pyrogram/methods/messages/send_animation.py index 46562214..9851c11b 100644 --- a/pyrogram/client/methods/messages/send_animation.py +++ b/pyrogram/methods/messages/send_animation.py @@ -20,13 +20,15 @@ import os import re from typing import Union, BinaryIO -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils +from pyrogram import StopTransmission +from pyrogram import raw +from pyrogram import types +from pyrogram import utils from pyrogram.errors import FilePartMissing +from pyrogram.scaffold import Scaffold -class SendAnimation(BaseClient): +class SendAnimation(Scaffold): async def send_animation( self, chat_id: Union[int, str], @@ -44,14 +46,14 @@ class SendAnimation(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () - ) -> Union["pyrogram.Message", None]: + ) -> Union["types.Message", None]: """Send animation files (animation or H.264/MPEG-4 AVC video without sound). Parameters: @@ -114,7 +116,7 @@ class SendAnimation(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -141,8 +143,9 @@ class SendAnimation(BaseClient): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - :obj:`Message` | ``None``: On success, the sent animation message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. + :obj:`~pyrogram.types.Message` | ``None``: On success, the sent animation message is returned, otherwise, + in case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is + returned. Example: .. code-block:: python @@ -158,7 +161,7 @@ class SendAnimation(BaseClient): # Keep track of the progress while uploading def progress(current, total): - print("{:.1f}%".format(current * 100 / total)) + print(f"{current * 100 / total:.1f}%") app.send_animation("me", "animation.gif", progress=progress) """ @@ -169,23 +172,23 @@ class SendAnimation(BaseClient): if os.path.isfile(animation): thumb = await self.save_file(thumb) file = await self.save_file(animation, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(animation) or "video/mp4", file=file, thumb=thumb, attributes=[ - types.DocumentAttributeVideo( + raw.types.DocumentAttributeVideo( supports_streaming=True, duration=duration, w=width, h=height ), - types.DocumentAttributeFilename(file_name=file_name or os.path.basename(animation)), - types.DocumentAttributeAnimated() + raw.types.DocumentAttributeFilename(file_name=file_name or os.path.basename(animation)), + raw.types.DocumentAttributeAnimated() ] ) elif re.match("^https?://", animation): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=animation ) else: @@ -193,26 +196,26 @@ class SendAnimation(BaseClient): else: thumb = await self.save_file(thumb) file = await self.save_file(animation, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(animation.name) or "video/mp4", file=file, thumb=thumb, attributes=[ - types.DocumentAttributeVideo( + raw.types.DocumentAttributeVideo( supports_streaming=True, duration=duration, w=width, h=height ), - types.DocumentAttributeFilename(file_name=animation.name), - types.DocumentAttributeAnimated() + raw.types.DocumentAttributeFilename(file_name=animation.name), + raw.types.DocumentAttributeAnimated() ] ) while True: try: r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=media, silent=disable_notification or None, @@ -227,15 +230,14 @@ class SendAnimation(BaseClient): await self.save_file(animation, file_id=file.id, file_part=e.x) else: for i in r.updates: - if isinstance( - i, - (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage) - ): - message = await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + message = await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) if unsave: @@ -243,7 +245,7 @@ class SendAnimation(BaseClient): document_id = utils.get_input_media_from_file_id(document.file_id, document.file_ref).id await self.send( - functions.messages.SaveGif( + raw.functions.messages.SaveGif( id=document_id, unsave=True ) @@ -251,5 +253,5 @@ class SendAnimation(BaseClient): return message - except BaseClient.StopTransmission: + except StopTransmission: return None diff --git a/pyrogram/client/methods/messages/send_audio.py b/pyrogram/methods/messages/send_audio.py similarity index 82% rename from pyrogram/client/methods/messages/send_audio.py rename to pyrogram/methods/messages/send_audio.py index dc460e97..fc5213cc 100644 --- a/pyrogram/client/methods/messages/send_audio.py +++ b/pyrogram/methods/messages/send_audio.py @@ -20,13 +20,15 @@ import os import re from typing import Union, BinaryIO -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils +from pyrogram import StopTransmission +from pyrogram import raw +from pyrogram import types +from pyrogram import utils from pyrogram.errors import FilePartMissing +from pyrogram.scaffold import Scaffold -class SendAudio(BaseClient): +class SendAudio(Scaffold): async def send_audio( self, chat_id: Union[int, str], @@ -42,17 +44,17 @@ class SendAudio(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () - ) -> Union["pyrogram.Message", None]: + ) -> Union["types.Message", None]: """Send audio files. - For sending voice messages, use the :obj:`send_voice()` method instead. + For sending voice messages, use the :meth:`~pyrogram.Client.send_voice` method instead. Parameters: chat_id (``int`` | ``str``): @@ -110,7 +112,7 @@ class SendAudio(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -137,8 +139,8 @@ class SendAudio(BaseClient): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - :obj:`Message` | ``None``: On success, the sent audio message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. + :obj:`~pyrogram.types.Message` | ``None``: On success, the sent audio message is returned, otherwise, in + case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned. Example: .. code-block:: python @@ -157,7 +159,7 @@ class SendAudio(BaseClient): # Keep track of the progress while uploading def progress(current, total): - print("{:.1f}%".format(current * 100 / total)) + print(f"{current * 100 / total:.1f}%") app.send_audio("me", "audio.mp3", progress=progress) """ @@ -168,21 +170,21 @@ class SendAudio(BaseClient): if os.path.isfile(audio): thumb = await self.save_file(thumb) file = await self.save_file(audio, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(audio) or "audio/mpeg", file=file, thumb=thumb, attributes=[ - types.DocumentAttributeAudio( + raw.types.DocumentAttributeAudio( duration=duration, performer=performer, title=title ), - types.DocumentAttributeFilename(file_name=file_name or os.path.basename(audio)) + raw.types.DocumentAttributeFilename(file_name=file_name or os.path.basename(audio)) ] ) elif re.match("^https?://", audio): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=audio ) else: @@ -190,24 +192,24 @@ class SendAudio(BaseClient): else: thumb = await self.save_file(thumb) file = await self.save_file(audio, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(audio.name) or "audio/mpeg", file=file, thumb=thumb, attributes=[ - types.DocumentAttributeAudio( + raw.types.DocumentAttributeAudio( duration=duration, performer=performer, title=title ), - types.DocumentAttributeFilename(file_name=audio.name) + raw.types.DocumentAttributeFilename(file_name=audio.name) ] ) while True: try: r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=media, silent=disable_notification or None, @@ -222,15 +224,14 @@ class SendAudio(BaseClient): await self.save_file(audio, file_id=file.id, file_part=e.x) else: for i in r.updates: - if isinstance( - i, - (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage) - ): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) - except BaseClient.StopTransmission: + except StopTransmission: return None diff --git a/pyrogram/client/methods/messages/send_cached_media.py b/pyrogram/methods/messages/send_cached_media.py similarity index 80% rename from pyrogram/client/methods/messages/send_cached_media.py rename to pyrogram/methods/messages/send_cached_media.py index d550cc27..3d805c4d 100644 --- a/pyrogram/client/methods/messages/send_cached_media.py +++ b/pyrogram/methods/messages/send_cached_media.py @@ -18,12 +18,13 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold -class SendCachedMedia(BaseClient): +class SendCachedMedia(Scaffold): async def send_cached_media( self, chat_id: Union[int, str], @@ -35,12 +36,12 @@ class SendCachedMedia(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None - ) -> Union["pyrogram.Message", None]: + ) -> Union["types.Message", None]: """Send any media stored on the Telegram servers using a file_id. This convenience method works with any valid file_id only. @@ -81,12 +82,12 @@ class SendCachedMedia(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - :obj:`Message`: On success, the sent media message is returned. + :obj:`~pyrogram.types.Message`: On success, the sent media message is returned. Example: .. code-block:: python @@ -95,7 +96,7 @@ class SendCachedMedia(BaseClient): """ r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=utils.get_input_media_from_file_id(file_id, file_ref), silent=disable_notification or None, @@ -108,10 +109,12 @@ class SendCachedMedia(BaseClient): ) for i in r.updates: - if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) diff --git a/pyrogram/client/methods/messages/send_chat_action.py b/pyrogram/methods/messages/send_chat_action.py similarity index 78% rename from pyrogram/client/methods/messages/send_chat_action.py rename to pyrogram/methods/messages/send_chat_action.py index 35a3d722..c9c5d569 100644 --- a/pyrogram/client/methods/messages/send_chat_action.py +++ b/pyrogram/methods/messages/send_chat_action.py @@ -19,30 +19,30 @@ import json from typing import Union -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold class ChatAction: - TYPING = types.SendMessageTypingAction - UPLOAD_PHOTO = types.SendMessageUploadPhotoAction - RECORD_VIDEO = types.SendMessageRecordVideoAction - UPLOAD_VIDEO = types.SendMessageUploadVideoAction - RECORD_AUDIO = types.SendMessageRecordAudioAction - UPLOAD_AUDIO = types.SendMessageUploadAudioAction - UPLOAD_DOCUMENT = types.SendMessageUploadDocumentAction - FIND_LOCATION = types.SendMessageGeoLocationAction - RECORD_VIDEO_NOTE = types.SendMessageRecordRoundAction - UPLOAD_VIDEO_NOTE = types.SendMessageUploadRoundAction - PLAYING = types.SendMessageGamePlayAction - CHOOSE_CONTACT = types.SendMessageChooseContactAction - CANCEL = types.SendMessageCancelAction + TYPING = raw.types.SendMessageTypingAction + UPLOAD_PHOTO = raw.types.SendMessageUploadPhotoAction + RECORD_VIDEO = raw.types.SendMessageRecordVideoAction + UPLOAD_VIDEO = raw.types.SendMessageUploadVideoAction + RECORD_AUDIO = raw.types.SendMessageRecordAudioAction + UPLOAD_AUDIO = raw.types.SendMessageUploadAudioAction + UPLOAD_DOCUMENT = raw.types.SendMessageUploadDocumentAction + FIND_LOCATION = raw.types.SendMessageGeoLocationAction + RECORD_VIDEO_NOTE = raw.types.SendMessageRecordRoundAction + UPLOAD_VIDEO_NOTE = raw.types.SendMessageUploadRoundAction + PLAYING = raw.types.SendMessageGamePlayAction + CHOOSE_CONTACT = raw.types.SendMessageChooseContactAction + CANCEL = raw.types.SendMessageCancelAction POSSIBLE_VALUES = list(map(lambda x: x.lower(), filter(lambda x: not x.startswith("__"), ChatAction.__dict__.keys()))) -class SendChatAction(BaseClient): +class SendChatAction(Scaffold): async def send_chat_action(self, chat_id: Union[int, str], action: str) -> bool: """Tell the other party that something is happening on your side. @@ -94,7 +94,7 @@ class SendChatAction(BaseClient): action = action() return await self.send( - functions.messages.SetTyping( + raw.functions.messages.SetTyping( peer=await self.resolve_peer(chat_id), action=action ) diff --git a/pyrogram/client/methods/messages/send_contact.py b/pyrogram/methods/messages/send_contact.py similarity index 77% rename from pyrogram/client/methods/messages/send_contact.py rename to pyrogram/methods/messages/send_contact.py index 0eacd8fd..50909e7c 100644 --- a/pyrogram/client/methods/messages/send_contact.py +++ b/pyrogram/methods/messages/send_contact.py @@ -18,12 +18,12 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class SendContact(BaseClient): +class SendContact(Scaffold): async def send_contact( self, chat_id: Union[int, str], @@ -35,12 +35,12 @@ class SendContact(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None - ) -> "pyrogram.Message": + ) -> "types.Message": """Send phone contacts. Parameters: @@ -71,12 +71,12 @@ class SendContact(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - :obj:`Message`: On success, the sent contact message is returned. + :obj:`~pyrogram.types.Message`: On success, the sent contact message is returned. Example: .. code-block:: python @@ -84,9 +84,9 @@ class SendContact(BaseClient): app.send_contact("me", "+39 123 456 7890", "Dan") """ r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaContact( + media=raw.types.InputMediaContact( phone_number=phone_number, first_name=first_name, last_name=last_name or "", @@ -102,10 +102,12 @@ class SendContact(BaseClient): ) for i in r.updates: - if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) diff --git a/pyrogram/client/methods/messages/send_dice.py b/pyrogram/methods/messages/send_dice.py similarity index 76% rename from pyrogram/client/methods/messages/send_dice.py rename to pyrogram/methods/messages/send_dice.py index 155185cd..f7734a4c 100644 --- a/pyrogram/client/methods/messages/send_dice.py +++ b/pyrogram/methods/messages/send_dice.py @@ -18,12 +18,12 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class SendDice(BaseClient): +class SendDice(Scaffold): async def send_dice( self, chat_id: Union[int, str], @@ -32,12 +32,12 @@ class SendDice(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None - ) -> Union["pyrogram.Message", None]: + ) -> Union["types.Message", None]: """Send a dice with a random value from 1 to 6. Parameters: @@ -60,12 +60,12 @@ class SendDice(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - :obj:`Message`: On success, the sent dice message is returned. + :obj:`~pyrogram.types.Message`: On success, the sent dice message is returned. Example: .. code-block:: python @@ -81,9 +81,9 @@ class SendDice(BaseClient): """ r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaDice(emoticon=emoji), + media=raw.types.InputMediaDice(emoticon=emoji), silent=disable_notification or None, reply_to_msg_id=reply_to_message_id, random_id=self.rnd_id(), @@ -94,10 +94,12 @@ class SendDice(BaseClient): ) for i in r.updates: - if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) diff --git a/pyrogram/client/methods/messages/send_document.py b/pyrogram/methods/messages/send_document.py similarity index 81% rename from pyrogram/client/methods/messages/send_document.py rename to pyrogram/methods/messages/send_document.py index 7f93d6cb..0c77a940 100644 --- a/pyrogram/client/methods/messages/send_document.py +++ b/pyrogram/methods/messages/send_document.py @@ -20,13 +20,15 @@ import os import re from typing import Union, BinaryIO -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils +from pyrogram import StopTransmission +from pyrogram import raw +from pyrogram import types +from pyrogram import utils from pyrogram.errors import FilePartMissing +from pyrogram.scaffold import Scaffold -class SendDocument(BaseClient): +class SendDocument(Scaffold): async def send_document( self, chat_id: Union[int, str], @@ -40,14 +42,14 @@ class SendDocument(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () - ) -> Union["pyrogram.Message", None]: + ) -> Union["types.Message", None]: """Send generic files. Parameters: @@ -97,7 +99,7 @@ class SendDocument(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -124,8 +126,8 @@ class SendDocument(BaseClient): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - :obj:`Message` | ``None``: On success, the sent document message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. + :obj:`~pyrogram.types.Message` | ``None``: On success, the sent document message is returned, otherwise, in + case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned. Example: .. code-block:: python @@ -138,28 +140,31 @@ class SendDocument(BaseClient): # Keep track of the progress while uploading def progress(current, total): - print("{:.1f}%".format(current * 100 / total)) + print(f"{current * 100 / total:.1f}%") app.send_document("me", "document.zip", progress=progress) """ file = None + # if isinstance(document, PurePath): + # document = str(document) + try: if isinstance(document, str): if os.path.isfile(document): thumb = await self.save_file(thumb) file = await self.save_file(document, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(document) or "application/zip", file=file, force_file=True, thumb=thumb, attributes=[ - types.DocumentAttributeFilename(file_name=file_name or os.path.basename(document)) + raw.types.DocumentAttributeFilename(file_name=file_name or os.path.basename(document)) ] ) elif re.match("^https?://", document): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=document ) else: @@ -167,19 +172,19 @@ class SendDocument(BaseClient): else: thumb = await self.save_file(thumb) file = await self.save_file(document, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(document.name) or "application/zip", file=file, thumb=thumb, attributes=[ - types.DocumentAttributeFilename(file_name=document.name) + raw.types.DocumentAttributeFilename(file_name=document.name) ] ) while True: try: r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=media, silent=disable_notification or None, @@ -194,15 +199,14 @@ class SendDocument(BaseClient): await self.save_file(document, file_id=file.id, file_part=e.x) else: for i in r.updates: - if isinstance( - i, - (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage) - ): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) - except BaseClient.StopTransmission: + except StopTransmission: return None diff --git a/pyrogram/client/methods/messages/send_location.py b/pyrogram/methods/messages/send_location.py similarity index 74% rename from pyrogram/client/methods/messages/send_location.py rename to pyrogram/methods/messages/send_location.py index b23d9b10..d1448550 100644 --- a/pyrogram/client/methods/messages/send_location.py +++ b/pyrogram/methods/messages/send_location.py @@ -18,12 +18,12 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class SendLocation(BaseClient): +class SendLocation(Scaffold): async def send_location( self, chat_id: Union[int, str], @@ -33,12 +33,12 @@ class SendLocation(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None - ) -> "pyrogram.Message": + ) -> "types.Message": """Send points on the map. Parameters: @@ -63,12 +63,12 @@ class SendLocation(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - :obj:`Message`: On success, the sent location message is returned. + :obj:`~pyrogram.types.Message`: On success, the sent location message is returned. Example: .. code-block:: python @@ -76,10 +76,10 @@ class SendLocation(BaseClient): app.send_location("me", 51.500729, -0.124583) """ r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaGeoPoint( - geo_point=types.InputGeoPoint( + media=raw.types.InputMediaGeoPoint( + geo_point=raw.types.InputGeoPoint( lat=latitude, long=longitude ) @@ -94,10 +94,12 @@ class SendLocation(BaseClient): ) for i in r.updates: - if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) diff --git a/pyrogram/client/methods/messages/send_media_group.py b/pyrogram/methods/messages/send_media_group.py similarity index 74% rename from pyrogram/client/methods/messages/send_media_group.py rename to pyrogram/methods/messages/send_media_group.py index 0fad6e91..6c9bd04d 100644 --- a/pyrogram/client/methods/messages/send_media_group.py +++ b/pyrogram/methods/messages/send_media_group.py @@ -21,22 +21,23 @@ import os import re from typing import Union, List -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold log = logging.getLogger(__name__) -class SendMediaGroup(BaseClient): +class SendMediaGroup(Scaffold): # TODO: Add progress parameter async def send_media_group( self, chat_id: Union[int, str], - media: List[Union["pyrogram.InputMediaPhoto", "pyrogram.InputMediaVideo"]], + media: List[Union["types.InputMediaPhoto", "types.InputMediaVideo"]], disable_notification: bool = None, reply_to_message_id: int = None - ) -> List["pyrogram.Message"]: + ) -> List["types.Message"]: """Send a group of photos or videos as an album. Parameters: @@ -45,7 +46,7 @@ class SendMediaGroup(BaseClient): For your personal cloud (Saved Messages) you can simply use "me" or "self". For a contact that exists in your Telegram address book you can use his phone number (str). - media (List of :obj:`InputMediaPhoto` and :obj:`InputMediaVideo`): + media (List of :obj:`~pyrogram.types.InputMediaPhoto` and :obj:`~pyrogram.types.InputMediaVideo`): A list describing photos and videos to be sent, must include 2–10 items. disable_notification (``bool``, *optional*): @@ -56,7 +57,7 @@ class SendMediaGroup(BaseClient): If the message is a reply, ID of the original message. Returns: - List of :obj:`Message`: On success, a list of the sent messages is returned. + List of :obj:`~pyrogram.types.Message`: On success, a list of the sent messages is returned. Example: .. code-block:: python @@ -75,19 +76,19 @@ class SendMediaGroup(BaseClient): multi_media = [] for i in media: - if isinstance(i, pyrogram.InputMediaPhoto): + if isinstance(i, types.InputMediaPhoto): if os.path.isfile(i.media): media = await self.send( - functions.messages.UploadMedia( + raw.functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaUploadedPhoto( + media=raw.types.InputMediaUploadedPhoto( file=await self.save_file(i.media) ) ) ) - media = types.InputMediaPhoto( - id=types.InputPhoto( + media = raw.types.InputMediaPhoto( + id=raw.types.InputPhoto( id=media.photo.id, access_hash=media.photo.access_hash, file_reference=media.photo.file_reference @@ -95,16 +96,16 @@ class SendMediaGroup(BaseClient): ) elif re.match("^https?://", i.media): media = await self.send( - functions.messages.UploadMedia( + raw.functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaPhotoExternal( + media=raw.types.InputMediaPhotoExternal( url=i.media ) ) ) - media = types.InputMediaPhoto( - id=types.InputPhoto( + media = raw.types.InputMediaPhoto( + id=raw.types.InputPhoto( id=media.photo.id, access_hash=media.photo.access_hash, file_reference=media.photo.file_reference @@ -112,30 +113,30 @@ class SendMediaGroup(BaseClient): ) else: media = utils.get_input_media_from_file_id(i.media, i.file_ref, 2) - elif isinstance(i, pyrogram.InputMediaVideo): + elif isinstance(i, types.InputMediaVideo): if os.path.isfile(i.media): media = await self.send( - functions.messages.UploadMedia( + raw.functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaUploadedDocument( + media=raw.types.InputMediaUploadedDocument( file=await self.save_file(i.media), - thumb=self.save_file(i.thumb), + thumb=await self.save_file(i.thumb), mime_type=self.guess_mime_type(i.media) or "video/mp4", attributes=[ - types.DocumentAttributeVideo( + raw.types.DocumentAttributeVideo( supports_streaming=i.supports_streaming or None, duration=i.duration, w=i.width, h=i.height ), - types.DocumentAttributeFilename(file_name=os.path.basename(i.media)) + raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media)) ] ) ) ) - media = types.InputMediaDocument( - id=types.InputDocument( + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=media.document.file_reference @@ -143,16 +144,16 @@ class SendMediaGroup(BaseClient): ) elif re.match("^https?://", i.media): media = await self.send( - functions.messages.UploadMedia( + raw.functions.messages.UploadMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaDocumentExternal( + media=raw.types.InputMediaDocumentExternal( url=i.media ) ) ) - media = types.InputMediaDocument( - id=types.InputDocument( + media = raw.types.InputMediaDocument( + id=raw.types.InputDocument( id=media.document.id, access_hash=media.document.access_hash, file_reference=media.document.file_reference @@ -162,7 +163,7 @@ class SendMediaGroup(BaseClient): media = utils.get_input_media_from_file_id(i.media, i.file_ref, 4) multi_media.append( - types.InputSingleMedia( + raw.types.InputSingleMedia( media=media, random_id=self.rnd_id(), **await self.parser.parse(i.caption, i.parse_mode) @@ -170,7 +171,7 @@ class SendMediaGroup(BaseClient): ) r = await self.send( - functions.messages.SendMultiMedia( + raw.functions.messages.SendMultiMedia( peer=await self.resolve_peer(chat_id), multi_media=multi_media, silent=disable_notification or None, @@ -180,9 +181,9 @@ class SendMediaGroup(BaseClient): return await utils.parse_messages( self, - types.messages.Messages( + raw.types.messages.Messages( messages=[m.message for m in filter( - lambda u: isinstance(u, (types.UpdateNewMessage, types.UpdateNewChannelMessage)), + lambda u: isinstance(u, (raw.types.UpdateNewMessage, raw.types.UpdateNewChannelMessage)), r.updates )], users=r.users, diff --git a/pyrogram/client/methods/messages/send_message.py b/pyrogram/methods/messages/send_message.py similarity index 82% rename from pyrogram/client/methods/messages/send_message.py rename to pyrogram/methods/messages/send_message.py index 58385bcf..e2ccc853 100644 --- a/pyrogram/client/methods/messages/send_message.py +++ b/pyrogram/methods/messages/send_message.py @@ -18,12 +18,12 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class SendMessage(BaseClient): +class SendMessage(Scaffold): async def send_message( self, chat_id: Union[int, str], @@ -34,12 +34,12 @@ class SendMessage(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None - ) -> "pyrogram.Message": + ) -> "types.Message": """Send text messages. Parameters: @@ -71,12 +71,12 @@ class SendMessage(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - :obj:`Message`: On success, the sent text message is returned. + :obj:`~pyrogram.types.Message`: On success, the sent text message is returned. Example: .. code-block:: python @@ -119,7 +119,7 @@ class SendMessage(BaseClient): message, entities = (await self.parser.parse(text, parse_mode)).values() r = await self.send( - functions.messages.SendMessage( + raw.functions.messages.SendMessage( peer=await self.resolve_peer(chat_id), no_webpage=disable_web_page_preview or None, silent=disable_notification or None, @@ -132,18 +132,18 @@ class SendMessage(BaseClient): ) ) - if isinstance(r, types.UpdateShortSentMessage): + if isinstance(r, raw.types.UpdateShortSentMessage): peer = await self.resolve_peer(chat_id) peer_id = ( peer.user_id - if isinstance(peer, types.InputPeerUser) + if isinstance(peer, raw.types.InputPeerUser) else -peer.chat_id ) - return pyrogram.Message( + return types.Message( message_id=r.id, - chat=pyrogram.Chat( + chat=types.Chat( id=peer_id, type="private", client=self @@ -152,17 +152,19 @@ class SendMessage(BaseClient): date=r.date, outgoing=r.out, entities=[ - pyrogram.MessageEntity._parse(None, entity, {}) + types.MessageEntity._parse(None, entity, {}) for entity in entities ], client=self ) for i in r.updates: - if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) diff --git a/pyrogram/client/methods/messages/send_photo.py b/pyrogram/methods/messages/send_photo.py similarity index 83% rename from pyrogram/client/methods/messages/send_photo.py rename to pyrogram/methods/messages/send_photo.py index 7c2c194c..06a6688b 100644 --- a/pyrogram/client/methods/messages/send_photo.py +++ b/pyrogram/methods/messages/send_photo.py @@ -21,12 +21,14 @@ import re from typing import Union, BinaryIO import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils +from pyrogram import raw +from pyrogram import types +from pyrogram import utils from pyrogram.errors import FilePartMissing +from pyrogram.scaffold import Scaffold -class SendPhoto(BaseClient): +class SendPhoto(Scaffold): async def send_photo( self, chat_id: Union[int, str], @@ -39,14 +41,14 @@ class SendPhoto(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () - ) -> Union["pyrogram.Message", None]: + ) -> Union["types.Message", None]: """Send photos. Parameters: @@ -91,7 +93,7 @@ class SendPhoto(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -118,8 +120,8 @@ class SendPhoto(BaseClient): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - :obj:`Message` | ``None``: On success, the sent photo message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. + :obj:`~pyrogram.types.Message` | ``None``: On success, the sent photo message is returned, otherwise, in + case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned. Example: .. code-block:: python @@ -142,12 +144,12 @@ class SendPhoto(BaseClient): if isinstance(photo, str): if os.path.isfile(photo): file = await self.save_file(photo, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedPhoto( + media = raw.types.InputMediaUploadedPhoto( file=file, ttl_seconds=ttl_seconds ) elif re.match("^https?://", photo): - media = types.InputMediaPhotoExternal( + media = raw.types.InputMediaPhotoExternal( url=photo, ttl_seconds=ttl_seconds ) @@ -155,7 +157,7 @@ class SendPhoto(BaseClient): media = utils.get_input_media_from_file_id(photo, file_ref, 2) else: file = await self.save_file(photo, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedPhoto( + media = raw.types.InputMediaUploadedPhoto( file=file, ttl_seconds=ttl_seconds ) @@ -163,7 +165,7 @@ class SendPhoto(BaseClient): while True: try: r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=media, silent=disable_notification or None, @@ -178,15 +180,14 @@ class SendPhoto(BaseClient): await self.save_file(photo, file_id=file.id, file_part=e.x) else: for i in r.updates: - if isinstance( - i, - (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage) - ): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) - except BaseClient.StopTransmission: + except pyrogram.StopTransmission: return None diff --git a/pyrogram/client/methods/messages/send_poll.py b/pyrogram/methods/messages/send_poll.py similarity index 79% rename from pyrogram/client/methods/messages/send_poll.py rename to pyrogram/methods/messages/send_poll.py index 7607a546..4758e83e 100644 --- a/pyrogram/client/methods/messages/send_poll.py +++ b/pyrogram/methods/messages/send_poll.py @@ -18,12 +18,12 @@ from typing import Union, List -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class SendPoll(BaseClient): +class SendPoll(Scaffold): async def send_poll( self, chat_id: Union[int, str], @@ -37,12 +37,12 @@ class SendPoll(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None - ) -> "pyrogram.Message": + ) -> "types.Message": """Send a new poll. Parameters: @@ -83,12 +83,12 @@ class SendPoll(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - :obj:`Message`: On success, the sent poll message is returned. + :obj:`~pyrogram.types.Message`: On success, the sent poll message is returned. Example: .. code-block:: python @@ -96,14 +96,14 @@ class SendPoll(BaseClient): app.send_poll(chat_id, "Is this a poll question?", ["Yes", "No", "Maybe"]) """ r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaPoll( - poll=types.Poll( + media=raw.types.InputMediaPoll( + poll=raw.types.Poll( id=0, question=question, answers=[ - types.PollAnswer(text=o, option=bytes([i])) + raw.types.PollAnswer(text=o, option=bytes([i])) for i, o in enumerate(options) ], multiple_choice=allows_multiple_answers or None, @@ -122,10 +122,12 @@ class SendPoll(BaseClient): ) for i in r.updates: - if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) diff --git a/pyrogram/client/methods/messages/send_sticker.py b/pyrogram/methods/messages/send_sticker.py similarity index 79% rename from pyrogram/client/methods/messages/send_sticker.py rename to pyrogram/methods/messages/send_sticker.py index 8025a0dd..6ab211f8 100644 --- a/pyrogram/client/methods/messages/send_sticker.py +++ b/pyrogram/methods/messages/send_sticker.py @@ -20,13 +20,15 @@ import os import re from typing import Union, BinaryIO -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils +from pyrogram import StopTransmission +from pyrogram import raw +from pyrogram import types +from pyrogram import utils from pyrogram.errors import FilePartMissing +from pyrogram.scaffold import Scaffold -class SendSticker(BaseClient): +class SendSticker(Scaffold): async def send_sticker( self, chat_id: Union[int, str], @@ -36,14 +38,14 @@ class SendSticker(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () - ) -> Union["pyrogram.Message", None]: + ) -> Union["types.Message", None]: """Send static .webp or animated .tgs stickers. Parameters: @@ -73,7 +75,7 @@ class SendSticker(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -100,8 +102,9 @@ class SendSticker(BaseClient): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - :obj:`Message` | ``None``: On success, the sent sticker message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. + :obj:`~pyrogram.types.Message` | ``None``: On success, the sent sticker message is returned, otherwise, + in case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is + returned. Example: .. code-block:: python @@ -118,33 +121,33 @@ class SendSticker(BaseClient): if isinstance(sticker, str): if os.path.isfile(sticker): file = await self.save_file(sticker, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(sticker) or "image/webp", file=file, attributes=[ - types.DocumentAttributeFilename(file_name=os.path.basename(sticker)) + raw.types.DocumentAttributeFilename(file_name=os.path.basename(sticker)) ] ) elif re.match("^https?://", sticker): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=sticker ) else: media = utils.get_input_media_from_file_id(sticker, file_ref, 8) else: file = await self.save_file(sticker, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(sticker.name) or "image/webp", file=file, attributes=[ - types.DocumentAttributeFilename(file_name=sticker.name) + raw.types.DocumentAttributeFilename(file_name=sticker.name) ] ) while True: try: r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=media, silent=disable_notification or None, @@ -159,15 +162,14 @@ class SendSticker(BaseClient): await self.save_file(sticker, file_id=file.id, file_part=e.x) else: for i in r.updates: - if isinstance( - i, - (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage) - ): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) - except BaseClient.StopTransmission: + except StopTransmission: return None diff --git a/pyrogram/client/methods/messages/send_venue.py b/pyrogram/methods/messages/send_venue.py similarity index 79% rename from pyrogram/client/methods/messages/send_venue.py rename to pyrogram/methods/messages/send_venue.py index f6f09d5e..e4611910 100644 --- a/pyrogram/client/methods/messages/send_venue.py +++ b/pyrogram/methods/messages/send_venue.py @@ -18,12 +18,12 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class SendVenue(BaseClient): +class SendVenue(Scaffold): async def send_venue( self, chat_id: Union[int, str], @@ -37,12 +37,12 @@ class SendVenue(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None - ) -> "pyrogram.Message": + ) -> "types.Message": """Send information about a venue. Parameters: @@ -80,12 +80,12 @@ class SendVenue(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - :obj:`Message`: On success, the sent venue message is returned. + :obj:`~pyrogram.types.Message`: On success, the sent venue message is returned. Example: .. code-block:: python @@ -95,10 +95,10 @@ class SendVenue(BaseClient): "Elizabeth Tower", "Westminster, London SW1A 0AA, UK") """ r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), - media=types.InputMediaVenue( - geo_point=types.InputGeoPoint( + media=raw.types.InputMediaVenue( + geo_point=raw.types.InputGeoPoint( lat=latitude, long=longitude ), @@ -118,10 +118,12 @@ class SendVenue(BaseClient): ) for i in r.updates: - if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage)): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) diff --git a/pyrogram/client/methods/messages/send_video.py b/pyrogram/methods/messages/send_video.py similarity index 82% rename from pyrogram/client/methods/messages/send_video.py rename to pyrogram/methods/messages/send_video.py index 87cecf5a..3b2bc03e 100644 --- a/pyrogram/client/methods/messages/send_video.py +++ b/pyrogram/methods/messages/send_video.py @@ -20,13 +20,15 @@ import os import re from typing import Union, BinaryIO -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils +from pyrogram import StopTransmission +from pyrogram import raw +from pyrogram import types +from pyrogram import utils from pyrogram.errors import FilePartMissing +from pyrogram.scaffold import Scaffold -class SendVideo(BaseClient): +class SendVideo(Scaffold): async def send_video( self, chat_id: Union[int, str], @@ -44,14 +46,14 @@ class SendVideo(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () - ) -> Union["pyrogram.Message", None]: + ) -> Union["types.Message", None]: """Send video files. Parameters: @@ -114,7 +116,7 @@ class SendVideo(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -141,8 +143,8 @@ class SendVideo(BaseClient): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - :obj:`Message` | ``None``: On success, the sent video message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. + :obj:`~pyrogram.types.Message` | ``None``: On success, the sent video message is returned, otherwise, in + case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned. Example: .. code-block:: python @@ -155,7 +157,7 @@ class SendVideo(BaseClient): # Keep track of the progress while uploading def progress(current, total): - print("{:.1f}%".format(current * 100 / total)) + print(f"{current * 100 / total:.1f}%") app.send_video("me", "video.mp4", progress=progress) """ @@ -166,22 +168,22 @@ class SendVideo(BaseClient): if os.path.isfile(video): thumb = await self.save_file(thumb) file = await self.save_file(video, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(video) or "video/mp4", file=file, thumb=thumb, attributes=[ - types.DocumentAttributeVideo( + raw.types.DocumentAttributeVideo( supports_streaming=supports_streaming or None, duration=duration, w=width, h=height ), - types.DocumentAttributeFilename(file_name=file_name or os.path.basename(video)) + raw.types.DocumentAttributeFilename(file_name=file_name or os.path.basename(video)) ] ) elif re.match("^https?://", video): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=video ) else: @@ -189,25 +191,25 @@ class SendVideo(BaseClient): else: thumb = await self.save_file(thumb) file = await self.save_file(video, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(video.name) or "video/mp4", file=file, thumb=thumb, attributes=[ - types.DocumentAttributeVideo( + raw.types.DocumentAttributeVideo( supports_streaming=supports_streaming or None, duration=duration, w=width, h=height ), - types.DocumentAttributeFilename(file_name=video.name) + raw.types.DocumentAttributeFilename(file_name=video.name) ] ) while True: try: r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=media, silent=disable_notification or None, @@ -222,15 +224,14 @@ class SendVideo(BaseClient): await self.save_file(video, file_id=file.id, file_part=e.x) else: for i in r.updates: - if isinstance( - i, - (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage) - ): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) - except BaseClient.StopTransmission: + except StopTransmission: return None diff --git a/pyrogram/client/methods/messages/send_video_note.py b/pyrogram/methods/messages/send_video_note.py similarity index 83% rename from pyrogram/client/methods/messages/send_video_note.py rename to pyrogram/methods/messages/send_video_note.py index c204f6ca..82a3688b 100644 --- a/pyrogram/client/methods/messages/send_video_note.py +++ b/pyrogram/methods/messages/send_video_note.py @@ -19,13 +19,15 @@ import os from typing import Union, BinaryIO -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils +from pyrogram import StopTransmission +from pyrogram import raw +from pyrogram import types +from pyrogram import utils from pyrogram.errors import FilePartMissing +from pyrogram.scaffold import Scaffold -class SendVideoNote(BaseClient): +class SendVideoNote(Scaffold): async def send_video_note( self, chat_id: Union[int, str], @@ -38,14 +40,14 @@ class SendVideoNote(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () - ) -> Union["pyrogram.Message", None]: + ) -> Union["types.Message", None]: """Send video messages. Parameters: @@ -87,7 +89,7 @@ class SendVideoNote(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -114,8 +116,9 @@ class SendVideoNote(BaseClient): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - :obj:`Message` | ``None``: On success, the sent video note message is returned, otherwise, in case the - upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. + :obj:`~pyrogram.types.Message` | ``None``: On success, the sent video note message is returned, otherwise, + in case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is + returned. Example: .. code-block:: python @@ -133,12 +136,12 @@ class SendVideoNote(BaseClient): if os.path.isfile(video_note): thumb = await self.save_file(thumb) file = await self.save_file(video_note, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(video_note) or "video/mp4", file=file, thumb=thumb, attributes=[ - types.DocumentAttributeVideo( + raw.types.DocumentAttributeVideo( round_message=True, duration=duration, w=length, @@ -151,12 +154,12 @@ class SendVideoNote(BaseClient): else: thumb = await self.save_file(thumb) file = await self.save_file(video_note, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(video_note.name) or "video/mp4", file=file, thumb=thumb, attributes=[ - types.DocumentAttributeVideo( + raw.types.DocumentAttributeVideo( round_message=True, duration=duration, w=length, @@ -168,7 +171,7 @@ class SendVideoNote(BaseClient): while True: try: r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=media, silent=disable_notification or None, @@ -183,15 +186,14 @@ class SendVideoNote(BaseClient): await self.save_file(video_note, file_id=file.id, file_part=e.x) else: for i in r.updates: - if isinstance( - i, - (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage) - ): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) - except BaseClient.StopTransmission: + except StopTransmission: return None diff --git a/pyrogram/client/methods/messages/send_voice.py b/pyrogram/methods/messages/send_voice.py similarity index 82% rename from pyrogram/client/methods/messages/send_voice.py rename to pyrogram/methods/messages/send_voice.py index 98221e8d..58d401d7 100644 --- a/pyrogram/client/methods/messages/send_voice.py +++ b/pyrogram/methods/messages/send_voice.py @@ -20,13 +20,15 @@ import os import re from typing import Union, BinaryIO -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient, utils +from pyrogram import StopTransmission +from pyrogram import raw +from pyrogram import types +from pyrogram import utils from pyrogram.errors import FilePartMissing +from pyrogram.scaffold import Scaffold -class SendVoice(BaseClient): +class SendVoice(Scaffold): async def send_voice( self, chat_id: Union[int, str], @@ -39,14 +41,14 @@ class SendVoice(BaseClient): reply_to_message_id: int = None, schedule_date: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () - ) -> Union["pyrogram.Message", None]: + ) -> Union["types.Message", None]: """Send audio files. Parameters: @@ -89,7 +91,7 @@ class SendVoice(BaseClient): schedule_date (``int``, *optional*): Date when the message will be automatically sent. Unix time. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -116,8 +118,8 @@ class SendVoice(BaseClient): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - :obj:`Message` | ``None``: On success, the sent voice message is returned, otherwise, in case the upload - is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned. + :obj:`~pyrogram.types.Message` | ``None``: On success, the sent voice message is returned, otherwise, in + case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned. Example: .. code-block:: python @@ -137,29 +139,29 @@ class SendVoice(BaseClient): if isinstance(voice, str): if os.path.isfile(voice): file = await self.save_file(voice, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(voice) or "audio/mpeg", file=file, attributes=[ - types.DocumentAttributeAudio( + raw.types.DocumentAttributeAudio( voice=True, duration=duration ) ] ) elif re.match("^https?://", voice): - media = types.InputMediaDocumentExternal( + media = raw.types.InputMediaDocumentExternal( url=voice ) else: media = utils.get_input_media_from_file_id(voice, file_ref, 3) else: file = await self.save_file(voice, progress=progress, progress_args=progress_args) - media = types.InputMediaUploadedDocument( + media = raw.types.InputMediaUploadedDocument( mime_type=self.guess_mime_type(voice.name) or "audio/mpeg", file=file, attributes=[ - types.DocumentAttributeAudio( + raw.types.DocumentAttributeAudio( voice=True, duration=duration ) @@ -169,7 +171,7 @@ class SendVoice(BaseClient): while True: try: r = await self.send( - functions.messages.SendMedia( + raw.functions.messages.SendMedia( peer=await self.resolve_peer(chat_id), media=media, silent=disable_notification or None, @@ -184,15 +186,14 @@ class SendVoice(BaseClient): await self.save_file(voice, file_id=file.id, file_part=e.x) else: for i in r.updates: - if isinstance( - i, - (types.UpdateNewMessage, types.UpdateNewChannelMessage, types.UpdateNewScheduledMessage) - ): - return await pyrogram.Message._parse( + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( self, i.message, {i.id: i for i in r.users}, {i.id: i for i in r.chats}, - is_scheduled=isinstance(i, types.UpdateNewScheduledMessage) + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) ) - except BaseClient.StopTransmission: + except StopTransmission: return None diff --git a/pyrogram/client/methods/messages/stop_poll.py b/pyrogram/methods/messages/stop_poll.py similarity index 79% rename from pyrogram/client/methods/messages/stop_poll.py rename to pyrogram/methods/messages/stop_poll.py index 79498e45..c0b07542 100644 --- a/pyrogram/client/methods/messages/stop_poll.py +++ b/pyrogram/methods/messages/stop_poll.py @@ -18,18 +18,18 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class StopPoll(BaseClient): +class StopPoll(Scaffold): async def stop_poll( self, chat_id: Union[int, str], message_id: int, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None - ) -> "pyrogram.Poll": + reply_markup: "types.InlineKeyboardMarkup" = None + ) -> "types.Poll": """Stop a poll which was sent by you. Stopped polls can't be reopened and nobody will be able to vote in it anymore. @@ -43,11 +43,11 @@ class StopPoll(BaseClient): message_id (``int``): Identifier of the original message with the poll. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - :obj:`Poll`: On success, the stopped poll with the final results is returned. + :obj:`~pyrogram.types.Poll`: On success, the stopped poll with the final results is returned. Example: .. code-block:: python @@ -57,11 +57,11 @@ class StopPoll(BaseClient): poll = (await self.get_messages(chat_id, message_id)).poll r = await self.send( - functions.messages.EditMessage( + raw.functions.messages.EditMessage( peer=await self.resolve_peer(chat_id), id=message_id, - media=types.InputMediaPoll( - poll=types.Poll( + media=raw.types.InputMediaPoll( + poll=raw.types.Poll( id=int(poll.id), closed=True, question="", @@ -72,4 +72,4 @@ class StopPoll(BaseClient): ) ) - return pyrogram.Poll._parse(self, r.updates[0]) + return types.Poll._parse(self, r.updates[0]) diff --git a/pyrogram/client/methods/messages/vote_poll.py b/pyrogram/methods/messages/vote_poll.py similarity index 86% rename from pyrogram/client/methods/messages/vote_poll.py rename to pyrogram/methods/messages/vote_poll.py index 667df0fb..e764e0bb 100644 --- a/pyrogram/client/methods/messages/vote_poll.py +++ b/pyrogram/methods/messages/vote_poll.py @@ -18,18 +18,18 @@ from typing import Union, List -import pyrogram -from pyrogram.api import functions -from pyrogram.client.ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class VotePoll(BaseClient): +class VotePoll(Scaffold): async def vote_poll( self, chat_id: Union[int, str], message_id: id, options: Union[int, List[int]] - ) -> "pyrogram.Poll": + ) -> "types.Poll": """Vote a poll. Parameters: @@ -45,7 +45,7 @@ class VotePoll(BaseClient): Index or list of indexes (for multiple answers) of the poll option(s) you want to vote for (0 to 9). Returns: - :obj:`Poll` - On success, the poll with the chosen option is returned. + :obj:`~pyrogram.types.Poll` - On success, the poll with the chosen option is returned. Example: .. code-block:: python @@ -57,11 +57,11 @@ class VotePoll(BaseClient): options = [options] if not isinstance(options, list) else options r = await self.send( - functions.messages.SendVote( + raw.functions.messages.SendVote( peer=await self.resolve_peer(chat_id), msg_id=message_id, options=[poll.options[option].data for option in options] ) ) - return pyrogram.Poll._parse(self, r.updates[0]) + return types.Poll._parse(self, r.updates[0]) diff --git a/pyrogram/client/methods/password/__init__.py b/pyrogram/methods/password/__init__.py similarity index 100% rename from pyrogram/client/methods/password/__init__.py rename to pyrogram/methods/password/__init__.py diff --git a/pyrogram/client/methods/password/change_cloud_password.py b/pyrogram/methods/password/change_cloud_password.py similarity index 80% rename from pyrogram/client/methods/password/change_cloud_password.py rename to pyrogram/methods/password/change_cloud_password.py index 54ec2891..4002ef1e 100644 --- a/pyrogram/client/methods/password/change_cloud_password.py +++ b/pyrogram/methods/password/change_cloud_password.py @@ -18,12 +18,12 @@ import os -from pyrogram.api import functions, types -from .utils import compute_hash, compute_check, btoi, itob -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold +from pyrogram.utils import compute_password_hash, compute_password_check, btoi, itob -class ChangeCloudPassword(BaseClient): +class ChangeCloudPassword(Scaffold): async def change_cloud_password( self, current_password: str, @@ -57,19 +57,19 @@ class ChangeCloudPassword(BaseClient): # Change password and hint app.change_cloud_password("current_password", "new_password", new_hint="hint") """ - r = await self.send(functions.account.GetPassword()) + r = await self.send(raw.functions.account.GetPassword()) if not r.has_password: raise ValueError("There is no cloud password to change") r.new_algo.salt1 += os.urandom(32) - new_hash = btoi(compute_hash(r.new_algo, new_password)) + new_hash = btoi(compute_password_hash(r.new_algo, new_password)) new_hash = itob(pow(r.new_algo.g, new_hash, btoi(r.new_algo.p))) await self.send( - functions.account.UpdatePasswordSettings( - password=compute_check(r, current_password), - new_settings=types.account.PasswordInputSettings( + raw.functions.account.UpdatePasswordSettings( + password=compute_password_check(r, current_password), + new_settings=raw.types.account.PasswordInputSettings( new_algo=r.new_algo, new_password_hash=new_hash, hint=new_hint diff --git a/pyrogram/client/methods/password/enable_cloud_password.py b/pyrogram/methods/password/enable_cloud_password.py similarity index 83% rename from pyrogram/client/methods/password/enable_cloud_password.py rename to pyrogram/methods/password/enable_cloud_password.py index b6291943..4fedca15 100644 --- a/pyrogram/client/methods/password/enable_cloud_password.py +++ b/pyrogram/methods/password/enable_cloud_password.py @@ -18,12 +18,12 @@ import os -from pyrogram.api import functions, types -from .utils import compute_hash, btoi, itob -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold +from pyrogram.utils import compute_password_hash, btoi, itob -class EnableCloudPassword(BaseClient): +class EnableCloudPassword(Scaffold): async def enable_cloud_password( self, password: str, @@ -62,19 +62,19 @@ class EnableCloudPassword(BaseClient): # Enable password with hint and email app.enable_cloud_password("password", hint="hint", email="user@email.com") """ - r = await self.send(functions.account.GetPassword()) + r = await self.send(raw.functions.account.GetPassword()) if r.has_password: raise ValueError("There is already a cloud password enabled") r.new_algo.salt1 += os.urandom(32) - new_hash = btoi(compute_hash(r.new_algo, password)) + new_hash = btoi(compute_password_hash(r.new_algo, password)) new_hash = itob(pow(r.new_algo.g, new_hash, btoi(r.new_algo.p))) await self.send( - functions.account.UpdatePasswordSettings( - password=types.InputCheckPasswordEmpty(), - new_settings=types.account.PasswordInputSettings( + raw.functions.account.UpdatePasswordSettings( + password=raw.types.InputCheckPasswordEmpty(), + new_settings=raw.types.account.PasswordInputSettings( new_algo=r.new_algo, new_password_hash=new_hash, hint=hint, diff --git a/pyrogram/client/methods/password/remove_cloud_password.py b/pyrogram/methods/password/remove_cloud_password.py similarity index 77% rename from pyrogram/client/methods/password/remove_cloud_password.py rename to pyrogram/methods/password/remove_cloud_password.py index 9d41a9db..ecebe226 100644 --- a/pyrogram/client/methods/password/remove_cloud_password.py +++ b/pyrogram/methods/password/remove_cloud_password.py @@ -16,12 +16,12 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api import functions, types -from .utils import compute_check -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold +from pyrogram.utils import compute_password_check -class RemoveCloudPassword(BaseClient): +class RemoveCloudPassword(Scaffold): async def remove_cloud_password( self, password: str @@ -43,16 +43,16 @@ class RemoveCloudPassword(BaseClient): app.remove_cloud_password("password") """ - r = await self.send(functions.account.GetPassword()) + r = await self.send(raw.functions.account.GetPassword()) if not r.has_password: raise ValueError("There is no cloud password to remove") await self.send( - functions.account.UpdatePasswordSettings( - password=compute_check(r, password), - new_settings=types.account.PasswordInputSettings( - new_algo=types.PasswordKdfAlgoUnknown(), + raw.functions.account.UpdatePasswordSettings( + password=compute_password_check(r, password), + new_settings=raw.types.account.PasswordInputSettings( + new_algo=raw.types.PasswordKdfAlgoUnknown(), new_password_hash=b"", hint="" ) diff --git a/pyrogram/client/methods/users/__init__.py b/pyrogram/methods/users/__init__.py similarity index 100% rename from pyrogram/client/methods/users/__init__.py rename to pyrogram/methods/users/__init__.py diff --git a/pyrogram/client/methods/users/block_user.py b/pyrogram/methods/users/block_user.py similarity index 92% rename from pyrogram/client/methods/users/block_user.py rename to pyrogram/methods/users/block_user.py index 8dd6e09d..64647889 100644 --- a/pyrogram/client/methods/users/block_user.py +++ b/pyrogram/methods/users/block_user.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class BlockUser(BaseClient): +class BlockUser(Scaffold): async def block_user( self, user_id: Union[int, str] @@ -45,7 +45,7 @@ class BlockUser(BaseClient): """ return bool( await self.send( - functions.contacts.Block( + raw.functions.contacts.Block( id=await self.resolve_peer(user_id) ) ) diff --git a/pyrogram/client/methods/users/delete_profile_photos.py b/pyrogram/methods/users/delete_profile_photos.py similarity index 86% rename from pyrogram/client/methods/users/delete_profile_photos.py rename to pyrogram/methods/users/delete_profile_photos.py index ac184da5..c5662126 100644 --- a/pyrogram/client/methods/users/delete_profile_photos.py +++ b/pyrogram/methods/users/delete_profile_photos.py @@ -18,12 +18,12 @@ from typing import List, Union -from pyrogram.api import functions -from pyrogram.client.ext import utils -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import utils +from pyrogram.scaffold import Scaffold -class DeleteProfilePhotos(BaseClient): +class DeleteProfilePhotos(Scaffold): async def delete_profile_photos( self, photo_ids: Union[str, List[str]] @@ -32,7 +32,7 @@ class DeleteProfilePhotos(BaseClient): Parameters: photo_ids (``str`` | List of ``str``): - A single :obj:`Photo` id as string or multiple ids as list of strings for deleting + A single :obj:`~pyrogram.types.Photo` id as string or multiple ids as list of strings for deleting more than one photos at once. Returns: @@ -54,7 +54,7 @@ class DeleteProfilePhotos(BaseClient): input_photos = [utils.get_input_media_from_file_id(i).id for i in photo_ids] return bool(await self.send( - functions.photos.DeletePhotos( + raw.functions.photos.DeletePhotos( id=input_photos ) )) diff --git a/pyrogram/client/methods/users/get_common_chats.py b/pyrogram/methods/users/get_common_chats.py similarity index 78% rename from pyrogram/client/methods/users/get_common_chats.py rename to pyrogram/methods/users/get_common_chats.py index fab202fd..5b788877 100644 --- a/pyrogram/client/methods/users/get_common_chats.py +++ b/pyrogram/methods/users/get_common_chats.py @@ -18,12 +18,12 @@ from typing import Union -import pyrogram -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class GetCommonChats(BaseClient): +class GetCommonChats(Scaffold): async def get_common_chats(self, user_id: Union[int, str]) -> list: """Get the common chats you have with a user. @@ -34,7 +34,7 @@ class GetCommonChats(BaseClient): For a contact that exists in your Telegram address book you can use his phone number (str). Returns: - List of :obj:`Chat`: On success, a list of the common chats is returned. + List of :obj:`~pyrogram.types.Chat`: On success, a list of the common chats is returned. Raises: ValueError: If the user_id doesn't belong to a user. @@ -48,15 +48,15 @@ class GetCommonChats(BaseClient): peer = await self.resolve_peer(user_id) - if isinstance(peer, types.InputPeerUser): + if isinstance(peer, raw.types.InputPeerUser): r = await self.send( - functions.messages.GetCommonChats( + raw.functions.messages.GetCommonChats( user_id=peer, max_id=0, limit=100, ) ) - return pyrogram.List([pyrogram.Chat._parse_chat(self, x) for x in r.chats]) + return types.List([types.Chat._parse_chat(self, x) for x in r.chats]) - raise ValueError('The user_id "{}" doesn\'t belong to a user'.format(user_id)) + raise ValueError(f'The user_id "{user_id}" doesn\'t belong to a user') diff --git a/pyrogram/client/methods/users/get_me.py b/pyrogram/methods/users/get_me.py similarity index 74% rename from pyrogram/client/methods/users/get_me.py rename to pyrogram/methods/users/get_me.py index 0efbddb2..38529671 100644 --- a/pyrogram/client/methods/users/get_me.py +++ b/pyrogram/methods/users/get_me.py @@ -16,17 +16,17 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -import pyrogram -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class GetMe(BaseClient): - async def get_me(self) -> "pyrogram.User": +class GetMe(Scaffold): + async def get_me(self) -> "types.User": """Get your own user identity. Returns: - :obj:`User`: Information about the own logged in user/bot. + :obj:`~pyrogram.types.User`: Information about the own logged in user/bot. Example: .. code-block:: python @@ -34,11 +34,11 @@ class GetMe(BaseClient): me = app.get_me() print(me) """ - return pyrogram.User._parse( + return types.User._parse( self, (await self.send( - functions.users.GetFullUser( - id=types.InputPeerSelf() + raw.functions.users.GetFullUser( + id=raw.types.InputUserSelf() ) )).user ) diff --git a/pyrogram/client/methods/users/get_profile_photos.py b/pyrogram/methods/users/get_profile_photos.py similarity index 81% rename from pyrogram/client/methods/users/get_profile_photos.py rename to pyrogram/methods/users/get_profile_photos.py index fded8dcb..b27687a1 100644 --- a/pyrogram/client/methods/users/get_profile_photos.py +++ b/pyrogram/methods/users/get_profile_photos.py @@ -18,19 +18,19 @@ from typing import Union, List -import pyrogram -from pyrogram.api import functions, types -from pyrogram.client.ext import utils -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram import utils +from pyrogram.scaffold import Scaffold -class GetProfilePhotos(BaseClient): +class GetProfilePhotos(Scaffold): async def get_profile_photos( self, chat_id: Union[int, str], offset: int = 0, limit: int = 100 - ) -> List["pyrogram.Photo"]: + ) -> List["types.Photo"]: """Get a list of profile pictures for a user or a chat. Parameters: @@ -48,7 +48,7 @@ class GetProfilePhotos(BaseClient): Values between 1—100 are accepted. Defaults to 100. Returns: - List of :obj:`Photo`: On success, a list of profile photos is returned. + List of :obj:`~pyrogram.types.Photo`: On success, a list of profile photos is returned. Example: .. code-block:: python @@ -64,14 +64,14 @@ class GetProfilePhotos(BaseClient): """ peer_id = await self.resolve_peer(chat_id) - if isinstance(peer_id, types.InputPeerChannel): + if isinstance(peer_id, raw.types.InputPeerChannel): r = await utils.parse_messages( self, await self.send( - functions.messages.Search( + raw.functions.messages.Search( peer=peer_id, q="", - filter=types.InputMessagesFilterChatPhotos(), + filter=raw.types.InputMessagesFilterChatPhotos(), min_date=0, max_date=0, offset_id=0, @@ -84,10 +84,10 @@ class GetProfilePhotos(BaseClient): ) ) - return pyrogram.List([message.new_chat_photo for message in r][:limit]) + return types.List([message.new_chat_photo for message in r][:limit]) else: r = await self.send( - functions.photos.GetUserPhotos( + raw.functions.photos.GetUserPhotos( user_id=peer_id, offset=offset, max_id=0, @@ -95,4 +95,4 @@ class GetProfilePhotos(BaseClient): ) ) - return pyrogram.List(pyrogram.Photo._parse(self, photo) for photo in r.photos) + return types.List(types.Photo._parse(self, photo) for photo in r.photos) diff --git a/pyrogram/client/methods/users/get_profile_photos_count.py b/pyrogram/methods/users/get_profile_photos_count.py similarity index 83% rename from pyrogram/client/methods/users/get_profile_photos_count.py rename to pyrogram/methods/users/get_profile_photos_count.py index affc00e1..65b4e168 100644 --- a/pyrogram/client/methods/users/get_profile_photos_count.py +++ b/pyrogram/methods/users/get_profile_photos_count.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions, types -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class GetProfilePhotosCount(BaseClient): +class GetProfilePhotosCount(Scaffold): async def get_profile_photos_count(self, chat_id: Union[int, str]) -> int: """Get the total count of profile pictures for a user. @@ -44,18 +44,18 @@ class GetProfilePhotosCount(BaseClient): peer_id = await self.resolve_peer(chat_id) - if isinstance(peer_id, types.InputPeerChannel): + if isinstance(peer_id, raw.types.InputPeerChannel): r = await self.send( - functions.messages.GetSearchCounters( + raw.functions.messages.GetSearchCounters( peer=peer_id, - filters=[types.InputMessagesFilterChatPhotos()], + filters=[raw.types.InputMessagesFilterChatPhotos()], ) ) return r[0].count else: r = await self.send( - functions.photos.GetUserPhotos( + raw.functions.photos.GetUserPhotos( user_id=peer_id, offset=0, max_id=0, @@ -63,7 +63,7 @@ class GetProfilePhotosCount(BaseClient): ) ) - if isinstance(r, types.photos.Photos): + if isinstance(r, raw.types.photos.Photos): return len(r.photos) else: return r.count diff --git a/pyrogram/client/methods/users/get_users.py b/pyrogram/methods/users/get_users.py similarity index 77% rename from pyrogram/client/methods/users/get_users.py rename to pyrogram/methods/users/get_users.py index 05476bc4..cf591d2b 100644 --- a/pyrogram/client/methods/users/get_users.py +++ b/pyrogram/methods/users/get_users.py @@ -19,16 +19,16 @@ import asyncio from typing import Iterable, Union, List -import pyrogram -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold -class GetUsers(BaseClient): +class GetUsers(Scaffold): async def get_users( self, user_ids: Union[Iterable[Union[int, str]], int, str] - ) -> Union["pyrogram.User", List["pyrogram.User"]]: + ) -> Union["types.User", List["types.User"]]: """Get information about a user. You can retrieve up to 200 users at once. @@ -39,9 +39,9 @@ class GetUsers(BaseClient): Iterators and Generators are also accepted. Returns: - :obj:`User` | List of :obj:`User`: In case *user_ids* was an integer or string the single requested user is - returned, otherwise, in case *user_ids* was an iterable a list of users is returned, even if the iterable - contained one item only. + :obj:`~pyrogram.types.User` | List of :obj:`~pyrogram.types.User`: In case *user_ids* was an integer or + string the single requested user is returned, otherwise, in case *user_ids* was an iterable a list of users + is returned, even if the iterable contained one item only. Example: .. code-block:: python @@ -57,14 +57,14 @@ class GetUsers(BaseClient): user_ids = await asyncio.gather(*[self.resolve_peer(i) for i in user_ids]) r = await self.send( - functions.users.GetUsers( + raw.functions.users.GetUsers( id=user_ids ) ) - users = pyrogram.List() + users = types.List() for i in r: - users.append(pyrogram.User._parse(self, i)) + users.append(types.User._parse(self, i)) return users if is_iterable else users[0] diff --git a/pyrogram/client/methods/users/iter_profile_photos.py b/pyrogram/methods/users/iter_profile_photos.py similarity index 80% rename from pyrogram/client/methods/users/iter_profile_photos.py rename to pyrogram/methods/users/iter_profile_photos.py index bdd3d8b7..ee196f65 100644 --- a/pyrogram/client/methods/users/iter_profile_photos.py +++ b/pyrogram/methods/users/iter_profile_photos.py @@ -16,27 +16,24 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from typing import Union, Generator, Optional +from typing import Union, AsyncGenerator, Optional -import pyrogram -from async_generator import async_generator, yield_ - -from ...ext import BaseClient +from pyrogram import types +from pyrogram.scaffold import Scaffold -class IterProfilePhotos(BaseClient): - @async_generator +class IterProfilePhotos(Scaffold): async def iter_profile_photos( self, chat_id: Union[int, str], offset: int = 0, limit: int = 0, - ) -> Optional[Generator["pyrogram.Message", None, None]]: + ) -> Optional[AsyncGenerator["types.Message", None]]: """Iterate through a chat or a user profile photos sequentially. - This convenience method does the same as repeatedly calling :meth:`~Client.get_profile_photos` in a loop, thus - saving you from the hassle of setting up boilerplate code. It is useful for getting all the profile photos with - a single call. + This convenience method does the same as repeatedly calling :meth:`~pyrogram.Client.get_profile_photos` in a + loop, thus saving you from the hassle of setting up boilerplate code. It is useful for getting all the profile + photos with a single call. Parameters: chat_id (``int`` | ``str``): @@ -52,7 +49,7 @@ class IterProfilePhotos(BaseClient): Sequential number of the first profile photo to be returned. Returns: - ``Generator``: A generator yielding :obj:`Photo` objects. + ``Generator``: A generator yielding :obj:`~pyrogram.types.Photo` objects. Example: .. code-block:: python @@ -77,7 +74,7 @@ class IterProfilePhotos(BaseClient): offset += len(photos) for photo in photos: - await yield_(photo) + yield photo current += 1 diff --git a/pyrogram/client/methods/users/set_profile_photo.py b/pyrogram/methods/users/set_profile_photo.py similarity index 94% rename from pyrogram/client/methods/users/set_profile_photo.py rename to pyrogram/methods/users/set_profile_photo.py index b9dbbf10..9d72c033 100644 --- a/pyrogram/client/methods/users/set_profile_photo.py +++ b/pyrogram/methods/users/set_profile_photo.py @@ -18,11 +18,11 @@ from typing import Union, BinaryIO -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class SetProfilePhoto(BaseClient): +class SetProfilePhoto(Scaffold): async def set_profile_photo( self, *, @@ -65,7 +65,7 @@ class SetProfilePhoto(BaseClient): return bool( await self.send( - functions.photos.UploadProfilePhoto( + raw.functions.photos.UploadProfilePhoto( file=await self.save_file(photo), video=await self.save_file(video) ) diff --git a/pyrogram/client/methods/users/unblock_user.py b/pyrogram/methods/users/unblock_user.py similarity index 91% rename from pyrogram/client/methods/users/unblock_user.py rename to pyrogram/methods/users/unblock_user.py index fddf9ff6..9f9e76bb 100644 --- a/pyrogram/client/methods/users/unblock_user.py +++ b/pyrogram/methods/users/unblock_user.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class UnblockUser(BaseClient): +class UnblockUser(Scaffold): async def unblock_user( self, user_id: Union[int, str] @@ -45,7 +45,7 @@ class UnblockUser(BaseClient): """ return bool( await self.send( - functions.contacts.Unblock( + raw.functions.contacts.Unblock( id=await self.resolve_peer(user_id) ) ) diff --git a/pyrogram/client/methods/users/update_profile.py b/pyrogram/methods/users/update_profile.py similarity index 93% rename from pyrogram/client/methods/users/update_profile.py rename to pyrogram/methods/users/update_profile.py index 145d5035..15c70793 100644 --- a/pyrogram/client/methods/users/update_profile.py +++ b/pyrogram/methods/users/update_profile.py @@ -16,11 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class UpdateProfile(BaseClient): +class UpdateProfile(Scaffold): async def update_profile( self, first_name: str = None, @@ -61,7 +61,7 @@ class UpdateProfile(BaseClient): return bool( await self.send( - functions.account.UpdateProfile( + raw.functions.account.UpdateProfile( first_name=first_name, last_name=last_name, about=bio diff --git a/pyrogram/client/methods/users/update_username.py b/pyrogram/methods/users/update_username.py similarity index 88% rename from pyrogram/client/methods/users/update_username.py rename to pyrogram/methods/users/update_username.py index 50e2388c..2689c59d 100644 --- a/pyrogram/client/methods/users/update_username.py +++ b/pyrogram/methods/users/update_username.py @@ -18,11 +18,11 @@ from typing import Union -from pyrogram.api import functions -from ...ext import BaseClient +from pyrogram import raw +from pyrogram.scaffold import Scaffold -class UpdateUsername(BaseClient): +class UpdateUsername(Scaffold): async def update_username( self, username: Union[str, None] @@ -31,7 +31,7 @@ class UpdateUsername(BaseClient): This method only works for users, not bots. Bot usernames must be changed via Bot Support or by recreating them from scratch using BotFather. To update a channel or supergroup username you can use - :meth:`~Client.update_chat_username`. + :meth:`~pyrogram.Client.update_chat_username`. Parameters: username (``str`` | ``None``): @@ -48,7 +48,7 @@ class UpdateUsername(BaseClient): return bool( await self.send( - functions.account.UpdateUsername( + raw.functions.account.UpdateUsername( username=username or "" ) ) diff --git a/pyrogram/methods/utilities/__init__.py b/pyrogram/methods/utilities/__init__.py new file mode 100644 index 00000000..d6ddcd3c --- /dev/null +++ b/pyrogram/methods/utilities/__init__.py @@ -0,0 +1,39 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from .add_handler import AddHandler +from .export_session_string import ExportSessionString +from .remove_handler import RemoveHandler +from .restart import Restart +from .run import Run +from .start import Start +from .stop import Stop +from .stop_transmission import StopTransmission + + +class Utilities( + AddHandler, + ExportSessionString, + RemoveHandler, + Restart, + Run, + Start, + Stop, + StopTransmission +): + pass diff --git a/pyrogram/methods/utilities/add_handler.py b/pyrogram/methods/utilities/add_handler.py new file mode 100644 index 00000000..f8d993cd --- /dev/null +++ b/pyrogram/methods/utilities/add_handler.py @@ -0,0 +1,63 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from pyrogram.handlers import DisconnectHandler +from pyrogram.handlers.handler import Handler +from pyrogram.scaffold import Scaffold + + +class AddHandler(Scaffold): + def add_handler(self, handler: "Handler", group: int = 0): + """Register an update handler. + + You can register multiple handlers, but at most one handler within a group will be used for a single update. + To handle the same update more than once, register your handler using a different group id (lower group id + == higher priority). This mechanism is explained in greater details at + :doc:`More on Updates <../../topics/more-on-updates>`. + + Parameters: + handler (``Handler``): + The handler to be registered. + + group (``int``, *optional*): + The group identifier, defaults to 0. + + Returns: + ``tuple``: A tuple consisting of *(handler, group)*. + + Example: + .. code-block:: python + :emphasize-lines: 8 + + from pyrogram import Client, MessageHandler + + def dump(client, message): + print(message) + + app = Client("my_account") + + app.add_handler(MessageHandler(dump)) + + app.run() + """ + if isinstance(handler, DisconnectHandler): + self.disconnect_handler = handler.callback + else: + self.dispatcher.add_handler(handler, group) + + return handler, group diff --git a/pyrogram/methods/utilities/export_session_string.py b/pyrogram/methods/utilities/export_session_string.py new file mode 100644 index 00000000..4b9a4fce --- /dev/null +++ b/pyrogram/methods/utilities/export_session_string.py @@ -0,0 +1,44 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from pyrogram.scaffold import Scaffold + + +class ExportSessionString(Scaffold): + async def export_session_string(self): + """Export the current authorized session as a serialized string. + + Session strings are useful for storing in-memory authorized sessions in a portable, serialized string. + More detailed information about session strings can be found at the dedicated page of + :doc:`Storage Engines <../../topics/storage-engines>`. + + Returns: + ``str``: The session serialized into a printable, url-safe string. + + Example: + .. code-block:: python + :emphasize-lines: 6 + + from pyrogram import Client + + app = Client("my_account") + + with app: + print(app.export_session_string()) + """ + return await self.storage.export_session_string() diff --git a/pyrogram/methods/utilities/idle.py b/pyrogram/methods/utilities/idle.py new file mode 100644 index 00000000..86131ea2 --- /dev/null +++ b/pyrogram/methods/utilities/idle.py @@ -0,0 +1,78 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import asyncio +import logging +import signal + +log = logging.getLogger(__name__) + +loop = asyncio.get_event_loop() +event = asyncio.Event() + + +async def idle(): + """Block the main script execution until a signal is received. + + This function will run indefinitely in order to block the main script execution and prevent it from + exiting while having client(s) that are still running in the background. + + It is useful for event-driven application only, that are, applications which react upon incoming Telegram + updates through handlers, rather than executing a set of methods sequentially. + + The way Pyrogram works, it will keep your handlers in a pool of worker threads, which are executed concurrently + outside the main thread; calling idle() will ensure the client(s) will be kept alive by not letting the main + script to end, until you decide to quit. + + Once a signal is received (e.g.: from CTRL+C) the function will terminate and your main script will continue. + Don't forget to call :meth:`~pyrogram.Client.stop` for each running client before the script ends. + + Example: + .. code-block:: python + :emphasize-lines: 13 + + from pyrogram import Client, idle + + app1 = Client("account1") + app2 = Client("account2") + app3 = Client("account3") + + ... # Set handlers up + + app1.start() + app2.start() + app3.start() + + idle() + + app1.stop() + app2.stop() + app3.stop() + """ + + def handler(): + log.info("Stop signal received") + event.set() + + asyncio.get_event_loop().add_signal_handler(signal.SIGINT, handler) + + log.info("Idle started") + await event.wait() + + log.info("Idle stopped") + event.clear() diff --git a/pyrogram/methods/utilities/remove_handler.py b/pyrogram/methods/utilities/remove_handler.py new file mode 100644 index 00000000..5a4de8c1 --- /dev/null +++ b/pyrogram/methods/utilities/remove_handler.py @@ -0,0 +1,59 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from pyrogram.handlers import DisconnectHandler +from pyrogram.handlers.handler import Handler +from pyrogram.scaffold import Scaffold + + +class RemoveHandler(Scaffold): + def remove_handler(self, handler: "Handler", group: int = 0): + """Remove a previously-registered update handler. + + Make sure to provide the right group where the handler was added in. You can use the return value of the + :meth:`~pyrogram.Client.add_handler` method, a tuple of *(handler, group)*, and pass it directly. + + Parameters: + handler (``Handler``): + The handler to be removed. + + group (``int``, *optional*): + The group identifier, defaults to 0. + + Example: + .. code-block:: python + :emphasize-lines: 11 + + from pyrogram import Client, MessageHandler + + def dump(client, message): + print(message) + + app = Client("my_account") + + handler = app.add_handler(MessageHandler(dump)) + + # Starred expression to unpack (handler, group) + app.remove_handler(*handler) + + app.run() + """ + if isinstance(handler, DisconnectHandler): + self.disconnect_handler = None + else: + self.dispatcher.remove_handler(handler, group) diff --git a/pyrogram/methods/utilities/restart.py b/pyrogram/methods/utilities/restart.py new file mode 100644 index 00000000..ad842bc4 --- /dev/null +++ b/pyrogram/methods/utilities/restart.py @@ -0,0 +1,70 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import asyncio + +from pyrogram.scaffold import Scaffold + + +class Restart(Scaffold): + async def restart(self, block: bool = True): + """Restart the Client. + + This method will first call :meth:`~pyrogram.Client.stop` and then :meth:`~pyrogram.Client.start` in a row in + order to restart a client using a single method. + + Parameters: + block (``bool``, *optional*): + Blocks the code execution until the client has been restarted. It is useful with ``block=False`` in case + you want to restart the own client *within* an handler in order not to cause a deadlock. + Defaults to True. + + Returns: + :obj:`~pyrogram.Client`: The restarted client itself. + + Raises: + ConnectionError: In case you try to restart a stopped Client. + + Example: + .. code-block:: python + :emphasize-lines: 8 + + from pyrogram import Client + + app = Client("my_account") + app.start() + + ... # Call API methods + + app.restart() + + ... # Call other API methods + + app.stop() + """ + + async def do_it(): + await self.stop() + await self.start() + + if block: + await do_it() + else: + asyncio.ensure_future(do_it()) + + return self diff --git a/pyrogram/methods/utilities/run.py b/pyrogram/methods/utilities/run.py new file mode 100644 index 00000000..dc49a524 --- /dev/null +++ b/pyrogram/methods/utilities/run.py @@ -0,0 +1,57 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import asyncio + +from pyrogram.methods.utilities.idle import idle +from pyrogram.scaffold import Scaffold + + +class Run(Scaffold): + def run(self, coroutine=None): + """Start the client, idle the main script and finally stop the client. + + This is a convenience method that calls :meth:`~pyrogram.Client.start`, :meth:`~pyrogram.idle` and + :meth:`~pyrogram.Client.stop` in sequence. It makes running a client less verbose, but is not suitable in case + you want to run more than one client in a single main script, since :meth:`~pyrogram.idle` will block after + starting the own client. + + Raises: + ConnectionError: In case you try to run an already started client. + + Example: + .. code-block:: python + :emphasize-lines: 7 + + from pyrogram import Client + + app = Client("my_account") + + ... # Set handlers up + + app.run() + """ + loop = asyncio.get_event_loop() + run = loop.run_until_complete + + if coroutine is not None: + run(coroutine) + else: + self.start() + run(idle()) + self.stop() diff --git a/pyrogram/methods/utilities/start.py b/pyrogram/methods/utilities/start.py new file mode 100644 index 00000000..8a886257 --- /dev/null +++ b/pyrogram/methods/utilities/start.py @@ -0,0 +1,69 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import logging + +from pyrogram import raw +from pyrogram.scaffold import Scaffold + +log = logging.getLogger(__name__) + + +class Start(Scaffold): + async def start(self): + """Start the client. + + This method connects the client to Telegram and, in case of new sessions, automatically manages the full + authorization process using an interactive prompt. + + Returns: + :obj:`~pyrogram.Client`: The started client itself. + + Raises: + ConnectionError: In case you try to start an already started client. + + Example: + .. code-block:: python + :emphasize-lines: 4 + + from pyrogram import Client + + app = Client("my_account") + app.start() + + ... # Call API methods + + app.stop() + """ + is_authorized = await self.connect() + + try: + if not is_authorized: + await self.authorize() + + if not await self.storage.is_bot() and self.takeout: + self.takeout_id = (await self.send(raw.functions.account.InitTakeoutSession())).id + log.warning(f"Takeout session {self.takeout_id} initiated") + + await self.send(raw.functions.updates.GetState()) + except (Exception, KeyboardInterrupt): + await self.disconnect() + raise + else: + await self.initialize() + return self diff --git a/pyrogram/methods/utilities/stop.py b/pyrogram/methods/utilities/stop.py new file mode 100644 index 00000000..b48a1431 --- /dev/null +++ b/pyrogram/methods/utilities/stop.py @@ -0,0 +1,65 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import asyncio + +from pyrogram.scaffold import Scaffold + + +class Stop(Scaffold): + async def stop(self, block: bool = True): + """Stop the Client. + + This method disconnects the client from Telegram and stops the underlying tasks. + + Parameters: + block (``bool``, *optional*): + Blocks the code execution until the client has been stopped. It is useful with ``block=False`` in case + you want to stop the own client *within* a handler in order not to cause a deadlock. + Defaults to True. + + Returns: + :obj:`~pyrogram.Client`: The stopped client itself. + + Raises: + ConnectionError: In case you try to stop an already stopped client. + + Example: + .. code-block:: python + :emphasize-lines: 8 + + from pyrogram import Client + + app = Client("my_account") + app.start() + + ... # Call API methods + + app.stop() + """ + + async def do_it(): + await self.terminate() + await self.disconnect() + + if block: + await do_it() + else: + asyncio.ensure_future(do_it()) + + return self diff --git a/pyrogram/methods/utilities/stop_transmission.py b/pyrogram/methods/utilities/stop_transmission.py new file mode 100644 index 00000000..6eaedf4d --- /dev/null +++ b/pyrogram/methods/utilities/stop_transmission.py @@ -0,0 +1,47 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import pyrogram +from pyrogram.scaffold import Scaffold + + +class StopTransmission(Scaffold): + def stop_transmission(self): + """Stop downloading or uploading a file. + + This method must be called inside a progress callback function in order to stop the transmission at the + desired time. The progress callback is called every time a file chunk is uploaded/downloaded. + + Example: + .. code-block:: python + :emphasize-lines: 9 + + from pyrogram import Client + + app = Client("my_account") + + # Example to stop transmission once the upload progress reaches 50% + # Useless in practice, but shows how to stop on command + def progress(current, total, client): + if (current * 100 / total) > 50: + client.stop_transmission() + + with app: + app.send_document("me", "files.zip", progress=progress, progress_args=(app,)) + """ + raise pyrogram.StopTransmission diff --git a/pyrogram/client/ext/mime.types b/pyrogram/mime.types similarity index 100% rename from pyrogram/client/ext/mime.types rename to pyrogram/mime.types diff --git a/pyrogram/client/parser/__init__.py b/pyrogram/parser/__init__.py similarity index 100% rename from pyrogram/client/parser/__init__.py rename to pyrogram/parser/__init__.py diff --git a/pyrogram/client/parser/html.py b/pyrogram/parser/html.py similarity index 74% rename from pyrogram/client/parser/html.py rename to pyrogram/parser/html.py index 3ce70d51..7fa1d94d 100644 --- a/pyrogram/client/parser/html.py +++ b/pyrogram/parser/html.py @@ -19,12 +19,11 @@ import html import logging import re -from collections import OrderedDict from html.parser import HTMLParser from typing import Union import pyrogram -from pyrogram.api import types +from pyrogram import raw from pyrogram.errors import PeerIdInvalid from . import utils @@ -34,7 +33,7 @@ log = logging.getLogger(__name__) class Parser(HTMLParser): MENTION_RE = re.compile(r"tg://user\?id=(\d+)") - def __init__(self, client: "pyrogram.BaseClient"): + def __init__(self, client: "pyrogram.Client"): super().__init__() self.client = client @@ -48,19 +47,19 @@ class Parser(HTMLParser): extra = {} if tag in ["b", "strong"]: - entity = types.MessageEntityBold + entity = raw.types.MessageEntityBold elif tag in ["i", "em"]: - entity = types.MessageEntityItalic + entity = raw.types.MessageEntityItalic elif tag == "u": - entity = types.MessageEntityUnderline + entity = raw.types.MessageEntityUnderline elif tag in ["s", "del", "strike"]: - entity = types.MessageEntityStrike + entity = raw.types.MessageEntityStrike elif tag == "blockquote": - entity = types.MessageEntityBlockquote + entity = raw.types.MessageEntityBlockquote elif tag == "code": - entity = types.MessageEntityCode + entity = raw.types.MessageEntityCode elif tag == "pre": - entity = types.MessageEntityPre + entity = raw.types.MessageEntityPre extra["language"] = "" elif tag == "a": url = attrs.get("href", "") @@ -68,10 +67,10 @@ class Parser(HTMLParser): mention = Parser.MENTION_RE.match(url) if mention: - entity = types.InputMessageEntityMentionName + entity = raw.types.InputMessageEntityMentionName extra["user_id"] = int(mention.group(1)) else: - entity = types.MessageEntityTextUrl + entity = raw.types.MessageEntityTextUrl extra["url"] = url else: return @@ -97,7 +96,7 @@ class Parser(HTMLParser): line, offset = self.getpos() offset += 1 - log.warning("Unmatched closing tag at line {}:{}".format(tag, line, offset)) + log.warning(f"Unmatched closing tag at line {line}:{offset}") else: if not self.tag_entities[tag]: self.tag_entities.pop(tag) @@ -107,7 +106,7 @@ class Parser(HTMLParser): class HTML: - def __init__(self, client: Union["pyrogram.BaseClient", None]): + def __init__(self, client: Union["pyrogram.Client", None]): self.client = client async def parse(self, text: str): @@ -122,14 +121,14 @@ class HTML: unclosed_tags = [] for tag, entities in parser.tag_entities.items(): - unclosed_tags.append("<{}> (x{})".format(tag, len(entities))) + unclosed_tags.append(f"<{tag}> (x{len(entities)})") - log.warning("Unclosed tags: {}".format(", ".join(unclosed_tags))) + log.warning(f"Unclosed tags: {', '.join(unclosed_tags)}") entities = [] for entity in parser.entities: - if isinstance(entity, types.InputMessageEntityMentionName): + if isinstance(entity, raw.types.InputMessageEntityMentionName): try: if self.client is not None: entity.user_id = await self.client.resolve_peer(entity.user_id) @@ -138,11 +137,10 @@ class HTML: entities.append(entity) - # TODO: OrderedDict to be removed in Python 3.6 - return OrderedDict([ - ("message", utils.remove_surrogates(parser.text)), - ("entities", sorted(entities, key=lambda e: e.offset)) - ]) + return { + "message": utils.remove_surrogates(parser.text), + "entities": sorted(entities, key=lambda e: e.offset) + } @staticmethod def unparse(text: str, entities: list): @@ -156,18 +154,18 @@ class HTML: end = start + entity.length if entity_type in ("bold", "italic", "underline", "strike"): - start_tag = "<{}>".format(entity_type[0]) - end_tag = "".format(entity_type[0]) + start_tag = f"<{entity_type[0]}>" + end_tag = "f" elif entity_type in ("code", "pre", "blockquote"): - start_tag = "<{}>".format(entity_type) - end_tag = "".format(entity_type) + start_tag = f"<{entity_type}>" + end_tag = f"" elif entity_type == "text_link": url = entity.url - start_tag = ''.format(url) + start_tag = f'' end_tag = "" elif entity_type == "text_mention": user = entity.user - start_tag = ''.format(user.id) + start_tag = f'' end_tag = "" else: continue diff --git a/pyrogram/client/parser/markdown.py b/pyrogram/parser/markdown.py similarity index 95% rename from pyrogram/client/parser/markdown.py rename to pyrogram/parser/markdown.py index 4c954efd..e821dbd3 100644 --- a/pyrogram/client/parser/markdown.py +++ b/pyrogram/parser/markdown.py @@ -34,7 +34,7 @@ PRE_DELIM = "```" MARKDOWN_RE = re.compile(r"({d})|\[(.+?)\]\((.+?)\)".format( d="|".join( ["".join(i) for i in [ - [r"\{}".format(j) for j in i] + [rf"\{j}" for j in i] for i in [ PRE_DELIM, CODE_DELIM, @@ -53,7 +53,7 @@ FIXED_WIDTH_DELIMS = [CODE_DELIM, PRE_DELIM] class Markdown: - def __init__(self, client: Union["pyrogram.BaseClient", None]): + def __init__(self, client: Union["pyrogram.Client", None]): self.html = HTML(client) async def parse(self, text: str, strict: bool = False): @@ -130,11 +130,11 @@ class Markdown: elif entity_type == "text_link": url = entity.url start_tag = "[" - end_tag = "]({})".format(url) + end_tag = f"]({url})" elif entity_type == "text_mention": user = entity.user start_tag = "[" - end_tag = "](tg://user?id={})".format(user.id) + end_tag = f"](tg://user?id={user.id})" else: continue diff --git a/pyrogram/client/parser/parser.py b/pyrogram/parser/parser.py similarity index 93% rename from pyrogram/client/parser/parser.py rename to pyrogram/parser/parser.py index eb4f2e19..64d17241 100644 --- a/pyrogram/client/parser/parser.py +++ b/pyrogram/parser/parser.py @@ -25,7 +25,7 @@ from .markdown import Markdown class Parser: - def __init__(self, client: Union["pyrogram.BaseClient", None]): + def __init__(self, client: Union["pyrogram.Client", None]): self.client = client self.html = HTML(client) self.markdown = Markdown(client) @@ -57,7 +57,7 @@ class Parser: return await self.html.parse(text) raise ValueError('parse_mode must be one of {} or None. Not "{}"'.format( - ", ".join('"{}"'.format(m) for m in pyrogram.Client.PARSE_MODES[:-1]), + ", ".join(f'"{m}"' for m in pyrogram.Client.PARSE_MODES[:-1]), mode )) diff --git a/pyrogram/client/parser/utils.py b/pyrogram/parser/utils.py similarity index 100% rename from pyrogram/client/parser/utils.py rename to pyrogram/parser/utils.py diff --git a/pyrogram/api/__init__.py b/pyrogram/raw/__init__.py similarity index 95% rename from pyrogram/api/__init__.py rename to pyrogram/raw/__init__.py index da5b075e..2bbf90d7 100644 --- a/pyrogram/api/__init__.py +++ b/pyrogram/raw/__init__.py @@ -18,6 +18,7 @@ from importlib import import_module +from . import types, functions, base, core from .all import objects for k, v in objects.items(): diff --git a/pyrogram/api/core/__init__.py b/pyrogram/raw/core/__init__.py similarity index 80% rename from pyrogram/api/core/__init__.py rename to pyrogram/raw/core/__init__.py index 22484f6f..0a4b2a82 100644 --- a/pyrogram/api/core/__init__.py +++ b/pyrogram/raw/core/__init__.py @@ -22,5 +22,10 @@ from .gzip_packed import GzipPacked from .list import List from .message import Message from .msg_container import MsgContainer -from .primitives import * +from .primitives.bool import Bool, BoolFalse, BoolTrue +from .primitives.bytes import Bytes +from .primitives.double import Double +from .primitives.int import Int, Long, Int128, Int256 +from .primitives.string import String +from .primitives.vector import Vector from .tl_object import TLObject diff --git a/pyrogram/api/core/future_salt.py b/pyrogram/raw/core/future_salt.py similarity index 83% rename from pyrogram/api/core/future_salt.py rename to pyrogram/raw/core/future_salt.py index cc9f7bc0..7d163e6b 100644 --- a/pyrogram/api/core/future_salt.py +++ b/pyrogram/raw/core/future_salt.py @@ -17,13 +17,14 @@ # along with Pyrogram. If not, see . from io import BytesIO +from typing import Any -from .primitives import Int, Long +from .primitives.int import Int, Long from .tl_object import TLObject class FutureSalt(TLObject): - ID = 0x0949d9dc + ID = 0x0949D9DC __slots__ = ["valid_since", "valid_until", "salt"] @@ -35,9 +36,9 @@ class FutureSalt(TLObject): self.salt = salt @staticmethod - def read(b: BytesIO, *args) -> "FutureSalt": - valid_since = Int.read(b) - valid_until = Int.read(b) - salt = Long.read(b) + def read(data: BytesIO, *args: Any) -> "FutureSalt": + valid_since = Int.read(data) + valid_until = Int.read(data) + salt = Long.read(data) return FutureSalt(valid_since, valid_until, salt) diff --git a/pyrogram/api/core/future_salts.py b/pyrogram/raw/core/future_salts.py similarity index 73% rename from pyrogram/api/core/future_salts.py rename to pyrogram/raw/core/future_salts.py index f22b4643..f8a48353 100644 --- a/pyrogram/api/core/future_salts.py +++ b/pyrogram/raw/core/future_salts.py @@ -17,30 +17,31 @@ # along with Pyrogram. If not, see . from io import BytesIO +from typing import Any, List -from . import FutureSalt -from .primitives import Int, Long +from .future_salt import FutureSalt +from .primitives.int import Int, Long from .tl_object import TLObject class FutureSalts(TLObject): - ID = 0xae500895 + ID = 0xAE500895 __slots__ = ["req_msg_id", "now", "salts"] QUALNAME = "FutureSalts" - def __init__(self, req_msg_id: int, now: int, salts: list): + def __init__(self, req_msg_id: int, now: int, salts: List[FutureSalt]): self.req_msg_id = req_msg_id self.now = now self.salts = salts @staticmethod - def read(b: BytesIO, *args) -> "FutureSalts": - req_msg_id = Long.read(b) - now = Int.read(b) + def read(data: BytesIO, *args: Any) -> "FutureSalts": + req_msg_id = Long.read(data) + now = Int.read(data) - count = Int.read(b) - salts = [FutureSalt.read(b) for _ in range(count)] + count = Int.read(data) + salts = [FutureSalt.read(data) for _ in range(count)] return FutureSalts(req_msg_id, now, salts) diff --git a/pyrogram/api/core/gzip_packed.py b/pyrogram/raw/core/gzip_packed.py similarity index 82% rename from pyrogram/api/core/gzip_packed.py rename to pyrogram/raw/core/gzip_packed.py index 1920c67d..094162d5 100644 --- a/pyrogram/api/core/gzip_packed.py +++ b/pyrogram/raw/core/gzip_packed.py @@ -18,13 +18,15 @@ from gzip import compress, decompress from io import BytesIO +from typing import cast, Any -from .primitives import Int, Bytes +from .primitives.bytes import Bytes +from .primitives.int import Int from .tl_object import TLObject class GzipPacked(TLObject): - ID = 0x3072cfa1 + ID = 0x3072CFA1 __slots__ = ["packed_data"] @@ -34,17 +36,17 @@ class GzipPacked(TLObject): self.packed_data = packed_data @staticmethod - def read(b: BytesIO, *args) -> "GzipPacked": + def read(data: BytesIO, *args: Any) -> "GzipPacked": # Return the Object itself instead of a GzipPacked wrapping it - return TLObject.read( + return cast(GzipPacked, TLObject.read( BytesIO( decompress( - Bytes.read(b) + Bytes.read(data) ) ) - ) + )) - def write(self) -> bytes: + def write(self, *args: Any) -> bytes: b = BytesIO() b.write(Int(self.ID, False)) diff --git a/pyrogram/api/core/list.py b/pyrogram/raw/core/list.py similarity index 81% rename from pyrogram/api/core/list.py rename to pyrogram/raw/core/list.py index 0e083f17..c0014b68 100644 --- a/pyrogram/api/core/list.py +++ b/pyrogram/raw/core/list.py @@ -16,13 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from typing import List as TList, Any + from .tl_object import TLObject -class List(list, TLObject): - __slots__ = [] - - def __repr__(self): - return "pyrogram.api.core.List([{}])".format( - ",".join(TLObject.__repr__(i) for i in self) - ) +class List(TList[Any], TLObject): + def __repr__(self) -> str: + return f"pyrogram.api.core.List([{','.join(TLObject.__repr__(i) for i in self)}])" diff --git a/pyrogram/api/core/message.py b/pyrogram/raw/core/message.py similarity index 81% rename from pyrogram/api/core/message.py rename to pyrogram/raw/core/message.py index 787aa378..e1e595a0 100644 --- a/pyrogram/api/core/message.py +++ b/pyrogram/raw/core/message.py @@ -17,13 +17,14 @@ # along with Pyrogram. If not, see . from io import BytesIO +from typing import Any -from .primitives import Int, Long +from .primitives.int import Int, Long from .tl_object import TLObject class Message(TLObject): - ID = 0x5bb8e511 # hex(crc32(b"message msg_id:long seqno:int bytes:int body:Object = Message")) + ID = 0x5BB8E511 # hex(crc32(b"message msg_id:long seqno:int bytes:int body:Object = Message")) __slots__ = ["msg_id", "seq_no", "length", "body"] @@ -36,15 +37,15 @@ class Message(TLObject): self.body = body @staticmethod - def read(b: BytesIO, *args) -> "Message": - msg_id = Long.read(b) - seq_no = Int.read(b) - length = Int.read(b) - body = b.read(length) + def read(data: BytesIO, *args: Any) -> "Message": + msg_id = Long.read(data) + seq_no = Int.read(data) + length = Int.read(data) + body = data.read(length) return Message(TLObject.read(BytesIO(body)), msg_id, seq_no, length) - def write(self) -> bytes: + def write(self, *args: Any) -> bytes: b = BytesIO() b.write(Long(self.msg_id)) diff --git a/pyrogram/api/core/msg_container.py b/pyrogram/raw/core/msg_container.py similarity index 79% rename from pyrogram/api/core/msg_container.py rename to pyrogram/raw/core/msg_container.py index dc6f755d..aecf7dfc 100644 --- a/pyrogram/api/core/msg_container.py +++ b/pyrogram/raw/core/msg_container.py @@ -17,28 +17,29 @@ # along with Pyrogram. If not, see . from io import BytesIO +from typing import List, Any from .message import Message -from .primitives import Int +from .primitives.int import Int from .tl_object import TLObject class MsgContainer(TLObject): - ID = 0x73f1f8dc + ID = 0x73F1F8DC __slots__ = ["messages"] QUALNAME = "MsgContainer" - def __init__(self, messages: list): + def __init__(self, messages: List[Message]): self.messages = messages @staticmethod - def read(b: BytesIO, *args) -> "MsgContainer": - count = Int.read(b) - return MsgContainer([Message.read(b) for _ in range(count)]) + def read(data: BytesIO, *args: Any) -> "MsgContainer": + count = Int.read(data) + return MsgContainer([Message.read(data) for _ in range(count)]) - def write(self) -> bytes: + def write(self, *args: Any) -> bytes: b = BytesIO() b.write(Int(self.ID, False)) diff --git a/pyrogram/api/core/primitives/__init__.py b/pyrogram/raw/core/primitives/__init__.py similarity index 89% rename from pyrogram/api/core/primitives/__init__.py rename to pyrogram/raw/core/primitives/__init__.py index f7b1c89e..9f6de65a 100644 --- a/pyrogram/api/core/primitives/__init__.py +++ b/pyrogram/raw/core/primitives/__init__.py @@ -22,5 +22,3 @@ from .double import Double from .int import Int, Long, Int128, Int256 from .string import String from .vector import Vector - -__all__ = ["Bool", "BoolFalse", "BoolTrue", "Bytes", "Double", "Int", "Long", "Int128", "Int256", "String", "Vector"] diff --git a/pyrogram/api/core/primitives/bool.py b/pyrogram/raw/core/primitives/bool.py similarity index 73% rename from pyrogram/api/core/primitives/bool.py rename to pyrogram/raw/core/primitives/bool.py index 96637225..a8fb5b4e 100644 --- a/pyrogram/api/core/primitives/bool.py +++ b/pyrogram/raw/core/primitives/bool.py @@ -17,31 +17,32 @@ # along with Pyrogram. If not, see . from io import BytesIO +from typing import Any from ..tl_object import TLObject -class BoolFalse(TLObject): - ID = 0xbc799737 +class BoolFalse(bytes, TLObject): + ID = 0xBC799737 value = False @classmethod - def read(cls, *args) -> bool: + def read(cls, *args: Any) -> bool: return cls.value - def __new__(cls) -> bytes: + def __new__(cls) -> bytes: # type: ignore return cls.ID.to_bytes(4, "little") class BoolTrue(BoolFalse): - ID = 0x997275b5 + ID = 0x997275B5 value = True -class Bool(TLObject): +class Bool(bytes, TLObject): @classmethod - def read(cls, b: BytesIO) -> bool: - return int.from_bytes(b.read(4), "little") == BoolTrue.ID + def read(cls, data: BytesIO, *args: Any) -> bool: + return int.from_bytes(data.read(4), "little") == BoolTrue.ID - def __new__(cls, value: bool) -> BoolTrue or BoolFalse: + def __new__(cls, value: bool) -> bytes: # type: ignore return BoolTrue() if value else BoolFalse() diff --git a/pyrogram/api/core/primitives/bytes.py b/pyrogram/raw/core/primitives/bytes.py similarity index 74% rename from pyrogram/api/core/primitives/bytes.py rename to pyrogram/raw/core/primitives/bytes.py index 298ea544..8c95ebde 100644 --- a/pyrogram/api/core/primitives/bytes.py +++ b/pyrogram/raw/core/primitives/bytes.py @@ -17,26 +17,27 @@ # along with Pyrogram. If not, see . from io import BytesIO +from typing import Any from ..tl_object import TLObject -class Bytes(TLObject): - @staticmethod - def read(b: BytesIO, *args) -> bytes: - length = int.from_bytes(b.read(1), "little") +class Bytes(bytes, TLObject): + @classmethod + def read(cls, data: BytesIO, *args: Any) -> bytes: + length = int.from_bytes(data.read(1), "little") if length <= 253: - x = b.read(length) - b.read(-(length + 1) % 4) + x = data.read(length) + data.read(-(length + 1) % 4) else: - length = int.from_bytes(b.read(3), "little") - x = b.read(length) - b.read(-length % 4) + length = int.from_bytes(data.read(3), "little") + x = data.read(length) + data.read(-length % 4) return x - def __new__(cls, value: bytes) -> bytes: + def __new__(cls, value: bytes) -> bytes: # type: ignore length = len(value) if length <= 253: diff --git a/pyrogram/api/core/primitives/double.py b/pyrogram/raw/core/primitives/double.py similarity index 78% rename from pyrogram/api/core/primitives/double.py rename to pyrogram/raw/core/primitives/double.py index 42cf0031..43dd5d2c 100644 --- a/pyrogram/api/core/primitives/double.py +++ b/pyrogram/raw/core/primitives/double.py @@ -18,14 +18,15 @@ from io import BytesIO from struct import unpack, pack +from typing import cast, Any from ..tl_object import TLObject -class Double(TLObject): - @staticmethod - def read(b: BytesIO, *args) -> float: - return unpack("d", b.read(8))[0] +class Double(bytes, TLObject): + @classmethod + def read(cls, data: BytesIO, *args: Any) -> float: + return cast(float, unpack("d", data.read(8))[0]) - def __new__(cls, value: float) -> bytes: + def __new__(cls, value: float) -> bytes: # type: ignore return pack("d", value) diff --git a/pyrogram/api/core/primitives/int.py b/pyrogram/raw/core/primitives/int.py similarity index 79% rename from pyrogram/api/core/primitives/int.py rename to pyrogram/raw/core/primitives/int.py index bbaf7f2f..7e6135d1 100644 --- a/pyrogram/api/core/primitives/int.py +++ b/pyrogram/raw/core/primitives/int.py @@ -17,18 +17,19 @@ # along with Pyrogram. If not, see . from io import BytesIO +from typing import Any from ..tl_object import TLObject -class Int(TLObject): +class Int(bytes, TLObject): SIZE = 4 @classmethod - def read(cls, b: BytesIO, signed: bool = True) -> int: - return int.from_bytes(b.read(cls.SIZE), "little", signed=signed) + def read(cls, data: BytesIO, signed: bool = True, *args: Any) -> int: + return int.from_bytes(data.read(cls.SIZE), "little", signed=signed) - def __new__(cls, value: int, signed: bool = True) -> bytes: + def __new__(cls, value: int, signed: bool = True) -> bytes: # type: ignore return value.to_bytes(cls.SIZE, "little", signed=signed) diff --git a/pyrogram/api/core/primitives/string.py b/pyrogram/raw/core/primitives/string.py similarity index 76% rename from pyrogram/api/core/primitives/string.py rename to pyrogram/raw/core/primitives/string.py index a0995c5b..dd25b5bf 100644 --- a/pyrogram/api/core/primitives/string.py +++ b/pyrogram/raw/core/primitives/string.py @@ -17,14 +17,15 @@ # along with Pyrogram. If not, see . from io import BytesIO +from typing import cast -from . import Bytes +from .bytes import Bytes class String(Bytes): - @staticmethod - def read(b: BytesIO, *args) -> str: - return super(String, String).read(b).decode(errors="replace") + @classmethod + def read(cls, data: BytesIO, *args) -> str: # type: ignore + return cast(bytes, super(String, String).read(data)).decode(errors="replace") - def __new__(cls, value: str) -> bytes: + def __new__(cls, value: str) -> bytes: # type: ignore return super().__new__(cls, value.encode()) diff --git a/pyrogram/api/core/primitives/vector.py b/pyrogram/raw/core/primitives/vector.py similarity index 73% rename from pyrogram/api/core/primitives/vector.py rename to pyrogram/raw/core/primitives/vector.py index 2c60f576..afb7d591 100644 --- a/pyrogram/api/core/primitives/vector.py +++ b/pyrogram/raw/core/primitives/vector.py @@ -17,39 +17,36 @@ # along with Pyrogram. If not, see . from io import BytesIO +from typing import cast, Union, Any -from . import Int +from .int import Int from ..list import List from ..tl_object import TLObject -class Vector(TLObject): - ID = 0x1cb5c415 +class Vector(bytes, TLObject): + ID = 0x1CB5C415 # Method added to handle the special case when a query returns a bare Vector (of Ints); # i.e., RpcResult body starts with 0x1cb5c415 (Vector Id) - e.g., messages.GetMessagesViews. @staticmethod - def _read(b: BytesIO) -> TLObject or int: + def _read(b: BytesIO) -> Union[int, Any]: try: return TLObject.read(b) except KeyError: b.seek(-4, 1) return Int.read(b) - @staticmethod - def read(b: BytesIO, t: TLObject = None) -> list: + @classmethod + def read(cls, data: BytesIO, t: Any = None, *args: Any) -> List: return List( - t.read(b) if t - else Vector._read(b) - for _ in range(Int.read(b)) + t.read(data) if t + else Vector._read(data) + for _ in range(Int.read(data)) ) - def __new__(cls, value: list, t: TLObject = None) -> bytes: + def __new__(cls, value: list, t: Any = None) -> bytes: # type: ignore return b"".join( [Int(cls.ID, False), Int(len(value))] - + [ - t(i) if t - else i.write() - for i in value - ] + + [cast(bytes, t(i)) if t else i.write() for i in value] ) diff --git a/pyrogram/api/core/tl_object.py b/pyrogram/raw/core/tl_object.py similarity index 71% rename from pyrogram/api/core/tl_object.py rename to pyrogram/raw/core/tl_object.py index d9d5722f..0391ab85 100644 --- a/pyrogram/api/core/tl_object.py +++ b/pyrogram/raw/core/tl_object.py @@ -16,38 +16,38 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from collections import OrderedDict from io import BytesIO from json import dumps +from typing import cast, List, Any, Union, Dict from ..all import objects class TLObject: - __slots__ = [] + __slots__: List[str] = [] QUALNAME = "Base" - @staticmethod - def read(b: BytesIO, *args): # TODO: Rename b -> data - return objects[int.from_bytes(b.read(4), "little")].read(b, *args) + @classmethod + def read(cls, data: BytesIO, *args: Any) -> Any: + return cast(TLObject, objects[int.from_bytes(data.read(4), "little")]).read(data, *args) - def write(self, *args) -> bytes: + def write(self, *args: Any) -> bytes: pass @staticmethod - def default(obj: "TLObject"): + def default(obj: "TLObject") -> Union[str, Dict[str, str]]: if isinstance(obj, bytes): return repr(obj) - return OrderedDict( - [("_", obj.QUALNAME)] - + [ - (attr, getattr(obj, attr)) + return { + "_": obj.QUALNAME, + **{ + attr: getattr(obj, attr) for attr in obj.__slots__ if getattr(obj, attr) is not None - ] - ) + } + } def __str__(self) -> str: return dumps(self, indent=4, default=TLObject.default, ensure_ascii=False) @@ -56,13 +56,13 @@ class TLObject: return "pyrogram.api.{}({})".format( self.QUALNAME, ", ".join( - "{}={}".format(attr, repr(getattr(self, attr))) + f"{attr}={repr(getattr(self, attr))}" for attr in self.__slots__ if getattr(self, attr) is not None ) ) - def __eq__(self, other: "TLObject") -> bool: + def __eq__(self, other: Any) -> bool: for attr in self.__slots__: try: if getattr(self, attr) != getattr(other, attr): @@ -75,8 +75,11 @@ class TLObject: def __len__(self) -> int: return len(self.write()) - def __getitem__(self, item): + def __getitem__(self, item: Any) -> Any: return getattr(self, item) - def __setitem__(self, key, value): + def __setitem__(self, key: Any, value: Any) -> Any: setattr(self, key, value) + + def __call__(self, *args: Any, **kwargs: Any) -> Any: + pass diff --git a/pyrogram/client/ext/base_client.py b/pyrogram/scaffold.py similarity index 65% rename from pyrogram/client/ext/base_client.py rename to pyrogram/scaffold.py index ca4e8f5b..0b3bf021 100644 --- a/pyrogram/client/ext/base_client.py +++ b/pyrogram/scaffold.py @@ -24,36 +24,21 @@ import sys from pathlib import Path from pyrogram import __version__ -from ..parser import Parser -from ...session.internals import MsgId +from pyrogram.parser import Parser +from pyrogram.session.internals import MsgId -class BaseClient: - class StopTransmission(StopAsyncIteration): - pass - - APP_VERSION = "Pyrogram {}".format(__version__) - - DEVICE_MODEL = "{} {}".format( - platform.python_implementation(), - platform.python_version() - ) - - SYSTEM_VERSION = "{} {}".format( - platform.system(), - platform.release() - ) +class Scaffold: + APP_VERSION = f"Pyrogram {__version__}" + DEVICE_MODEL = f"{platform.python_implementation()} {platform.python_version()}" + SYSTEM_VERSION = f"{platform.system()} {platform.release()}" LANG_CODE = "en" PARENT_DIR = Path(sys.argv[0]).parent INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/joinchat/)([\w-]+)$") - DIALOGS_AT_ONCE = 100 - UPDATES_WORKERS = 4 - DOWNLOAD_WORKERS = 4 - OFFLINE_SLEEP = 900 - WORKERS = 4 + WORKERS = min(32, os.cpu_count() + 4) WORKDIR = PARENT_DIR CONFIG_FILE = PARENT_DIR / "config.ini" @@ -76,20 +61,44 @@ class BaseClient: mime_types_to_extensions = {} extensions_to_mime_types = {} - with open("{}/mime.types".format(os.path.dirname(__file__)), "r", encoding="UTF-8") as f: + with open(f"{os.path.dirname(__file__)}/mime.types", "r", encoding="UTF-8") as f: for match in re.finditer(r"^([^#\s]+)\s+(.+)$", f.read(), flags=re.M): mime_type, extensions = match.groups() - extensions = [".{}".format(ext) for ext in extensions.split(" ")] + extensions = [f".{ext}" for ext in extensions.split(" ")] for ext in extensions: extensions_to_mime_types[ext] = mime_type mime_types_to_extensions[mime_type] = " ".join(extensions) - is_idling = False - def __init__(self): + self.session_name = None + self.api_id = None + self.api_hash = None + self.app_version = None + self.device_model = None + self.system_version = None + self.lang_code = None + self.ipv6 = None + self.proxy = None + self.test_mode = None + self.bot_token = None + self.phone_number = None + self.phone_code = None + self.password = None + self.force_sms = None + self.workers = None + self.workdir = None + self.config_file = None + self.plugins = None + self.parse_mode = None + self.no_updates = None + self.takeout = None + self.sleep_threshold = None + + self.executor = None + self.storage = None self.rnd_id = MsgId @@ -98,21 +107,22 @@ class BaseClient: self.parse_mode = "combined" self.session = None + self.media_sessions = {} self.media_sessions_lock = asyncio.Lock() self.is_connected = None self.is_initialized = None + self.no_updates = None self.takeout_id = None - self.updates_queue = asyncio.Queue() - self.updates_worker_tasks = [] - self.download_queue = asyncio.Queue() - self.download_worker_tasks = [] + self.dispatcher = None self.disconnect_handler = None + self.loop = None + async def send(self, *args, **kwargs): pass @@ -172,3 +182,36 @@ class BaseClient: def guess_extension(self, *args, **kwargs): pass + + def load_config(self, *args, **kwargs): + pass + + def load_session(self, *args, **kwargs): + pass + + def load_plugins(self, *args, **kwargs): + pass + + async def handle_download(self, *args, **kwargs): + pass + + async def start(self, *args, **kwargs): + pass + + async def stop(self, *args, **kwargs): + pass + + async def connect(self, *args, **kwargs): + pass + + async def authorize(self, *args, **kwargs): + pass + + async def disconnect(self, *args, **kwargs): + pass + + async def initialize(self, *args, **kwargs): + pass + + async def terminate(self, *args, **kwargs): + pass diff --git a/pyrogram/session/auth.py b/pyrogram/session/auth.py index 6795928a..2aa65821 100644 --- a/pyrogram/session/auth.py +++ b/pyrogram/session/auth.py @@ -24,10 +24,10 @@ from io import BytesIO from os import urandom import pyrogram -from pyrogram.api import functions, types -from pyrogram.api.core import TLObject, Long, Int +from pyrogram import raw from pyrogram.connection import Connection -from pyrogram.crypto import AES, RSA, Prime +from pyrogram.crypto import aes, rsa, prime +from pyrogram.raw.core import TLObject, Long, Int from .internals import MsgId log = logging.getLogger(__name__) @@ -36,9 +36,9 @@ log = logging.getLogger(__name__) class Auth: MAX_RETRIES = 5 - def __init__(self, client: "pyrogram.Client", dc_id: int): + def __init__(self, client: "pyrogram.Client", dc_id: int, test_mode: bool): self.dc_id = dc_id - self.test_mode = client.storage.test_mode() + self.test_mode = test_mode self.ipv6 = client.ipv6 self.proxy = client.proxy @@ -78,40 +78,40 @@ class Auth: self.connection = Connection(self.dc_id, self.test_mode, self.ipv6, self.proxy) try: - log.info("Start creating a new auth key on DC{}".format(self.dc_id)) + log.info(f"Start creating a new auth key on DC{self.dc_id}") await self.connection.connect() # Step 1; Step 2 nonce = int.from_bytes(urandom(16), "little", signed=True) - log.debug("Send req_pq: {}".format(nonce)) - res_pq = await self.send(functions.ReqPqMulti(nonce=nonce)) - log.debug("Got ResPq: {}".format(res_pq.server_nonce)) - log.debug("Server public key fingerprints: {}".format(res_pq.server_public_key_fingerprints)) + log.debug(f"Send req_pq: {nonce}") + res_pq = await self.send(raw.functions.ReqPqMulti(nonce=nonce)) + log.debug(f"Got ResPq: {res_pq.server_nonce}") + log.debug(f"Server public key fingerprints: {res_pq.server_public_key_fingerprints}") for i in res_pq.server_public_key_fingerprints: - if i in RSA.server_public_keys: - log.debug("Using fingerprint: {}".format(i)) + if i in rsa.server_public_keys: + log.debug(f"Using fingerprint: {i}") public_key_fingerprint = i break else: - log.debug("Fingerprint unknown: {}".format(i)) + log.debug(f"Fingerprint unknown: {i}") else: raise Exception("Public key not found") # Step 3 pq = int.from_bytes(res_pq.pq, "big") - log.debug("Start PQ factorization: {}".format(pq)) + log.debug(f"Start PQ factorization: {pq}") start = time.time() - g = Prime.decompose(pq) + g = prime.decompose(pq) p, q = sorted((g, pq // g)) # p < q - log.debug("Done PQ factorization ({}s): {} {}".format(round(time.time() - start, 3), p, q)) + log.debug(f"Done PQ factorization ({round(time.time() - start, 3)}s): {p} {q}") # Step 4 server_nonce = res_pq.server_nonce new_nonce = int.from_bytes(urandom(32), "little", signed=True) - data = types.PQInnerData( + data = raw.types.PQInnerData( pq=res_pq.pq, p=p.to_bytes(4, "big"), q=q.to_bytes(4, "big"), @@ -123,14 +123,14 @@ class Auth: sha = sha1(data).digest() padding = urandom(- (len(data) + len(sha)) % 255) data_with_hash = sha + data + padding - encrypted_data = RSA.encrypt(data_with_hash, public_key_fingerprint) + encrypted_data = rsa.encrypt(data_with_hash, public_key_fingerprint) log.debug("Done encrypt data with RSA") # Step 5. TODO: Handle "server_DH_params_fail". Code assumes response is ok log.debug("Send req_DH_params") server_dh_params = await self.send( - functions.ReqDHParams( + raw.functions.ReqDHParams( nonce=nonce, server_nonce=server_nonce, p=p.to_bytes(4, "big"), @@ -157,7 +157,7 @@ class Auth: server_nonce = int.from_bytes(server_nonce, "little", signed=True) - answer_with_hash = AES.ige256_decrypt(encrypted_answer, tmp_aes_key, tmp_aes_iv) + answer_with_hash = aes.ige256_decrypt(encrypted_answer, tmp_aes_key, tmp_aes_iv) answer = answer_with_hash[20:] server_dh_inner_data = TLObject.read(BytesIO(answer)) @@ -167,7 +167,7 @@ class Auth: dh_prime = int.from_bytes(server_dh_inner_data.dh_prime, "big") delta_time = server_dh_inner_data.server_time - time.time() - log.debug("Delta time: {}".format(round(delta_time, 3))) + log.debug(f"Delta time: {round(delta_time, 3)}") # Step 6 g = server_dh_inner_data.g @@ -176,7 +176,7 @@ class Auth: retry_id = 0 - data = types.ClientDHInnerData( + data = raw.types.ClientDHInnerData( nonce=nonce, server_nonce=server_nonce, retry_id=retry_id, @@ -186,11 +186,11 @@ class Auth: sha = sha1(data).digest() padding = urandom(- (len(data) + len(sha)) % 16) data_with_hash = sha + data + padding - encrypted_data = AES.ige256_encrypt(data_with_hash, tmp_aes_key, tmp_aes_iv) + encrypted_data = aes.ige256_encrypt(data_with_hash, tmp_aes_key, tmp_aes_iv) log.debug("Send set_client_DH_params") set_client_dh_params_answer = await self.send( - functions.SetClientDHParams( + raw.functions.SetClientDHParams( nonce=nonce, server_nonce=server_nonce, encrypted_data=encrypted_data @@ -210,7 +210,7 @@ class Auth: # Security checks ####################### - assert dh_prime == Prime.CURRENT_DH_PRIME + assert dh_prime == prime.CURRENT_DH_PRIME log.debug("DH parameters check: OK") # https://core.telegram.org/mtproto/security_guidelines#g-a-and-g-b-validation @@ -241,15 +241,11 @@ class Auth: log.debug("Nonce fields check: OK") # Step 9 - server_salt = AES.xor(new_nonce[:8], server_nonce[:8]) + server_salt = aes.xor(new_nonce[:8], server_nonce[:8]) - log.debug("Server salt: {}".format(int.from_bytes(server_salt, "little"))) + log.debug(f"Server salt: {int.from_bytes(server_salt, 'little')}") - log.info( - "Done auth key exchange: {}".format( - set_client_dh_params_answer.__class__.__name__ - ) - ) + log.info(f"Done auth key exchange: {set_client_dh_params_answer.__class__.__name__}") except Exception as e: if retries_left: retries_left -= 1 diff --git a/pyrogram/session/internals/msg_factory.py b/pyrogram/session/internals/msg_factory.py index 3f4c3026..bf44b7d3 100644 --- a/pyrogram/session/internals/msg_factory.py +++ b/pyrogram/session/internals/msg_factory.py @@ -16,10 +16,9 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api.functions import Ping -from pyrogram.api.types import MsgsAck, HttpWait - -from pyrogram.api.core import Message, MsgContainer, TLObject +from pyrogram.raw.core import Message, MsgContainer, TLObject +from pyrogram.raw.functions import Ping +from pyrogram.raw.types import MsgsAck, HttpWait from .msg_id import MsgId from .seq_no import SeqNo @@ -27,13 +26,14 @@ not_content_related = (Ping, HttpWait, MsgsAck, MsgContainer) class MsgFactory: - def __init__(self): + def __init__(self, server_time: float = 0): self.seq_no = SeqNo() + self.server_time = server_time def __call__(self, body: TLObject) -> Message: return Message( body, - MsgId(), + MsgId(self.server_time), self.seq_no(not isinstance(body, not_content_related)), len(body) ) diff --git a/pyrogram/session/internals/msg_id.py b/pyrogram/session/internals/msg_id.py index e52815e9..58474222 100644 --- a/pyrogram/session/internals/msg_id.py +++ b/pyrogram/session/internals/msg_id.py @@ -16,20 +16,18 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from threading import Lock -from time import time +from time import monotonic class MsgId: + reference_clock = monotonic() last_time = 0 - offset = 0 - lock = Lock() + msg_id_offset = 0 - def __new__(cls) -> int: - with cls.lock: - now = time() - cls.offset = cls.offset + 4 if now == cls.last_time else 0 - msg_id = int(now * 2 ** 32) + cls.offset - cls.last_time = now + def __new__(cls, server_time: float = 0) -> int: + now = monotonic() - cls.reference_clock + server_time + cls.msg_id_offset = cls.msg_id_offset + 4 if now == cls.last_time else 0 + msg_id = int(now * 2 ** 32) + cls.msg_id_offset + cls.last_time = now - return msg_id + return msg_id diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index beb4affa..6c385199 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -18,18 +18,20 @@ import asyncio import logging +import time +from concurrent.futures.thread import ThreadPoolExecutor from datetime import datetime, timedelta from hashlib import sha1 from io import BytesIO import pyrogram from pyrogram import __copyright__, __license__, __version__ -from pyrogram.api import functions, types -from pyrogram.api.all import layer -from pyrogram.api.core import TLObject, MsgContainer, Int, Long, FutureSalt, FutureSalts +from pyrogram import raw from pyrogram.connection import Connection -from pyrogram.crypto import MTProto +from pyrogram.crypto import mtproto from pyrogram.errors import RPCError, InternalServerError, AuthKeyDuplicated, FloodWait +from pyrogram.raw.all import layer +from pyrogram.raw.core import TLObject, MsgContainer, Int, Long, FutureSalt, FutureSalts from .internals import MsgId, MsgFactory log = logging.getLogger(__name__) @@ -43,13 +45,13 @@ class Result: class Session: INITIAL_SALT = 0x616e67656c696361 - NET_WORKERS = 1 START_TIMEOUT = 1 WAIT_TIMEOUT = 15 SLEEP_THRESHOLD = 60 MAX_RETRIES = 5 ACKS_THRESHOLD = 8 PING_INTERVAL = 5 + EXECUTOR_SIZE_THRESHOLD = 512 notice_displayed = False @@ -67,22 +69,26 @@ class Session: 64: "[64] invalid container" } + executor = ThreadPoolExecutor(2, thread_name_prefix="CryptoWorker") + def __init__( self, - client: pyrogram, + client: "pyrogram.Client", dc_id: int, auth_key: bytes, + test_mode: bool, is_media: bool = False, is_cdn: bool = False ): if not Session.notice_displayed: - print("Pyrogram v{}, {}".format(__version__, __copyright__)) - print("Licensed under the terms of the " + __license__, end="\n\n") + print(f"Pyrogram v{__version__}, {__copyright__}") + print(f"Licensed under the terms of the {__license__}", end="\n\n") Session.notice_displayed = True self.client = client self.dc_id = dc_id self.auth_key = auth_key + self.test_mode = test_mode self.is_media = is_media self.is_cdn = is_cdn @@ -90,14 +96,13 @@ class Session: self.auth_key_id = sha1(auth_key).digest()[-8:] - self.session_id = Long(MsgId()) + self.session_id = Long(MsgId(time.time())) self.msg_factory = MsgFactory() self.current_salt = None self.pending_acks = set() - self.recv_queue = asyncio.Queue() self.results = {} self.ping_task = None @@ -106,16 +111,17 @@ class Session: self.next_salt_task = None self.next_salt_task_event = asyncio.Event() - self.net_worker_task = None - self.recv_task = None + self.network_task = None self.is_connected = asyncio.Event() + self.loop = asyncio.get_event_loop() + async def start(self): while True: self.connection = Connection( self.dc_id, - self.client.storage.test_mode(), + self.test_mode, self.client.ipv6, self.client.proxy ) @@ -123,27 +129,27 @@ class Session: try: await self.connection.connect() - self.net_worker_task = asyncio.ensure_future(self.net_worker()) - self.recv_task = asyncio.ensure_future(self.recv()) + self.network_task = self.loop.create_task(self.network_worker()) self.current_salt = FutureSalt(0, 0, Session.INITIAL_SALT) self.current_salt = FutureSalt( 0, 0, (await self._send( - functions.Ping(ping_id=0), + raw.functions.Ping(ping_id=0), timeout=self.START_TIMEOUT )).new_server_salt ) - self.current_salt = \ - (await self._send(functions.GetFutureSalts(num=1), timeout=self.START_TIMEOUT)).salts[0] + self.current_salt = (await self._send( + raw.functions.GetFutureSalts(num=1), + timeout=self.START_TIMEOUT)).salts[0] - self.next_salt_task = asyncio.ensure_future(self.next_salt()) + self.next_salt_task = self.loop.create_task(self.next_salt_worker()) if not self.is_cdn: await self._send( - functions.InvokeWithLayer( + raw.functions.InvokeWithLayer( layer=layer, - query=functions.InitConnection( + query=raw.functions.InitConnection( api_id=self.client.api_id, app_version=self.client.app_version, device_model=self.client.device_model, @@ -151,17 +157,17 @@ class Session: system_lang_code=self.client.lang_code, lang_code=self.client.lang_code, lang_pack="", - query=functions.help.GetConfig(), + query=raw.functions.help.GetConfig(), ) ), timeout=self.START_TIMEOUT ) - self.ping_task = asyncio.ensure_future(self.ping()) + self.ping_task = self.loop.create_task(self.ping_worker()) - log.info("Session initialized: Layer {}".format(layer)) - log.info("Device: {} - {}".format(self.client.device_model, self.client.app_version)) - log.info("System: {} ({})".format(self.client.system_version, self.client.lang_code.upper())) + log.info(f"Session initialized: Layer {layer}") + log.info(f"Device: {self.client.device_model} - {self.client.app_version}") + log.info(f"System: {self.client.system_version} ({self.client.lang_code.upper()})") except AuthKeyDuplicated as e: await self.stop() @@ -195,11 +201,8 @@ class Session: self.connection.close() - if self.recv_task: - await self.recv_task - - if self.net_worker_task: - await self.net_worker_task + if self.network_task: + await self.network_task for i in self.results.values(): i.event.set() @@ -216,76 +219,78 @@ class Session: await self.stop() await self.start() - async def net_worker(self): - logging.info("NetWorkerTask started") + async def handle_packet(self, packet): + if len(packet) <= self.EXECUTOR_SIZE_THRESHOLD: + data = mtproto.unpack( + BytesIO(packet), + self.session_id, + self.auth_key, + self.auth_key_id + ) + else: + data = await self.loop.run_in_executor( + self.executor, + mtproto.unpack, + BytesIO(packet), + self.session_id, + self.auth_key, + self.auth_key_id + ) - while True: - packet = await self.recv_queue.get() + messages = ( + data.body.messages + if isinstance(data.body, MsgContainer) + else [data] + ) - if packet is None: - break + log.debug(f"Received:\n{data}") + + for msg in messages: + if msg.seq_no == 0: + server_time = msg.msg_id / (2 ** 32) + self.msg_factory.server_time = server_time + log.info(f"Time synced: {datetime.utcfromtimestamp(server_time)} UTC") + + if msg.seq_no % 2 != 0: + if msg.msg_id in self.pending_acks: + continue + else: + self.pending_acks.add(msg.msg_id) + + if isinstance(msg.body, (raw.types.MsgDetailedInfo, raw.types.MsgNewDetailedInfo)): + self.pending_acks.add(msg.body.answer_msg_id) + continue + + if isinstance(msg.body, raw.types.NewSessionCreated): + continue + + msg_id = None + + if isinstance(msg.body, (raw.types.BadMsgNotification, raw.types.BadServerSalt)): + msg_id = msg.body.bad_msg_id + elif isinstance(msg.body, (FutureSalts, raw.types.RpcResult)): + msg_id = msg.body.req_msg_id + elif isinstance(msg.body, raw.types.Pong): + msg_id = msg.body.msg_id + else: + if self.client is not None: + self.loop.create_task(self.client.handle_updates(msg.body)) + + if msg_id in self.results: + self.results[msg_id].value = getattr(msg.body, "result", msg.body) + self.results[msg_id].event.set() + + if len(self.pending_acks) >= self.ACKS_THRESHOLD: + log.debug(f"Send {len(self.pending_acks)} acks") try: - data = MTProto.unpack( - BytesIO(packet), - self.session_id, - self.auth_key, - self.auth_key_id - ) + await self._send(raw.types.MsgsAck(msg_ids=list(self.pending_acks)), False) + except (OSError, TimeoutError): + pass + else: + self.pending_acks.clear() - messages = ( - data.body.messages - if isinstance(data.body, MsgContainer) - else [data] - ) - - log.debug("Received:\n{}".format(data)) - - for msg in messages: - if msg.seq_no % 2 != 0: - if msg.msg_id in self.pending_acks: - continue - else: - self.pending_acks.add(msg.msg_id) - - if isinstance(msg.body, (types.MsgDetailedInfo, types.MsgNewDetailedInfo)): - self.pending_acks.add(msg.body.answer_msg_id) - continue - - if isinstance(msg.body, types.NewSessionCreated): - continue - - msg_id = None - - if isinstance(msg.body, (types.BadMsgNotification, types.BadServerSalt)): - msg_id = msg.body.bad_msg_id - elif isinstance(msg.body, (FutureSalts, types.RpcResult)): - msg_id = msg.body.req_msg_id - elif isinstance(msg.body, types.Pong): - msg_id = msg.body.msg_id - else: - if self.client is not None: - self.client.updates_queue.put_nowait(msg.body) - - if msg_id in self.results: - self.results[msg_id].value = getattr(msg.body, "result", msg.body) - self.results[msg_id].event.set() - - if len(self.pending_acks) >= self.ACKS_THRESHOLD: - log.info("Send {} acks".format(len(self.pending_acks))) - - try: - await self._send(types.MsgsAck(msg_ids=list(self.pending_acks)), False) - except (OSError, TimeoutError): - pass - else: - self.pending_acks.clear() - except Exception as e: - log.error(e, exc_info=True) - - log.info("NetWorkerTask stopped") - - async def ping(self): + async def ping_worker(self): log.info("PingTask started") while True: @@ -298,7 +303,7 @@ class Session: try: await self._send( - functions.PingDelayDisconnect( + raw.functions.PingDelayDisconnect( ping_id=0, disconnect_delay=self.WAIT_TIMEOUT + 10 ), False ) @@ -307,7 +312,7 @@ class Session: log.info("PingTask stopped") - async def next_salt(self): + async def next_salt_worker(self): log.info("NextSaltTask started") while True: @@ -331,33 +336,31 @@ class Session: break try: - self.current_salt = (await self._send(functions.GetFutureSalts(num=1))).salts[0] + self.current_salt = (await self._send(raw.functions.GetFutureSalts(num=1))).salts[0] except (OSError, TimeoutError, RPCError): self.connection.close() break log.info("NextSaltTask stopped") - async def recv(self): - log.info("RecvTask started") + async def network_worker(self): + log.info("NetworkTask started") while True: packet = await self.connection.recv() if packet is None or len(packet) == 4: - self.recv_queue.put_nowait(None) - if packet: - log.warning("Server sent \"{}\"".format(Int.read(BytesIO(packet)))) + log.warning(f'Server sent "{Int.read(BytesIO(packet))}"') if self.is_connected.is_set(): - asyncio.ensure_future(self.restart()) + self.loop.create_task(self.restart()) break - self.recv_queue.put_nowait(packet) + self.loop.create_task(self.handle_packet(packet)) - log.info("RecvTask stopped") + log.info("NetworkTask stopped") async def _send(self, data: TLObject, wait_response: bool = True, timeout: float = WAIT_TIMEOUT): message = self.msg_factory(data) @@ -366,15 +369,26 @@ class Session: if wait_response: self.results[msg_id] = Result() - log.debug("Sent:\n{}".format(message)) + log.debug(f"Sent:\n{message}") - payload = MTProto.pack( - message, - self.current_salt.salt, - self.session_id, - self.auth_key, - self.auth_key_id - ) + if len(message) <= self.EXECUTOR_SIZE_THRESHOLD: + payload = mtproto.pack( + message, + self.current_salt.salt, + self.session_id, + self.auth_key, + self.auth_key_id + ) + else: + payload = await self.loop.run_in_executor( + self.executor, + mtproto.pack, + message, + self.current_salt.salt, + self.session_id, + self.auth_key, + self.auth_key_id + ) try: await self.connection.send(payload) @@ -392,15 +406,15 @@ class Session: if result is None: raise TimeoutError - elif isinstance(result, types.RpcError): - if isinstance(data, (functions.InvokeWithoutUpdates, functions.InvokeWithTakeout)): + elif isinstance(result, raw.types.RpcError): + if isinstance(data, (raw.functions.InvokeWithoutUpdates, raw.functions.InvokeWithTakeout)): data = data.query RPCError.raise_it(result, type(data)) - elif isinstance(result, types.BadMsgNotification): + elif isinstance(result, raw.types.BadMsgNotification): raise Exception(self.BAD_MSG_DESCRIPTION.get( result.error_code, - "Error code {}".format(result.error_code) + f"Error code {result.error_code}" )) else: return result @@ -417,7 +431,7 @@ class Session: except asyncio.TimeoutError: pass - if isinstance(data, (functions.InvokeWithoutUpdates, functions.InvokeWithTakeout)): + if isinstance(data, (raw.functions.InvokeWithoutUpdates, raw.functions.InvokeWithTakeout)): query = data.query else: query = data @@ -433,8 +447,7 @@ class Session: if amount > sleep_threshold: raise - log.warning('[{}] Sleeping for {}s (required by "{}")'.format( - self.client.session_name, amount, query)) + log.warning(f'[{self.client.session_name}] Sleeping for {amount}s (required by "{query}")') await asyncio.sleep(amount) except (OSError, TimeoutError, InternalServerError) as e: @@ -442,9 +455,7 @@ class Session: raise e from None (log.warning if retries < 2 else log.info)( - '[{}] Retrying "{}" due to {}'.format( - Session.MAX_RETRIES - retries + 1, - query, e)) + f'[{Session.MAX_RETRIES - retries + 1}] Retrying "{query}" due to {e}') await asyncio.sleep(0.5) diff --git a/pyrogram/client/storage/__init__.py b/pyrogram/storage/__init__.py similarity index 100% rename from pyrogram/client/storage/__init__.py rename to pyrogram/storage/__init__.py diff --git a/pyrogram/client/storage/file_storage.py b/pyrogram/storage/file_storage.py similarity index 93% rename from pyrogram/client/storage/file_storage.py rename to pyrogram/storage/file_storage.py index 07716ce5..a335761a 100644 --- a/pyrogram/client/storage/file_storage.py +++ b/pyrogram/storage/file_storage.py @@ -78,7 +78,7 @@ class FileStorage(SQLiteStorage): self.version(version) - def open(self): + async def open(self): path = self.database file_exists = path.is_file() @@ -93,7 +93,7 @@ class FileStorage(SQLiteStorage): path.rename(path.name + ".OLD") - log.warning('The old session file has been renamed to "{}.OLD"'.format(path.name)) + log.warning(f'The old session file has been renamed to "{path.name}.OLD"') self.migrate_from_json(session_json) @@ -102,7 +102,7 @@ class FileStorage(SQLiteStorage): return if Path(path.name + ".OLD").is_file(): - log.warning('Old session file detected: "{}.OLD". You can remove this file now'.format(path.name)) + log.warning(f'Old session file detected: "{path.name}.OLD". You can remove this file now') self.conn = sqlite3.connect(str(path), timeout=1, check_same_thread=False) @@ -117,5 +117,5 @@ class FileStorage(SQLiteStorage): except sqlite3.OperationalError: pass - def delete(self): + async def delete(self): os.remove(self.database) diff --git a/pyrogram/client/storage/memory_storage.py b/pyrogram/storage/memory_storage.py similarity index 81% rename from pyrogram/client/storage/memory_storage.py rename to pyrogram/storage/memory_storage.py index b698d2ce..7e009497 100644 --- a/pyrogram/client/storage/memory_storage.py +++ b/pyrogram/storage/memory_storage.py @@ -30,7 +30,7 @@ class MemoryStorage(SQLiteStorage): def __init__(self, name: str): super().__init__(name) - def open(self): + async def open(self): self.conn = sqlite3.connect(":memory:", check_same_thread=False) self.create() @@ -42,12 +42,12 @@ class MemoryStorage(SQLiteStorage): ) ) - self.dc_id(dc_id) - self.test_mode(test_mode) - self.auth_key(auth_key) - self.user_id(user_id) - self.is_bot(is_bot) - self.date(0) + await self.dc_id(dc_id) + await self.test_mode(test_mode) + await self.auth_key(auth_key) + await self.user_id(user_id) + await self.is_bot(is_bot) + await self.date(0) - def delete(self): - pass + async def delete(self): + raise NotImplementedError diff --git a/pyrogram/client/storage/schema.sql b/pyrogram/storage/schema.sql similarity index 95% rename from pyrogram/client/storage/schema.sql rename to pyrogram/storage/schema.sql index aa76c4b0..39c986b5 100644 --- a/pyrogram/client/storage/schema.sql +++ b/pyrogram/storage/schema.sql @@ -18,7 +18,8 @@ * along with Pyrogram. If not, see . */ -CREATE TABLE sessions ( +CREATE TABLE sessions +( dc_id INTEGER PRIMARY KEY, test_mode INTEGER, auth_key BLOB, @@ -27,7 +28,8 @@ CREATE TABLE sessions ( is_bot INTEGER ); -CREATE TABLE peers ( +CREATE TABLE peers +( id INTEGER PRIMARY KEY, access_hash INTEGER, type INTEGER NOT NULL, @@ -36,7 +38,8 @@ CREATE TABLE peers ( last_update_on INTEGER NOT NULL DEFAULT (CAST(STRFTIME('%s', 'now') AS INTEGER)) ); -CREATE TABLE version ( +CREATE TABLE version +( number INTEGER PRIMARY KEY ); diff --git a/pyrogram/client/storage/sqlite_storage.py b/pyrogram/storage/sqlite_storage.py similarity index 76% rename from pyrogram/client/storage/sqlite_storage.py rename to pyrogram/storage/sqlite_storage.py index 14279b0a..2f3768df 100644 --- a/pyrogram/client/storage/sqlite_storage.py +++ b/pyrogram/storage/sqlite_storage.py @@ -23,30 +23,30 @@ from pathlib import Path from threading import Lock from typing import List, Tuple, Any -from pyrogram.api import types -from pyrogram.client.ext import utils +from pyrogram import raw from .storage import Storage +from .. import utils def get_input_peer(peer_id: int, access_hash: int, peer_type: str): if peer_type in ["user", "bot"]: - return types.InputPeerUser( + return raw.types.InputPeerUser( user_id=peer_id, access_hash=access_hash ) if peer_type == "group": - return types.InputPeerChat( + return raw.types.InputPeerChat( chat_id=-peer_id ) if peer_type in ["channel", "supergroup"]: - return types.InputPeerChannel( + return raw.types.InputPeerChannel( channel_id=utils.get_channel_id(peer_id), access_hash=access_hash ) - raise ValueError("Invalid peer type: {}".format(peer_type)) + raise ValueError(f"Invalid peer type: {peer_type}") class SQLiteStorage(Storage): @@ -74,23 +74,23 @@ class SQLiteStorage(Storage): (2, None, None, 0, None, None) ) - def open(self): + async def open(self): raise NotImplementedError - def save(self): - self.date(int(time.time())) + async def save(self): + await self.date(int(time.time())) with self.lock: self.conn.commit() - def close(self): + async def close(self): with self.lock: self.conn.close() - def delete(self): + async def delete(self): raise NotImplementedError - def update_peers(self, peers: List[Tuple[int, int, str, str, str]]): + async def update_peers(self, peers: List[Tuple[int, int, str, str, str]]): with self.lock: self.conn.executemany( "REPLACE INTO peers (id, access_hash, type, username, phone_number)" @@ -98,39 +98,39 @@ class SQLiteStorage(Storage): peers ) - def get_peer_by_id(self, peer_id: int): + async def get_peer_by_id(self, peer_id: int): r = self.conn.execute( "SELECT id, access_hash, type FROM peers WHERE id = ?", (peer_id,) ).fetchone() if r is None: - raise KeyError("ID not found: {}".format(peer_id)) + raise KeyError(f"ID not found: {peer_id}") return get_input_peer(*r) - def get_peer_by_username(self, username: str): + async def get_peer_by_username(self, username: str): r = self.conn.execute( "SELECT id, access_hash, type, last_update_on FROM peers WHERE username = ?", (username,) ).fetchone() if r is None: - raise KeyError("Username not found: {}".format(username)) + raise KeyError(f"Username not found: {username}") if abs(time.time() - r[3]) > self.USERNAME_TTL: - raise KeyError("Username expired: {}".format(username)) + raise KeyError(f"Username expired: {username}") return get_input_peer(*r[:3]) - def get_peer_by_phone_number(self, phone_number: str): + async def get_peer_by_phone_number(self, phone_number: str): r = self.conn.execute( "SELECT id, access_hash, type FROM peers WHERE phone_number = ?", (phone_number,) ).fetchone() if r is None: - raise KeyError("Phone number not found: {}".format(phone_number)) + raise KeyError(f"Phone number not found: {phone_number}") return get_input_peer(*r) @@ -138,7 +138,7 @@ class SQLiteStorage(Storage): attr = inspect.stack()[2].function return self.conn.execute( - "SELECT {} FROM sessions".format(attr) + f"SELECT {attr} FROM sessions" ).fetchone()[0] def _set(self, value: Any): @@ -146,29 +146,29 @@ class SQLiteStorage(Storage): with self.lock, self.conn: self.conn.execute( - "UPDATE sessions SET {} = ?".format(attr), + f"UPDATE sessions SET {attr} = ?", (value,) ) def _accessor(self, value: Any = object): return self._get() if value == object else self._set(value) - def dc_id(self, value: int = object): + async def dc_id(self, value: int = object): return self._accessor(value) - def test_mode(self, value: bool = object): + async def test_mode(self, value: bool = object): return self._accessor(value) - def auth_key(self, value: bytes = object): + async def auth_key(self, value: bytes = object): return self._accessor(value) - def date(self, value: int = object): + async def date(self, value: int = object): return self._accessor(value) - def user_id(self, value: int = object): + async def user_id(self, value: int = object): return self._accessor(value) - def is_bot(self, value: bool = object): + async def is_bot(self, value: bool = object): return self._accessor(value) def version(self, value: int = object): diff --git a/pyrogram/client/storage/storage.py b/pyrogram/storage/storage.py similarity index 65% rename from pyrogram/client/storage/storage.py rename to pyrogram/storage/storage.py index 8cd7e6f3..3ef83027 100644 --- a/pyrogram/client/storage/storage.py +++ b/pyrogram/storage/storage.py @@ -28,56 +28,56 @@ class Storage: def __init__(self, name: str): self.name = name - def open(self): + async def open(self): raise NotImplementedError - def save(self): + async def save(self): raise NotImplementedError - def close(self): + async def close(self): raise NotImplementedError - def delete(self): + async def delete(self): raise NotImplementedError - def update_peers(self, peers: List[Tuple[int, int, str, str, str]]): + async def update_peers(self, peers: List[Tuple[int, int, str, str, str]]): raise NotImplementedError - def get_peer_by_id(self, peer_id: int): + async def get_peer_by_id(self, peer_id: int): raise NotImplementedError - def get_peer_by_username(self, username: str): + async def get_peer_by_username(self, username: str): raise NotImplementedError - def get_peer_by_phone_number(self, phone_number: str): + async def get_peer_by_phone_number(self, phone_number: str): raise NotImplementedError - def dc_id(self, value: int = object): + async def dc_id(self, value: int = object): raise NotImplementedError - def test_mode(self, value: bool = object): + async def test_mode(self, value: bool = object): raise NotImplementedError - def auth_key(self, value: bytes = object): + async def auth_key(self, value: bytes = object): raise NotImplementedError - def date(self, value: int = object): + async def date(self, value: int = object): raise NotImplementedError - def user_id(self, value: int = object): + async def user_id(self, value: int = object): raise NotImplementedError - def is_bot(self, value: bool = object): + async def is_bot(self, value: bool = object): raise NotImplementedError - def export_session_string(self): + async def export_session_string(self): return base64.urlsafe_b64encode( struct.pack( self.SESSION_STRING_FORMAT, - self.dc_id(), - self.test_mode(), - self.auth_key(), - self.user_id(), - self.is_bot() + await self.dc_id(), + await self.test_mode(), + await self.auth_key(), + await self.user_id(), + await self.is_bot() ) ).decode().rstrip("=") diff --git a/pyrogram/sync.py b/pyrogram/sync.py new file mode 100644 index 00000000..80288e68 --- /dev/null +++ b/pyrogram/sync.py @@ -0,0 +1,80 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +import asyncio +import functools +import inspect +import threading + +from pyrogram import types +from pyrogram.methods import Methods +from pyrogram.methods.utilities import idle as idle_module + + +def async_to_sync(obj, name): + function = getattr(obj, name) + loop = asyncio.get_event_loop() + + async def consume_generator(coroutine): + return [i async for i in coroutine] + + @functools.wraps(function) + def async_to_sync_wrap(*args, **kwargs): + coroutine = function(*args, **kwargs) + + if loop.is_running(): + if threading.current_thread() is threading.main_thread(): + return coroutine + else: + if inspect.iscoroutine(coroutine): + return asyncio.run_coroutine_threadsafe(coroutine, loop).result() + + if inspect.isasyncgen(coroutine): + return asyncio.run_coroutine_threadsafe(consume_generator(coroutine), loop).result() + + if inspect.iscoroutine(coroutine): + return loop.run_until_complete(coroutine) + + if inspect.isasyncgen(coroutine): + return loop.run_until_complete(consume_generator(coroutine)) + + setattr(obj, name, async_to_sync_wrap) + + +def wrap(source): + for name in dir(source): + method = getattr(source, name) + + if not name.startswith("_"): + if inspect.iscoroutinefunction(method) or inspect.isasyncgenfunction(method): + async_to_sync(source, name) + + +# Wrap all Client's relevant methods +wrap(Methods) + +# Wrap types' bound methods +for class_name in dir(types): + cls = getattr(types, class_name) + + if inspect.isclass(cls): + wrap(cls) + +# Special case for idle, because it's not inside Methods +async_to_sync(idle_module, "idle") +idle = getattr(idle_module, "idle") diff --git a/pyrogram/client/ext/syncer.py b/pyrogram/syncer.py similarity index 87% rename from pyrogram/client/ext/syncer.py rename to pyrogram/syncer.py index 65fb2104..1a9d77f3 100644 --- a/pyrogram/client/ext/syncer.py +++ b/pyrogram/syncer.py @@ -39,7 +39,7 @@ class Syncer: cls.lock = asyncio.Lock() async with cls.lock: - cls.sync(client) + await cls.sync(client) cls.clients[id(client)] = client @@ -49,7 +49,7 @@ class Syncer: @classmethod async def remove(cls, client): async with cls.lock: - cls.sync(client) + await cls.sync(client) del cls.clients[id(client)] @@ -73,19 +73,16 @@ class Syncer: except asyncio.TimeoutError: async with cls.lock: for client in cls.clients.values(): - cls.sync(client) + await cls.sync(client) else: break @classmethod - def sync(cls, client): + async def sync(cls, client): try: start = time.time() - client.storage.save() + await client.storage.save() except Exception as e: log.critical(e, exc_info=True) else: - log.info('Synced "{}" in {:.6} ms'.format( - client.storage.name, - (time.time() - start) * 1000 - )) + log.info(f'Synced "{client.storage.name}" in {(time.time() - start) * 1000:.6} ms') diff --git a/pyrogram/client/types/__init__.py b/pyrogram/types/__init__.py similarity index 100% rename from pyrogram/client/types/__init__.py rename to pyrogram/types/__init__.py index 1fa7c9ce..f0a0665f 100644 --- a/pyrogram/client/types/__init__.py +++ b/pyrogram/types/__init__.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from .authorization import * from .bots_and_keyboards import * from .inline_mode import * from .input_media import * @@ -23,6 +24,5 @@ from .input_message_content import * from .list import List from .messages_and_media import * from .object import Object -from .authorization import * from .update import * from .user_and_chats import * diff --git a/pyrogram/client/types/authorization/__init__.py b/pyrogram/types/authorization/__init__.py similarity index 100% rename from pyrogram/client/types/authorization/__init__.py rename to pyrogram/types/authorization/__init__.py index 18d57c93..28480341 100644 --- a/pyrogram/client/types/authorization/__init__.py +++ b/pyrogram/types/authorization/__init__.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from .terms_of_service import TermsOfService from .sent_code import SentCode +from .terms_of_service import TermsOfService __all__ = ["TermsOfService", "SentCode"] diff --git a/pyrogram/client/types/authorization/sent_code.py b/pyrogram/types/authorization/sent_code.py similarity index 74% rename from pyrogram/client/types/authorization/sent_code.py rename to pyrogram/types/authorization/sent_code.py index f1fd49da..fcbfeace 100644 --- a/pyrogram/client/types/authorization/sent_code.py +++ b/pyrogram/types/authorization/sent_code.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api import types +from pyrogram import raw from ..object import Object @@ -30,16 +30,16 @@ class SentCode(Object): *"flash_call"* (code is in the last 5 digits of the caller's phone number). phone_code_hash (``str``): - Confirmation code identifier useful for the next authorization steps (either :meth:`~Client.sign_in` or - :meth:`~Client.sign_up`). + Confirmation code identifier useful for the next authorization steps (either + :meth:`~pyrogram.Client.sign_in` or :meth:`~pyrogram.Client.sign_up`). next_type (``str``): - Type of the next code to be sent with :meth:`~Client.resend_code`. + Type of the next code to be sent with :meth:`~pyrogram.Client.resend_code`. Can be *"sms"* (code will be sent via SMS), *"call"* (code will be sent via voice call) or *"flash_call"* (code will be in the last 5 digits of caller's phone number). timeout (``int``): - Delay in seconds before calling :meth:`~Client.resend_code`. + Delay in seconds before calling :meth:`~pyrogram.Client.resend_code`. """ def __init__( @@ -57,25 +57,25 @@ class SentCode(Object): self.timeout = timeout @staticmethod - def _parse(sent_code: types.auth.SentCode) -> "SentCode": + def _parse(sent_code: raw.types.auth.SentCode) -> "SentCode": type = sent_code.type - if isinstance(type, types.auth.SentCodeTypeApp): + if isinstance(type, raw.types.auth.SentCodeTypeApp): type = "app" - elif isinstance(type, types.auth.SentCodeTypeSms): + elif isinstance(type, raw.types.auth.SentCodeTypeSms): type = "sms" - elif isinstance(type, types.auth.SentCodeTypeCall): + elif isinstance(type, raw.types.auth.SentCodeTypeCall): type = "call" - elif isinstance(type, types.auth.SentCodeTypeFlashCall): + elif isinstance(type, raw.types.auth.SentCodeTypeFlashCall): type = "flash_call" next_type = sent_code.next_type - if isinstance(next_type, types.auth.CodeTypeSms): + if isinstance(next_type, raw.types.auth.CodeTypeSms): next_type = "sms" - elif isinstance(next_type, types.auth.CodeTypeCall): + elif isinstance(next_type, raw.types.auth.CodeTypeCall): next_type = "call" - elif isinstance(next_type, types.auth.CodeTypeFlashCall): + elif isinstance(next_type, raw.types.auth.CodeTypeFlashCall): next_type = "flash_call" return SentCode( diff --git a/pyrogram/client/types/authorization/terms_of_service.py b/pyrogram/types/authorization/terms_of_service.py similarity index 77% rename from pyrogram/client/types/authorization/terms_of_service.py rename to pyrogram/types/authorization/terms_of_service.py index ab7e1348..33a94d0a 100644 --- a/pyrogram/client/types/authorization/terms_of_service.py +++ b/pyrogram/types/authorization/terms_of_service.py @@ -18,13 +18,13 @@ from typing import List -from pyrogram.api import types -from ..messages_and_media import MessageEntity +from pyrogram import raw +from pyrogram import types from ..object import Object class TermsOfService(Object): - """Telegram's Terms of Service returned by :meth:`~Client.sign_in`. + """Telegram's Terms of Service returned by :meth:`~pyrogram.Client.sign_in`. Parameters: id (``str``): @@ -33,11 +33,11 @@ class TermsOfService(Object): text (``str``): Terms of Service text. - entities (List of :obj:`MessageEntity`): + entities (List of :obj:`~pyrogram.types.MessageEntity`): Special entities like URLs that appear in the text. """ - def __init__(self, *, id: str, text: str, entities: List[MessageEntity]): + def __init__(self, *, id: str, text: str, entities: List["types.MessageEntity"]): super().__init__() self.id = id @@ -45,12 +45,12 @@ class TermsOfService(Object): self.entities = entities @staticmethod - def _parse(terms_of_service: types.help.TermsOfService) -> "TermsOfService": + def _parse(terms_of_service: "raw.types.help.TermsOfService") -> "TermsOfService": return TermsOfService( id=terms_of_service.id.data, text=terms_of_service.text, entities=[ - MessageEntity._parse(None, entity, {}) + types.MessageEntity._parse(None, entity, {}) for entity in terms_of_service.entities ] ) diff --git a/pyrogram/client/types/bots_and_keyboards/__init__.py b/pyrogram/types/bots_and_keyboards/__init__.py similarity index 100% rename from pyrogram/client/types/bots_and_keyboards/__init__.py rename to pyrogram/types/bots_and_keyboards/__init__.py diff --git a/pyrogram/client/types/bots_and_keyboards/callback_game.py b/pyrogram/types/bots_and_keyboards/callback_game.py similarity index 100% rename from pyrogram/client/types/bots_and_keyboards/callback_game.py rename to pyrogram/types/bots_and_keyboards/callback_game.py diff --git a/pyrogram/client/types/bots_and_keyboards/callback_query.py b/pyrogram/types/bots_and_keyboards/callback_query.py similarity index 79% rename from pyrogram/client/types/bots_and_keyboards/callback_query.py rename to pyrogram/types/bots_and_keyboards/callback_query.py index a15a7c35..326c78bb 100644 --- a/pyrogram/client/types/bots_and_keyboards/callback_query.py +++ b/pyrogram/types/bots_and_keyboards/callback_query.py @@ -21,11 +21,11 @@ from struct import pack from typing import Union, List, Match import pyrogram -from pyrogram.api import types +from pyrogram import raw +from pyrogram import types from ..object import Object from ..update import Update -from ..user_and_chats import User -from ...ext import utils +from ... import utils class CallbackQuery(Object, Update): @@ -39,14 +39,14 @@ class CallbackQuery(Object, Update): id (``str``): Unique identifier for this query. - from_user (:obj:`User`): + from_user (:obj:`~pyrogram.types.User`): Sender. chat_instance (``str``, *optional*): Global identifier, uniquely corresponding to the chat to which the message with the callback button was sent. Useful for high scores in games. - message (:obj:`Message`, *optional*): + message (:obj:`~pyrogram.types.Message`, *optional*): Message with the callback button that originated the query. Note that message content and message date will not be available if the message is too old. @@ -67,11 +67,11 @@ class CallbackQuery(Object, Update): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, id: str, - from_user: User, + from_user: "types.User", chat_instance: str, - message: "pyrogram.Message" = None, + message: "types.Message" = None, inline_message_id: str = None, data: Union[str, bytes] = None, game_short_name: str = None, @@ -93,9 +93,9 @@ class CallbackQuery(Object, Update): message = None inline_message_id = None - if isinstance(callback_query, types.UpdateBotCallbackQuery): + if isinstance(callback_query, raw.types.UpdateBotCallbackQuery): message = await client.get_messages(utils.get_peer_id(callback_query.peer), callback_query.msg_id) - elif isinstance(callback_query, types.UpdateInlineBotCallbackQuery): + elif isinstance(callback_query, raw.types.UpdateInlineBotCallbackQuery): inline_message_id = b64encode( pack( " Union["pyrogram.Message", bool]: + reply_markup: "types.InlineKeyboardMarkup" = None + ) -> Union["types.Message", bool]: """Edit the text of messages attached to callback queries. - Bound method *edit_message_text* of :obj:`CallbackQuery`. + Bound method *edit_message_text* of :obj:`~pyrogram.types.CallbackQuery`. Parameters: text (``str``): @@ -193,12 +193,12 @@ class CallbackQuery(Object, Update): disable_web_page_preview (``bool``, *optional*): Disables link previews for links in this message. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - :obj:`Message` | ``bool``: On success, if the edited message was sent by the bot, the edited message is - returned, otherwise True is returned (message sent via the bot, as inline query result). + :obj:`~pyrogram.types.Message` | ``bool``: On success, if the edited message was sent by the bot, the edited + message is returned, otherwise True is returned (message sent via the bot, as inline query result). Raises: RPCError: In case of a Telegram RPC error. @@ -225,11 +225,11 @@ class CallbackQuery(Object, Update): self, caption: str, parse_mode: Union[str, None] = object, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None - ) -> Union["pyrogram.Message", bool]: + reply_markup: "types.InlineKeyboardMarkup" = None + ) -> Union["types.Message", bool]: """Edit the caption of media messages attached to callback queries. - Bound method *edit_message_caption* of :obj:`CallbackQuery`. + Bound method *edit_message_caption* of :obj:`~pyrogram.types.CallbackQuery`. Parameters: caption (``str``): @@ -242,12 +242,12 @@ class CallbackQuery(Object, Update): Pass "html" to enable HTML-style parsing only. Pass None to completely disable style parsing. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - :obj:`Message` | ``bool``: On success, if the edited message was sent by the bot, the edited message is - returned, otherwise True is returned (message sent via the bot, as inline query result). + :obj:`~pyrogram.types.Message` | ``bool``: On success, if the edited message was sent by the bot, the edited + message is returned, otherwise True is returned (message sent via the bot, as inline query result). Raises: RPCError: In case of a Telegram RPC error. @@ -256,23 +256,23 @@ class CallbackQuery(Object, Update): async def edit_message_media( self, - media: "pyrogram.InputMedia", - reply_markup: "pyrogram.InlineKeyboardMarkup" = None - ) -> Union["pyrogram.Message", bool]: + media: "types.InputMedia", + reply_markup: "types.InlineKeyboardMarkup" = None + ) -> Union["types.Message", bool]: """Edit animation, audio, document, photo or video messages attached to callback queries. - Bound method *edit_message_media* of :obj:`CallbackQuery`. + Bound method *edit_message_media* of :obj:`~pyrogram.types.CallbackQuery`. Parameters: - media (:obj:`InputMedia`): + media (:obj:`~pyrogram.types.InputMedia`): One of the InputMedia objects describing an animation, audio, document, photo or video. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - :obj:`Message` | ``bool``: On success, if the edited message was sent by the bot, the edited message is - returned, otherwise True is returned (message sent via the bot, as inline query result). + :obj:`~pyrogram.types.Message` | ``bool``: On success, if the edited message was sent by the bot, the edited + message is returned, otherwise True is returned (message sent via the bot, as inline query result). Raises: RPCError: In case of a Telegram RPC error. @@ -293,19 +293,19 @@ class CallbackQuery(Object, Update): async def edit_message_reply_markup( self, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None - ) -> Union["pyrogram.Message", bool]: + reply_markup: "types.InlineKeyboardMarkup" = None + ) -> Union["types.Message", bool]: """Edit only the reply markup of messages attached to callback queries. - Bound method *edit_message_reply_markup* of :obj:`CallbackQuery`. + Bound method *edit_message_reply_markup* of :obj:`~pyrogram.types.CallbackQuery`. Parameters: - reply_markup (:obj:`InlineKeyboardMarkup`): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`): An InlineKeyboardMarkup object. Returns: - :obj:`Message` | ``bool``: On success, if the edited message was sent by the bot, the edited message is - returned, otherwise True is returned (message sent via the bot, as inline query result). + :obj:`~pyrogram.types.Message` | ``bool``: On success, if the edited message was sent by the bot, the edited + message is returned, otherwise True is returned (message sent via the bot, as inline query result). Raises: RPCError: In case of a Telegram RPC error. diff --git a/pyrogram/client/types/bots_and_keyboards/force_reply.py b/pyrogram/types/bots_and_keyboards/force_reply.py similarity index 95% rename from pyrogram/client/types/bots_and_keyboards/force_reply.py rename to pyrogram/types/bots_and_keyboards/force_reply.py index 14870318..97c88db0 100644 --- a/pyrogram/client/types/bots_and_keyboards/force_reply.py +++ b/pyrogram/types/bots_and_keyboards/force_reply.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api.types import ReplyKeyboardForceReply +from pyrogram import raw from ..object import Object @@ -52,7 +52,7 @@ class ForceReply(Object): ) def write(self): - return ReplyKeyboardForceReply( + return raw.types.ReplyKeyboardForceReply( single_use=True, selective=self.selective or None ) diff --git a/pyrogram/client/types/bots_and_keyboards/game_high_score.py b/pyrogram/types/bots_and_keyboards/game_high_score.py similarity index 75% rename from pyrogram/client/types/bots_and_keyboards/game_high_score.py rename to pyrogram/types/bots_and_keyboards/game_high_score.py index 1e9b7157..a9af42ee 100644 --- a/pyrogram/client/types/bots_and_keyboards/game_high_score.py +++ b/pyrogram/types/bots_and_keyboards/game_high_score.py @@ -17,17 +17,16 @@ # along with Pyrogram. If not, see . import pyrogram - -from pyrogram.api import types -from pyrogram.client.types.object import Object -from pyrogram.client.types.user_and_chats import User +from pyrogram import raw +from pyrogram import types +from ..object import Object class GameHighScore(Object): """One row of the high scores table for a game. Parameters: - user (:obj:`User`): + user (:obj:`~pyrogram.types.User`): User. score (``int``): @@ -40,8 +39,8 @@ class GameHighScore(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, - user: User, + client: "pyrogram.Client" = None, + user: "types.User", score: int, position: int = None ): @@ -52,20 +51,20 @@ class GameHighScore(Object): self.position = position @staticmethod - def _parse(client, game_high_score: types.HighScore, users: dict) -> "GameHighScore": + def _parse(client, game_high_score: raw.types.HighScore, users: dict) -> "GameHighScore": users = {i.id: i for i in users} return GameHighScore( - user=User._parse(client, users[game_high_score.user_id]), + user=types.User._parse(client, users[game_high_score.user_id]), score=game_high_score.score, position=game_high_score.pos, client=client ) @staticmethod - def _parse_action(client, service: types.MessageService, users: dict): + def _parse_action(client, service: raw.types.MessageService, users: dict): return GameHighScore( - user=User._parse(client, users[service.from_id]), + user=types.User._parse(client, users[service.from_id]), score=service.action.score, client=client ) diff --git a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_button.py b/pyrogram/types/bots_and_keyboards/inline_keyboard_button.py similarity index 85% rename from pyrogram/client/types/bots_and_keyboards/inline_keyboard_button.py rename to pyrogram/types/bots_and_keyboards/inline_keyboard_button.py index 0b186b40..2d5212d9 100644 --- a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_button.py +++ b/pyrogram/types/bots_and_keyboards/inline_keyboard_button.py @@ -18,12 +18,8 @@ from typing import Union -from pyrogram.api.types import ( - KeyboardButtonUrl, KeyboardButtonCallback, - KeyboardButtonSwitchInline, KeyboardButtonGame -) - -from .callback_game import CallbackGame +from pyrogram import raw +from pyrogram import types from ..object import Object @@ -66,7 +62,7 @@ class InlineKeyboardButton(Object): url: str = None, switch_inline_query: str = None, switch_inline_query_current_chat: str = None, - callback_game: CallbackGame = None + callback_game: "types.CallbackGame" = None ): super().__init__() @@ -80,13 +76,13 @@ class InlineKeyboardButton(Object): @staticmethod def read(o): - if isinstance(o, KeyboardButtonUrl): + if isinstance(o, raw.types.KeyboardButtonUrl): return InlineKeyboardButton( text=o.text, url=o.url ) - if isinstance(o, KeyboardButtonCallback): + if isinstance(o, raw.types.KeyboardButtonCallback): # Try decode data to keep it as string, but if fails, fallback to bytes so we don't lose any information, # instead of decoding by ignoring/replacing errors. try: @@ -99,7 +95,7 @@ class InlineKeyboardButton(Object): callback_data=data ) - if isinstance(o, KeyboardButtonSwitchInline): + if isinstance(o, raw.types.KeyboardButtonSwitchInline): if o.same_peer: return InlineKeyboardButton( text=o.text, @@ -111,30 +107,30 @@ class InlineKeyboardButton(Object): switch_inline_query=o.query ) - if isinstance(o, KeyboardButtonGame): + if isinstance(o, raw.types.KeyboardButtonGame): return InlineKeyboardButton( text=o.text, - callback_game=CallbackGame() + callback_game=types.CallbackGame() ) def write(self): if self.callback_data is not None: # Telegram only wants bytes, but we are allowed to pass strings too, for convenience. data = bytes(self.callback_data, "utf-8") if isinstance(self.callback_data, str) else self.callback_data - return KeyboardButtonCallback(text=self.text, data=data) + return raw.types.KeyboardButtonCallback(text=self.text, data=data) if self.url is not None: - return KeyboardButtonUrl(text=self.text, url=self.url) + return raw.types.KeyboardButtonUrl(text=self.text, url=self.url) if self.switch_inline_query is not None: - return KeyboardButtonSwitchInline(text=self.text, query=self.switch_inline_query) + return raw.types.KeyboardButtonSwitchInline(text=self.text, query=self.switch_inline_query) if self.switch_inline_query_current_chat is not None: - return KeyboardButtonSwitchInline( + return raw.types.KeyboardButtonSwitchInline( text=self.text, query=self.switch_inline_query_current_chat, same_peer=True ) if self.callback_game is not None: - return KeyboardButtonGame(text=self.text) + return raw.types.KeyboardButtonGame(text=self.text) diff --git a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_markup.py b/pyrogram/types/bots_and_keyboards/inline_keyboard_markup.py similarity index 79% rename from pyrogram/client/types/bots_and_keyboards/inline_keyboard_markup.py rename to pyrogram/types/bots_and_keyboards/inline_keyboard_markup.py index fb79b4db..6332c7cf 100644 --- a/pyrogram/client/types/bots_and_keyboards/inline_keyboard_markup.py +++ b/pyrogram/types/bots_and_keyboards/inline_keyboard_markup.py @@ -18,9 +18,8 @@ from typing import List -from pyrogram.api.types import ReplyInlineMarkup, KeyboardButtonRow - -from . import InlineKeyboardButton +from pyrogram import raw +from pyrogram import types from ..object import Object @@ -28,14 +27,11 @@ class InlineKeyboardMarkup(Object): """An inline keyboard that appears right next to the message it belongs to. Parameters: - inline_keyboard (List of List of :obj:`InlineKeyboardButton`): + inline_keyboard (List of List of :obj:`~pyrogram.types.InlineKeyboardButton`): List of button rows, each represented by a List of InlineKeyboardButton objects. """ - def __init__( - self, - inline_keyboard: List[List[InlineKeyboardButton]] - ): + def __init__(self, inline_keyboard: List[List["types.InlineKeyboardButton"]]): super().__init__() self.inline_keyboard = inline_keyboard @@ -48,7 +44,7 @@ class InlineKeyboardMarkup(Object): row = [] for j in i.buttons: - row.append(InlineKeyboardButton.read(j)) + row.append(types.InlineKeyboardButton.read(j)) inline_keyboard.append(row) @@ -57,8 +53,8 @@ class InlineKeyboardMarkup(Object): ) def write(self): - return ReplyInlineMarkup( - rows=[KeyboardButtonRow( + return raw.types.ReplyInlineMarkup( + rows=[raw.types.KeyboardButtonRow( buttons=[j.write() for j in i] ) for i in self.inline_keyboard] ) diff --git a/pyrogram/client/types/bots_and_keyboards/keyboard_button.py b/pyrogram/types/bots_and_keyboards/keyboard_button.py similarity index 82% rename from pyrogram/client/types/bots_and_keyboards/keyboard_button.py rename to pyrogram/types/bots_and_keyboards/keyboard_button.py index 022f19de..855c11bd 100644 --- a/pyrogram/client/types/bots_and_keyboards/keyboard_button.py +++ b/pyrogram/types/bots_and_keyboards/keyboard_button.py @@ -16,9 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api.types import KeyboardButton as RawKeyboardButton -from pyrogram.api.types import KeyboardButtonRequestPhone, KeyboardButtonRequestGeoLocation - +from pyrogram import raw from ..object import Object @@ -55,16 +53,16 @@ class KeyboardButton(Object): @staticmethod def read(o): - if isinstance(o, RawKeyboardButton): + if isinstance(o, raw.types.KeyboardButton): return o.text - if isinstance(o, KeyboardButtonRequestPhone): + if isinstance(o, raw.types.KeyboardButtonRequestPhone): return KeyboardButton( text=o.text, request_contact=True ) - if isinstance(o, KeyboardButtonRequestGeoLocation): + if isinstance(o, raw.types.KeyboardButtonRequestGeoLocation): return KeyboardButton( text=o.text, request_location=True @@ -74,8 +72,8 @@ class KeyboardButton(Object): # TODO: Enforce optional args mutual exclusiveness if self.request_contact: - return KeyboardButtonRequestPhone(text=self.text) + return raw.types.KeyboardButtonRequestPhone(text=self.text) elif self.request_location: - return KeyboardButtonRequestGeoLocation(text=self.text) + return raw.types.KeyboardButtonRequestGeoLocation(text=self.text) else: - return RawKeyboardButton(text=self.text) + return raw.types.KeyboardButton(text=self.text) diff --git a/pyrogram/client/types/bots_and_keyboards/reply_keyboard_markup.py b/pyrogram/types/bots_and_keyboards/reply_keyboard_markup.py similarity index 88% rename from pyrogram/client/types/bots_and_keyboards/reply_keyboard_markup.py rename to pyrogram/types/bots_and_keyboards/reply_keyboard_markup.py index f56087b9..e4283c8b 100644 --- a/pyrogram/client/types/bots_and_keyboards/reply_keyboard_markup.py +++ b/pyrogram/types/bots_and_keyboards/reply_keyboard_markup.py @@ -18,10 +18,8 @@ from typing import List, Union -from pyrogram.api.types import KeyboardButtonRow -from pyrogram.api.types import ReplyKeyboardMarkup as RawReplyKeyboardMarkup - -from . import KeyboardButton +from pyrogram import raw +from pyrogram import types from ..object import Object @@ -29,7 +27,7 @@ class ReplyKeyboardMarkup(Object): """A custom keyboard with reply options. Parameters: - keyboard (List of List of :obj:`KeyboardButton`): + keyboard (List of List of :obj:`~pyrogram.types.KeyboardButton`): List of button rows, each represented by a List of KeyboardButton objects. resize_keyboard (``bool``, *optional*): @@ -52,7 +50,7 @@ class ReplyKeyboardMarkup(Object): def __init__( self, - keyboard: List[List[Union[KeyboardButton, str]]], + keyboard: List[List[Union["types.KeyboardButton", str]]], resize_keyboard: bool = None, one_time_keyboard: bool = None, selective: bool = None @@ -72,7 +70,7 @@ class ReplyKeyboardMarkup(Object): row = [] for j in i.buttons: - row.append(KeyboardButton.read(j)) + row.append(types.KeyboardButton.read(j)) keyboard.append(row) @@ -84,10 +82,10 @@ class ReplyKeyboardMarkup(Object): ) def write(self): - return RawReplyKeyboardMarkup( - rows=[KeyboardButtonRow( + return raw.types.ReplyKeyboardMarkup( + rows=[raw.types.KeyboardButtonRow( buttons=[ - KeyboardButton(j).write() + types.KeyboardButton(j).write() if isinstance(j, str) else j.write() for j in i ] diff --git a/pyrogram/client/types/bots_and_keyboards/reply_keyboard_remove.py b/pyrogram/types/bots_and_keyboards/reply_keyboard_remove.py similarity index 96% rename from pyrogram/client/types/bots_and_keyboards/reply_keyboard_remove.py rename to pyrogram/types/bots_and_keyboards/reply_keyboard_remove.py index 2143870a..f595d06d 100644 --- a/pyrogram/client/types/bots_and_keyboards/reply_keyboard_remove.py +++ b/pyrogram/types/bots_and_keyboards/reply_keyboard_remove.py @@ -16,8 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api.types import ReplyKeyboardHide - +from pyrogram import raw from ..object import Object @@ -53,6 +52,6 @@ class ReplyKeyboardRemove(Object): ) def write(self): - return ReplyKeyboardHide( + return raw.types.ReplyKeyboardHide( selective=self.selective or None ) diff --git a/pyrogram/client/types/inline_mode/__init__.py b/pyrogram/types/inline_mode/__init__.py similarity index 100% rename from pyrogram/client/types/inline_mode/__init__.py rename to pyrogram/types/inline_mode/__init__.py index 4980377d..b532c2e9 100644 --- a/pyrogram/client/types/inline_mode/__init__.py +++ b/pyrogram/types/inline_mode/__init__.py @@ -16,12 +16,12 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +from .chosen_inline_result import ChosenInlineResult from .inline_query import InlineQuery from .inline_query_result import InlineQueryResult from .inline_query_result_animation import InlineQueryResultAnimation from .inline_query_result_article import InlineQueryResultArticle from .inline_query_result_photo import InlineQueryResultPhoto -from .chosen_inline_result import ChosenInlineResult __all__ = [ "InlineQuery", "InlineQueryResult", "InlineQueryResultArticle", "InlineQueryResultPhoto", diff --git a/pyrogram/client/types/inline_mode/chosen_inline_result.py b/pyrogram/types/inline_mode/chosen_inline_result.py similarity index 67% rename from pyrogram/client/types/inline_mode/chosen_inline_result.py rename to pyrogram/types/inline_mode/chosen_inline_result.py index b7180b0b..11185d9b 100644 --- a/pyrogram/client/types/inline_mode/chosen_inline_result.py +++ b/pyrogram/types/inline_mode/chosen_inline_result.py @@ -15,31 +15,15 @@ # # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -# -# This file is part of Pyrogram. -# -# Pyrogram is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Pyrogram is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Pyrogram. If not, see . from base64 import b64encode from struct import pack import pyrogram -from pyrogram.api import types -from pyrogram.client.types.object import Object -from pyrogram.client.types.update import Update -from pyrogram.client.types.user_and_chats import User -from pyrogram.client.types.messages_and_media import Location +from pyrogram import raw +from pyrogram import types +from ..object import Object +from ..update import Update class ChosenInlineResult(Object, Update): @@ -49,13 +33,13 @@ class ChosenInlineResult(Object, Update): result_id (``str``): The unique identifier for the result that was chosen. - from_user (:obj:`User`): + from_user (:obj:`~pyrogram.types.User`): The user that chose the result. query (``str``): The query that was used to obtain the result. - location (:obj:`Location`, *optional*): + location (:obj:`~pyrogram.types.Location`, *optional*): Sender location, only for bots that require user location. inline_message_id (``str``, *optional*): @@ -72,11 +56,11 @@ class ChosenInlineResult(Object, Update): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, result_id: str, - from_user: User, + from_user: "types.User", query: str, - location: "pyrogram.Location" = None, + location: "types.Location" = None, inline_message_id: str = None ): super().__init__(client) @@ -88,10 +72,10 @@ class ChosenInlineResult(Object, Update): self.inline_message_id = inline_message_id @staticmethod - def _parse(client, chosen_inline_result: types.UpdateBotInlineSend, users) -> "ChosenInlineResult": + def _parse(client, chosen_inline_result: raw.types.UpdateBotInlineSend, users) -> "ChosenInlineResult": inline_message_id = None - if isinstance(chosen_inline_result.msg_id, types.InputBotInlineMessageID): + if isinstance(chosen_inline_result.msg_id, raw.types.InputBotInlineMessageID): inline_message_id = b64encode( pack( " "InlineQuery": + def _parse(client, inline_query: raw.types.UpdateBotInlineQuery, users: dict) -> "InlineQuery": return InlineQuery( id=str(inline_query.query_id), - from_user=User._parse(client, users[inline_query.user_id]), + from_user=types.User._parse(client, users[inline_query.user_id]), query=inline_query.query, offset=inline_query.offset, - location=Location( + location=types.Location( longitude=inline_query.geo.long, latitude=inline_query.geo.lat, client=client @@ -90,7 +88,7 @@ class InlineQuery(Object, Update): async def answer( self, - results: List[InlineQueryResult], + results: List["types.InlineQueryResult"], cache_time: int = 300, is_gallery: bool = False, is_personal: bool = False, @@ -98,7 +96,7 @@ class InlineQuery(Object, Update): switch_pm_text: str = "", switch_pm_parameter: str = "" ): - """Bound method *answer* of :obj:`InlineQuery`. + """Bound method *answer* of :obj:`~pyrogram.types.InlineQuery`. Use this method as a shortcut for: @@ -115,7 +113,7 @@ class InlineQuery(Object, Update): inline_query.answer([...]) Parameters: - results (List of :obj:`InlineQueryResult`): + results (List of :obj:`~pyrogram.types.InlineQueryResult`): A list of results for the inline query. cache_time (``int``, *optional*): diff --git a/pyrogram/types/inline_mode/inline_query_result.py b/pyrogram/types/inline_mode/inline_query_result.py new file mode 100644 index 00000000..c70e52c0 --- /dev/null +++ b/pyrogram/types/inline_mode/inline_query_result.py @@ -0,0 +1,70 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-2020 Dan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from uuid import uuid4 + +from pyrogram import types +from ..object import Object + +"""- :obj:`~pyrogram.types.InlineQueryResultCachedAudio` + - :obj:`~pyrogram.types.InlineQueryResultCachedDocument` + - :obj:`~pyrogram.types.InlineQueryResultCachedGif` + - :obj:`~pyrogram.types.InlineQueryResultCachedMpeg4Gif` + - :obj:`~pyrogram.types.InlineQueryResultCachedPhoto` + - :obj:`~pyrogram.types.InlineQueryResultCachedSticker` + - :obj:`~pyrogram.types.InlineQueryResultCachedVideo` + - :obj:`~pyrogram.types.InlineQueryResultCachedVoice` + - :obj:`~pyrogram.types.InlineQueryResultAudio` + - :obj:`~pyrogram.types.InlineQueryResultContact` + - :obj:`~pyrogram.types.InlineQueryResultGame` + - :obj:`~pyrogram.types.InlineQueryResultDocument` + - :obj:`~pyrogram.types.InlineQueryResultGif` + - :obj:`~pyrogram.types.InlineQueryResultLocation` + - :obj:`~pyrogram.types.InlineQueryResultMpeg4Gif` + - :obj:`~pyrogram.types.InlineQueryResultPhoto` + - :obj:`~pyrogram.types.InlineQueryResultVenue` + - :obj:`~pyrogram.types.InlineQueryResultVideo` + - :obj:`~pyrogram.types.InlineQueryResultVoice`""" + + +class InlineQueryResult(Object): + """One result of an inline query. + + Pyrogram currently supports results of the following types: + + - :obj:`~pyrogram.types.InlineQueryResultArticle` + - :obj:`~pyrogram.types.InlineQueryResultPhoto` + - :obj:`~pyrogram.types.InlineQueryResultAnimation` + """ + + def __init__( + self, + type: str, + id: str, + input_message_content: "types.InputMessageContent", + reply_markup: "types.InlineKeyboardMarkup" + ): + super().__init__() + + self.type = type + self.id = str(uuid4()) if id is None else str(id) + self.input_message_content = input_message_content + self.reply_markup = reply_markup + + async def write(self): + pass diff --git a/pyrogram/client/types/inline_mode/inline_query_result_animation.py b/pyrogram/types/inline_mode/inline_query_result_animation.py similarity index 87% rename from pyrogram/client/types/inline_mode/inline_query_result_animation.py rename to pyrogram/types/inline_mode/inline_query_result_animation.py index d53bbd59..bd0e7037 100644 --- a/pyrogram/client/types/inline_mode/inline_query_result_animation.py +++ b/pyrogram/types/inline_mode/inline_query_result_animation.py @@ -18,11 +18,10 @@ from typing import Union -from pyrogram.api import types +from pyrogram import raw +from pyrogram import types +from pyrogram.parser import Parser from .inline_query_result import InlineQueryResult -from ..bots_and_keyboards import InlineKeyboardMarkup -from ..input_message_content import InputMessageContent -from ...parser import Parser class InlineQueryResultAnimation(InlineQueryResult): @@ -61,10 +60,10 @@ class InlineQueryResultAnimation(InlineQueryResult): Pass "html" to enable HTML-style parsing only. Pass None to completely disable style parsing. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. - input_message_content (:obj:`InputMessageContent`): + input_message_content (:obj:`~pyrogram.types.InputMessageContent`): Content of the message to be sent instead of the photo. """ @@ -77,8 +76,8 @@ class InlineQueryResultAnimation(InlineQueryResult): description: str = None, caption: str = None, parse_mode: Union[str, None] = object, - reply_markup: InlineKeyboardMarkup = None, - input_message_content: InputMessageContent = None + reply_markup: "types.InlineKeyboardMarkup" = None, + input_message_content: "types.InputMessageContent" = None ): super().__init__("gif", id, input_message_content, reply_markup) @@ -92,7 +91,7 @@ class InlineQueryResultAnimation(InlineQueryResult): self.input_message_content = input_message_content async def write(self): - animation = types.InputWebDocument( + animation = raw.types.InputWebDocument( url=self.animation_url, size=0, mime_type="image/gif", @@ -102,14 +101,14 @@ class InlineQueryResultAnimation(InlineQueryResult): if self.thumb_url is None: thumb = animation else: - thumb = types.InputWebDocument( + thumb = raw.types.InputWebDocument( url=self.thumb_url, size=0, mime_type="image/gif", attributes=[] ) - return types.InputBotInlineResult( + return raw.types.InputBotInlineResult( id=self.id, type=self.type, title=self.title, @@ -119,7 +118,7 @@ class InlineQueryResultAnimation(InlineQueryResult): send_message=( self.input_message_content.write(self.reply_markup) if self.input_message_content - else types.InputBotInlineMessageMediaAuto( + else raw.types.InputBotInlineMessageMediaAuto( reply_markup=self.reply_markup.write() if self.reply_markup else None, **await(Parser(None)).parse(self.caption, self.parse_mode) ) diff --git a/pyrogram/client/types/inline_mode/inline_query_result_article.py b/pyrogram/types/inline_mode/inline_query_result_article.py similarity index 83% rename from pyrogram/client/types/inline_mode/inline_query_result_article.py rename to pyrogram/types/inline_mode/inline_query_result_article.py index 65e85a0f..42bf6f0a 100644 --- a/pyrogram/client/types/inline_mode/inline_query_result_article.py +++ b/pyrogram/types/inline_mode/inline_query_result_article.py @@ -16,10 +16,10 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api import types +from pyrogram import raw +from pyrogram import types + from .inline_query_result import InlineQueryResult -from ..bots_and_keyboards import InlineKeyboardMarkup -from ..input_message_content import InputMessageContent class InlineQueryResultArticle(InlineQueryResult): @@ -29,7 +29,7 @@ class InlineQueryResultArticle(InlineQueryResult): title (``str``): Title for the result. - input_message_content (:obj:`InputMessageContent`): + input_message_content (:obj:`~pyrogram.types.InputMessageContent`): Content of the message to be sent. id (``str``, *optional*): @@ -45,16 +45,16 @@ class InlineQueryResultArticle(InlineQueryResult): thumb_url (``str``, *optional*): URL of the thumbnail for the result. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): Inline keyboard attached to the message. """ def __init__( self, title: str, - input_message_content: InputMessageContent, + input_message_content: "types.InputMessageContent", id: str = None, - reply_markup: InlineKeyboardMarkup = None, + reply_markup: "types.InlineKeyboardMarkup" = None, url: str = None, description: str = None, thumb_url: str = None @@ -67,14 +67,14 @@ class InlineQueryResultArticle(InlineQueryResult): self.thumb_url = thumb_url async def write(self): - return types.InputBotInlineResult( + return raw.types.InputBotInlineResult( id=self.id, type=self.type, send_message=await self.input_message_content.write(self.reply_markup), title=self.title, description=self.description, url=self.url, - thumb=types.InputWebDocument( + thumb=raw.types.InputWebDocument( url=self.thumb_url, size=0, mime_type="image/jpeg", diff --git a/pyrogram/client/types/inline_mode/inline_query_result_photo.py b/pyrogram/types/inline_mode/inline_query_result_photo.py similarity index 86% rename from pyrogram/client/types/inline_mode/inline_query_result_photo.py rename to pyrogram/types/inline_mode/inline_query_result_photo.py index e3890b9b..7287abc0 100644 --- a/pyrogram/client/types/inline_mode/inline_query_result_photo.py +++ b/pyrogram/types/inline_mode/inline_query_result_photo.py @@ -18,11 +18,10 @@ from typing import Union -from pyrogram.api import types +from pyrogram import raw +from pyrogram import types +from pyrogram.parser import Parser from .inline_query_result import InlineQueryResult -from ..bots_and_keyboards import InlineKeyboardMarkup -from ..input_message_content import InputMessageContent -from ...parser import Parser class InlineQueryResultPhoto(InlineQueryResult): @@ -61,10 +60,10 @@ class InlineQueryResultPhoto(InlineQueryResult): Pass "html" to enable HTML-style parsing only. Pass None to completely disable style parsing. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. - input_message_content (:obj:`InputMessageContent`): + input_message_content (:obj:`~pyrogram.types.InputMessageContent`): Content of the message to be sent instead of the photo. """ @@ -77,8 +76,8 @@ class InlineQueryResultPhoto(InlineQueryResult): description: str = None, caption: str = None, parse_mode: Union[str, None] = object, - reply_markup: InlineKeyboardMarkup = None, - input_message_content: InputMessageContent = None + reply_markup: "types.InlineKeyboardMarkup" = None, + input_message_content: "types.InputMessageContent" = None ): super().__init__("photo", id, input_message_content, reply_markup) @@ -92,7 +91,7 @@ class InlineQueryResultPhoto(InlineQueryResult): self.input_message_content = input_message_content async def write(self): - photo = types.InputWebDocument( + photo = raw.types.InputWebDocument( url=self.photo_url, size=0, mime_type="image/jpeg", @@ -102,14 +101,14 @@ class InlineQueryResultPhoto(InlineQueryResult): if self.thumb_url is None: thumb = photo else: - thumb = types.InputWebDocument( + thumb = raw.types.InputWebDocument( url=self.thumb_url, size=0, mime_type="image/jpeg", attributes=[] ) - return types.InputBotInlineResult( + return raw.types.InputBotInlineResult( id=self.id, type=self.type, title=self.title, @@ -119,7 +118,7 @@ class InlineQueryResultPhoto(InlineQueryResult): send_message=( await self.input_message_content.write(self.reply_markup) if self.input_message_content - else types.InputBotInlineMessageMediaAuto( + else raw.types.InputBotInlineMessageMediaAuto( reply_markup=self.reply_markup.write() if self.reply_markup else None, **await(Parser(None)).parse(self.caption, self.parse_mode) ) diff --git a/pyrogram/client/types/input_media/__init__.py b/pyrogram/types/input_media/__init__.py similarity index 100% rename from pyrogram/client/types/input_media/__init__.py rename to pyrogram/types/input_media/__init__.py diff --git a/pyrogram/client/types/input_media/input_media.py b/pyrogram/types/input_media/input_media.py similarity index 83% rename from pyrogram/client/types/input_media/input_media.py rename to pyrogram/types/input_media/input_media.py index 7d849732..f692cb83 100644 --- a/pyrogram/client/types/input_media/input_media.py +++ b/pyrogram/types/input_media/input_media.py @@ -24,11 +24,11 @@ class InputMedia(Object): It should be one of: - - :obj:`InputMediaAnimation` - - :obj:`InputMediaDocument` - - :obj:`InputMediaAudio` - - :obj:`InputMediaPhoto` - - :obj:`InputMediaVideo` + - :obj:`~pyrogram.types.InputMediaAnimation` + - :obj:`~pyrogram.types.InputMediaDocument` + - :obj:`~pyrogram.types.InputMediaAudio` + - :obj:`~pyrogram.types.InputMediaPhoto` + - :obj:`~pyrogram.types.InputMediaVideo` """ def __init__(self, media: str, file_ref: str, caption: str, parse_mode: str): diff --git a/pyrogram/client/types/input_media/input_media_animation.py b/pyrogram/types/input_media/input_media_animation.py similarity index 98% rename from pyrogram/client/types/input_media/input_media_animation.py rename to pyrogram/types/input_media/input_media_animation.py index ee746689..786a4ee0 100644 --- a/pyrogram/client/types/input_media/input_media_animation.py +++ b/pyrogram/types/input_media/input_media_animation.py @@ -18,7 +18,7 @@ from typing import Union -from . import InputMedia +from .input_media import InputMedia class InputMediaAnimation(InputMedia): diff --git a/pyrogram/client/types/input_media/input_media_audio.py b/pyrogram/types/input_media/input_media_audio.py similarity index 94% rename from pyrogram/client/types/input_media/input_media_audio.py rename to pyrogram/types/input_media/input_media_audio.py index 66cd9e1f..a5ae9fca 100644 --- a/pyrogram/client/types/input_media/input_media_audio.py +++ b/pyrogram/types/input_media/input_media_audio.py @@ -18,13 +18,13 @@ from typing import Union -from . import InputMedia +from .input_media import InputMedia class InputMediaAudio(InputMedia): """An audio to be sent inside an album. - It is intended to be used with :obj:`send_media_group() `. + It is intended to be used with :meth:`~pyrogram.Client.send_media_group`. Parameters: media (``str``): @@ -70,7 +70,7 @@ class InputMediaAudio(InputMedia): caption: str = "", parse_mode: Union[str, None] = object, duration: int = 0, - performer: int = "", + performer: str = "", title: str = "" ): super().__init__(media, file_ref, caption, parse_mode) diff --git a/pyrogram/client/types/input_media/input_media_document.py b/pyrogram/types/input_media/input_media_document.py similarity index 98% rename from pyrogram/client/types/input_media/input_media_document.py rename to pyrogram/types/input_media/input_media_document.py index 7ff3ca0b..1df2c3c3 100644 --- a/pyrogram/client/types/input_media/input_media_document.py +++ b/pyrogram/types/input_media/input_media_document.py @@ -18,7 +18,7 @@ from typing import Union -from . import InputMedia +from .input_media import InputMedia class InputMediaDocument(InputMedia): diff --git a/pyrogram/client/types/input_media/input_media_photo.py b/pyrogram/types/input_media/input_media_photo.py similarity index 94% rename from pyrogram/client/types/input_media/input_media_photo.py rename to pyrogram/types/input_media/input_media_photo.py index f40bdef7..f4e5df8e 100644 --- a/pyrogram/client/types/input_media/input_media_photo.py +++ b/pyrogram/types/input_media/input_media_photo.py @@ -18,12 +18,12 @@ from typing import Union -from . import InputMedia +from .input_media import InputMedia class InputMediaPhoto(InputMedia): """A photo to be sent inside an album. - It is intended to be used with :obj:`send_media_group() `. + It is intended to be used with :obj:`~pyrogram.Client.send_media_group`. Parameters: media (``str``): diff --git a/pyrogram/client/types/input_media/input_media_video.py b/pyrogram/types/input_media/input_media_video.py similarity index 96% rename from pyrogram/client/types/input_media/input_media_video.py rename to pyrogram/types/input_media/input_media_video.py index 6b986a32..dc65d002 100644 --- a/pyrogram/client/types/input_media/input_media_video.py +++ b/pyrogram/types/input_media/input_media_video.py @@ -18,12 +18,12 @@ from typing import Union -from . import InputMedia +from .input_media import InputMedia class InputMediaVideo(InputMedia): """A video to be sent inside an album. - It is intended to be used with :obj:`send_media_group() `. + It is intended to be used with :obj:`~pyrogram.Client.send_media_group`. Parameters: media (``str``): diff --git a/pyrogram/client/types/input_media/input_phone_contact.py b/pyrogram/types/input_media/input_phone_contact.py similarity index 93% rename from pyrogram/client/types/input_media/input_phone_contact.py rename to pyrogram/types/input_media/input_phone_contact.py index e2c3aca1..58c73252 100644 --- a/pyrogram/client/types/input_media/input_phone_contact.py +++ b/pyrogram/types/input_media/input_phone_contact.py @@ -16,8 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api.types import InputPhoneContact as RawInputPhoneContact - +from pyrogram import raw from pyrogram.session.internals import MsgId from ..object import Object @@ -44,7 +43,7 @@ class InputPhoneContact(Object): phone: str, first_name: str, last_name: str = ""): - return RawInputPhoneContact( + return raw.types.InputPhoneContact( client_id=MsgId(), phone="+" + phone.strip("+"), first_name=first_name, diff --git a/pyrogram/client/types/input_message_content/__init__.py b/pyrogram/types/input_message_content/__init__.py similarity index 100% rename from pyrogram/client/types/input_message_content/__init__.py rename to pyrogram/types/input_message_content/__init__.py diff --git a/pyrogram/client/types/input_message_content/input_message_content.py b/pyrogram/types/input_message_content/input_message_content.py similarity index 83% rename from pyrogram/client/types/input_message_content/input_message_content.py rename to pyrogram/types/input_message_content/input_message_content.py index f97e3cd9..4ecbc0a6 100644 --- a/pyrogram/client/types/input_message_content/input_message_content.py +++ b/pyrogram/types/input_message_content/input_message_content.py @@ -18,9 +18,9 @@ from ..object import Object -"""- :obj:`InputLocationMessageContent` - - :obj:`InputVenueMessageContent` - - :obj:`InputContactMessageContent`""" +"""- :obj:`~pyrogram.types.InputLocationMessageContent` + - :obj:`~pyrogram.types.InputVenueMessageContent` + - :obj:`~pyrogram.types.InputContactMessageContent`""" class InputMessageContent(Object): @@ -28,7 +28,7 @@ class InputMessageContent(Object): Pyrogram currently supports the following types: - - :obj:`InputTextMessageContent` + - :obj:`~pyrogram.types.InputTextMessageContent` """ def __init__(self): diff --git a/pyrogram/client/types/input_message_content/input_text_message_content.py b/pyrogram/types/input_message_content/input_text_message_content.py similarity index 95% rename from pyrogram/client/types/input_message_content/input_text_message_content.py rename to pyrogram/types/input_message_content/input_text_message_content.py index 1247011e..ac584cc2 100644 --- a/pyrogram/client/types/input_message_content/input_text_message_content.py +++ b/pyrogram/types/input_message_content/input_text_message_content.py @@ -18,9 +18,9 @@ from typing import Union -from pyrogram.api import types +from pyrogram import raw +from pyrogram.parser import Parser from .input_message_content import InputMessageContent -from ...parser import Parser class InputTextMessageContent(InputMessageContent): @@ -49,7 +49,7 @@ class InputTextMessageContent(InputMessageContent): self.disable_web_page_preview = disable_web_page_preview async def write(self, reply_markup): - return types.InputBotInlineMessageText( + return raw.types.InputBotInlineMessageText( no_webpage=self.disable_web_page_preview or None, reply_markup=reply_markup.write() if reply_markup else None, **await(Parser(None)).parse(self.message_text, self.parse_mode) diff --git a/pyrogram/client/types/list.py b/pyrogram/types/list.py similarity index 88% rename from pyrogram/client/types/list.py rename to pyrogram/types/list.py index 118c4304..2bdc425b 100644 --- a/pyrogram/client/types/list.py +++ b/pyrogram/types/list.py @@ -27,6 +27,4 @@ class List(list): return Object.__str__(self) def __repr__(self): - return "pyrogram.client.types.list.List([{}])".format( - ",".join(Object.__repr__(i) for i in self) - ) + return f"pyrogram.types.List([{','.join(Object.__repr__(i) for i in self)}])" diff --git a/pyrogram/client/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py similarity index 100% rename from pyrogram/client/types/messages_and_media/__init__.py rename to pyrogram/types/messages_and_media/__init__.py index d2424043..aeae6375 100644 --- a/pyrogram/client/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -19,6 +19,7 @@ from .animation import Animation from .audio import Audio from .contact import Contact +from .dice import Dice from .document import Document from .game import Game from .location import Location @@ -35,7 +36,6 @@ from .video import Video from .video_note import VideoNote from .voice import Voice from .webpage import WebPage -from .dice import Dice __all__ = [ "Animation", "Audio", "Contact", "Document", "Game", "Location", "Message", "MessageEntity", "Photo", "Thumbnail", diff --git a/pyrogram/client/types/messages_and_media/animation.py b/pyrogram/types/messages_and_media/animation.py similarity index 88% rename from pyrogram/client/types/messages_and_media/animation.py rename to pyrogram/types/messages_and_media/animation.py index 497f943e..97f34e96 100644 --- a/pyrogram/client/types/messages_and_media/animation.py +++ b/pyrogram/types/messages_and_media/animation.py @@ -20,10 +20,10 @@ from struct import pack from typing import List import pyrogram -from pyrogram.api import types -from .thumbnail import Thumbnail +from pyrogram import raw +from pyrogram import types +from pyrogram.utils import encode_file_id, encode_file_ref from ..object import Object -from ...ext.utils import encode_file_id, encode_file_ref class Animation(Object): @@ -57,14 +57,14 @@ class Animation(Object): date (``int``, *optional*): Date the animation was sent in Unix time. - thumbs (List of :obj:`Thumbnail`, *optional*): + thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): Animation thumbnails. """ def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, file_id: str, file_ref: str, width: int, @@ -74,7 +74,7 @@ class Animation(Object): mime_type: str = None, file_size: int = None, date: int = None, - thumbs: List[Thumbnail] = None + thumbs: List["types.Thumbnail"] = None ): super().__init__(client) @@ -92,8 +92,8 @@ class Animation(Object): @staticmethod def _parse( client, - animation: types.Document, - video_attributes: types.DocumentAttributeVideo, + animation: "raw.types.Document", + video_attributes: "raw.types.DocumentAttributeVideo", file_name: str ) -> "Animation": return Animation( @@ -114,6 +114,6 @@ class Animation(Object): file_size=animation.size, file_name=file_name, date=animation.date, - thumbs=Thumbnail._parse(client, animation), + thumbs=types.Thumbnail._parse(client, animation), client=client ) diff --git a/pyrogram/client/types/messages_and_media/audio.py b/pyrogram/types/messages_and_media/audio.py similarity index 88% rename from pyrogram/client/types/messages_and_media/audio.py rename to pyrogram/types/messages_and_media/audio.py index bd360126..a54b6c9f 100644 --- a/pyrogram/client/types/messages_and_media/audio.py +++ b/pyrogram/types/messages_and_media/audio.py @@ -20,10 +20,10 @@ from struct import pack from typing import List import pyrogram -from pyrogram.api import types -from .thumbnail import Thumbnail +from pyrogram import raw +from pyrogram import types +from pyrogram.utils import encode_file_id, encode_file_ref from ..object import Object -from ...ext.utils import encode_file_id, encode_file_ref class Audio(Object): @@ -57,14 +57,14 @@ class Audio(Object): title (``str``, *optional*): Title of the audio as defined by sender or by audio tags. - thumbs (List of :obj:`Thumbnail`, *optional*): + thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): Thumbnails of the music file album cover. """ def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, file_id: str, file_ref: str, duration: int, @@ -74,7 +74,7 @@ class Audio(Object): date: int = None, performer: str = None, title: str = None, - thumbs: List[Thumbnail] = None + thumbs: List["types.Thumbnail"] = None ): super().__init__(client) @@ -92,8 +92,8 @@ class Audio(Object): @staticmethod def _parse( client, - audio: types.Document, - audio_attributes: types.DocumentAttributeAudio, + audio: "raw.types.Document", + audio_attributes: "raw.types.DocumentAttributeAudio", file_name: str ) -> "Audio": return Audio( @@ -114,6 +114,6 @@ class Audio(Object): file_size=audio.size, file_name=file_name, date=audio.date, - thumbs=Thumbnail._parse(client, audio), + thumbs=types.Thumbnail._parse(client, audio), client=client ) diff --git a/pyrogram/client/types/messages_and_media/contact.py b/pyrogram/types/messages_and_media/contact.py similarity index 92% rename from pyrogram/client/types/messages_and_media/contact.py rename to pyrogram/types/messages_and_media/contact.py index c2289ee1..8ce25d40 100644 --- a/pyrogram/client/types/messages_and_media/contact.py +++ b/pyrogram/types/messages_and_media/contact.py @@ -17,8 +17,7 @@ # along with Pyrogram. If not, see . import pyrogram - -from pyrogram.api import types +from pyrogram import raw from ..object import Object @@ -45,7 +44,7 @@ class Contact(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, phone_number: str, first_name: str, last_name: str = None, @@ -61,7 +60,7 @@ class Contact(Object): self.vcard = vcard @staticmethod - def _parse(client, contact: types.MessageMediaContact) -> "Contact": + def _parse(client: "pyrogram.Client", contact: "raw.types.MessageMediaContact") -> "Contact": return Contact( phone_number=contact.phone_number, first_name=contact.first_name, diff --git a/pyrogram/client/types/messages_and_media/dice.py b/pyrogram/types/messages_and_media/dice.py similarity index 88% rename from pyrogram/client/types/messages_and_media/dice.py rename to pyrogram/types/messages_and_media/dice.py index e76cad1e..e89fb38b 100644 --- a/pyrogram/client/types/messages_and_media/dice.py +++ b/pyrogram/types/messages_and_media/dice.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . import pyrogram -from pyrogram.api import types +from pyrogram import raw from ..object import Object @@ -32,14 +32,14 @@ class Dice(Object): Value of the dice, 1-6 for currently supported base emoji. """ - def __init__(self, *, client: "pyrogram.BaseClient" = None, emoji: str, value: int): + def __init__(self, *, client: "pyrogram.Client" = None, emoji: str, value: int): super().__init__(client) self.emoji = emoji self.value = value @staticmethod - def _parse(client, dice: types.MessageMediaDice) -> "Dice": + def _parse(client, dice: "raw.types.MessageMediaDice") -> "Dice": return Dice( emoji=dice.emoticon, value=dice.value, diff --git a/pyrogram/client/types/messages_and_media/document.py b/pyrogram/types/messages_and_media/document.py similarity index 86% rename from pyrogram/client/types/messages_and_media/document.py rename to pyrogram/types/messages_and_media/document.py index ec6a5edc..19975b74 100644 --- a/pyrogram/client/types/messages_and_media/document.py +++ b/pyrogram/types/messages_and_media/document.py @@ -20,10 +20,10 @@ from struct import pack from typing import List import pyrogram -from pyrogram.api import types -from .thumbnail import Thumbnail +from pyrogram import raw +from pyrogram import types +from pyrogram.utils import encode_file_id, encode_file_ref from ..object import Object -from ...ext.utils import encode_file_id, encode_file_ref class Document(Object): @@ -48,21 +48,21 @@ class Document(Object): date (``int``, *optional*): Date the document was sent in Unix time. - thumbs (List of :obj:`Thumbnail`, *optional*): + thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): Document thumbnails as defined by sender. """ def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, file_id: str, file_ref: str, file_name: str = None, mime_type: str = None, file_size: int = None, date: int = None, - thumbs: List[Thumbnail] = None + thumbs: List["types.Thumbnail"] = None ): super().__init__(client) @@ -75,7 +75,7 @@ class Document(Object): self.thumbs = thumbs @staticmethod - def _parse(client, document: types.Document, file_name: str) -> "Document": + def _parse(client, document: "raw.types.Document", file_name: str) -> "Document": return Document( file_id=encode_file_id( pack( @@ -91,6 +91,6 @@ class Document(Object): mime_type=document.mime_type, file_size=document.size, date=document.date, - thumbs=Thumbnail._parse(client, document), + thumbs=types.Thumbnail._parse(client, document), client=client ) diff --git a/pyrogram/client/types/messages_and_media/game.py b/pyrogram/types/messages_and_media/game.py similarity index 79% rename from pyrogram/client/types/messages_and_media/game.py rename to pyrogram/types/messages_and_media/game.py index f828a270..a80888a2 100644 --- a/pyrogram/client/types/messages_and_media/game.py +++ b/pyrogram/types/messages_and_media/game.py @@ -17,9 +17,8 @@ # along with Pyrogram. If not, see . import pyrogram -from pyrogram.api import types -from .animation import Animation -from .photo import Photo +from pyrogram import raw +from pyrogram import types from ..object import Object @@ -40,10 +39,10 @@ class Game(Object): description (``str``): Description of the game. - photo (:obj:`Photo`): + photo (:obj:`~pyrogram.types.Photo`): Photo that will be displayed in the game message in chats. - animation (:obj:`Animation`, *optional*): + animation (:obj:`~pyrogram.types.Animation`, *optional*): Animation that will be displayed in the game message in chats. Upload via BotFather. """ @@ -51,13 +50,13 @@ class Game(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, id: int, title: str, short_name: str, description: str, - photo: Photo, - animation: Animation = None + photo: "types.Photo", + animation: "types.Animation" = None ): super().__init__(client) @@ -69,8 +68,8 @@ class Game(Object): self.animation = animation @staticmethod - def _parse(client, message: types.Message) -> "Game": - game = message.media.game # type: types.Game + def _parse(client, message: "raw.types.Message") -> "Game": + game: "raw.types.Game" = message.media.game animation = None if game.document: @@ -78,14 +77,14 @@ class Game(Object): file_name = getattr( attributes.get( - types.DocumentAttributeFilename, None + raw.types.DocumentAttributeFilename, None ), "file_name", None ) - animation = Animation._parse( + animation = types.Animation._parse( client, game.document, - attributes.get(types.DocumentAttributeVideo, None), + attributes.get(raw.types.DocumentAttributeVideo, None), file_name ) @@ -94,7 +93,7 @@ class Game(Object): title=game.title, short_name=game.short_name, description=game.description, - photo=Photo._parse(client, game.photo), + photo=types.Photo._parse(client, game.photo), animation=animation, client=client ) diff --git a/pyrogram/client/types/messages_and_media/location.py b/pyrogram/types/messages_and_media/location.py similarity index 88% rename from pyrogram/client/types/messages_and_media/location.py rename to pyrogram/types/messages_and_media/location.py index 38af642f..ac122a6d 100644 --- a/pyrogram/client/types/messages_and_media/location.py +++ b/pyrogram/types/messages_and_media/location.py @@ -18,7 +18,7 @@ import pyrogram -from pyrogram.api import types +from pyrogram import raw from ..object import Object @@ -36,7 +36,7 @@ class Location(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, longitude: float, latitude: float ): @@ -46,8 +46,8 @@ class Location(Object): self.latitude = latitude @staticmethod - def _parse(client, geo_point: types.GeoPoint) -> "Location": - if isinstance(geo_point, types.GeoPoint): + def _parse(client, geo_point: "raw.types.GeoPoint") -> "Location": + if isinstance(geo_point, raw.types.GeoPoint): return Location( longitude=geo_point.long, latitude=geo_point.lat, diff --git a/pyrogram/client/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py similarity index 83% rename from pyrogram/client/types/messages_and_media/message.py rename to pyrogram/types/messages_and_media/message.py index 8bf7cac4..51bb4293 100644 --- a/pyrogram/client/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -20,19 +20,13 @@ from functools import partial from typing import List, Match, Union, BinaryIO import pyrogram -from pyrogram.api import types -from pyrogram.client.types.input_media import InputMedia +from pyrogram import raw +from pyrogram import types +from pyrogram import utils from pyrogram.errors import MessageIdsEmpty -from .contact import Contact -from .location import Location -from .message_entity import MessageEntity -from ..messages_and_media.photo import Photo +from pyrogram.parser import utils as parser_utils, Parser from ..object import Object from ..update import Update -from ..user_and_chats.chat import Chat -from ..user_and_chats.user import User -from ...ext import utils -from ...parser import utils as parser_utils, Parser class Str(str): @@ -68,19 +62,19 @@ class Message(Object, Update): date (``int``, *optional*): Date the message was sent in Unix time. - chat (:obj:`Chat`, *optional*): + chat (:obj:`~pyrogram.types.Chat`, *optional*): Conversation the message belongs to. - from_user (:obj:`User`, *optional*): + from_user (:obj:`~pyrogram.types.User`, *optional*): Sender, empty for messages sent to channels. - forward_from (:obj:`User`, *optional*): + forward_from (:obj:`~pyrogram.types.User`, *optional*): For forwarded messages, sender of the original message. forward_sender_name (``str``, *optional*): For messages forwarded from users who have hidden their accounts, name of the user. - forward_from_chat (:obj:`Chat`, *optional*): + forward_from_chat (:obj:`~pyrogram.types.Chat`, *optional*): For messages forwarded from channels, information about the original channel. forward_from_message_id (``int``, *optional*): @@ -92,7 +86,7 @@ class Message(Object, Update): forward_date (``int``, *optional*): For forwarded messages, date the original message was sent in Unix time. - reply_to_message (:obj:`Message`, *optional*): + reply_to_message (:obj:`~pyrogram.types.Message`, *optional*): For replies, the original message. Note that the Message object in this field will not contain further reply_to_message fields even if it itself is a reply. @@ -129,38 +123,38 @@ class Message(Object, Update): *text.html* to get the marked up message text. In case there is no entity, the fields will contain the same text as *text*. - entities (List of :obj:`MessageEntity`, *optional*): + entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): For text messages, special entities like usernames, URLs, bot commands, etc. that appear in the text. - caption_entities (List of :obj:`MessageEntity`, *optional*): + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): For messages with a caption, special entities like usernames, URLs, bot commands, etc. that appear in the caption. - audio (:obj:`Audio`, *optional*): + audio (:obj:`~pyrogram.types.Audio`, *optional*): Message is an audio file, information about the file. - document (:obj:`Document`, *optional*): + document (:obj:`~pyrogram.types.Document`, *optional*): Message is a general file, information about the file. - photo (:obj:`Photo`, *optional*): + photo (:obj:`~pyrogram.types.Photo`, *optional*): Message is a photo, information about the photo. - sticker (:obj:`Sticker`, *optional*): + sticker (:obj:`~pyrogram.types.Sticker`, *optional*): Message is a sticker, information about the sticker. - animation (:obj:`Animation`, *optional*): + animation (:obj:`~pyrogram.types.Animation`, *optional*): Message is an animation, information about the animation. - game (:obj:`Game`, *optional*): + game (:obj:`~pyrogram.types.Game`, *optional*): Message is a game, information about the game. - video (:obj:`Video`, *optional*): + video (:obj:`~pyrogram.types.Video`, *optional*): Message is a video, information about the video. - voice (:obj:`Voice`, *optional*): + voice (:obj:`~pyrogram.types.Voice`, *optional*): Message is a voice message, information about the file. - video_note (:obj:`VideoNote`, *optional*): + video_note (:obj:`~pyrogram.types.VideoNote`, *optional*): Message is a video note, information about the video message. caption (``str``, *optional*): @@ -169,35 +163,35 @@ class Message(Object, Update): *caption.html* to get the marked up caption text. In case there is no caption entity, the fields will contain the same text as *caption*. - contact (:obj:`Contact`, *optional*): + contact (:obj:`~pyrogram.types.Contact`, *optional*): Message is a shared contact, information about the contact. - location (:obj:`Location`, *optional*): + location (:obj:`~pyrogram.types.Location`, *optional*): Message is a shared location, information about the location. - venue (:obj:`Venue`, *optional*): + venue (:obj:`~pyrogram.types.Venue`, *optional*): Message is a venue, information about the venue. - web_page (:obj:`WebPage`, *optional*): + web_page (:obj:`~pyrogram.types.WebPage`, *optional*): Message was sent with a webpage preview. - poll (:obj:`Poll`, *optional*): + poll (:obj:`~pyrogram.types.Poll`, *optional*): Message is a native poll, information about the poll. - dice (:obj:`Dice`, *optional*): + dice (:obj:`~pyrogram.types.Dice`, *optional*): A dice containing a value that is randomly generated by Telegram. - new_chat_members (List of :obj:`User`, *optional*): + new_chat_members (List of :obj:`~pyrogram.types.User`, *optional*): New members that were added to the group or supergroup and information about them (the bot itself may be one of these members). - left_chat_member (:obj:`User`, *optional*): + left_chat_member (:obj:`~pyrogram.types.User`, *optional*): A member was removed from the group, information about them (this member may be the bot itself). new_chat_title (``str``, *optional*): A chat title was changed to this value. - new_chat_photo (:obj:`Photo`, *optional*): + new_chat_photo (:obj:`~pyrogram.types.Photo`, *optional*): A chat photo was change to this value. delete_chat_photo (``bool``, *optional*): @@ -230,19 +224,19 @@ class Message(Object, Update): in interpreting it. But it is smaller than 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing this identifier. - pinned_message (:obj:`Message`, *optional*): + pinned_message (:obj:`~pyrogram.types.Message`, *optional*): Specified message was pinned. Note that the Message object in this field will not contain further reply_to_message fields even if it is itself a reply. - game_high_score (:obj:`GameHighScore`, *optional*): + game_high_score (:obj:`~pyrogram.types.GameHighScore`, *optional*): The game score for a user. The reply_to_message field will contain the game Message. views (``int``, *optional*): Channel post views. - via_bot (:obj:`User`): + via_bot (:obj:`~pyrogram.types.User`): The information of the bot that generated the message from an inline query of a user. outgoing (``bool``, *optional*): @@ -261,9 +255,9 @@ class Message(Object, Update): command (List of ``str``, *optional*): A list containing the command and its arguments, if any. E.g.: "/start 1 2 3" would produce ["start", "1", "2", "3"]. - Only applicable when using :obj:`Filters.command `. + Only applicable when using :obj:`~pyrogram.filters.command`. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. """ @@ -273,14 +267,14 @@ class Message(Object, Update): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, message_id: int, date: int = None, - chat: Chat = None, - from_user: User = None, - forward_from: User = None, + chat: "types.Chat" = None, + from_user: "types.User" = None, + forward_from: "types.User" = None, forward_sender_name: str = None, - forward_from_chat: Chat = None, + forward_from_chat: "types.Chat" = None, forward_from_message_id: int = None, forward_signature: str = None, forward_date: int = None, @@ -295,28 +289,28 @@ class Message(Object, Update): media_group_id: str = None, author_signature: str = None, text: Str = None, - entities: List["pyrogram.MessageEntity"] = None, - caption_entities: List["pyrogram.MessageEntity"] = None, - audio: "pyrogram.Audio" = None, - document: "pyrogram.Document" = None, - photo: "pyrogram.Photo" = None, - sticker: "pyrogram.Sticker" = None, - animation: "pyrogram.Animation" = None, - game: "pyrogram.Game" = None, - video: "pyrogram.Video" = None, - voice: "pyrogram.Voice" = None, - video_note: "pyrogram.VideoNote" = None, + entities: List["types.MessageEntity"] = None, + caption_entities: List["types.MessageEntity"] = None, + audio: "types.Audio" = None, + document: "types.Document" = None, + photo: "types.Photo" = None, + sticker: "types.Sticker" = None, + animation: "types.Animation" = None, + game: "types.Game" = None, + video: "types.Video" = None, + voice: "types.Voice" = None, + video_note: "types.VideoNote" = None, caption: Str = None, - contact: "pyrogram.Contact" = None, - location: "pyrogram.Location" = None, - venue: "pyrogram.Venue" = None, - web_page: "pyrogram.WebPage" = None, - poll: "pyrogram.Poll" = None, - dice: "pyrogram.Dice" = None, - new_chat_members: List[User] = None, - left_chat_member: User = None, + contact: "types.Contact" = None, + location: "types.Location" = None, + venue: "types.Venue" = None, + web_page: "types.WebPage" = None, + poll: "types.Poll" = None, + dice: "types.Dice" = None, + new_chat_members: List["types.User"] = None, + left_chat_member: "types.User" = None, new_chat_title: str = None, - new_chat_photo: "pyrogram.Photo" = None, + new_chat_photo: "types.Photo" = None, delete_chat_photo: bool = None, group_chat_created: bool = None, supergroup_chat_created: bool = None, @@ -326,15 +320,15 @@ class Message(Object, Update): pinned_message: "Message" = None, game_high_score: int = None, views: int = None, - via_bot: User = None, + via_bot: "types.User" = None, outgoing: bool = None, matches: List[Match] = None, command: List[str] = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None ): super().__init__(client) @@ -398,12 +392,18 @@ class Message(Object, Update): self.reply_markup = reply_markup @staticmethod - async def _parse(client, message: types.Message or types.MessageService or types.MessageEmpty, users: dict, - chats: dict, is_scheduled: bool = False, replies: int = 1): - if isinstance(message, types.MessageEmpty): + async def _parse( + client, + message: raw.base.Message, + users: dict, + chats: dict, + is_scheduled: bool = False, + replies: int = 1 + ): + if isinstance(message, raw.types.MessageEmpty): return Message(message_id=message.id, empty=True, client=client) - if isinstance(message, types.MessageService): + if isinstance(message, raw.types.MessageService): action = message.action new_chat_members = None @@ -416,32 +416,32 @@ class Message(Object, Update): channel_chat_created = None new_chat_photo = None - if isinstance(action, types.MessageActionChatAddUser): - new_chat_members = [User._parse(client, users[i]) for i in action.users] - elif isinstance(action, types.MessageActionChatJoinedByLink): - new_chat_members = [User._parse(client, users[message.from_id])] - elif isinstance(action, types.MessageActionChatDeleteUser): - left_chat_member = User._parse(client, users[action.user_id]) - elif isinstance(action, types.MessageActionChatEditTitle): + if isinstance(action, raw.types.MessageActionChatAddUser): + new_chat_members = [types.User._parse(client, users[i]) for i in action.users] + elif isinstance(action, raw.types.MessageActionChatJoinedByLink): + new_chat_members = [types.User._parse(client, users[message.from_id])] + elif isinstance(action, raw.types.MessageActionChatDeleteUser): + left_chat_member = types.User._parse(client, users[action.user_id]) + elif isinstance(action, raw.types.MessageActionChatEditTitle): new_chat_title = action.title - elif isinstance(action, types.MessageActionChatDeletePhoto): + elif isinstance(action, raw.types.MessageActionChatDeletePhoto): delete_chat_photo = True - elif isinstance(action, types.MessageActionChatMigrateTo): + elif isinstance(action, raw.types.MessageActionChatMigrateTo): migrate_to_chat_id = action.channel_id - elif isinstance(action, types.MessageActionChannelMigrateFrom): + elif isinstance(action, raw.types.MessageActionChannelMigrateFrom): migrate_from_chat_id = action.chat_id - elif isinstance(action, types.MessageActionChatCreate): + elif isinstance(action, raw.types.MessageActionChatCreate): group_chat_created = True - elif isinstance(action, types.MessageActionChannelCreate): + elif isinstance(action, raw.types.MessageActionChannelCreate): channel_chat_created = True - elif isinstance(action, types.MessageActionChatEditPhoto): - new_chat_photo = Photo._parse(client, action.photo) + elif isinstance(action, raw.types.MessageActionChatEditPhoto): + new_chat_photo = types.Photo._parse(client, action.photo) parsed_message = Message( message_id=message.id, date=message.date, - chat=Chat._parse(client, message, users, chats), - from_user=User._parse(client, users.get(message.from_id, None)), + chat=types.Chat._parse(client, message, users, chats), + from_user=types.User._parse(client, users.get(message.from_id, None)), service=True, new_chat_members=new_chat_members, left_chat_member=left_chat_member, @@ -456,7 +456,7 @@ class Message(Object, Update): # TODO: supergroup_chat_created ) - if isinstance(action, types.MessageActionPinMessage): + if isinstance(action, raw.types.MessageActionPinMessage): try: parsed_message.pinned_message = await client.get_messages( parsed_message.chat.id, @@ -466,8 +466,8 @@ class Message(Object, Update): except MessageIdsEmpty: pass - if isinstance(action, types.MessageActionGameScore): - parsed_message.game_high_score = pyrogram.GameHighScore._parse_action(client, message, users) + if isinstance(action, raw.types.MessageActionGameScore): + parsed_message.game_high_score = types.GameHighScore._parse_action(client, message, users) if message.reply_to_msg_id and replies: try: @@ -481,9 +481,9 @@ class Message(Object, Update): return parsed_message - if isinstance(message, types.Message): - entities = [MessageEntity._parse(client, entity, users) for entity in message.entities] - entities = pyrogram.List(filter(lambda x: x is not None, entities)) + if isinstance(message, raw.types.Message): + entities = [types.MessageEntity._parse(client, entity, users) for entity in message.entities] + entities = types.List(filter(lambda x: x is not None, entities)) forward_from = None forward_sender_name = None @@ -492,17 +492,17 @@ class Message(Object, Update): forward_signature = None forward_date = None - forward_header = message.fwd_from # type: types.MessageFwdHeader + forward_header = message.fwd_from # type: raw.types.MessageFwdHeader if forward_header: forward_date = forward_header.date if forward_header.from_id: - forward_from = User._parse(client, users[forward_header.from_id]) + forward_from = types.User._parse(client, users[forward_header.from_id]) elif forward_header.from_name: forward_sender_name = forward_header.from_name else: - forward_from_chat = Chat._parse_channel_chat(client, chats[forward_header.channel_id]) + forward_from_chat = types.Chat._parse_channel_chat(client, chats[forward_header.channel_id]) forward_from_message_id = forward_header.channel_post forward_signature = forward_header.post_author @@ -525,87 +525,87 @@ class Message(Object, Update): media = message.media if media: - if isinstance(media, types.MessageMediaPhoto): - photo = Photo._parse(client, media.photo, media.ttl_seconds) - elif isinstance(media, types.MessageMediaGeo): - location = Location._parse(client, media.geo) - elif isinstance(media, types.MessageMediaContact): - contact = Contact._parse(client, media) - elif isinstance(media, types.MessageMediaVenue): - venue = pyrogram.Venue._parse(client, media) - elif isinstance(media, types.MessageMediaGame): - game = pyrogram.Game._parse(client, message) - elif isinstance(media, types.MessageMediaDocument): + if isinstance(media, raw.types.MessageMediaPhoto): + photo = types.Photo._parse(client, media.photo, media.ttl_seconds) + elif isinstance(media, raw.types.MessageMediaGeo): + location = types.Location._parse(client, media.geo) + elif isinstance(media, raw.types.MessageMediaContact): + contact = types.Contact._parse(client, media) + elif isinstance(media, raw.types.MessageMediaVenue): + venue = types.Venue._parse(client, media) + elif isinstance(media, raw.types.MessageMediaGame): + game = types.Game._parse(client, message) + elif isinstance(media, raw.types.MessageMediaDocument): doc = media.document - if isinstance(doc, types.Document): + if isinstance(doc, raw.types.Document): attributes = {type(i): i for i in doc.attributes} file_name = getattr( attributes.get( - types.DocumentAttributeFilename, None + raw.types.DocumentAttributeFilename, None ), "file_name", None ) - if types.DocumentAttributeAudio in attributes: - audio_attributes = attributes[types.DocumentAttributeAudio] + if raw.types.DocumentAttributeAudio in attributes: + audio_attributes = attributes[raw.types.DocumentAttributeAudio] if audio_attributes.voice: - voice = pyrogram.Voice._parse(client, doc, audio_attributes) + voice = types.Voice._parse(client, doc, audio_attributes) else: - audio = pyrogram.Audio._parse(client, doc, audio_attributes, file_name) - elif types.DocumentAttributeAnimated in attributes: - video_attributes = attributes.get(types.DocumentAttributeVideo, None) + audio = types.Audio._parse(client, doc, audio_attributes, file_name) + elif raw.types.DocumentAttributeAnimated in attributes: + video_attributes = attributes.get(raw.types.DocumentAttributeVideo, None) - animation = pyrogram.Animation._parse(client, doc, video_attributes, file_name) - elif types.DocumentAttributeVideo in attributes: - video_attributes = attributes[types.DocumentAttributeVideo] + animation = types.Animation._parse(client, doc, video_attributes, file_name) + elif raw.types.DocumentAttributeVideo in attributes: + video_attributes = attributes[raw.types.DocumentAttributeVideo] if video_attributes.round_message: - video_note = pyrogram.VideoNote._parse(client, doc, video_attributes) + video_note = types.VideoNote._parse(client, doc, video_attributes) else: - video = pyrogram.Video._parse(client, doc, video_attributes, file_name, - media.ttl_seconds) - elif types.DocumentAttributeSticker in attributes: - sticker = await pyrogram.Sticker._parse( + video = types.Video._parse(client, doc, video_attributes, file_name, + media.ttl_seconds) + elif raw.types.DocumentAttributeSticker in attributes: + sticker = await types.Sticker._parse( client, doc, - attributes.get(types.DocumentAttributeImageSize, None), - attributes[types.DocumentAttributeSticker], + attributes.get(raw.types.DocumentAttributeImageSize, None), + attributes[raw.types.DocumentAttributeSticker], file_name ) else: - document = pyrogram.Document._parse(client, doc, file_name) - elif isinstance(media, types.MessageMediaWebPage): - if isinstance(media.webpage, types.WebPage): - web_page = pyrogram.WebPage._parse(client, media.webpage) + document = types.Document._parse(client, doc, file_name) + elif isinstance(media, raw.types.MessageMediaWebPage): + if isinstance(media.webpage, raw.types.WebPage): + web_page = types.WebPage._parse(client, media.webpage) else: media = None - elif isinstance(media, types.MessageMediaPoll): - poll = pyrogram.Poll._parse(client, media) - elif isinstance(media, types.MessageMediaDice): - dice = pyrogram.Dice._parse(client, media) + elif isinstance(media, raw.types.MessageMediaPoll): + poll = types.Poll._parse(client, media) + elif isinstance(media, raw.types.MessageMediaDice): + dice = types.Dice._parse(client, media) else: media = None reply_markup = message.reply_markup if reply_markup: - if isinstance(reply_markup, types.ReplyKeyboardForceReply): - reply_markup = pyrogram.ForceReply.read(reply_markup) - elif isinstance(reply_markup, types.ReplyKeyboardMarkup): - reply_markup = pyrogram.ReplyKeyboardMarkup.read(reply_markup) - elif isinstance(reply_markup, types.ReplyInlineMarkup): - reply_markup = pyrogram.InlineKeyboardMarkup.read(reply_markup) - elif isinstance(reply_markup, types.ReplyKeyboardHide): - reply_markup = pyrogram.ReplyKeyboardRemove.read(reply_markup) + if isinstance(reply_markup, raw.types.ReplyKeyboardForceReply): + reply_markup = types.ForceReply.read(reply_markup) + elif isinstance(reply_markup, raw.types.ReplyKeyboardMarkup): + reply_markup = types.ReplyKeyboardMarkup.read(reply_markup) + elif isinstance(reply_markup, raw.types.ReplyInlineMarkup): + reply_markup = types.InlineKeyboardMarkup.read(reply_markup) + elif isinstance(reply_markup, raw.types.ReplyKeyboardHide): + reply_markup = types.ReplyKeyboardRemove.read(reply_markup) else: reply_markup = None parsed_message = Message( message_id=message.id, date=message.date, - chat=Chat._parse(client, message, users, chats), - from_user=User._parse(client, users.get(message.from_id, None)), + chat=types.Chat._parse(client, message, users, chats), + from_user=types.User._parse(client, users.get(message.from_id, None)), text=( Str(message.message).init(entities) or None if media is None or web_page is not None @@ -655,7 +655,7 @@ class Message(Object, Update): poll=poll, dice=dice, views=message.views, - via_bot=User._parse(client, users.get(message.via_bot_id, None)), + via_bot=types.User._parse(client, users.get(message.via_bot_id, None)), outgoing=message.out, reply_markup=reply_markup, client=client @@ -676,9 +676,9 @@ class Message(Object, Update): @property def link(self) -> str: if self.chat.type in ("group", "supergroup", "channel") and self.chat.username: - return "https://t.me/{}/{}".format(self.chat.username, self.message_id) + return f"https://t.me/{self.chat.username}/{self.message_id}" else: - return "https://t.me/c/{}/{}".format(utils.get_channel_id(self.chat.id), self.message_id) + return f"https://t.me/c/{utils.get_channel_id(self.chat.id)}/{self.message_id}" async def reply_text( self, @@ -690,7 +690,7 @@ class Message(Object, Update): reply_to_message_id: int = None, reply_markup=None ) -> "Message": - """Bound method *reply_text* of :obj:`Message`. + """Bound method *reply_text* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -733,7 +733,7 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -774,16 +774,16 @@ class Message(Object, Update): thumb: str = None, disable_notification: bool = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, reply_to_message_id: int = None, progress: callable = None, progress_args: tuple = () ) -> "Message": - """Bound method *reply_animation* :obj:`Message`. + """Bound method *reply_animation* :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -847,7 +847,7 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -874,8 +874,9 @@ class Message(Object, Update): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. + On success, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. Raises: RPCError: In case of a Telegram RPC error. @@ -917,15 +918,15 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () ) -> "Message": - """Bound method *reply_audio* of :obj:`Message`. + """Bound method *reply_audio* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -989,7 +990,7 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -1016,8 +1017,9 @@ class Message(Object, Update): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. + On success, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. Raises: RPCError: In case of a Telegram RPC error. @@ -1055,13 +1057,13 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None ) -> "Message": - """Bound method *reply_cached_media* of :obj:`Message`. + """Bound method *reply_cached_media* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -1108,12 +1110,12 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - On success, the sent :obj:`Message` is returned. + On success, the sent :obj:`~pyrogram.types.Message` is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -1136,7 +1138,7 @@ class Message(Object, Update): ) async def reply_chat_action(self, action: str) -> bool: - """Bound method *reply_chat_action* of :obj:`Message`. + """Bound method *reply_chat_action* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -1183,13 +1185,13 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None ) -> "Message": - """Bound method *reply_contact* of :obj:`Message`. + """Bound method *reply_contact* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -1231,12 +1233,12 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - On success, the sent :obj:`Message` is returned. + On success, the sent :obj:`~pyrogram.types.Message` is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -1269,15 +1271,15 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () ) -> "Message": - """Bound method *reply_document* of :obj:`Message`. + """Bound method *reply_document* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -1332,7 +1334,7 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -1359,8 +1361,9 @@ class Message(Object, Update): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. + On success, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. Raises: RPCError: In case of a Telegram RPC error. @@ -1392,13 +1395,13 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None ) -> "Message": - """Bound method *reply_game* of :obj:`Message`. + """Bound method *reply_game* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -1430,12 +1433,12 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An object for an inline keyboard. If empty, one ‘Play game_title’ button will be shown automatically. If not empty, the first button must launch the game. Returns: - On success, the sent :obj:`Message` is returned. + On success, the sent :obj:`~pyrogram.types.Message` is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -1463,7 +1466,7 @@ class Message(Object, Update): reply_to_message_id: int = None, hide_via: bool = None ) -> "Message": - """Bound method *reply_inline_bot_result* of :obj:`Message`. + """Bound method *reply_inline_bot_result* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -1531,13 +1534,13 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None ) -> "Message": - """Bound method *reply_location* of :obj:`Message`. + """Bound method *reply_location* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -1573,12 +1576,12 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - On success, the sent :obj:`Message` is returned. + On success, the sent :obj:`~pyrogram.types.Message` is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -1600,12 +1603,12 @@ class Message(Object, Update): async def reply_media_group( self, - media: List[Union["pyrogram.InputMediaPhoto", "pyrogram.InputMediaVideo"]], + media: List[Union["types.InputMediaPhoto", "types.InputMediaVideo"]], quote: bool = None, disable_notification: bool = None, reply_to_message_id: int = None - ) -> "Message": - """Bound method *reply_media_group* of :obj:`Message`. + ) -> List["types.Message"]: + """Bound method *reply_media_group* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -1623,8 +1626,8 @@ class Message(Object, Update): Parameters: media (``list``): - A list containing either :obj:`InputMediaPhoto ` or - :obj:`InputMediaVideo ` objects + A list containing either :obj:`~pyrogram.types.InputMediaPhoto` or + :obj:`~pyrogram.types.InputMediaVideo` objects describing photos and videos to be sent, must include 2–10 items. quote (``bool``, *optional*): @@ -1640,7 +1643,7 @@ class Message(Object, Update): If the message is a reply, ID of the original message. Returns: - On success, a :obj:`Messages` object is returned containing all the + On success, a :obj:`~pyrogram.types.Messages` object is returned containing all the single messages sent. Raises: @@ -1670,15 +1673,15 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () ) -> "Message": - """Bound method *reply_photo* of :obj:`Message`. + """Bound method *reply_photo* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -1732,7 +1735,7 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -1759,8 +1762,9 @@ class Message(Object, Update): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. + On success, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. Raises: RPCError: In case of a Telegram RPC error. @@ -1793,13 +1797,13 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None ) -> "Message": - """Bound method *reply_poll* of :obj:`Message`. + """Bound method *reply_poll* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -1835,12 +1839,12 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - On success, the sent :obj:`Message` is returned. + On success, the sent :obj:`~pyrogram.types.Message` is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -1868,15 +1872,15 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () ) -> "Message": - """Bound method *reply_sticker* of :obj:`Message`. + """Bound method *reply_sticker* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -1915,7 +1919,7 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -1942,8 +1946,9 @@ class Message(Object, Update): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. + On success, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. Raises: RPCError: In case of a Telegram RPC error. @@ -1977,13 +1982,13 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None ) -> "Message": - """Bound method *reply_venue* of :obj:`Message`. + """Bound method *reply_venue* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -2034,12 +2039,12 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. Returns: - On success, the sent :obj:`Message` is returned. + On success, the sent :obj:`~pyrogram.types.Message` is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -2078,15 +2083,15 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () ) -> "Message": - """Bound method *reply_video* of :obj:`Message`. + """Bound method *reply_video* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -2153,7 +2158,7 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message. - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -2180,8 +2185,9 @@ class Message(Object, Update): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. + On success, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. Raises: RPCError: In case of a Telegram RPC error. @@ -2221,15 +2227,15 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () ) -> "Message": - """Bound method *reply_video_note* of :obj:`Message`. + """Bound method *reply_video_note* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -2280,7 +2286,7 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -2307,8 +2313,9 @@ class Message(Object, Update): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. + On success, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. Raises: RPCError: In case of a Telegram RPC error. @@ -2344,15 +2351,15 @@ class Message(Object, Update): disable_notification: bool = None, reply_to_message_id: int = None, reply_markup: Union[ - "pyrogram.InlineKeyboardMarkup", - "pyrogram.ReplyKeyboardMarkup", - "pyrogram.ReplyKeyboardRemove", - "pyrogram.ForceReply" + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" ] = None, progress: callable = None, progress_args: tuple = () ) -> "Message": - """Bound method *reply_voice* of :obj:`Message`. + """Bound method *reply_voice* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -2404,7 +2411,7 @@ class Message(Object, Update): reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message - reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.ForceReply`, *optional*): Additional interface options. An object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. @@ -2431,8 +2438,9 @@ class Message(Object, Update): You can either keep *\*args* or add every single extra argument in your function signature. Returns: - On success, the sent :obj:`Message` is returned. - In case the upload is deliberately stopped with :meth:`~Client.stop_transmission`, None is returned instead. + On success, the sent :obj:`~pyrogram.types.Message` is returned. + In case the upload is deliberately stopped with :meth:`~pyrogram.Client.stop_transmission`, None is returned + instead. Raises: RPCError: In case of a Telegram RPC error. @@ -2462,9 +2470,9 @@ class Message(Object, Update): text: str, parse_mode: Union[str, None] = object, disable_web_page_preview: bool = None, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None + reply_markup: "types.InlineKeyboardMarkup" = None ) -> "Message": - """Bound method *edit_text* of :obj:`Message`. + """Bound method *edit_text* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -2495,11 +2503,11 @@ class Message(Object, Update): disable_web_page_preview (``bool``, *optional*): Disables link previews for links in this message. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - On success, the edited :obj:`Message` is returned. + On success, the edited :obj:`~pyrogram.types.Message` is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -2519,9 +2527,9 @@ class Message(Object, Update): self, caption: str, parse_mode: Union[str, None] = object, - reply_markup: "pyrogram.InlineKeyboardMarkup" = None + reply_markup: "types.InlineKeyboardMarkup" = None ) -> "Message": - """Bound method *edit_caption* of :obj:`Message`. + """Bound method *edit_caption* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -2549,11 +2557,11 @@ class Message(Object, Update): Pass "html" to enable HTML-style parsing only. Pass None to completely disable style parsing. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - On success, the edited :obj:`Message` is returned. + On success, the edited :obj:`~pyrogram.types.Message` is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -2566,8 +2574,12 @@ class Message(Object, Update): reply_markup=reply_markup ) - async def edit_media(self, media: InputMedia, reply_markup: "pyrogram.InlineKeyboardMarkup" = None) -> "Message": - """Bound method *edit_media* of :obj:`Message`. + async def edit_media( + self, + media: "types.InputMedia", + reply_markup: "types.InlineKeyboardMarkup" = None + ) -> "Message": + """Bound method *edit_media* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -2585,14 +2597,14 @@ class Message(Object, Update): message.edit_media(media) Parameters: - media (:obj:`InputMedia`): + media (:obj:`~pyrogram.types.InputMedia`): One of the InputMedia objects describing an animation, audio, document, photo or video. - reply_markup (:obj:`InlineKeyboardMarkup`, *optional*): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): An InlineKeyboardMarkup object. Returns: - On success, the edited :obj:`Message` is returned. + On success, the edited :obj:`~pyrogram.types.Message` is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -2604,8 +2616,8 @@ class Message(Object, Update): reply_markup=reply_markup ) - async def edit_reply_markup(self, reply_markup: "pyrogram.InlineKeyboardMarkup" = None) -> "Message": - """Bound method *edit_reply_markup* of :obj:`Message`. + async def edit_reply_markup(self, reply_markup: "types.InlineKeyboardMarkup" = None) -> "Message": + """Bound method *edit_reply_markup* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -2623,12 +2635,12 @@ class Message(Object, Update): message.edit_reply_markup(inline_reply_markup) Parameters: - reply_markup (:obj:`InlineKeyboardMarkup`): + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`): An InlineKeyboardMarkup object. Returns: On success, if edited message is sent by the bot, the edited - :obj:`Message` is returned, otherwise True is returned. + :obj:`~pyrogram.types.Message` is returned, otherwise True is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -2646,8 +2658,8 @@ class Message(Object, Update): as_copy: bool = False, remove_caption: bool = False, schedule_date: int = None - ) -> "Message": - """Bound method *forward* of :obj:`Message`. + ) -> Union["types.Message", List["types.Message"]]: + """Bound method *forward* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -2696,7 +2708,7 @@ class Message(Object, Update): if self.service: raise ValueError("Unable to copy service messages") - if self.game and not self._client.is_bot: + if self.game and not await self._client.storage.is_bot(): raise ValueError("Users cannot send messages with Game media type") if self.text: @@ -2805,7 +2817,7 @@ class Message(Object, Update): ) async def delete(self, revoke: bool = True): - """Bound method *delete* of :obj:`Message`. + """Bound method *delete* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -2841,7 +2853,7 @@ class Message(Object, Update): ) async def click(self, x: int or str = 0, y: int = None, quote: bool = None, timeout: int = 10): - """Bound method *click* of :obj:`Message`. + """Bound method *click* of :obj:`~pyrogram.types.Message`. Use as a shortcut for clicking a button attached to the message instead of: @@ -2893,7 +2905,7 @@ class Message(Object, Update): Timeout in seconds. Returns: - - The result of :meth:`~Client.request_callback_answer` in case of inline callback button clicks. + - The result of :meth:`~pyrogram.Client.request_callback_answer` in case of inline callback button clicks. - The result of :meth:`~Message.reply()` in case of normal button clicks. - A string in case the inline button is a URL, a *switch_inline_query* or a *switch_inline_query_current_chat* button. @@ -2904,10 +2916,10 @@ class Message(Object, Update): TimeoutError: In case, after clicking an inline button, the bot fails to answer within the timeout. """ - if isinstance(self.reply_markup, pyrogram.ReplyKeyboardMarkup): + if isinstance(self.reply_markup, types.ReplyKeyboardMarkup): keyboard = self.reply_markup.keyboard is_inline = False - elif isinstance(self.reply_markup, pyrogram.InlineKeyboardMarkup): + elif isinstance(self.reply_markup, types.InlineKeyboardMarkup): keyboard = self.reply_markup.inline_keyboard is_inline = True else: @@ -2921,12 +2933,12 @@ class Message(Object, Update): for button in row ][x] except IndexError: - raise ValueError("The button at index {} doesn't exist".format(x)) + raise ValueError(f"The button at index {x} doesn't exist") elif isinstance(x, int) and isinstance(y, int): try: button = keyboard[y][x] except IndexError: - raise ValueError("The button at position ({}, {}) doesn't exist".format(x, y)) + raise ValueError(f"The button at position ({x}, {y}) doesn't exist") elif isinstance(x, str) and y is None: label = x.encode("utf-16", "surrogatepass").decode("utf-16") @@ -2938,7 +2950,7 @@ class Message(Object, Update): if label == button.text ][0] except IndexError: - raise ValueError("The button with label '{}' doesn't exists".format(x)) + raise ValueError(f"The button with label '{x}' doesn't exists") else: raise ValueError("Invalid arguments") @@ -2963,8 +2975,8 @@ class Message(Object, Update): async def retract_vote( self, - ) -> "pyrogram.Poll": - """Bound method *retract_vote* of :obj:`Message`. + ) -> "types.Poll": + """Bound method *retract_vote* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -2981,7 +2993,7 @@ class Message(Object, Update): message.retract_vote() Returns: - :obj:`Poll`: On success, the poll with the retracted vote is returned. + :obj:`~pyrogram.types.Poll`: On success, the poll with the retracted vote is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -2999,7 +3011,7 @@ class Message(Object, Update): progress: callable = None, progress_args: tuple = () ) -> str: - """Bound method *download* of :obj:`Message`. + """Bound method *download* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -3063,8 +3075,8 @@ class Message(Object, Update): async def vote( self, option: int, - ) -> "pyrogram.Poll": - """Bound method *vote* of :obj:`Message`. + ) -> "types.Poll": + """Bound method *vote* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: @@ -3086,7 +3098,7 @@ class Message(Object, Update): Index of the poll option you want to vote for (0 to 9). Returns: - :obj:`Poll`: On success, the poll with the chosen option is returned. + :obj:`~pyrogram.types.Poll`: On success, the poll with the chosen option is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -3095,11 +3107,11 @@ class Message(Object, Update): return await self._client.vote_poll( chat_id=self.chat.id, message_id=self.message_id, - option=option + options=option ) - async def pin(self, disable_notification: bool = None) -> "Message": - """Bound method *pin* of :obj:`Message`. + async def pin(self, disable_notification: bool = None) -> bool: + """Bound method *pin* of :obj:`~pyrogram.types.Message`. Use as a shortcut for: diff --git a/pyrogram/client/types/messages_and_media/message_entity.py b/pyrogram/types/messages_and_media/message_entity.py similarity index 68% rename from pyrogram/client/types/messages_and_media/message_entity.py rename to pyrogram/types/messages_and_media/message_entity.py index a1e39a0f..a88a91c8 100644 --- a/pyrogram/client/types/messages_and_media/message_entity.py +++ b/pyrogram/types/messages_and_media/message_entity.py @@ -17,10 +17,9 @@ # along with Pyrogram. If not, see . import pyrogram - -from pyrogram.api import types +from pyrogram import raw +from pyrogram import types from ..object import Object -from ..user_and_chats.user import User class MessageEntity(Object): @@ -43,38 +42,38 @@ class MessageEntity(Object): url (``str``, *optional*): For "text_link" only, url that will be opened after user taps on the text. - user (:obj:`User`, *optional*): + user (:obj:`~pyrogram.types.User`, *optional*): For "text_mention" only, the mentioned user. """ ENTITIES = { - types.MessageEntityMention.ID: "mention", - types.MessageEntityHashtag.ID: "hashtag", - types.MessageEntityCashtag.ID: "cashtag", - types.MessageEntityBotCommand.ID: "bot_command", - types.MessageEntityUrl.ID: "url", - types.MessageEntityEmail.ID: "email", - types.MessageEntityBold.ID: "bold", - types.MessageEntityItalic.ID: "italic", - types.MessageEntityCode.ID: "code", - types.MessageEntityPre.ID: "pre", - types.MessageEntityUnderline.ID: "underline", - types.MessageEntityStrike.ID: "strike", - types.MessageEntityBlockquote.ID: "blockquote", - types.MessageEntityTextUrl.ID: "text_link", - types.MessageEntityMentionName.ID: "text_mention", - types.MessageEntityPhone.ID: "phone_number" + raw.types.MessageEntityMention.ID: "mention", + raw.types.MessageEntityHashtag.ID: "hashtag", + raw.types.MessageEntityCashtag.ID: "cashtag", + raw.types.MessageEntityBotCommand.ID: "bot_command", + raw.types.MessageEntityUrl.ID: "url", + raw.types.MessageEntityEmail.ID: "email", + raw.types.MessageEntityBold.ID: "bold", + raw.types.MessageEntityItalic.ID: "italic", + raw.types.MessageEntityCode.ID: "code", + raw.types.MessageEntityPre.ID: "pre", + raw.types.MessageEntityUnderline.ID: "underline", + raw.types.MessageEntityStrike.ID: "strike", + raw.types.MessageEntityBlockquote.ID: "blockquote", + raw.types.MessageEntityTextUrl.ID: "text_link", + raw.types.MessageEntityMentionName.ID: "text_mention", + raw.types.MessageEntityPhone.ID: "phone_number" } def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, type: str, offset: int, length: int, url: str = None, - user: User = None + user: "types.User" = None ): super().__init__(client) @@ -96,6 +95,6 @@ class MessageEntity(Object): offset=entity.offset, length=entity.length, url=getattr(entity, "url", None), - user=User._parse(client, users.get(getattr(entity, "user_id", None), None)), + user=types.User._parse(client, users.get(getattr(entity, "user_id", None), None)), client=client ) diff --git a/pyrogram/client/types/messages_and_media/photo.py b/pyrogram/types/messages_and_media/photo.py similarity index 82% rename from pyrogram/client/types/messages_and_media/photo.py rename to pyrogram/types/messages_and_media/photo.py index fe0678ab..a6f572d4 100644 --- a/pyrogram/client/types/messages_and_media/photo.py +++ b/pyrogram/types/messages_and_media/photo.py @@ -20,10 +20,10 @@ from struct import pack from typing import List import pyrogram -from pyrogram.api import types -from .thumbnail import Thumbnail +from pyrogram import raw +from pyrogram import types +from pyrogram.utils import encode_file_id, encode_file_ref from ..object import Object -from ...ext.utils import encode_file_id, encode_file_ref class Photo(Object): @@ -51,14 +51,14 @@ class Photo(Object): ttl_seconds (``int``, *optional*): Time-to-live seconds, for secret photos. - thumbs (List of :obj:`Thumbnail`, *optional*): + thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): Available thumbnails of this photo. """ def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, file_id: str, file_ref: str, width: int, @@ -66,7 +66,7 @@ class Photo(Object): file_size: int, date: int, ttl_seconds: int = None, - thumbs: List[Thumbnail] = None + thumbs: List["types.Thumbnail"] = None ): super().__init__(client) @@ -80,9 +80,9 @@ class Photo(Object): self.thumbs = thumbs @staticmethod - def _parse(client, photo: types.Photo, ttl_seconds: int = None) -> "Photo": - if isinstance(photo, types.Photo): - big = list(filter(lambda p: isinstance(p, types.PhotoSize), photo.sizes))[-1] + def _parse(client, photo: "raw.types.Photo", ttl_seconds: int = None) -> "Photo": + if isinstance(photo, raw.types.Photo): + big = list(filter(lambda p: isinstance(p, raw.types.PhotoSize), photo.sizes))[-1] return Photo( file_id=encode_file_id( @@ -99,6 +99,6 @@ class Photo(Object): file_size=big.size, date=photo.date, ttl_seconds=ttl_seconds, - thumbs=Thumbnail._parse(client, photo), + thumbs=types.Thumbnail._parse(client, photo), client=client ) diff --git a/pyrogram/client/types/messages_and_media/poll.py b/pyrogram/types/messages_and_media/poll.py similarity index 88% rename from pyrogram/client/types/messages_and_media/poll.py rename to pyrogram/types/messages_and_media/poll.py index d1dd2b21..459c24bb 100644 --- a/pyrogram/client/types/messages_and_media/poll.py +++ b/pyrogram/types/messages_and_media/poll.py @@ -19,8 +19,8 @@ from typing import List, Union import pyrogram -from pyrogram.api import types -from .poll_option import PollOption +from pyrogram import raw +from pyrogram import types from ..object import Object from ..update import Update @@ -35,7 +35,7 @@ class Poll(Object, Update): question (``str``): Poll question, 1-255 characters. - options (List of :obj:`PollOption`): + options (List of :obj:`~pyrogram.types.PollOption`): List of poll options. total_voter_count (``int``): @@ -60,10 +60,10 @@ class Poll(Object, Update): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, id: str, question: str, - options: List[PollOption], + options: List["types.PollOption"], total_voter_count: int, is_closed: bool, is_anonymous: bool = None, @@ -86,9 +86,9 @@ class Poll(Object, Update): self.chosen_option = chosen_option @staticmethod - def _parse(client, media_poll: Union[types.MessageMediaPoll, types.UpdateMessagePoll]) -> "Poll": - poll = media_poll.poll # type: types.Poll - results = media_poll.results.results # type: types.PollResults + def _parse(client, media_poll: Union["raw.types.MessageMediaPoll", "raw.types.UpdateMessagePoll"]) -> "Poll": + poll = media_poll.poll # type: raw.types.Poll + results = media_poll.results.results chosen_option = None options = [] @@ -103,7 +103,7 @@ class Poll(Object, Update): chosen_option = i options.append( - PollOption( + types.PollOption( text=answer.text, voter_count=voter_count, data=answer.option, @@ -125,7 +125,7 @@ class Poll(Object, Update): ) @staticmethod - def _parse_update(client, update: types.UpdateMessagePoll): + def _parse_update(client, update: "raw.types.UpdateMessagePoll"): if update.poll is not None: return Poll._parse(client, update) @@ -138,7 +138,7 @@ class Poll(Object, Update): chosen_option = i options.append( - PollOption( + types.PollOption( text="", voter_count=result.voters, data=result.option, diff --git a/pyrogram/client/types/messages_and_media/poll_option.py b/pyrogram/types/messages_and_media/poll_option.py similarity index 96% rename from pyrogram/client/types/messages_and_media/poll_option.py rename to pyrogram/types/messages_and_media/poll_option.py index da7daff3..93fda559 100644 --- a/pyrogram/client/types/messages_and_media/poll_option.py +++ b/pyrogram/types/messages_and_media/poll_option.py @@ -38,7 +38,7 @@ class PollOption(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, text: str, voter_count: int, data: bytes diff --git a/pyrogram/client/types/messages_and_media/sticker.py b/pyrogram/types/messages_and_media/sticker.py similarity index 84% rename from pyrogram/client/types/messages_and_media/sticker.py rename to pyrogram/types/messages_and_media/sticker.py index aca7d3a3..76e7264f 100644 --- a/pyrogram/client/types/messages_and_media/sticker.py +++ b/pyrogram/types/messages_and_media/sticker.py @@ -22,11 +22,11 @@ from typing import List from async_lru import alru_cache import pyrogram -from pyrogram.api import types, functions +from pyrogram import raw +from pyrogram import types from pyrogram.errors import StickersetInvalid -from .thumbnail import Thumbnail +from pyrogram.utils import encode_file_id, encode_file_ref from ..object import Object -from ...ext.utils import encode_file_id, encode_file_ref class Sticker(Object): @@ -66,7 +66,7 @@ class Sticker(Object): set_name (``str``, *optional*): Name of the sticker set to which the sticker belongs. - thumbs (List of :obj:`Thumbnail`, *optional*): + thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): Sticker thumbnails in the .webp or .jpg format. """ @@ -75,7 +75,7 @@ class Sticker(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, file_id: str, file_ref: str, width: int, @@ -87,7 +87,7 @@ class Sticker(Object): date: int = None, emoji: str = None, set_name: str = None, - thumbs: List[Thumbnail] = None + thumbs: List["types.Thumbnail"] = None ): super().__init__(client) @@ -110,8 +110,8 @@ class Sticker(Object): async def _get_sticker_set_name(send, input_sticker_set_id): try: return (await send( - functions.messages.GetStickerSet( - stickerset=types.InputStickerSetID( + raw.functions.messages.GetStickerSet( + stickerset=raw.types.InputStickerSetID( id=input_sticker_set_id[0], access_hash=input_sticker_set_id[1] ) @@ -121,11 +121,16 @@ class Sticker(Object): return None @staticmethod - async def _parse(client, sticker: types.Document, image_size_attributes: types.DocumentAttributeImageSize, - sticker_attributes: types.DocumentAttributeSticker, file_name: str) -> "Sticker": + async def _parse( + client, + sticker: "raw.types.Document", + image_size_attributes: "raw.types.DocumentAttributeImageSize", + sticker_attributes: "raw.types.DocumentAttributeSticker", + file_name: str + ) -> "Sticker": sticker_set = sticker_attributes.stickerset - if isinstance(sticker_set, types.InputStickerSetID): + if isinstance(sticker_set, raw.types.InputStickerSetID): input_sticker_set_id = (sticker_set.id, sticker_set.access_hash) set_name = await Sticker._get_sticker_set_name(client.send, input_sticker_set_id) else: @@ -152,6 +157,6 @@ class Sticker(Object): mime_type=sticker.mime_type, file_name=file_name, date=sticker.date, - thumbs=Thumbnail._parse(client, sticker), + thumbs=types.Thumbnail._parse(client, sticker), client=client ) diff --git a/pyrogram/client/types/messages_and_media/stripped_thumbnail.py b/pyrogram/types/messages_and_media/stripped_thumbnail.py similarity index 88% rename from pyrogram/client/types/messages_and_media/stripped_thumbnail.py rename to pyrogram/types/messages_and_media/stripped_thumbnail.py index 546f9a48..8f22dd80 100644 --- a/pyrogram/client/types/messages_and_media/stripped_thumbnail.py +++ b/pyrogram/types/messages_and_media/stripped_thumbnail.py @@ -17,7 +17,7 @@ # along with Pyrogram. If not, see . import pyrogram -from pyrogram.api import types +from pyrogram import raw from ..object import Object @@ -32,7 +32,7 @@ class StrippedThumbnail(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, data: bytes ): super().__init__(client) @@ -40,7 +40,7 @@ class StrippedThumbnail(Object): self.data = data @staticmethod - def _parse(client, stripped_thumbnail: types.PhotoStrippedSize) -> "StrippedThumbnail": + def _parse(client, stripped_thumbnail: "raw.types.PhotoStrippedSize") -> "StrippedThumbnail": return StrippedThumbnail( data=stripped_thumbnail.bytes, client=client diff --git a/pyrogram/client/types/messages_and_media/thumbnail.py b/pyrogram/types/messages_and_media/thumbnail.py similarity index 86% rename from pyrogram/client/types/messages_and_media/thumbnail.py rename to pyrogram/types/messages_and_media/thumbnail.py index c48b8fb5..cd9eeb59 100644 --- a/pyrogram/client/types/messages_and_media/thumbnail.py +++ b/pyrogram/types/messages_and_media/thumbnail.py @@ -20,9 +20,9 @@ from struct import pack from typing import Union, List import pyrogram -from pyrogram.api import types -from pyrogram.client.ext.utils import encode_file_id -from .stripped_thumbnail import StrippedThumbnail +from pyrogram import raw +from pyrogram import types +from pyrogram.utils import encode_file_id from ..object import Object @@ -46,7 +46,7 @@ class Thumbnail(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, file_id: str, width: int, height: int, @@ -62,12 +62,12 @@ class Thumbnail(Object): @staticmethod def _parse( client, - media: Union[types.Photo, types.Document] - ) -> Union[List[Union[StrippedThumbnail, "Thumbnail"]], None]: - if isinstance(media, types.Photo): + media: Union["raw.types.Photo", "raw.types.Document"] + ) -> Union[List[Union["types.StrippedThumbnail", "Thumbnail"]], None]: + if isinstance(media, raw.types.Photo): raw_thumbnails = media.sizes[:-1] media_type = 2 - elif isinstance(media, types.Document): + elif isinstance(media, raw.types.Document): raw_thumbnails = media.thumbs media_type = 14 @@ -82,7 +82,7 @@ class Thumbnail(Object): # TODO: Enable this # if isinstance(thumbnail, types.PhotoStrippedSize): # thumbnails.append(StrippedThumbnail._parse(client, thumbnail)) - if isinstance(thumbnail, types.PhotoSize): + if isinstance(thumbnail, raw.types.PhotoSize): thumbnails.append( Thumbnail( file_id=encode_file_id( diff --git a/pyrogram/client/types/messages_and_media/venue.py b/pyrogram/types/messages_and_media/venue.py similarity index 86% rename from pyrogram/client/types/messages_and_media/venue.py rename to pyrogram/types/messages_and_media/venue.py index a638bd4c..05f3e33e 100644 --- a/pyrogram/client/types/messages_and_media/venue.py +++ b/pyrogram/types/messages_and_media/venue.py @@ -17,8 +17,8 @@ # along with Pyrogram. If not, see . import pyrogram -from pyrogram.api import types -from .location import Location +from pyrogram import raw +from pyrogram import types from ..object import Object @@ -26,7 +26,7 @@ class Venue(Object): """A venue. Parameters: - location (:obj:`Location`): + location (:obj:`~pyrogram.types.Location`): Venue location. title (``str``): @@ -47,8 +47,8 @@ class Venue(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, - location: Location, + client: "pyrogram.Client" = None, + location: "types.Location", title: str, address: str, foursquare_id: str = None, @@ -63,9 +63,9 @@ class Venue(Object): self.foursquare_type = foursquare_type @staticmethod - def _parse(client, venue: types.MessageMediaVenue): + def _parse(client, venue: "raw.types.MessageMediaVenue"): return Venue( - location=Location._parse(client, venue.geo), + location=types.Location._parse(client, venue.geo), title=venue.title, address=venue.address, foursquare_id=venue.venue_id or None, diff --git a/pyrogram/client/types/messages_and_media/video.py b/pyrogram/types/messages_and_media/video.py similarity index 89% rename from pyrogram/client/types/messages_and_media/video.py rename to pyrogram/types/messages_and_media/video.py index 16388b18..182ef94e 100644 --- a/pyrogram/client/types/messages_and_media/video.py +++ b/pyrogram/types/messages_and_media/video.py @@ -20,10 +20,10 @@ from struct import pack from typing import List import pyrogram -from pyrogram.api import types -from .thumbnail import Thumbnail +from pyrogram import raw +from pyrogram import types +from pyrogram.utils import encode_file_id, encode_file_ref from ..object import Object -from ...ext.utils import encode_file_id, encode_file_ref class Video(Object): @@ -63,14 +63,14 @@ class Video(Object): ttl_seconds (``int``. *optional*): Time-to-live seconds, for secret photos. - thumbs (List of :obj:`Thumbnail`, *optional*): + thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): Video thumbnails. """ def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, file_id: str, file_ref: str, width: int, @@ -82,7 +82,7 @@ class Video(Object): file_size: int = None, date: int = None, ttl_seconds: int = None, - thumbs: List[Thumbnail] = None + thumbs: List["types.Thumbnail"] = None ): super().__init__(client) @@ -102,8 +102,8 @@ class Video(Object): @staticmethod def _parse( client, - video: types.Document, - video_attributes: types.DocumentAttributeVideo, + video: "raw.types.Document", + video_attributes: "raw.types.DocumentAttributeVideo", file_name: str, ttl_seconds: int = None ) -> "Video": @@ -127,6 +127,6 @@ class Video(Object): file_size=video.size, date=video.date, ttl_seconds=ttl_seconds, - thumbs=Thumbnail._parse(client, video), + thumbs=types.Thumbnail._parse(client, video), client=client ) diff --git a/pyrogram/client/types/messages_and_media/video_note.py b/pyrogram/types/messages_and_media/video_note.py similarity index 84% rename from pyrogram/client/types/messages_and_media/video_note.py rename to pyrogram/types/messages_and_media/video_note.py index 1feb5a2d..e12117eb 100644 --- a/pyrogram/client/types/messages_and_media/video_note.py +++ b/pyrogram/types/messages_and_media/video_note.py @@ -20,10 +20,10 @@ from struct import pack from typing import List import pyrogram -from pyrogram.api import types -from .thumbnail import Thumbnail +from pyrogram import raw +from pyrogram import types +from pyrogram.utils import encode_file_id, encode_file_ref from ..object import Object -from ...ext.utils import encode_file_id, encode_file_ref class VideoNote(Object): @@ -51,19 +51,19 @@ class VideoNote(Object): date (``int``, *optional*): Date the video note was sent in Unix time. - thumbs (List of :obj:`Thumbnail`, *optional*): + thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*): Video thumbnails. """ def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, file_id: str, file_ref: str, length: int, duration: int, - thumbs: List[Thumbnail] = None, + thumbs: List["types.Thumbnail"] = None, mime_type: str = None, file_size: int = None, date: int = None @@ -80,7 +80,11 @@ class VideoNote(Object): self.thumbs = thumbs @staticmethod - def _parse(client, video_note: types.Document, video_attributes: types.DocumentAttributeVideo) -> "VideoNote": + def _parse( + client, + video_note: "raw.types.Document", + video_attributes: "raw.types.DocumentAttributeVideo" + ) -> "VideoNote": return VideoNote( file_id=encode_file_id( pack( @@ -97,6 +101,6 @@ class VideoNote(Object): file_size=video_note.size, mime_type=video_note.mime_type, date=video_note.date, - thumbs=Thumbnail._parse(client, video_note), + thumbs=types.Thumbnail._parse(client, video_note), client=client ) diff --git a/pyrogram/client/types/messages_and_media/voice.py b/pyrogram/types/messages_and_media/voice.py similarity index 91% rename from pyrogram/client/types/messages_and_media/voice.py rename to pyrogram/types/messages_and_media/voice.py index dec82af9..987d233f 100644 --- a/pyrogram/client/types/messages_and_media/voice.py +++ b/pyrogram/types/messages_and_media/voice.py @@ -19,9 +19,9 @@ from struct import pack import pyrogram -from pyrogram.api import types +from pyrogram import raw +from pyrogram.utils import encode_file_id, encode_file_ref from ..object import Object -from ...ext.utils import encode_file_id, encode_file_ref class Voice(Object): @@ -53,7 +53,7 @@ class Voice(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, file_id: str, file_ref: str, duration: int, @@ -73,7 +73,7 @@ class Voice(Object): self.date = date @staticmethod - def _parse(client, voice: types.Document, attributes: types.DocumentAttributeAudio) -> "Voice": + def _parse(client, voice: "raw.types.Document", attributes: "raw.types.DocumentAttributeAudio") -> "Voice": return Voice( file_id=encode_file_id( pack( diff --git a/pyrogram/client/types/messages_and_media/webpage.py b/pyrogram/types/messages_and_media/webpage.py similarity index 73% rename from pyrogram/client/types/messages_and_media/webpage.py rename to pyrogram/types/messages_and_media/webpage.py index ebebfc1c..edd94934 100644 --- a/pyrogram/client/types/messages_and_media/webpage.py +++ b/pyrogram/types/messages_and_media/webpage.py @@ -17,7 +17,8 @@ # along with Pyrogram. If not, see . import pyrogram -from pyrogram.api import types +from pyrogram import raw +from pyrogram import types from ..object import Object @@ -49,19 +50,19 @@ class WebPage(Object): description (``str``, *optional*): Description of this webpage. - audio (:obj:`Audio`, *optional*): + audio (:obj:`~pyrogram.types.Audio`, *optional*): Webpage preview is an audio file, information about the file. - document (:obj:`Document`, *optional*): + document (:obj:`~pyrogram.types.Document`, *optional*): Webpage preview is a general file, information about the file. - photo (:obj:`Photo`, *optional*): + photo (:obj:`~pyrogram.types.Photo`, *optional*): Webpage preview is a photo, information about the photo. - animation (:obj:`Animation`, *optional*): + animation (:obj:`~pyrogram.types.Animation`, *optional*): Webpage preview is an animation, information about the animation. - video (:obj:`Video`, *optional*): + video (:obj:`~pyrogram.types.Video`, *optional*): Webpage preview is a video, information about the video. embed_url (``str``, *optional*): @@ -86,7 +87,7 @@ class WebPage(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, id: str, url: str, display_url: str, @@ -94,11 +95,11 @@ class WebPage(Object): site_name: str = None, title: str = None, description: str = None, - audio: "pyrogram.Audio" = None, - document: "pyrogram.Document" = None, - photo: "pyrogram.Photo" = None, - animation: "pyrogram.Animation" = None, - video: "pyrogram.Video" = None, + audio: "types.Audio" = None, + document: "types.Document" = None, + photo: "types.Photo" = None, + animation: "types.Animation" = None, + video: "types.Video" = None, embed_url: str = None, embed_type: str = None, embed_width: int = None, @@ -128,41 +129,41 @@ class WebPage(Object): self.author = author @staticmethod - def _parse(client, webpage: types.WebPage) -> "WebPage": + def _parse(client, webpage: "raw.types.WebPage") -> "WebPage": audio = None document = None photo = None animation = None video = None - if isinstance(webpage.photo, types.Photo): - photo = pyrogram.Photo._parse(client, webpage.photo) + if isinstance(webpage.photo, raw.types.Photo): + photo = types.Photo._parse(client, webpage.photo) doc = webpage.document - if isinstance(doc, types.Document): + if isinstance(doc, raw.types.Document): attributes = {type(i): i for i in doc.attributes} file_name = getattr( attributes.get( - types.DocumentAttributeFilename, None + raw.types.DocumentAttributeFilename, None ), "file_name", None ) - if types.DocumentAttributeAudio in attributes: - audio_attributes = attributes[types.DocumentAttributeAudio] - audio = pyrogram.Audio._parse(client, doc, audio_attributes, file_name) + if raw.types.DocumentAttributeAudio in attributes: + audio_attributes = attributes[raw.types.DocumentAttributeAudio] + audio = types.Audio._parse(client, doc, audio_attributes, file_name) - elif types.DocumentAttributeAnimated in attributes: - video_attributes = attributes.get(types.DocumentAttributeVideo, None) - animation = pyrogram.Animation._parse(client, doc, video_attributes, file_name) + elif raw.types.DocumentAttributeAnimated in attributes: + video_attributes = attributes.get(raw.types.DocumentAttributeVideo, None) + animation = types.Animation._parse(client, doc, video_attributes, file_name) - elif types.DocumentAttributeVideo in attributes: - video_attributes = attributes[types.DocumentAttributeVideo] - video = pyrogram.Video._parse(client, doc, video_attributes, file_name) + elif raw.types.DocumentAttributeVideo in attributes: + video_attributes = attributes[raw.types.DocumentAttributeVideo] + video = types.Video._parse(client, doc, video_attributes, file_name) else: - document = pyrogram.Document._parse(client, doc, file_name) + document = types.Document._parse(client, doc, file_name) return WebPage( id=str(webpage.id), diff --git a/pyrogram/client/types/object.py b/pyrogram/types/object.py similarity index 77% rename from pyrogram/client/types/object.py rename to pyrogram/types/object.py index 750e0be7..887b8e08 100644 --- a/pyrogram/client/types/object.py +++ b/pyrogram/types/object.py @@ -17,7 +17,6 @@ # along with Pyrogram. If not, see . import typing -from collections import OrderedDict from datetime import datetime from json import dumps @@ -26,18 +25,18 @@ import pyrogram class Meta(type, metaclass=type("", (type,), {"__str__": lambda _: "~hi"})): def __str__(self): - return "".format(self.__name__) + return f"" class Object(metaclass=Meta): - def __init__(self, client: "pyrogram.BaseClient" = None): + def __init__(self, client: "pyrogram.Client" = None): self._client = client - def bind(self, client: "pyrogram.BaseClient"): + def bind(self, client: "pyrogram.Client"): """Bind a Client instance to this Pyrogram Object Parameters: - client (:obj:`Client`): + client (:obj:`~pyrogram.types.Client`): The Client instance to bind this object with. Useful to re-enable bound methods after serializing and deserializing Pyrogram objects with ``repr`` and ``eval``. """ @@ -53,27 +52,29 @@ class Object(metaclass=Meta): if isinstance(obj, typing.Match): return repr(obj) - return OrderedDict( - [("_", "pyrogram." + obj.__class__.__name__)] - + [ - (attr, "*" * len(getattr(obj, attr))) - if attr == "phone_number" - else (attr, str(datetime.fromtimestamp(getattr(obj, attr)))) - if attr.endswith("date") - else (attr, getattr(obj, attr)) + return { + "_": obj.__class__.__name__, + **{ + attr: ( + "*" * len(getattr(obj, attr)) + if attr == "phone_number" else + str(datetime.fromtimestamp(getattr(obj, attr))) + if attr.endswith("date") else + getattr(obj, attr) + ) for attr in filter(lambda x: not x.startswith("_"), obj.__dict__) if getattr(obj, attr) is not None - ] - ) + } + } def __str__(self) -> str: return dumps(self, indent=4, default=Object.default, ensure_ascii=False) def __repr__(self) -> str: - return "pyrogram.{}({})".format( + return "pyrogram.types.{}({})".format( self.__class__.__name__, ", ".join( - "{}={}".format(attr, repr(getattr(self, attr))) + f"{attr}={repr(getattr(self, attr))}" for attr in filter(lambda x: not x.startswith("_"), self.__dict__) if getattr(self, attr) is not None ) diff --git a/pyrogram/client/types/update.py b/pyrogram/types/update.py similarity index 83% rename from pyrogram/client/types/update.py rename to pyrogram/types/update.py index 3f70f580..7231a92b 100644 --- a/pyrogram/client/types/update.py +++ b/pyrogram/types/update.py @@ -16,17 +16,12 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -class StopPropagation(StopAsyncIteration): - pass - - -class ContinuePropagation(StopAsyncIteration): - pass +import pyrogram class Update: def stop_propagation(self): - raise StopPropagation + raise pyrogram.StopPropagation def continue_propagation(self): - raise ContinuePropagation + raise pyrogram.ContinuePropagation diff --git a/pyrogram/client/types/user_and_chats/__init__.py b/pyrogram/types/user_and_chats/__init__.py similarity index 100% rename from pyrogram/client/types/user_and_chats/__init__.py rename to pyrogram/types/user_and_chats/__init__.py diff --git a/pyrogram/client/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py similarity index 81% rename from pyrogram/client/types/user_and_chats/chat.py rename to pyrogram/types/user_and_chats/chat.py index 85ef0a1f..a0f40eed 100644 --- a/pyrogram/client/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -19,12 +19,10 @@ from typing import Union, List, Generator, Optional import pyrogram -from pyrogram.api import types -from .chat_permissions import ChatPermissions -from .chat_photo import ChatPhoto -from .restriction import Restriction +from pyrogram import raw +from pyrogram import types +from pyrogram import utils from ..object import Object -from ...ext import utils class Chat(Object): @@ -65,51 +63,51 @@ class Chat(Object): last_name (``str``, *optional*): Last name of the other party in a private chat, for private chats. - photo (:obj:`ChatPhoto`, *optional*): + photo (:obj:`~pyrogram.types.ChatPhoto`, *optional*): Chat photo. Suitable for downloads only. description (``str``, *optional*): Bio, for private chats and bots or description for groups, supergroups and channels. - Returned only in :meth:`~Client.get_chat`. + Returned only in :meth:`~pyrogram.Client.get_chat`. invite_link (``str``, *optional*): Chat invite link, for groups, supergroups and channels. - Returned only in :meth:`~Client.get_chat`. + Returned only in :meth:`~pyrogram.Client.get_chat`. - pinned_message (:obj:`Message`, *optional*): + pinned_message (:obj:`~pyrogram.types.Message`, *optional*): Pinned message, for groups, supergroups channels and own chat. - Returned only in :meth:`~Client.get_chat`. + Returned only in :meth:`~pyrogram.Client.get_chat`. sticker_set_name (``str``, *optional*): For supergroups, name of group sticker set. - Returned only in :meth:`~Client.get_chat`. + Returned only in :meth:`~pyrogram.Client.get_chat`. can_set_sticker_set (``bool``, *optional*): True, if the group sticker set can be changed by you. - Returned only in :meth:`~Client.get_chat`. + Returned only in :meth:`~pyrogram.Client.get_chat`. members_count (``int``, *optional*): Chat members count, for groups, supergroups and channels only. - restrictions (List of :obj:`Restriction`, *optional*): + restrictions (List of :obj:`~pyrogram.types.Restriction`, *optional*): The list of reasons why this chat might be unavailable to some users. This field is available only in case *is_restricted* is True. - permissions (:obj:`ChatPermissions` *optional*): + permissions (:obj:`~pyrogram.types.ChatPermissions` *optional*): Default chat member permissions, for groups and supergroups. distance (``int``, *optional*): Distance in meters of this group chat from your location. - Returned only in :meth:`~Client.get_nearby_chats`. + Returned only in :meth:`~pyrogram.Client.get_nearby_chats`. - linked_chat (:obj:`Chat`, *optional*): + linked_chat (:obj:`~pyrogram.types.Chat`, *optional*): The linked discussion group (in case of channels) or the linked channel (in case of supergroups). """ def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, id: int, type: str, is_verified: bool = None, @@ -121,17 +119,17 @@ class Chat(Object): username: str = None, first_name: str = None, last_name: str = None, - photo: ChatPhoto = None, + photo: "types.ChatPhoto" = None, description: str = None, invite_link: str = None, pinned_message=None, sticker_set_name: str = None, can_set_sticker_set: bool = None, members_count: int = None, - restrictions: List[Restriction] = None, - permissions: "pyrogram.ChatPermissions" = None, + restrictions: List["types.Restriction"] = None, + permissions: "types.ChatPermissions" = None, distance: int = None, - linked_chat: "pyrogram.Chat" = None + linked_chat: "types.Chat" = None ): super().__init__(client) @@ -159,7 +157,7 @@ class Chat(Object): self.linked_chat = linked_chat @staticmethod - def _parse_user_chat(client, user: types.User) -> "Chat": + def _parse_user_chat(client, user: raw.types.User) -> "Chat": peer_id = user.id return Chat( @@ -172,13 +170,13 @@ class Chat(Object): username=user.username, first_name=user.first_name, last_name=user.last_name, - photo=ChatPhoto._parse(client, user.photo, peer_id, user.access_hash), - restrictions=pyrogram.List([Restriction._parse(r) for r in user.restriction_reason]) or None, + photo=types.ChatPhoto._parse(client, user.photo, peer_id, user.access_hash), + restrictions=types.List([types.Restriction._parse(r) for r in user.restriction_reason]) or None, client=client ) @staticmethod - def _parse_chat_chat(client, chat: types.Chat) -> "Chat": + def _parse_chat_chat(client, chat: raw.types.Chat) -> "Chat": peer_id = -chat.id return Chat( @@ -186,14 +184,14 @@ class Chat(Object): type="group", title=chat.title, is_creator=getattr(chat, "creator", None), - photo=ChatPhoto._parse(client, getattr(chat, "photo", None), peer_id, 0), - permissions=ChatPermissions._parse(getattr(chat, "default_banned_rights", None)), + photo=types.ChatPhoto._parse(client, getattr(chat, "photo", None), peer_id, 0), + permissions=types.ChatPermissions._parse(getattr(chat, "default_banned_rights", None)), members_count=getattr(chat, "participants_count", None), client=client ) @staticmethod - def _parse_channel_chat(client, channel: types.Channel) -> "Chat": + def _parse_channel_chat(client, channel: raw.types.Channel) -> "Chat": peer_id = utils.get_channel_id(channel.id) restriction_reason = getattr(channel, "restriction_reason", []) @@ -206,35 +204,35 @@ class Chat(Object): is_scam=getattr(channel, "scam", None), title=channel.title, username=getattr(channel, "username", None), - photo=ChatPhoto._parse(client, getattr(channel, "photo", None), peer_id, channel.access_hash), - restrictions=pyrogram.List([Restriction._parse(r) for r in restriction_reason]) or None, - permissions=ChatPermissions._parse(getattr(channel, "default_banned_rights", None)), + photo=types.ChatPhoto._parse(client, getattr(channel, "photo", None), peer_id, channel.access_hash), + restrictions=types.List([types.Restriction._parse(r) for r in restriction_reason]) or None, + permissions=types.ChatPermissions._parse(getattr(channel, "default_banned_rights", None)), members_count=getattr(channel, "participants_count", None), client=client ) @staticmethod - def _parse(client, message: types.Message or types.MessageService, users: dict, chats: dict) -> "Chat": - if isinstance(message.to_id, types.PeerUser): + def _parse(client, message: raw.types.Message or raw.types.MessageService, users: dict, chats: dict) -> "Chat": + if isinstance(message.to_id, raw.types.PeerUser): return Chat._parse_user_chat(client, users[message.to_id.user_id if message.out else message.from_id]) - if isinstance(message.to_id, types.PeerChat): + if isinstance(message.to_id, raw.types.PeerChat): return Chat._parse_chat_chat(client, chats[message.to_id.chat_id]) return Chat._parse_channel_chat(client, chats[message.to_id.channel_id]) @staticmethod def _parse_dialog(client, peer, users: dict, chats: dict): - if isinstance(peer, types.PeerUser): + if isinstance(peer, raw.types.PeerUser): return Chat._parse_user_chat(client, users[peer.user_id]) - elif isinstance(peer, types.PeerChat): + elif isinstance(peer, raw.types.PeerChat): return Chat._parse_chat_chat(client, chats[peer.chat_id]) else: return Chat._parse_channel_chat(client, chats[peer.channel_id]) @staticmethod - async def _parse_full(client, chat_full: types.messages.ChatFull or types.UserFull) -> "Chat": - if isinstance(chat_full, types.UserFull): + async def _parse_full(client, chat_full: raw.types.messages.ChatFull or raw.types.UserFull) -> "Chat": + if isinstance(chat_full, raw.types.UserFull): parsed_chat = Chat._parse_user_chat(client, chat_full.user) parsed_chat.description = chat_full.about @@ -252,15 +250,15 @@ class Chat(Object): if full_chat.id == c.id: chat = c - if isinstance(full_chat, types.ChannelFull): + if isinstance(full_chat, raw.types.ChannelFull): if full_chat.linked_chat_id == c.id: linked_chat = c - if isinstance(full_chat, types.ChatFull): + if isinstance(full_chat, raw.types.ChatFull): parsed_chat = Chat._parse_chat_chat(client, chat) parsed_chat.description = full_chat.about or None - if isinstance(full_chat.participants, types.ChatParticipants): + if isinstance(full_chat.participants, raw.types.ChatParticipants): parsed_chat.members_count = len(full_chat.participants.participants) else: parsed_chat = Chat._parse_channel_chat(client, chat) @@ -278,22 +276,22 @@ class Chat(Object): message_ids=full_chat.pinned_msg_id ) - if isinstance(full_chat.exported_invite, types.ChatInviteExported): + if isinstance(full_chat.exported_invite, raw.types.ChatInviteExported): parsed_chat.invite_link = full_chat.exported_invite.link return parsed_chat @staticmethod - def _parse_chat(client, chat: Union[types.Chat, types.User, types.Channel]) -> "Chat": - if isinstance(chat, types.Chat): + def _parse_chat(client, chat: Union[raw.types.Chat, raw.types.User, raw.types.Channel]) -> "Chat": + if isinstance(chat, raw.types.Chat): return Chat._parse_chat_chat(client, chat) - elif isinstance(chat, types.User): + elif isinstance(chat, raw.types.User): return Chat._parse_user_chat(client, chat) else: return Chat._parse_channel_chat(client, chat) async def archive(self): - """Bound method *archive* of :obj:`Chat`. + """Bound method *archive* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -316,7 +314,7 @@ class Chat(Object): return await self._client.archive_chats(self.id) async def unarchive(self): - """Bound method *unarchive* of :obj:`Chat`. + """Bound method *unarchive* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -340,7 +338,7 @@ class Chat(Object): # TODO: Remove notes about "All Members Are Admins" for basic groups, the attribute doesn't exist anymore async def set_title(self, title: str) -> bool: - """Bound method *set_title* of :obj:`Chat`. + """Bound method *set_title* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -378,7 +376,7 @@ class Chat(Object): ) async def set_description(self, description: str) -> bool: - """Bound method *set_description* of :obj:`Chat`. + """Bound method *set_description* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -412,7 +410,7 @@ class Chat(Object): ) async def set_photo(self, photo: str) -> bool: - """Bound method *set_photo* of :obj:`Chat`. + """Bound method *set_photo* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -430,7 +428,7 @@ class Chat(Object): Parameters: photo (``str``): - New chat photo. You can pass a :obj:`Photo` id or a file path to upload a new photo. + New chat photo. You can pass a :obj:`~pyrogram.types.Photo` id or a file path to upload a new photo. Returns: ``bool``: True on success. @@ -449,8 +447,8 @@ class Chat(Object): self, user_id: Union[int, str], until_date: int = 0 - ) -> Union["pyrogram.Message", bool]: - """Bound method *kick_member* of :obj:`Chat`. + ) -> Union["types.Message", bool]: + """Bound method *kick_member* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -482,7 +480,7 @@ class Chat(Object): considered to be banned forever. Defaults to 0 (ban forever). Returns: - :obj:`Message` | ``bool``: On success, a service message will be returned (when applicable), otherwise, in + :obj:`~pyrogram.types.Message` | ``bool``: On success, a service message will be returned (when applicable), otherwise, in case a message object couldn't be returned, True is returned. Raises: @@ -499,7 +497,7 @@ class Chat(Object): self, user_id: Union[int, str] ) -> bool: - """Bound method *unban_member* of :obj:`Chat`. + """Bound method *unban_member* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -535,10 +533,10 @@ class Chat(Object): async def restrict_member( self, user_id: Union[int, str], - permissions: ChatPermissions, + permissions: "types.ChatPermissions", until_date: int = 0, - ) -> "pyrogram.Chat": - """Bound method *unban_member* of :obj:`Chat`. + ) -> "types.Chat": + """Bound method *unban_member* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -560,7 +558,7 @@ class Chat(Object): Unique identifier (int) or username (str) of the target user. For a contact that exists in your Telegram address book you can use his phone number (str). - permissions (:obj:`ChatPermissions`): + permissions (:obj:`~pyrogram.types.ChatPermissions`): New user permissions. until_date (``int``, *optional*): @@ -569,7 +567,7 @@ class Chat(Object): considered to be banned forever. Defaults to 0 (ban forever). Returns: - :obj:`Chat`: On success, a chat object is returned. + :obj:`~pyrogram.types.Chat`: On success, a chat object is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -594,7 +592,7 @@ class Chat(Object): can_pin_messages: bool = False, can_promote_members: bool = False ) -> bool: - """Bound method *promote_member* of :obj:`Chat`. + """Bound method *promote_member* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -663,7 +661,7 @@ class Chat(Object): ) async def join(self): - """Bound method *join* of :obj:`Chat`. + """Bound method *join* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -680,7 +678,7 @@ class Chat(Object): This only works for public groups, channels that have set a username or linked chats. Returns: - :obj:`Chat`: On success, a chat object is returned. + :obj:`~pyrogram.types.Chat`: On success, a chat object is returned. Raises: RPCError: In case of a Telegram RPC error. @@ -689,7 +687,7 @@ class Chat(Object): return await self._client.join_chat(self.username or self.id) async def leave(self): - """Bound method *leave* of :obj:`Chat`. + """Bound method *leave* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -709,7 +707,7 @@ class Chat(Object): return await self._client.leave_chat(self.id) async def export_invite_link(self): - """Bound method *export_invite_link* of :obj:`Chat`. + """Bound method *export_invite_link* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -734,8 +732,8 @@ class Chat(Object): async def get_member( self, user_id: Union[int, str], - ) -> "pyrogram.ChatMember": - """Bound method *get_member* of :obj:`Chat`. + ) -> "types.ChatMember": + """Bound method *get_member* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -752,7 +750,7 @@ class Chat(Object): chat.get_member(user_id) Returns: - :obj:`ChatMember`: On success, a chat member is returned. + :obj:`~pyrogram.types.ChatMember`: On success, a chat member is returned. """ return await self._client.get_chat_member( @@ -766,8 +764,8 @@ class Chat(Object): limit: int = 200, query: str = "", filter: str = "all" - ) -> List["pyrogram.ChatMember"]: - """Bound method *get_members* of :obj:`Chat`. + ) -> List["types.ChatMember"]: + """Bound method *get_members* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -782,7 +780,7 @@ class Chat(Object): chat.get_members() Returns: - List of :obj:`ChatMember`: On success, a list of chat members is returned. + List of :obj:`~pyrogram.types.ChatMember`: On success, a list of chat members is returned. """ return await self._client.get_chat_members( @@ -798,8 +796,8 @@ class Chat(Object): limit: int = 0, query: str = "", filter: str = "all" - ) -> Optional[Generator["pyrogram.ChatMember", None, None]]: - """Bound method *iter_members* of :obj:`Chat`. + ) -> Optional[Generator["types.ChatMember", None, None]]: + """Bound method *iter_members* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: @@ -815,7 +813,7 @@ class Chat(Object): print(member.user.first_name) Returns: - ``Generator``: A generator yielding :obj:`ChatMember` objects. + ``Generator``: A generator yielding :obj:`~pyrogram.types.ChatMember` objects. """ return self._client.iter_chat_members( @@ -830,7 +828,7 @@ class Chat(Object): user_ids: Union[Union[int, str], List[Union[int, str]]], forward_limit: int = 100 ) -> bool: - """Bound method *add_members* of :obj:`Chat`. + """Bound method *add_members* of :obj:`~pyrogram.types.Chat`. Use as a shortcut for: diff --git a/pyrogram/client/types/user_and_chats/chat_member.py b/pyrogram/types/user_and_chats/chat_member.py similarity index 89% rename from pyrogram/client/types/user_and_chats/chat_member.py rename to pyrogram/types/user_and_chats/chat_member.py index 203be137..31a27402 100644 --- a/pyrogram/client/types/user_and_chats/chat_member.py +++ b/pyrogram/types/user_and_chats/chat_member.py @@ -17,8 +17,8 @@ # along with Pyrogram. If not, see . import pyrogram - -from pyrogram.api import types +from pyrogram import raw +from pyrogram import types from ..object import Object @@ -26,7 +26,7 @@ class ChatMember(Object): """Contains information about one member of a chat. Parameters: - user (:obj:`User`): + user (:obj:`~pyrogram.types.User`): Information about the user. status (``str``): @@ -45,14 +45,14 @@ class ChatMember(Object): Date when the user joined, unix time. Not available for creator. - invited_by (:obj:`User`, *optional*): + invited_by (:obj:`~pyrogram.types.User`, *optional*): Administrators and self member only. Information about the user who invited this member. In case the user joined by himself this will be the same as "user". - promoted_by (:obj:`User`, *optional*): + promoted_by (:obj:`~pyrogram.types.User`, *optional*): Administrators only. Information about the user who promoted this member as administrator. - restricted_by (:obj:`User`, *optional*): + restricted_by (:obj:`~pyrogram.types.User`, *optional*): Restricted and kicked only. Information about the user who restricted or kicked this member. is_member (``bool``, *optional*): @@ -128,15 +128,15 @@ class ChatMember(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, - user: "pyrogram.User", + client: "pyrogram.Client" = None, + user: "types.User", status: str, title: str = None, until_date: int = None, joined_date: int = None, - invited_by: "pyrogram.User" = None, - promoted_by: "pyrogram.User" = None, - restricted_by: "pyrogram.User" = None, + invited_by: "types.User" = None, + promoted_by: "types.User" = None, + restricted_by: "types.User" = None, is_member: bool = None, # Admin permissions @@ -193,14 +193,16 @@ class ChatMember(Object): @staticmethod def _parse(client, member, users) -> "ChatMember": - user = pyrogram.User._parse(client, users[member.user_id]) + user = types.User._parse(client, users[member.user_id]) invited_by = ( - pyrogram.User._parse(client, users[member.inviter_id]) + types.User._parse(client, users[member.inviter_id]) if getattr(member, "inviter_id", None) else None ) - if isinstance(member, (types.ChannelParticipant, types.ChannelParticipantSelf, types.ChatParticipant)): + if isinstance(member, (raw.types.ChannelParticipant, + raw.types.ChannelParticipantSelf, + raw.types.ChatParticipant)): return ChatMember( user=user, status="member", @@ -209,7 +211,7 @@ class ChatMember(Object): client=client ) - if isinstance(member, (types.ChannelParticipantCreator, types.ChatParticipantCreator)): + if isinstance(member, (raw.types.ChannelParticipantCreator, raw.types.ChatParticipantCreator)): return ChatMember( user=user, status="creator", @@ -217,7 +219,7 @@ class ChatMember(Object): client=client ) - if isinstance(member, types.ChatParticipantAdmin): + if isinstance(member, raw.types.ChatParticipantAdmin): return ChatMember( user=user, status="administrator", @@ -226,7 +228,7 @@ class ChatMember(Object): client=client ) - if isinstance(member, types.ChannelParticipantAdmin): + if isinstance(member, raw.types.ChannelParticipantAdmin): permissions = member.admin_rights return ChatMember( @@ -235,7 +237,7 @@ class ChatMember(Object): title=member.rank, joined_date=member.date, invited_by=invited_by, - promoted_by=pyrogram.User._parse(client, users[member.promoted_by]), + promoted_by=types.User._parse(client, users[member.promoted_by]), can_be_edited=member.can_edit, can_change_info=permissions.change_info, can_post_messages=permissions.post_messages, @@ -248,7 +250,7 @@ class ChatMember(Object): client=client ) - if isinstance(member, types.ChannelParticipantBanned): + if isinstance(member, raw.types.ChannelParticipantBanned): denied_permissions = member.banned_rights return ChatMember( @@ -257,7 +259,7 @@ class ChatMember(Object): until_date=denied_permissions.until_date, joined_date=member.date, is_member=not member.left, - restricted_by=pyrogram.User._parse(client, users[member.kicked_by]), + restricted_by=types.User._parse(client, users[member.kicked_by]), can_send_messages=not denied_permissions.send_messages, can_send_media_messages=not denied_permissions.send_media, can_send_stickers=not denied_permissions.send_stickers, diff --git a/pyrogram/client/types/user_and_chats/chat_permissions.py b/pyrogram/types/user_and_chats/chat_permissions.py similarity index 96% rename from pyrogram/client/types/user_and_chats/chat_permissions.py rename to pyrogram/types/user_and_chats/chat_permissions.py index 03d3e072..2d9306ad 100644 --- a/pyrogram/client/types/user_and_chats/chat_permissions.py +++ b/pyrogram/types/user_and_chats/chat_permissions.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api import types +from pyrogram import raw from ..object import Object @@ -103,8 +103,8 @@ class ChatPermissions(Object): self.can_pin_messages = can_pin_messages @staticmethod - def _parse(denied_permissions: types.ChatBannedRights) -> "ChatPermissions": - if isinstance(denied_permissions, types.ChatBannedRights): + def _parse(denied_permissions: "raw.types.ChatBannedRights") -> "ChatPermissions": + if isinstance(denied_permissions, raw.types.ChatBannedRights): return ChatPermissions( can_send_messages=not denied_permissions.send_messages, can_send_media_messages=not denied_permissions.send_media, diff --git a/pyrogram/client/types/user_and_chats/chat_photo.py b/pyrogram/types/user_and_chats/chat_photo.py similarity index 86% rename from pyrogram/client/types/user_and_chats/chat_photo.py rename to pyrogram/types/user_and_chats/chat_photo.py index 1966b1be..58a9fcc1 100644 --- a/pyrogram/client/types/user_and_chats/chat_photo.py +++ b/pyrogram/types/user_and_chats/chat_photo.py @@ -17,12 +17,13 @@ # along with Pyrogram. If not, see . from struct import pack +from typing import Union import pyrogram -from pyrogram.api import types -from pyrogram.client.ext import utils +from pyrogram import raw +from pyrogram.utils import encode_file_id from ..object import Object -from ...ext.utils import encode_file_id +from ... import utils class ChatPhoto(Object): @@ -41,7 +42,7 @@ class ChatPhoto(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, small_file_id: str, big_file_id: str ): @@ -51,8 +52,13 @@ class ChatPhoto(Object): self.big_file_id = big_file_id @staticmethod - def _parse(client, chat_photo: types.UserProfilePhoto or types.ChatPhoto, peer_id: int, peer_access_hash: int): - if not isinstance(chat_photo, (types.UserProfilePhoto, types.ChatPhoto)): + def _parse( + client, + chat_photo: Union["raw.types.UserProfilePhoto", "raw.types.ChatPhoto"], + peer_id: int, + peer_access_hash: int + ): + if not isinstance(chat_photo, (raw.types.UserProfilePhoto, raw.types.ChatPhoto)): return None if peer_access_hash is None: diff --git a/pyrogram/client/types/user_and_chats/chat_preview.py b/pyrogram/types/user_and_chats/chat_preview.py similarity index 79% rename from pyrogram/client/types/user_and_chats/chat_preview.py rename to pyrogram/types/user_and_chats/chat_preview.py index fa48a319..1a0f9c94 100644 --- a/pyrogram/client/types/user_and_chats/chat_preview.py +++ b/pyrogram/types/user_and_chats/chat_preview.py @@ -19,10 +19,9 @@ from typing import List import pyrogram -from pyrogram.api import types -from ..messages_and_media import Photo +from pyrogram import raw +from pyrogram import types from ..object import Object -from ..user_and_chats.user import User class ChatPreview(Object): @@ -38,22 +37,22 @@ class ChatPreview(Object): members_count (``int``): Chat members count. - photo (:obj:`Photo`, *optional*): + photo (:obj:`~pyrogram.types.Photo`, *optional*): Chat photo. - members (List of :obj:`User`, *optional*): + members (List of :obj:`~pyrogram.types.User`, *optional*): Preview of some of the chat members. """ def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, title: str, type: str, members_count: int, - photo: Photo = None, - members: List[User] = None + photo: "types.Photo" = None, + members: List["types.User"] = None ): super().__init__(client) @@ -64,15 +63,15 @@ class ChatPreview(Object): self.members = members @staticmethod - def _parse(client, chat_invite: types.ChatInvite) -> "ChatPreview": + def _parse(client, chat_invite: "raw.types.ChatInvite") -> "ChatPreview": return ChatPreview( title=chat_invite.title, type=("group" if not chat_invite.channel else "channel" if chat_invite.broadcast else "supergroup"), members_count=chat_invite.participants_count, - photo=Photo._parse(client, chat_invite.photo), - members=[User._parse(client, user) for user in chat_invite.participants] or None, + photo=types.Photo._parse(client, chat_invite.photo), + members=[types.User._parse(client, user) for user in chat_invite.participants] or None, client=client ) diff --git a/pyrogram/client/types/user_and_chats/dialog.py b/pyrogram/types/user_and_chats/dialog.py similarity index 83% rename from pyrogram/client/types/user_and_chats/dialog.py rename to pyrogram/types/user_and_chats/dialog.py index bbe06a2c..b0212a27 100644 --- a/pyrogram/client/types/user_and_chats/dialog.py +++ b/pyrogram/types/user_and_chats/dialog.py @@ -17,21 +17,20 @@ # along with Pyrogram. If not, see . import pyrogram - -from pyrogram.api import types +from pyrogram import raw +from pyrogram import types from ..object import Object -from ..user_and_chats import Chat -from ...ext import utils +from ... import utils class Dialog(Object): """A user's dialog. Parameters: - chat (:obj:`Chat `): + chat (:obj:`~pyrogram.types.Chat`): Conversation the dialog belongs to. - top_message (:obj:`Message`): + top_message (:obj:`~pyrogram.types.Message`): The last message sent in the dialog at this time. unread_messages_count (``int``): @@ -50,9 +49,9 @@ class Dialog(Object): def __init__( self, *, - client: "pyrogram.BaseClient" = None, - chat: Chat, - top_message: "pyrogram.Message", + client: "pyrogram.Client" = None, + chat: "types.Chat", + top_message: "types.Message", unread_messages_count: int, unread_mentions_count: int, unread_mark: bool, @@ -68,9 +67,9 @@ class Dialog(Object): self.is_pinned = is_pinned @staticmethod - def _parse(client, dialog: types.Dialog, messages, users, chats) -> "Dialog": + def _parse(client, dialog: "raw.types.Dialog", messages, users, chats) -> "Dialog": return Dialog( - chat=Chat._parse_dialog(client, dialog.peer, users, chats), + chat=types.Chat._parse_dialog(client, dialog.peer, users, chats), top_message=messages.get(utils.get_peer_id(dialog.peer)), unread_messages_count=dialog.unread_count, unread_mentions_count=dialog.unread_mentions_count, diff --git a/pyrogram/client/types/user_and_chats/restriction.py b/pyrogram/types/user_and_chats/restriction.py similarity index 93% rename from pyrogram/client/types/user_and_chats/restriction.py rename to pyrogram/types/user_and_chats/restriction.py index abf04b77..fd8b7a63 100644 --- a/pyrogram/client/types/user_and_chats/restriction.py +++ b/pyrogram/types/user_and_chats/restriction.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . -from pyrogram.api import types +from pyrogram import raw from ..object import Object @@ -42,7 +42,7 @@ class Restriction(Object): self.text = text @staticmethod - def _parse(restriction: types.RestrictionReason) -> "Restriction": + def _parse(restriction: "raw.types.RestrictionReason") -> "Restriction": return Restriction( platform=restriction.platform, reason=restriction.reason, diff --git a/pyrogram/client/types/user_and_chats/user.py b/pyrogram/types/user_and_chats/user.py similarity index 79% rename from pyrogram/client/types/user_and_chats/user.py rename to pyrogram/types/user_and_chats/user.py index f386e161..e9a95182 100644 --- a/pyrogram/client/types/user_and_chats/user.py +++ b/pyrogram/types/user_and_chats/user.py @@ -16,17 +16,49 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrogram. If not, see . +import html from typing import List import pyrogram -from pyrogram.api import types -from pyrogram.client.ext import Link -from .chat_photo import ChatPhoto -from .restriction import Restriction +from pyrogram import raw +from pyrogram import types from ..object import Object from ..update import Update +class Link(str): + HTML = "{text}" + MD = "[{text}]({url})" + + def __init__(self, url: str, text: str, style: str): + super().__init__() + + self.url = url + self.text = text + self.style = style + + @staticmethod + def format(url: str, text: str, style: str): + if style in ["md", "markdown"]: + fmt = Link.MD + elif style in ["combined", "html", None]: + fmt = Link.HTML + else: + raise ValueError(f"{style} is not a valid style/parse mode") + + return fmt.format(url=url, text=html.escape(text)) + + # noinspection PyArgumentList + def __new__(cls, url, text, style): + return str.__new__(cls, Link.format(url, text, style)) + + def __call__(self, other: str = None, *, style: str = None): + return Link.format(self.url, other or self.text, style or self.style) + + def __str__(self): + return Link.format(self.url, self.text, self.style) + + class User(Object, Update): """A Telegram user or bot. @@ -100,10 +132,10 @@ class User(Object, Update): phone_number (``str``, *optional*): User's phone number. - photo (:obj:`ChatPhoto `, *optional*): + photo (:obj:`~pyrogram.types.ChatPhoto`, *optional*): User's or bot's current profile photo. Suitable for downloads only. - restrictions (List of :obj:`Restriction`, *optional*): + restrictions (List of :obj:`~pyrogram.types.Restriction`, *optional*): The list of reasons why this bot might be unavailable to some users. This field is available only in case *is_restricted* is True. """ @@ -111,7 +143,7 @@ class User(Object, Update): def __init__( self, *, - client: "pyrogram.BaseClient" = None, + client: "pyrogram.Client" = None, id: int, is_self: bool = None, is_contact: bool = None, @@ -131,8 +163,8 @@ class User(Object, Update): language_code: str = None, dc_id: int = None, phone_number: str = None, - photo: ChatPhoto = None, - restrictions: List[Restriction] = None + photo: "types.ChatPhoto" = None, + restrictions: List["types.Restriction"] = None ): super().__init__(client) @@ -160,10 +192,10 @@ class User(Object, Update): @property def mention(self): - return Link("tg://user?id={}".format(self.id), self.first_name, self._client.parse_mode) + return Link(f"tg://user?id={self.id}", self.first_name, self._client.parse_mode) @staticmethod - def _parse(client, user: types.User) -> "User" or None: + def _parse(client, user: "raw.types.User") -> "User" or None: if user is None: return None @@ -185,22 +217,22 @@ class User(Object, Update): language_code=user.lang_code, dc_id=getattr(user.photo, "dc_id", None), phone_number=user.phone, - photo=ChatPhoto._parse(client, user.photo, user.id, user.access_hash), - restrictions=pyrogram.List([Restriction._parse(r) for r in user.restriction_reason]) or None, + photo=types.ChatPhoto._parse(client, user.photo, user.id, user.access_hash), + restrictions=types.List([types.Restriction._parse(r) for r in user.restriction_reason]) or None, client=client ) @staticmethod - def _parse_status(user_status: types.UpdateUserStatus, is_bot: bool = False): - if isinstance(user_status, types.UserStatusOnline): + def _parse_status(user_status: "raw.types.UpdateUserStatus", is_bot: bool = False): + if isinstance(user_status, raw.types.UserStatusOnline): status, date = "online", user_status.expires - elif isinstance(user_status, types.UserStatusOffline): + elif isinstance(user_status, raw.types.UserStatusOffline): status, date = "offline", user_status.was_online - elif isinstance(user_status, types.UserStatusRecently): + elif isinstance(user_status, raw.types.UserStatusRecently): status, date = "recently", None - elif isinstance(user_status, types.UserStatusLastWeek): + elif isinstance(user_status, raw.types.UserStatusLastWeek): status, date = "within_week", None - elif isinstance(user_status, types.UserStatusLastMonth): + elif isinstance(user_status, raw.types.UserStatusLastMonth): status, date = "within_month", None else: status, date = "long_time_ago", None @@ -224,7 +256,7 @@ class User(Object, Update): } @staticmethod - def _parse_user_status(client, user_status: types.UpdateUserStatus): + def _parse_user_status(client, user_status: "raw.types.UpdateUserStatus"): return User( id=user_status.user_id, **User._parse_status(user_status.status), @@ -232,7 +264,7 @@ class User(Object, Update): ) async def archive(self): - """Bound method *archive* of :obj:`User`. + """Bound method *archive* of :obj:`~pyrogram.types.User`. Use as a shortcut for: @@ -255,7 +287,7 @@ class User(Object, Update): return await self._client.archive_chats(self.id) async def unarchive(self): - """Bound method *unarchive* of :obj:`User`. + """Bound method *unarchive* of :obj:`~pyrogram.types.User`. Use as a shortcut for: @@ -278,7 +310,7 @@ class User(Object, Update): return await self._client.unarchive_chats(self.id) def block(self): - """Bound method *block* of :obj:`User`. + """Bound method *block* of :obj:`~pyrogram.types.User`. Use as a shortcut for: @@ -301,7 +333,7 @@ class User(Object, Update): return self._client.block_user(self.id) def unblock(self): - """Bound method *unblock* of :obj:`User`. + """Bound method *unblock* of :obj:`~pyrogram.types.User`. Use as a shortcut for: @@ -324,7 +356,7 @@ class User(Object, Update): return self._client.unblock_user(self.id) def get_common_chats(self): - """Bound method *get_common_chats* of :obj:`User`. + """Bound method *get_common_chats* of :obj:`~pyrogram.types.User`. Use as a shortcut for: diff --git a/pyrogram/client/ext/utils.py b/pyrogram/utils.py similarity index 58% rename from pyrogram/client/ext/utils.py rename to pyrogram/utils.py index 9359ff05..89ee7f6c 100644 --- a/pyrogram/client/ext/utils.py +++ b/pyrogram/utils.py @@ -18,16 +18,18 @@ import asyncio import base64 +import functools +import hashlib +import os import struct -import sys from concurrent.futures.thread import ThreadPoolExecutor +from getpass import getpass from typing import List from typing import Union -import pyrogram -from pyrogram.api.types import PeerUser, PeerChat, PeerChannel -from . import BaseClient -from ...api import types +from pyrogram import raw +from pyrogram import types +from pyrogram.scaffold import Scaffold def decode_file_id(s: str) -> bytes: @@ -83,18 +85,15 @@ def decode_file_ref(file_ref: str) -> bytes: return base64.urlsafe_b64decode(file_ref + "=" * (-len(file_ref) % 4)) -async def ainput(prompt: str = ""): - print(prompt, end="", flush=True) - +async def ainput(prompt: str = "", *, hide: bool = False): with ThreadPoolExecutor(1) as executor: - return (await asyncio.get_event_loop().run_in_executor( - executor, sys.stdin.readline - )).rstrip() + func = functools.partial(getpass if hide else input, prompt) + return await asyncio.get_event_loop().run_in_executor(executor, func) def get_offset_date(dialogs): for m in reversed(dialogs.messages): - if isinstance(m, types.MessageEmpty): + if isinstance(m, raw.types.MessageEmpty): continue else: return m.date @@ -106,32 +105,30 @@ def get_input_media_from_file_id( file_id_str: str, file_ref: str = None, expected_media_type: int = None -) -> Union[types.InputMediaPhoto, types.InputMediaDocument]: +) -> Union["raw.types.InputMediaPhoto", "raw.types.InputMediaDocument"]: try: decoded = decode_file_id(file_id_str) except Exception: - raise ValueError("Failed to decode file_id: {}".format(file_id_str)) + raise ValueError(f"Failed to decode file_id: {file_id_str}") else: media_type = decoded[0] if expected_media_type is not None: if media_type != expected_media_type: - media_type_str = BaseClient.MEDIA_TYPE_ID.get(media_type, None) - expected_media_type_str = BaseClient.MEDIA_TYPE_ID.get(expected_media_type, None) + media_type_str = Scaffold.MEDIA_TYPE_ID.get(media_type, None) + expected_media_type_str = Scaffold.MEDIA_TYPE_ID.get(expected_media_type, None) - raise ValueError( - 'Expected: "{}", got "{}" file_id instead'.format(expected_media_type_str, media_type_str) - ) + raise ValueError(f'Expected: "{expected_media_type_str}", got "{media_type_str}" file_id instead') if media_type in (0, 1, 14): - raise ValueError("This file_id can only be used for download: {}".format(file_id_str)) + raise ValueError(f"This file_id can only be used for download: {file_id_str}") if media_type == 2: unpacked = struct.unpack(" List["pyrogram.Message"]: +async def parse_messages(client, messages: "raw.types.messages.Messages", replies: int = 1) -> List["types.Message"]: users = {i.id: i for i in messages.users} chats = {i.id: i for i in messages.chats} if not messages.messages: - return pyrogram.List() + return types.List() parsed_messages = [] for message in messages.messages: - parsed_messages.append(await pyrogram.Message._parse(client, message, users, chats, replies=0)) + parsed_messages.append(await types.Message._parse(client, message, users, chats, replies=0)) if replies: messages_with_replies = {i.id: getattr(i, "reply_to_msg_id", None) for i in messages.messages} @@ -183,10 +180,10 @@ async def parse_messages(client, messages: types.messages.Messages, replies: int if reply.message_id == reply_id: message.reply_to_message = reply - return pyrogram.List(parsed_messages) + return types.List(parsed_messages) -def parse_deleted_messages(client, update) -> List["pyrogram.Message"]: +def parse_deleted_messages(client, update) -> List["types.Message"]: messages = update.messages channel_id = getattr(update, "channel_id", None) @@ -194,9 +191,9 @@ def parse_deleted_messages(client, update) -> List["pyrogram.Message"]: for message in messages: parsed_messages.append( - pyrogram.Message( + types.Message( message_id=message, - chat=pyrogram.Chat( + chat=types.Chat( id=get_channel_id(channel_id), type="channel", client=client @@ -205,14 +202,14 @@ def parse_deleted_messages(client, update) -> List["pyrogram.Message"]: ) ) - return pyrogram.List(parsed_messages) + return types.List(parsed_messages) -def unpack_inline_message_id(inline_message_id: str) -> types.InputBotInlineMessageID: +def unpack_inline_message_id(inline_message_id: str) -> "raw.types.InputBotInlineMessageID": r = inline_message_id + "=" * (-len(inline_message_id) % 4) - r = struct.unpack(" int: - if isinstance(peer, PeerUser): +def get_peer_id(peer: raw.base.Peer) -> int: + if isinstance(peer, raw.types.PeerUser): return peer.user_id - if isinstance(peer, PeerChat): + if isinstance(peer, raw.types.PeerChat): return -peer.chat_id - if isinstance(peer, PeerChannel): + if isinstance(peer, raw.types.PeerChannel): return MAX_CHANNEL_ID - peer.channel_id - raise ValueError("Peer type invalid: {}".format(peer)) + raise ValueError(f"Peer type invalid: {peer}") def get_peer_type(peer_id: int) -> str: @@ -248,8 +245,91 @@ def get_peer_type(peer_id: int) -> str: elif 0 < peer_id <= MAX_USER_ID: return "user" - raise ValueError("Peer id invalid: {}".format(peer_id)) + raise ValueError(f"Peer id invalid: {peer_id}") def get_channel_id(peer_id: int) -> int: return MAX_CHANNEL_ID - peer_id + + +def btoi(b: bytes) -> int: + return int.from_bytes(b, "big") + + +def itob(i: int) -> bytes: + return i.to_bytes(256, "big") + + +def sha256(data: bytes) -> bytes: + return hashlib.sha256(data).digest() + + +def xor(a: bytes, b: bytes) -> bytes: + return bytes(i ^ j for i, j in zip(a, b)) + + +def compute_password_hash(algo: raw.types.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow, + password: str) -> bytes: + hash1 = sha256(algo.salt1 + password.encode() + algo.salt1) + hash2 = sha256(algo.salt2 + hash1 + algo.salt2) + hash3 = hashlib.pbkdf2_hmac("sha512", hash2, algo.salt1, 100000) + + return sha256(algo.salt2 + hash3 + algo.salt2) + + +# noinspection PyPep8Naming +def compute_password_check(r: raw.types.account.Password, password: str) -> raw.types.InputCheckPasswordSRP: + algo = r.current_algo + + p_bytes = algo.p + p = btoi(algo.p) + + g_bytes = itob(algo.g) + g = algo.g + + B_bytes = r.srp_B + B = btoi(B_bytes) + + srp_id = r.srp_id + + x_bytes = compute_password_hash(algo, password) + x = btoi(x_bytes) + + g_x = pow(g, x, p) + + k_bytes = sha256(p_bytes + g_bytes) + k = btoi(k_bytes) + + kg_x = (k * g_x) % p + + while True: + a_bytes = os.urandom(256) + a = btoi(a_bytes) + + A = pow(g, a, p) + A_bytes = itob(A) + + u = btoi(sha256(A_bytes + B_bytes)) + + if u > 0: + break + + g_b = (B - kg_x) % p + + ux = u * x + a_ux = a + ux + S = pow(g_b, a_ux, p) + S_bytes = itob(S) + + K_bytes = sha256(S_bytes) + + M1_bytes = sha256( + xor(sha256(p_bytes), sha256(g_bytes)) + + sha256(algo.salt1) + + sha256(algo.salt2) + + A_bytes + + B_bytes + + K_bytes + ) + + return raw.types.InputCheckPasswordSRP(srp_id=srp_id, A=A_bytes, M1=M1_bytes) diff --git a/requirements.txt b/requirements.txt index 1af97061..72ed1aa5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ pyaes==1.6.1 pysocks==1.7.1 -async_lru==1.0.1 -async_generator==1.10 \ No newline at end of file +async_lru==1.0.2 \ No newline at end of file diff --git a/setup.py b/setup.py index 0e9bb2db..3b88bab7 100644 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ with open("README.md", encoding="utf-8") as f: class Clean(Command): DIST = ["./build", "./dist", "./Pyrogram.egg-info"] - API = ["pyrogram/errors/exceptions", "pyrogram/api/functions", "pyrogram/api/types", "pyrogram/api/all.py"] + API = ["pyrogram/errors/exceptions", "pyrogram/raw/functions", "pyrogram/raw/types", "pyrogram/raw/all.py"] DOCS = [ "docs/source/telegram", "docs/build", "docs/source/api/methods", "docs/source/api/types", "docs/source/api/bound-methods" @@ -139,17 +139,17 @@ setup( author_email="dan@pyrogram.org", license="LGPLv3+", classifiers=[ - "Development Status :: 4 - Beta", + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Natural Language :: English", "License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", @@ -167,11 +167,11 @@ setup( "Source": "https://github.com/pyrogram/pyrogram", "Documentation": "https://docs.pyrogram.org", }, - python_requires="~=3.5", + python_requires="~=3.6", packages=find_packages(exclude=["compiler*"]), package_data={ - "pyrogram.client.ext": ["mime.types"], - "pyrogram.client.storage": ["schema.sql"] + "pyrogram": ["mime.types"], + "pyrogram.storage": ["schema.sql"] }, zip_safe=False, install_requires=requires,